mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 10:04:00 +08:00
initial CVS import
This commit is contained in:
commit
ba63b7daca
38
CREDITS
Normal file
38
CREDITS
Normal file
@ -0,0 +1,38 @@
|
||||
The following people have contributed directly or indirectly
|
||||
to the ntfs-3g project.
|
||||
|
||||
Please let ntfs-3g-devel@lists.sf.net know if you believe
|
||||
someone is missing, or if you prefer not to be listed.
|
||||
|
||||
Dominique L Bouix
|
||||
Gergely Erdelyi
|
||||
Anton Altaparmakov
|
||||
Peter Boross
|
||||
Don Bright
|
||||
Mario Emmenlauer
|
||||
Yuval Fledel
|
||||
Kano from Kanotix
|
||||
Roland Kletzing
|
||||
Maarten Lankhorst
|
||||
Gergely Madarasz
|
||||
Patrick McLean
|
||||
Florent Mertens
|
||||
Yura Pakhuchiy
|
||||
Miklos Szeredi
|
||||
Bartosz Taudul
|
||||
Zhanglinbao
|
||||
Wade Fitzpatrick
|
||||
Carsten Einig
|
||||
Adam Cecile
|
||||
Bruno Damour
|
||||
Ales Fruman
|
||||
Curt McDowell
|
||||
Thomas Franken
|
||||
Jonatan Lambert
|
||||
Klaus Knopper
|
||||
Zhanglinbao
|
||||
Ismail Donmez
|
||||
Laszlo Dvornik
|
||||
Pallaghy Ajtony
|
||||
Szabolcs Szakacsits
|
||||
|
17
Makefile.am
Normal file
17
Makefile.am
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
SUBDIRS = include libntfs-3g src
|
||||
|
||||
EXTRA_DIST = AUTHORS CREDITS COPYING INSTALL NEWS README autogen.sh
|
||||
AUTOMAKE_OPTIONS = gnu
|
||||
|
||||
MAINTAINERCLEANFILES = configure Makefile.in aclocal.m4 compile depcomp \
|
||||
install-sh ltmain.sh missing config.guess config.sub config.h.in INSTALL
|
||||
|
||||
libtool: $(LIBTOOL_DEPS)
|
||||
$(SHELL) ./config.status --recheck
|
||||
|
||||
strip:
|
||||
(cd src && $(MAKE) strip) || exit 1;
|
||||
|
||||
libs:
|
||||
(cd libntfs-3g && $(MAKE) libs) || exit 1;
|
63
README
Normal file
63
README
Normal file
@ -0,0 +1,63 @@
|
||||
|
||||
INTRODUCTION
|
||||
============
|
||||
|
||||
The ntfs-3g driver is an open source, freely available read/write NTFS
|
||||
driver, which provides safe and fast handling of the Windows XP, Windows
|
||||
Server 2003 and Windows 2000 filesystems. Almost the full POSIX filesystem
|
||||
functionality is supported, the major exceptions are changing the file
|
||||
ownerships and the access rights.
|
||||
|
||||
The purpose of the project is to develop, continuously quality test and
|
||||
support a trustable, featureful and high performance solution for hardware
|
||||
platforms and operating systems whose users need to reliably interoperate
|
||||
with NTFS. Besides this practical goal, the project also aims to explore
|
||||
the limits of the hybrid, kernel/user space filesystem driver approach,
|
||||
performance, reliability and feature richness per invested effort wise.
|
||||
|
||||
The driver currently is in BETA status, which means that we weren't
|
||||
reported and haven't found any data corruption or loss during ordinary
|
||||
driver use and in our extensive quality testing before release of the
|
||||
latest version of ntfs-3g, however we are aware of some usability issues
|
||||
and driver restrictions which are all documented and planned to be resolved
|
||||
in the future.
|
||||
|
||||
You can find news, technical answers, problem submission instructions,
|
||||
performance evaluation and other informations on the project web site:
|
||||
|
||||
http://www.ntfs-3g.org
|
||||
|
||||
|
||||
QUICK INSTALLATION
|
||||
==================
|
||||
|
||||
Make sure you have the basic Linux development tools and the full FUSE
|
||||
package (http://fuse.sourceforge.net) is already installed correctly on
|
||||
the computer. Then type:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install # or 'sudo make install' if you aren't root.
|
||||
|
||||
|
||||
USAGE
|
||||
=====
|
||||
|
||||
If there was no error during installation then the NTFS volume can be
|
||||
read-write mounted for everybody the following way (unmount the volume if
|
||||
it was already mounted, and replace /dev/hda1 and /mnt/windows, if needed):
|
||||
|
||||
ntfs-3g /dev/hda1 /mnt/windows
|
||||
|
||||
You may also need to set the 'locale' option to make all files with national
|
||||
characters visible. Replace the below hu_HU.utf8 with the appropriate setting.
|
||||
|
||||
ntfs-3g /dev/hda1 /mnt/windows -o locale=hu_HU.utf8
|
||||
|
||||
Please see the ntfs-3g manual page for more options and examples.
|
||||
|
||||
You can also make NTFS to be mounted during boot by putting the below
|
||||
line at the end of the /etc/fstab file:
|
||||
|
||||
/dev/hda1 /mnt/windows ntfs-3g defaults 0 0
|
||||
|
22
autogen.sh
Executable file
22
autogen.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
# Run this to generate configure, Makefile.in's, etc
|
||||
|
||||
(autoreconf --version) < /dev/null > /dev/null 2>&1 || {
|
||||
(autoconf --version) < /dev/null > /dev/null 2>&1 || {
|
||||
echo
|
||||
echo "**Error**: You must have the GNU Build System (autoconf, automake, "
|
||||
echo "libtool, etc) to update the ntfs-3g build system. Download the "
|
||||
echo "appropriate packages for your distribution, or get the source "
|
||||
echo "tar balls from ftp://ftp.gnu.org/pub/gnu/."
|
||||
exit 1
|
||||
}
|
||||
echo
|
||||
echo "**Error**: Your version of autoconf is too old (you need at least 2.57)"
|
||||
echo "to update the ntfs-3g build system. Download the appropriate "
|
||||
echo "updated package for your distribution, or get the source tar ball "
|
||||
echo "from ftp://ftp.gnu.org/pub/gnu/."
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo Running autoreconf --verbose --install
|
||||
autoreconf --force --verbose --install
|
169
configure.ac
Normal file
169
configure.ac
Normal file
@ -0,0 +1,169 @@
|
||||
#
|
||||
# configure.ac - Source file to generate "./configure" to prepare package for
|
||||
# compilation.
|
||||
#
|
||||
# Copyright (c) 2000-2006 Anton Altaparmakov
|
||||
# Copyright (c) 2003 Jan Kratochvil
|
||||
# Copyright (c) 2005-2006 Szabolcs Szakacsits
|
||||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT([ntfs-3g],[0.20061031-BETA],[ntfs-3g-devel@lists.sf.net])
|
||||
|
||||
AC_CANONICAL_HOST([])
|
||||
AC_CANONICAL_TARGET([])
|
||||
AC_CONFIG_SRCDIR([config.h.in])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AM_INIT_AUTOMAKE
|
||||
AM_MAINTAINER_MODE
|
||||
AM_ENABLE_SHARED
|
||||
AM_ENABLE_STATIC
|
||||
|
||||
AC_PREFIX_DEFAULT(/usr/local)
|
||||
if test "x$prefix" = "xNONE"; then
|
||||
prefix=$ac_default_prefix
|
||||
ac_configure_args="$ac_configure_args --prefix $prefix"
|
||||
fi
|
||||
|
||||
# Command-line options.
|
||||
AC_ARG_ENABLE(debug,
|
||||
AS_HELP_STRING(--enable-debug,enable additional debugging code and
|
||||
output), ,
|
||||
enable_debug=no
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(really-static,
|
||||
AS_HELP_STRING(--enable-really-static,create static binaries
|
||||
for the utilities), ,
|
||||
enable_really_static=no
|
||||
)
|
||||
AM_CONDITIONAL(REALLYSTATIC, test "$enable_really_static" = yes)
|
||||
|
||||
AC_ARG_ENABLE(warnings,
|
||||
AS_HELP_STRING(--enable-warnings,enable additional compiler warnings), ,
|
||||
enable_warnings=no
|
||||
)
|
||||
|
||||
# Use GNU extensions if available.
|
||||
AC_GNU_SOURCE
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_PROG_INSTALL
|
||||
AC_PATH_PROG(RM, rm, rm)
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
# Libraries often install their metadata .pc files in directories not searched
|
||||
# by pkg-config. Let's workaround this.
|
||||
export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/usr/lib/pkgconfig:/opt/gnome/lib/pkgconfig:/usr/share/pkgconfig:/usr/local/lib/pkgconfig:$prefix/lib/pkgconfig:/opt/gnome/share/pkgconfig:/usr/local/share/pkgconfig
|
||||
|
||||
# Enable large file support.
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
case "$target_os" in
|
||||
linux*)
|
||||
PKG_CHECK_MODULES(FUSE_MODULE, fuse >= 2.5.0, [ compile_fuse_module=true ],
|
||||
[
|
||||
AC_MSG_ERROR([ntfs-3g requires FUSE >= 2.5.0. Please see http://fuse.sf.net/ or install __all__ the precompiled fuse packages.])
|
||||
]);;
|
||||
*)
|
||||
AC_MSG_ERROR([ntfs-3g can be built only under Linux.])
|
||||
;;
|
||||
esac
|
||||
|
||||
# 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)
|
||||
|
||||
# Add our compiler switches not discarding 'CFLAGS' as they may have been
|
||||
# passed to us by rpmbuild(8).
|
||||
# We add -Wall to enable some compiler warnings.
|
||||
CFLAGS="$CFLAGS -Wall"
|
||||
|
||||
# Add lots of extra warnings if --enable-warnings was specified.
|
||||
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"
|
||||
fi
|
||||
|
||||
# Add debugging switches if --enable-debug was specified.
|
||||
if test "$enable_debug" = "yes"; then
|
||||
CFLAGS="$CFLAGS -ggdb3 -DDEBUG"
|
||||
fi
|
||||
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CPPFLAGS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(LIBS)
|
||||
|
||||
AC_SUBST(LIBNTFS_3G_CFLAGS)
|
||||
|
||||
AC_SUBST(AUTODIRS)
|
||||
|
||||
# Checks for libraries.
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
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 \
|
||||
endian.h byteswap.h sys/byteorder.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 sys/sysmacros.h linux/major.h linux/fd.h linux/hdreg.h \
|
||||
machine/endian.h gcrypt.h windows.h gnutls/pkcs12.h syslog.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_STDBOOL
|
||||
AC_C_BIGENDIAN(,
|
||||
[AC_DEFINE([WORDS_LITTLEENDIAN], 1,
|
||||
[Define to 1 if your processor stores words with the least significant
|
||||
byte first (like Intel and VAX, unlike Motorola and SPARC).])]
|
||||
,)
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_STRUCT_ST_BLOCKS
|
||||
AC_CHECK_MEMBERS([struct stat.st_rdev])
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_GETMNTENT
|
||||
AC_FUNC_MBRTOWC
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_STAT
|
||||
AC_FUNC_STRFTIME
|
||||
AC_FUNC_UTIME_NULL
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS([atexit basename dup2 fdatasync getopt_long hasmntopt mbsinit \
|
||||
memmove memset realpath regcomp setlocale setxattr strcasecmp strchr \
|
||||
strdup strerror strnlen strtol strtoul sysconf utime])
|
||||
|
||||
# Makefiles to be created by configure.
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
include/Makefile
|
||||
include/ntfs-3g/Makefile
|
||||
libntfs-3g/Makefile
|
||||
src/Makefile
|
||||
src/ntfs-3g.8
|
||||
])
|
||||
AC_OUTPUT
|
3
include/Makefile.am
Normal file
3
include/Makefile.am
Normal file
@ -0,0 +1,3 @@
|
||||
SUBDIRS = ntfs-3g
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
34
include/ntfs-3g/Makefile.am
Normal file
34
include/ntfs-3g/Makefile.am
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
linux_ntfsincludedir = $(includedir)/ntfs-3g
|
||||
linux_ntfsinclude_HEADERS = \
|
||||
attrib.h \
|
||||
attrlist.h \
|
||||
bitmap.h \
|
||||
bootsect.h \
|
||||
collate.h \
|
||||
compat.h \
|
||||
compress.h \
|
||||
debug.h \
|
||||
device.h \
|
||||
device_io.h \
|
||||
dir.h \
|
||||
endians.h \
|
||||
index.h \
|
||||
inode.h \
|
||||
layout.h \
|
||||
lcnalloc.h \
|
||||
list.h \
|
||||
logfile.h \
|
||||
logging.h \
|
||||
mft.h \
|
||||
mst.h \
|
||||
ntfstime.h \
|
||||
runlist.h \
|
||||
security.h \
|
||||
support.h \
|
||||
types.h \
|
||||
unistr.h \
|
||||
version.h \
|
||||
volume.h
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
359
include/ntfs-3g/attrib.h
Normal file
359
include/ntfs-3g/attrib.h
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* attrib.h - Exports for attribute handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_ATTRIB_H
|
||||
#define _NTFS_ATTRIB_H
|
||||
|
||||
/* Forward declarations */
|
||||
typedef struct _ntfs_attr ntfs_attr;
|
||||
typedef struct _ntfs_attr_search_ctx ntfs_attr_search_ctx;
|
||||
|
||||
#include "types.h"
|
||||
#include "inode.h"
|
||||
#include "unistr.h"
|
||||
#include "runlist.h"
|
||||
#include "volume.h"
|
||||
#include "debug.h"
|
||||
#include "logging.h"
|
||||
|
||||
extern ntfschar AT_UNNAMED[];
|
||||
|
||||
/**
|
||||
* enum ntfs_lcn_special_values - special return values for ntfs_*_vcn_to_lcn()
|
||||
*
|
||||
* Special return values for ntfs_rl_vcn_to_lcn() and ntfs_attr_vcn_to_lcn().
|
||||
*
|
||||
* TODO: Describe them.
|
||||
*/
|
||||
typedef enum {
|
||||
LCN_HOLE = -1, /* Keep this as highest value or die! */
|
||||
LCN_RL_NOT_MAPPED = -2,
|
||||
LCN_ENOENT = -3,
|
||||
LCN_EINVAL = -4,
|
||||
LCN_EIO = -5,
|
||||
} ntfs_lcn_special_values;
|
||||
|
||||
/**
|
||||
* struct ntfs_attr_search_ctx - search context used in attribute search functions
|
||||
* @mrec: buffer containing mft record to search
|
||||
* @attr: attribute record in @mrec where to begin/continue search
|
||||
* @is_first: if true lookup_attr() begins search with @attr, else after @attr
|
||||
*
|
||||
* Structure must be initialized to zero before the first call to one of the
|
||||
* attribute search functions. Initialize @mrec to point to the mft record to
|
||||
* search, and @attr to point to the first attribute within @mrec (not necessary
|
||||
* if calling the _first() functions), and set @is_first to TRUE (not necessary
|
||||
* if calling the _first() functions).
|
||||
*
|
||||
* If @is_first is TRUE, the search begins with @attr. If @is_first is FALSE,
|
||||
* the search begins after @attr. This is so that, after the first call to one
|
||||
* of the search attribute functions, we can call the function again, without
|
||||
* any modification of the search context, to automagically get the next
|
||||
* matching attribute.
|
||||
*/
|
||||
struct _ntfs_attr_search_ctx {
|
||||
MFT_RECORD *mrec;
|
||||
ATTR_RECORD *attr;
|
||||
BOOL is_first;
|
||||
ntfs_inode *ntfs_ino;
|
||||
ATTR_LIST_ENTRY *al_entry;
|
||||
ntfs_inode *base_ntfs_ino;
|
||||
MFT_RECORD *base_mrec;
|
||||
ATTR_RECORD *base_attr;
|
||||
};
|
||||
|
||||
extern void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
|
||||
MFT_RECORD *mrec);
|
||||
extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
const VCN lowest_vcn, const u8 *val, const u32 val_len,
|
||||
ntfs_attr_search_ctx *ctx);
|
||||
|
||||
extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
|
||||
/**
|
||||
* ntfs_attrs_walk - syntactic sugar for walking all attributes in an inode
|
||||
* @ctx: initialised attribute search context
|
||||
*
|
||||
* Syntactic sugar for walking attributes in an inode.
|
||||
*
|
||||
* Return 0 on success and -1 on error with errno set to the error code from
|
||||
* ntfs_attr_lookup().
|
||||
*
|
||||
* Example: When you want to enumerate all attributes in an open ntfs inode
|
||||
* @ni, you can simply do:
|
||||
*
|
||||
* int err;
|
||||
* ntfs_attr_search_ctx *ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
* if (!ctx)
|
||||
* // Error code is in errno. Handle this case.
|
||||
* while (!(err = ntfs_attrs_walk(ctx))) {
|
||||
* ATTR_RECORD *attr = ctx->attr;
|
||||
* // attr now contains the next attribute. Do whatever you want
|
||||
* // with it and then just continue with the while loop.
|
||||
* }
|
||||
* if (err && errno != ENOENT)
|
||||
* // Ooops. An error occurred! You should handle this case.
|
||||
* // Now finished with all attributes in the inode.
|
||||
*/
|
||||
static __inline__ int ntfs_attrs_walk(ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
return ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0,
|
||||
NULL, 0, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* struct ntfs_attr - ntfs in memory non-resident attribute structure
|
||||
* @rl: if not NULL, the decompressed runlist
|
||||
* @ni: base ntfs inode to which this attribute belongs
|
||||
* @type: attribute type
|
||||
* @name: Unicode name of the attribute
|
||||
* @name_len: length of @name in Unicode characters
|
||||
* @state: NTFS attribute specific flags describing this attribute
|
||||
* @allocated_size: copy from the attribute record
|
||||
* @data_size: copy from the attribute record
|
||||
* @initialized_size: copy from the attribute record
|
||||
* @compressed_size: copy from the attribute record
|
||||
* @compression_block_size: size of a compression block (cb)
|
||||
* @compression_block_size_bits: log2 of the size of a cb
|
||||
* @compression_block_clusters: number of clusters per cb
|
||||
*
|
||||
* This structure exists purely to provide a mechanism of caching the runlist
|
||||
* of an attribute. If you want to operate on a particular attribute extent,
|
||||
* you should not be using this structure at all. If you want to work with a
|
||||
* resident attribute, you should not be using this structure at all. As a
|
||||
* fail-safe check make sure to test NAttrNonResident() and if it is false, you
|
||||
* know you shouldn't be using this structure.
|
||||
*
|
||||
* If you want to work on a resident attribute or on a specific attribute
|
||||
* extent, you should use ntfs_lookup_attr() to retrieve the attribute (extent)
|
||||
* record, edit that, and then write back the mft record (or set the
|
||||
* corresponding ntfs inode dirty for delayed write back).
|
||||
*
|
||||
* @rl is the decompressed runlist of the attribute described by this
|
||||
* structure. Obviously this only makes sense if the attribute is not resident,
|
||||
* i.e. NAttrNonResident() is true. If the runlist hasn't been decompressed yet
|
||||
* @rl is NULL, so be prepared to cope with @rl == NULL.
|
||||
*
|
||||
* @ni is the base ntfs inode of the attribute described by this structure.
|
||||
*
|
||||
* @type is the attribute type (see layout.h for the definition of ATTR_TYPES),
|
||||
* @name and @name_len are the little endian Unicode name and the name length
|
||||
* in Unicode characters of the attribute, respectively.
|
||||
*
|
||||
* @state contains NTFS attribute specific flags describing this attribute
|
||||
* structure. See ntfs_attr_state_bits above.
|
||||
*/
|
||||
struct _ntfs_attr {
|
||||
runlist_element *rl;
|
||||
ntfs_inode *ni;
|
||||
ATTR_TYPES type;
|
||||
ntfschar *name;
|
||||
u32 name_len;
|
||||
unsigned long state;
|
||||
s64 allocated_size;
|
||||
s64 data_size;
|
||||
s64 initialized_size;
|
||||
s64 compressed_size;
|
||||
u32 compression_block_size;
|
||||
u8 compression_block_size_bits;
|
||||
u8 compression_block_clusters;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum ntfs_attr_state_bits - bits for the state field in the ntfs_attr structure
|
||||
*/
|
||||
typedef enum {
|
||||
NA_Initialized, /* 1: structure is initialized. */
|
||||
NA_NonResident, /* 1: Attribute is not resident. */
|
||||
} ntfs_attr_state_bits;
|
||||
|
||||
#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state)
|
||||
#define set_nattr_flag(na, flag) set_bit(NA_##flag, (na)->state)
|
||||
#define clear_nattr_flag(na, flag) clear_bit(NA_##flag, (na)->state)
|
||||
|
||||
#define NAttrInitialized(na) test_nattr_flag(na, Initialized)
|
||||
#define NAttrSetInitialized(na) set_nattr_flag(na, Initialized)
|
||||
#define NAttrClearInitialized(na) clear_nattr_flag(na, Initialized)
|
||||
|
||||
#define NAttrNonResident(na) test_nattr_flag(na, NonResident)
|
||||
#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident)
|
||||
#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident)
|
||||
|
||||
#define GenNAttrIno(func_name,flag) \
|
||||
static inline int NAttr##func_name(ntfs_attr *na) \
|
||||
{ \
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) \
|
||||
return (na->ni->flags & FILE_ATTR_##flag); \
|
||||
return 0; \
|
||||
} \
|
||||
static inline void NAttrSet##func_name(ntfs_attr *na) \
|
||||
{ \
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) \
|
||||
na->ni->flags |= FILE_ATTR_##flag; \
|
||||
else \
|
||||
ntfs_log_trace("BUG! Should be called only for "\
|
||||
"unnamed data attribute.\n"); \
|
||||
} \
|
||||
static inline void NAttrClear##func_name(ntfs_attr *na) \
|
||||
{ \
|
||||
if (na->type == AT_DATA && na->name == AT_UNNAMED) \
|
||||
na->ni->flags &= ~FILE_ATTR_##flag; \
|
||||
}
|
||||
|
||||
GenNAttrIno(Compressed, COMPRESSED)
|
||||
GenNAttrIno(Encrypted, ENCRYPTED)
|
||||
GenNAttrIno(Sparse, SPARSE_FILE)
|
||||
|
||||
/**
|
||||
* union attr_val - Union of all known attribute values
|
||||
*
|
||||
* For convenience. Used in the attr structure.
|
||||
*/
|
||||
typedef union {
|
||||
u8 _default; /* Unnamed u8 to serve as default when just using
|
||||
a_val without specifying any of the below. */
|
||||
STANDARD_INFORMATION std_inf;
|
||||
ATTR_LIST_ENTRY al_entry;
|
||||
FILE_NAME_ATTR filename;
|
||||
OBJECT_ID_ATTR obj_id;
|
||||
SECURITY_DESCRIPTOR_ATTR sec_desc;
|
||||
VOLUME_NAME vol_name;
|
||||
VOLUME_INFORMATION vol_inf;
|
||||
DATA_ATTR data;
|
||||
INDEX_ROOT index_root;
|
||||
INDEX_BLOCK index_blk;
|
||||
BITMAP_ATTR bmp;
|
||||
REPARSE_POINT reparse;
|
||||
EA_INFORMATION ea_inf;
|
||||
EA_ATTR ea;
|
||||
PROPERTY_SET property_set;
|
||||
LOGGED_UTILITY_STREAM logged_util_stream;
|
||||
EFS_ATTR_HEADER efs;
|
||||
} attr_val;
|
||||
|
||||
extern void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
|
||||
const BOOL compressed, const BOOL encrypted, const BOOL sparse,
|
||||
const s64 allocated_size, const s64 data_size,
|
||||
const s64 initialized_size, const s64 compressed_size,
|
||||
const u8 compression_unit);
|
||||
|
||||
extern ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern void ntfs_attr_close(ntfs_attr *na);
|
||||
|
||||
extern s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count,
|
||||
void *b);
|
||||
extern s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count,
|
||||
const void *b);
|
||||
|
||||
extern void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
|
||||
ntfschar *name, u32 name_len, s64 *data_size);
|
||||
|
||||
extern s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos,
|
||||
const s64 bk_cnt, const u32 bk_size, void *dst);
|
||||
extern s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos,
|
||||
s64 bk_cnt, const u32 bk_size, void *src);
|
||||
|
||||
extern int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn);
|
||||
extern int ntfs_attr_map_whole_runlist(ntfs_attr *na);
|
||||
|
||||
extern LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn);
|
||||
extern runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn);
|
||||
|
||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type, const s64 size);
|
||||
extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||
const ATTR_TYPES type);
|
||||
|
||||
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,
|
||||
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,
|
||||
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, u8 *val, s64 size);
|
||||
extern int ntfs_attr_rm(ntfs_attr *na);
|
||||
|
||||
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
|
||||
|
||||
extern int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
|
||||
const u32 new_size);
|
||||
|
||||
extern int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni);
|
||||
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);
|
||||
|
||||
// FIXME / TODO: Above here the file is cleaned up. (AIA)
|
||||
/**
|
||||
* get_attribute_value_length - return the length of the value of an attribute
|
||||
* @a: pointer to a buffer containing the attribute record
|
||||
*
|
||||
* Return the byte size of the attribute value of the attribute @a (as it
|
||||
* would be after eventual decompression and filling in of holes if sparse).
|
||||
* If we return 0, check errno. If errno is 0 the actual length was 0,
|
||||
* otherwise errno describes the error.
|
||||
*
|
||||
* FIXME: Describe possible errnos.
|
||||
*/
|
||||
s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a);
|
||||
|
||||
/**
|
||||
* get_attribute_value - return the attribute value of an attribute
|
||||
* @vol: volume on which the attribute is present
|
||||
* @a: attribute to get the value of
|
||||
* @b: destination buffer for the attribute value
|
||||
*
|
||||
* Make a copy of the attribute value of the attribute @a into the destination
|
||||
* buffer @b. Note, that the size of @b has to be at least equal to the value
|
||||
* returned by get_attribute_value_length(@a).
|
||||
*
|
||||
* Return number of bytes copied. If this is zero check errno. If errno is 0
|
||||
* then nothing was read due to a zero-length attribute value, otherwise
|
||||
* errno describes the error.
|
||||
*/
|
||||
s64 ntfs_get_attribute_value(const ntfs_volume *vol, const ATTR_RECORD *a,
|
||||
u8 *b);
|
||||
|
||||
void ntfs_attr_name_free(char **name);
|
||||
char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len);
|
||||
|
||||
int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
|
||||
u32 name_len);
|
||||
|
||||
#endif /* defined _NTFS_ATTRIB_H */
|
||||
|
51
include/ntfs-3g/attrlist.h
Normal file
51
include/ntfs-3g/attrlist.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* attrlist.h - Exports for attribute list attribute handling.
|
||||
* Originated from Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
*
|
||||
* 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_ATTRLIST_H
|
||||
#define _NTFS_ATTRLIST_H
|
||||
|
||||
#include "attrib.h"
|
||||
|
||||
extern int ntfs_attrlist_need(ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr);
|
||||
extern int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx);
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_mark_dirty - set the attribute list dirty
|
||||
* @ni: ntfs inode which base inode contain dirty attribute list
|
||||
*
|
||||
* Set the attribute list dirty so it is written out later (at the latest at
|
||||
* ntfs_inode_close() time).
|
||||
*
|
||||
* This function cannot fail.
|
||||
*/
|
||||
static __inline__ void ntfs_attrlist_mark_dirty(ntfs_inode *ni)
|
||||
{
|
||||
if (ni->nr_extents == -1)
|
||||
NInoAttrListSetDirty(ni->base_ni);
|
||||
else
|
||||
NInoAttrListSetDirty(ni);
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_ATTRLIST_H */
|
74
include/ntfs-3g/bitmap.h
Normal file
74
include/ntfs-3g/bitmap.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* bitmap.h - Exports for bitmap handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
*
|
||||
* 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_BITMAP_H
|
||||
#define _NTFS_BITMAP_H
|
||||
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
|
||||
/*
|
||||
* NOTES:
|
||||
*
|
||||
* - Operations are 8-bit only to ensure the functions work both on little
|
||||
* and big endian machines! So don't make them 32-bit ops!
|
||||
* - bitmap starts at bit = 0 and ends at bit = bitmap size - 1.
|
||||
* - _Caller_ has to make sure that the bit to operate on is less than the
|
||||
* size of the bitmap.
|
||||
*/
|
||||
|
||||
extern void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value);
|
||||
extern char ntfs_bit_get(const u8 *bitmap, const u64 bit);
|
||||
extern char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value);
|
||||
extern int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count);
|
||||
extern int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count);
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_set_bit - set a bit in a bitmap
|
||||
* @na: attribute containing the bitmap
|
||||
* @bit: bit to set
|
||||
*
|
||||
* Set the @bit in the bitmap described by the attribute @na.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
static __inline__ int ntfs_bitmap_set_bit(ntfs_attr *na, s64 bit)
|
||||
{
|
||||
return ntfs_bitmap_set_run(na, bit, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_clear_bit - clear a bit in a bitmap
|
||||
* @na: attribute containing the bitmap
|
||||
* @bit: bit to clear
|
||||
*
|
||||
* Clear @bit in the bitmap described by the attribute @na.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
static __inline__ int ntfs_bitmap_clear_bit(ntfs_attr *na, s64 bit)
|
||||
{
|
||||
return ntfs_bitmap_clear_run(na, bit, 1);
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_BITMAP_H */
|
||||
|
47
include/ntfs-3g/bootsect.h
Normal file
47
include/ntfs-3g/bootsect.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* bootsect.h - Exports for bootsector record handling. Originated from the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2000-2002 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_BOOTSECT_H
|
||||
#define _NTFS_BOOTSECT_H
|
||||
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
#include "layout.h"
|
||||
|
||||
/**
|
||||
* is_boot_sector_ntfs - check a boot sector for describing an ntfs volume
|
||||
* @b: buffer containing the boot sector
|
||||
* @silent: if 1 don't display progress information
|
||||
*
|
||||
* This function checks the boot sector in @b for describing a valid ntfs
|
||||
* volume. Return TRUE if @b is a valid NTFS boot sector or FALSE otherwise.
|
||||
* If silent is FALSE, progress output will be output to stdout. If silent is
|
||||
* TRUE no output to stdout will occur. Errors/warnings to stderr will occur
|
||||
* disregarding the value of silent (but only if configure was run with
|
||||
* --enable-debug).
|
||||
*/
|
||||
extern BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, BOOL silent);
|
||||
extern int ntfs_boot_sector_parse(ntfs_volume *vol,
|
||||
const NTFS_BOOT_SECTOR *bs);
|
||||
|
||||
#endif /* defined _NTFS_BOOTSECT_H */
|
||||
|
37
include/ntfs-3g/collate.h
Normal file
37
include/ntfs-3g/collate.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* collate.h - Defines for NTFS collation handling. Originated from the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
*
|
||||
* 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_COLLATE_H
|
||||
#define _NTFS_COLLATE_H
|
||||
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
|
||||
#define NTFS_COLLATION_ERROR -2
|
||||
|
||||
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 */
|
54
include/ntfs-3g/compat.h
Normal file
54
include/ntfs-3g/compat.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* compat.h - Tweaks for Windows compatibility.
|
||||
*
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
* Copyright (c) 2002-2004 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_COMPAT_H
|
||||
#define _NTFS_COMPAT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
#ifndef HAVE_FFS
|
||||
#define HAVE_FFS
|
||||
extern int ffs(int i);
|
||||
#endif /* HAVE_FFS */
|
||||
|
||||
#define HAVE_STDIO_H /* mimic config.h */
|
||||
#define HAVE_STDARG_H
|
||||
|
||||
#define atoll _atoi64
|
||||
#define fdatasync commit
|
||||
#define __inline__ inline
|
||||
#define __attribute__(X) /*nothing*/
|
||||
|
||||
#else /* !defined WINDOWS */
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0 /* unix is binary by default */
|
||||
#endif
|
||||
|
||||
#endif /* defined WINDOWS */
|
||||
|
||||
#endif /* defined _NTFS_COMPAT_H */
|
||||
|
33
include/ntfs-3g/compress.h
Normal file
33
include/ntfs-3g/compress.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* compress.h - Exports for compressed attribute handling.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_COMPRESS_H
|
||||
#define _NTFS_COMPRESS_H
|
||||
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
|
||||
extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count,
|
||||
void *b);
|
||||
|
||||
#endif /* defined _NTFS_COMPRESS_H */
|
||||
|
47
include/ntfs-3g/debug.h
Normal file
47
include/ntfs-3g/debug.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* debug.h - Debugging output functions. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2004 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_DEBUG_H
|
||||
#define _NTFS_DEBUG_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
struct _runlist_element;
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void ntfs_debug_runlist_dump(const struct _runlist_element *rl);
|
||||
#else
|
||||
static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl __attribute__((unused))) {}
|
||||
#endif
|
||||
|
||||
#define NTFS_BUG(msg) \
|
||||
{ \
|
||||
int ___i; \
|
||||
ntfs_log_critical("Bug in %s(): %s\n", __FUNCTION__, msg); \
|
||||
ntfs_log_debug("Forcing segmentation fault!"); \
|
||||
___i = ((int*)NULL)[1]; \
|
||||
}
|
||||
|
||||
#endif /* defined _NTFS_DEBUG_H */
|
128
include/ntfs-3g/device.h
Normal file
128
include/ntfs-3g/device.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* device.h - Exports for low level device io. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* 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
|
||||
* 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_DEVICE_H
|
||||
#define _NTFS_DEVICE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "device_io.h"
|
||||
#include "types.h"
|
||||
#include "support.h"
|
||||
#include "volume.h"
|
||||
|
||||
/**
|
||||
* enum ntfs_device_state_bits -
|
||||
*
|
||||
* Defined bits for the state field in the ntfs_device structure.
|
||||
*/
|
||||
typedef enum {
|
||||
ND_Open, /* 1: Device is open. */
|
||||
ND_ReadOnly, /* 1: Device is read-only. */
|
||||
ND_Dirty, /* 1: Device is dirty, needs sync. */
|
||||
ND_Block, /* 1: Device is a block device. */
|
||||
} ntfs_device_state_bits;
|
||||
|
||||
#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
|
||||
#define set_ndev_flag(nd, flag) set_bit(ND_##flag, (nd)->d_state)
|
||||
#define clear_ndev_flag(nd, flag) clear_bit(ND_##flag, (nd)->d_state)
|
||||
|
||||
#define NDevOpen(nd) test_ndev_flag(nd, Open)
|
||||
#define NDevSetOpen(nd) set_ndev_flag(nd, Open)
|
||||
#define NDevClearOpen(nd) clear_ndev_flag(nd, Open)
|
||||
|
||||
#define NDevReadOnly(nd) test_ndev_flag(nd, ReadOnly)
|
||||
#define NDevSetReadOnly(nd) set_ndev_flag(nd, ReadOnly)
|
||||
#define NDevClearReadOnly(nd) clear_ndev_flag(nd, ReadOnly)
|
||||
|
||||
#define NDevDirty(nd) test_ndev_flag(nd, Dirty)
|
||||
#define NDevSetDirty(nd) set_ndev_flag(nd, Dirty)
|
||||
#define NDevClearDirty(nd) clear_ndev_flag(nd, Dirty)
|
||||
|
||||
#define NDevBlock(nd) test_ndev_flag(nd, Block)
|
||||
#define NDevSetBlock(nd) set_ndev_flag(nd, Block)
|
||||
#define NDevClearBlock(nd) clear_ndev_flag(nd, Block)
|
||||
|
||||
/**
|
||||
* struct ntfs_device -
|
||||
*
|
||||
* The ntfs device structure defining all operations needed to access the low
|
||||
* level device underlying the ntfs volume.
|
||||
*/
|
||||
struct ntfs_device {
|
||||
struct ntfs_device_operations *d_ops; /* Device operations. */
|
||||
unsigned long d_state; /* State of the device. */
|
||||
char *d_name; /* Name of device. */
|
||||
void *d_private; /* Private data used by the
|
||||
device operations. */
|
||||
};
|
||||
|
||||
struct stat;
|
||||
|
||||
/**
|
||||
* struct ntfs_device_operations -
|
||||
*
|
||||
* The ntfs device operations defining all operations that can be performed on
|
||||
* the low level device described by an ntfs device structure.
|
||||
*/
|
||||
struct ntfs_device_operations {
|
||||
int (*open)(struct ntfs_device *dev, int flags);
|
||||
int (*close)(struct ntfs_device *dev);
|
||||
s64 (*seek)(struct ntfs_device *dev, s64 offset, int whence);
|
||||
s64 (*read)(struct ntfs_device *dev, void *buf, s64 count);
|
||||
s64 (*write)(struct ntfs_device *dev, const void *buf, s64 count);
|
||||
s64 (*pread)(struct ntfs_device *dev, void *buf, s64 count, s64 offset);
|
||||
s64 (*pwrite)(struct ntfs_device *dev, const void *buf, s64 count,
|
||||
s64 offset);
|
||||
int (*sync)(struct ntfs_device *dev);
|
||||
int (*stat)(struct ntfs_device *dev, struct stat *buf);
|
||||
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 s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
void *b);
|
||||
extern s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const void *b);
|
||||
|
||||
extern s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b);
|
||||
extern s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b);
|
||||
|
||||
extern s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, void *b);
|
||||
extern s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b);
|
||||
|
||||
extern s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size);
|
||||
extern s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev);
|
||||
extern int ntfs_device_heads_get(struct ntfs_device *dev);
|
||||
extern int ntfs_device_sectors_per_track_get(struct ntfs_device *dev);
|
||||
extern int ntfs_device_sector_size_get(struct ntfs_device *dev);
|
||||
extern int ntfs_device_block_size_set(struct ntfs_device *dev, int block_size);
|
||||
|
||||
#endif /* defined _NTFS_DEVICE_H */
|
77
include/ntfs-3g/device_io.h
Normal file
77
include/ntfs-3g/device_io.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* device_io.h - Exports for default device io. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* 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
|
||||
* 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_DEVICE_IO_H
|
||||
#define _NTFS_DEVICE_IO_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
|
||||
|
||||
#ifndef __CYGWIN32__
|
||||
|
||||
/* Not on Cygwin; use standard Unix style low level device operations. */
|
||||
#define ntfs_device_default_io_ops ntfs_device_unix_io_ops
|
||||
|
||||
#else /* __CYGWIN32__ */
|
||||
|
||||
#ifndef HDIO_GETGEO
|
||||
# define HDIO_GETGEO 0x301
|
||||
/**
|
||||
* struct hd_geometry -
|
||||
*/
|
||||
struct hd_geometry {
|
||||
unsigned char heads;
|
||||
unsigned char sectors;
|
||||
unsigned short cylinders;
|
||||
unsigned long start;
|
||||
};
|
||||
#endif
|
||||
#ifndef BLKGETSIZE
|
||||
# define BLKGETSIZE 0x1260
|
||||
#endif
|
||||
#ifndef BLKSSZGET
|
||||
# define BLKSSZGET 0x1268
|
||||
#endif
|
||||
#ifndef BLKGETSIZE64
|
||||
# define BLKGETSIZE64 0x80041272
|
||||
#endif
|
||||
#ifndef BLKBSZSET
|
||||
# define BLKBSZSET 0x40041271
|
||||
#endif
|
||||
|
||||
/* On Cygwin; use Win32 low level device operations. */
|
||||
#define ntfs_device_default_io_ops ntfs_device_win32_io_ops
|
||||
|
||||
#endif /* __CYGWIN32__ */
|
||||
|
||||
|
||||
/* Forward declaration. */
|
||||
struct ntfs_device_operations;
|
||||
|
||||
extern struct ntfs_device_operations ntfs_device_default_io_ops;
|
||||
|
||||
#endif /* NO_NTFS_DEVICE_DEFAULT_IO_OPS */
|
||||
|
||||
#endif /* defined _NTFS_DEVICE_IO_H */
|
||||
|
111
include/ntfs-3g/dir.h
Normal file
111
include/ntfs-3g/dir.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* dir.h - Exports for directory handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Anton Altaparmakov
|
||||
* Copyright (c) 2005-2006 Yura Pakhuchiy
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
*
|
||||
* 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_DIR_H
|
||||
#define _NTFS_DIR_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define PATH_SEP '/'
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 1024
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We do not have these under DJGPP, so define our version that do not conflict
|
||||
* with other S_IFs defined under DJGPP.
|
||||
*/
|
||||
#ifdef DJGPP
|
||||
#ifndef S_IFLNK
|
||||
#define S_IFLNK 0120000
|
||||
#endif
|
||||
#ifndef S_ISLNK
|
||||
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
|
||||
#endif
|
||||
#ifndef S_IFSOCK
|
||||
#define S_IFSOCK 0140000
|
||||
#endif
|
||||
#ifndef S_ISSOCK
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The little endian Unicode strings $I30, $SII, $SDH, $O, $Q, $R
|
||||
* as a global constant.
|
||||
*/
|
||||
extern ntfschar NTFS_INDEX_I30[5];
|
||||
extern ntfschar NTFS_INDEX_SII[5];
|
||||
extern ntfschar NTFS_INDEX_SDH[5];
|
||||
extern ntfschar NTFS_INDEX_O[3];
|
||||
extern ntfschar NTFS_INDEX_Q[3];
|
||||
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 ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
|
||||
const char *pathname);
|
||||
|
||||
extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len,
|
||||
dev_t type);
|
||||
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni,
|
||||
ntfschar *name, u8 name_len, dev_t type, dev_t dev);
|
||||
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni,
|
||||
ntfschar *name, u8 name_len, ntfschar *target, u8 target_len);
|
||||
extern int ntfs_check_empty_dir(ntfs_inode *ni);
|
||||
extern int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
|
||||
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
|
||||
u8 name_len);
|
||||
|
||||
/*
|
||||
* File types (adapted from include <linux/fs.h>)
|
||||
*/
|
||||
#define NTFS_DT_UNKNOWN 0
|
||||
#define NTFS_DT_FIFO 1
|
||||
#define NTFS_DT_CHR 2
|
||||
#define NTFS_DT_DIR 4
|
||||
#define NTFS_DT_BLK 6
|
||||
#define NTFS_DT_REG 8
|
||||
#define NTFS_DT_LNK 10
|
||||
#define NTFS_DT_SOCK 12
|
||||
#define NTFS_DT_WHT 14
|
||||
|
||||
/*
|
||||
* This is the "ntfs_filldir" function type, used by ntfs_readdir() to let
|
||||
* the caller specify what kind of dirent layout it wants to have.
|
||||
* This allows the caller to read directories into their application or
|
||||
* to have different dirent layouts depending on the binary type.
|
||||
*/
|
||||
typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name,
|
||||
const int name_len, const int name_type, const s64 pos,
|
||||
const MFT_REF mref, const unsigned dt_type);
|
||||
|
||||
extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
||||
void *dirent, ntfs_filldir_t filldir);
|
||||
|
||||
#endif /* defined _NTFS_DIR_H */
|
||||
|
203
include/ntfs-3g/endians.h
Normal file
203
include/ntfs-3g/endians.h
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* endians.h - Definitions related to handling of byte ordering.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2005 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_ENDIANS_H
|
||||
#define _NTFS_ENDIANS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Notes:
|
||||
* We define the conversion functions including typecasts since the
|
||||
* defaults don't necessarily perform appropriate typecasts.
|
||||
* Also, using our own functions means that we can change them if it
|
||||
* turns out that we do need to use the unaligned access macros on
|
||||
* architectures requiring aligned memory accesses...
|
||||
*/
|
||||
|
||||
#ifdef HAVE_ENDIAN_H
|
||||
#include <endian.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_ENDIAN_H
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
#ifdef HAVE_MACHINE_ENDIAN_H
|
||||
#include <machine/endian.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_BYTEORDER_H
|
||||
#include <sys/byteorder.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifndef __BYTE_ORDER
|
||||
# if defined(_BYTE_ORDER)
|
||||
# define __BYTE_ORDER _BYTE_ORDER
|
||||
# define __LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
# define __BIG_ENDIAN _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__)
|
||||
# define __BYTE_ORDER __BYTE_ORDER__
|
||||
# define __LITTLE_ENDIAN __LITTLE_ENDIAN__
|
||||
# define __BIG_ENDIAN __BIG_ENDIAN__
|
||||
# elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \
|
||||
defined(WORDS_LITTLEENDIAN)
|
||||
# define __BYTE_ORDER 1
|
||||
# define __LITTLE_ENDIAN 1
|
||||
# define __BIG_ENDIAN 0
|
||||
# elif (!defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN)) || \
|
||||
defined(WORDS_BIGENDIAN)
|
||||
# define __BYTE_ORDER 0
|
||||
# define __LITTLE_ENDIAN 1
|
||||
# define __BIG_ENDIAN 0
|
||||
# else
|
||||
# error "__BYTE_ORDER is not defined."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define __ntfs_bswap_constant_16(x) \
|
||||
(u16)((((u16)(x) & 0xff00) >> 8) | \
|
||||
(((u16)(x) & 0x00ff) << 8))
|
||||
|
||||
#define __ntfs_bswap_constant_32(x) \
|
||||
(u32)((((u32)(x) & 0xff000000u) >> 24) | \
|
||||
(((u32)(x) & 0x00ff0000u) >> 8) | \
|
||||
(((u32)(x) & 0x0000ff00u) << 8) | \
|
||||
(((u32)(x) & 0x000000ffu) << 24))
|
||||
|
||||
#define __ntfs_bswap_constant_64(x) \
|
||||
(u64)((((u64)(x) & 0xff00000000000000ull) >> 56) | \
|
||||
(((u64)(x) & 0x00ff000000000000ull) >> 40) | \
|
||||
(((u64)(x) & 0x0000ff0000000000ull) >> 24) | \
|
||||
(((u64)(x) & 0x000000ff00000000ull) >> 8) | \
|
||||
(((u64)(x) & 0x00000000ff000000ull) << 8) | \
|
||||
(((u64)(x) & 0x0000000000ff0000ull) << 24) | \
|
||||
(((u64)(x) & 0x000000000000ff00ull) << 40) | \
|
||||
(((u64)(x) & 0x00000000000000ffull) << 56))
|
||||
|
||||
#ifdef HAVE_BYTESWAP_H
|
||||
# include <byteswap.h>
|
||||
#else
|
||||
# define bswap_16(x) __ntfs_bswap_constant_16(x)
|
||||
# define bswap_32(x) __ntfs_bswap_constant_32(x)
|
||||
# define bswap_64(x) __ntfs_bswap_constant_64(x)
|
||||
#endif
|
||||
|
||||
#if defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
|
||||
#define __le16_to_cpu(x) (x)
|
||||
#define __le32_to_cpu(x) (x)
|
||||
#define __le64_to_cpu(x) (x)
|
||||
|
||||
#define __cpu_to_le16(x) (x)
|
||||
#define __cpu_to_le32(x) (x)
|
||||
#define __cpu_to_le64(x) (x)
|
||||
|
||||
#define __constant_le16_to_cpu(x) (x)
|
||||
#define __constant_le32_to_cpu(x) (x)
|
||||
#define __constant_le64_to_cpu(x) (x)
|
||||
|
||||
#define __constant_cpu_to_le16(x) (x)
|
||||
#define __constant_cpu_to_le32(x) (x)
|
||||
#define __constant_cpu_to_le64(x) (x)
|
||||
|
||||
#elif defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
|
||||
#define __le16_to_cpu(x) bswap_16(x)
|
||||
#define __le32_to_cpu(x) bswap_32(x)
|
||||
#define __le64_to_cpu(x) bswap_64(x)
|
||||
|
||||
#define __cpu_to_le16(x) bswap_16(x)
|
||||
#define __cpu_to_le32(x) bswap_32(x)
|
||||
#define __cpu_to_le64(x) bswap_64(x)
|
||||
|
||||
#define __constant_le16_to_cpu(x) __ntfs_bswap_constant_16((u16)(x))
|
||||
#define __constant_le32_to_cpu(x) __ntfs_bswap_constant_32((u32)(x))
|
||||
#define __constant_le64_to_cpu(x) __ntfs_bswap_constant_64((u64)(x))
|
||||
|
||||
#define __constant_cpu_to_le16(x) __ntfs_bswap_constant_16((u16)(x))
|
||||
#define __constant_cpu_to_le32(x) __ntfs_bswap_constant_32((u32)(x))
|
||||
#define __constant_cpu_to_le64(x) __ntfs_bswap_constant_64((u64)(x))
|
||||
|
||||
#else
|
||||
|
||||
#error "You must define __BYTE_ORDER to be __LITTLE_ENDIAN or __BIG_ENDIAN."
|
||||
|
||||
#endif
|
||||
|
||||
/* Unsigned from LE to CPU conversion. */
|
||||
|
||||
#define le16_to_cpu(x) (u16)__le16_to_cpu((u16)(x))
|
||||
#define le32_to_cpu(x) (u32)__le32_to_cpu((u32)(x))
|
||||
#define le64_to_cpu(x) (u64)__le64_to_cpu((u64)(x))
|
||||
|
||||
#define le16_to_cpup(x) (u16)__le16_to_cpu(*(const u16*)(x))
|
||||
#define le32_to_cpup(x) (u32)__le32_to_cpu(*(const u32*)(x))
|
||||
#define le64_to_cpup(x) (u64)__le64_to_cpu(*(const u64*)(x))
|
||||
|
||||
/* Signed from LE to CPU conversion. */
|
||||
|
||||
#define sle16_to_cpu(x) (s16)__le16_to_cpu((s16)(x))
|
||||
#define sle32_to_cpu(x) (s32)__le32_to_cpu((s32)(x))
|
||||
#define sle64_to_cpu(x) (s64)__le64_to_cpu((s64)(x))
|
||||
|
||||
#define sle16_to_cpup(x) (s16)__le16_to_cpu(*(s16*)(x))
|
||||
#define sle32_to_cpup(x) (s32)__le32_to_cpu(*(s32*)(x))
|
||||
#define sle64_to_cpup(x) (s64)__le64_to_cpu(*(s64*)(x))
|
||||
|
||||
/* Unsigned from CPU to LE conversion. */
|
||||
|
||||
#define cpu_to_le16(x) (u16)__cpu_to_le16((u16)(x))
|
||||
#define cpu_to_le32(x) (u32)__cpu_to_le32((u32)(x))
|
||||
#define cpu_to_le64(x) (u64)__cpu_to_le64((u64)(x))
|
||||
|
||||
#define cpu_to_le16p(x) (u16)__cpu_to_le16(*(u16*)(x))
|
||||
#define cpu_to_le32p(x) (u32)__cpu_to_le32(*(u32*)(x))
|
||||
#define cpu_to_le64p(x) (u64)__cpu_to_le64(*(u64*)(x))
|
||||
|
||||
/* Signed from CPU to LE conversion. */
|
||||
|
||||
#define cpu_to_sle16(x) (s16)__cpu_to_le16((s16)(x))
|
||||
#define cpu_to_sle32(x) (s32)__cpu_to_le32((s32)(x))
|
||||
#define cpu_to_sle64(x) (s64)__cpu_to_le64((s64)(x))
|
||||
|
||||
#define cpu_to_sle16p(x) (s16)__cpu_to_le16(*(s16*)(x))
|
||||
#define cpu_to_sle32p(x) (s32)__cpu_to_le32(*(s32*)(x))
|
||||
#define cpu_to_sle64p(x) (s64)__cpu_to_le64(*(s64*)(x))
|
||||
|
||||
/* Constant endianness conversion defines. */
|
||||
|
||||
#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) __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 */
|
131
include/ntfs-3g/index.h
Normal file
131
include/ntfs-3g/index.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* index.h - Defines for NTFS index handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_INDEX_H
|
||||
#define _NTFS_INDEX_H
|
||||
|
||||
#include "attrib.h"
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
#include "mft.h"
|
||||
|
||||
#define VCN_INDEX_ROOT_PARENT ((VCN)-2)
|
||||
|
||||
#define MAX_PARENT_VCN 32
|
||||
|
||||
/**
|
||||
* struct ntfs_index_context -
|
||||
* @ni: inode containing the @entry described by this context
|
||||
* @name: name of the index described by this context
|
||||
* @name_len: length of the index name
|
||||
* @entry: index entry (points into @ir or @ia)
|
||||
* @data: index entry data (points into @entry)
|
||||
* @data_len: length in bytes of @data
|
||||
* @is_in_root: TRUE if @entry is in @ir or FALSE if it is in @ia
|
||||
* @ir: index root if @is_in_root or NULL otherwise
|
||||
* @actx: attribute search context if in root or NULL otherwise
|
||||
* @ia: index block if @is_in_root is FALSE or NULL otherwise
|
||||
* @ia_na: opened INDEX_ALLOCATION attribute
|
||||
* @ib_vcn: VCN from which @ia where read from
|
||||
* @parent_pos: parent entries' positions in the index block
|
||||
* @parent_vcn: entry's parent node or VCN_INDEX_ROOT_PARENT
|
||||
* @new_vcn: new VCN if we need to create a new index block
|
||||
* @median: move to the parent if splitting index blocks
|
||||
* @ib_dirty: TRUE if index block was changed
|
||||
* @block_size: index block size
|
||||
* @vcn_size_bits: VCN size bits for this index block
|
||||
*
|
||||
* @ni is the inode this context belongs to.
|
||||
*
|
||||
* @entry is the index entry described by this context. @data and @data_len
|
||||
* are the index entry data and its length in bytes, respectively. @data
|
||||
* simply points into @entry. This is probably what the user is interested in.
|
||||
*
|
||||
* If @is_in_root is TRUE, @entry is in the index root attribute @ir described
|
||||
* by the attribute search context @actx and inode @ni. @ia, @ib_vcn and
|
||||
* @ib_dirty are undefined in this case.
|
||||
*
|
||||
* If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia
|
||||
* and @ib_vcn point to the index allocation block and VCN where it's placed,
|
||||
* respectively. @ir and @actx are NULL in this case. @ia_na is opened
|
||||
* INDEX_ALLOCATION attribute. @ib_dirty is TRUE if index block was changed and
|
||||
* FALSE otherwise.
|
||||
*
|
||||
* To obtain a context call ntfs_index_ctx_get().
|
||||
*
|
||||
* When finished with the @entry and its @data, call ntfs_index_ctx_put() to
|
||||
* free the context and other associated resources.
|
||||
*
|
||||
* If the index entry was modified, call ntfs_index_entry_mark_dirty() before
|
||||
* the call to ntfs_index_ctx_put() to ensure that the changes are written
|
||||
* to disk.
|
||||
*/
|
||||
typedef struct {
|
||||
ntfs_inode *ni;
|
||||
ntfschar *name;
|
||||
u32 name_len;
|
||||
INDEX_ENTRY *entry;
|
||||
void *data;
|
||||
u16 data_len;
|
||||
COLLATION_RULES cr;
|
||||
BOOL is_in_root;
|
||||
INDEX_ROOT *ir;
|
||||
ntfs_attr_search_ctx *actx;
|
||||
INDEX_BLOCK *ib;
|
||||
ntfs_attr *ia_na;
|
||||
int parent_pos[MAX_PARENT_VCN]; /* parent entries' positions */
|
||||
VCN ib_vcn;
|
||||
VCN parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */
|
||||
int max_depth; /* number of the parent nodes */
|
||||
int pindex; /* maximum it's the number of the parent nodes */
|
||||
BOOL ib_dirty;
|
||||
u32 block_size;
|
||||
u8 vcn_size_bits;
|
||||
} ntfs_index_context;
|
||||
|
||||
extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
|
||||
ntfschar *name, u32 name_len);
|
||||
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
|
||||
extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx);
|
||||
|
||||
extern int ntfs_index_lookup(const void *key, const int key_len,
|
||||
ntfs_index_context *ictx);
|
||||
|
||||
extern int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn,
|
||||
MFT_REF mref);
|
||||
extern int ntfs_index_rm(ntfs_index_context *ictx);
|
||||
|
||||
extern INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr);
|
||||
|
||||
extern VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie);
|
||||
|
||||
extern void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx);
|
||||
|
||||
extern char *ntfs_ie_filename_get(INDEX_ENTRY *ie);
|
||||
extern void ntfs_ie_filename_dump(INDEX_ENTRY *ie);
|
||||
extern void ntfs_ih_filename_dump(INDEX_HEADER *ih);
|
||||
|
||||
#endif /* _NTFS_INDEX_H */
|
||||
|
176
include/ntfs-3g/inode.h
Normal file
176
include/ntfs-3g/inode.h
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* inode.h - Defines for NTFS inode handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001,2002 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_INODE_H
|
||||
#define _NTFS_INODE_H
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct _ntfs_inode ntfs_inode;
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "support.h"
|
||||
#include "volume.h"
|
||||
|
||||
/**
|
||||
* enum ntfs_inode_state_bits -
|
||||
*
|
||||
* Defined bits for the state field in the ntfs_inode structure.
|
||||
* (f) = files only, (d) = directories only
|
||||
*/
|
||||
typedef enum {
|
||||
NI_Dirty, /* 1: Mft record needs to be written to disk. */
|
||||
|
||||
/* The NI_AttrList* tests only make sense for base inodes. */
|
||||
NI_AttrList, /* 1: Mft record contains an attribute list. */
|
||||
NI_AttrListDirty, /* 1: Attribute list needs to be written to the
|
||||
mft record and then to disk. */
|
||||
NI_FileNameDirty, /* 1: FILE_NAME attributes need to be updated
|
||||
in the index. */
|
||||
} ntfs_inode_state_bits;
|
||||
|
||||
#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
|
||||
#define set_nino_flag(ni, flag) set_bit(NI_##flag, (ni)->state)
|
||||
#define clear_nino_flag(ni, flag) clear_bit(NI_##flag, (ni)->state)
|
||||
|
||||
#define test_and_set_nino_flag(ni, flag) \
|
||||
test_and_set_bit(NI_##flag, (ni)->state)
|
||||
#define test_and_clear_nino_flag(ni, flag) \
|
||||
test_and_clear_bit(NI_##flag, (ni)->state)
|
||||
|
||||
#define NInoDirty(ni) test_nino_flag(ni, Dirty)
|
||||
#define NInoSetDirty(ni) set_nino_flag(ni, Dirty)
|
||||
#define NInoClearDirty(ni) clear_nino_flag(ni, Dirty)
|
||||
#define NInoTestAndSetDirty(ni) test_and_set_nino_flag(ni, Dirty)
|
||||
#define NInoTestAndClearDirty(ni) test_and_clear_nino_flag(ni, Dirty)
|
||||
|
||||
#define NInoAttrList(ni) test_nino_flag(ni, AttrList)
|
||||
#define NInoSetAttrList(ni) set_nino_flag(ni, AttrList)
|
||||
#define NInoClearAttrList(ni) clear_nino_flag(ni, AttrList)
|
||||
|
||||
|
||||
#define test_nino_al_flag(ni, flag) test_nino_flag(ni, AttrList##flag)
|
||||
#define set_nino_al_flag(ni, flag) set_nino_flag(ni, AttrList##flag)
|
||||
#define clear_nino_al_flag(ni, flag) clear_nino_flag(ni, AttrList##flag)
|
||||
|
||||
#define test_and_set_nino_al_flag(ni, flag) \
|
||||
test_and_set_nino_flag(ni, AttrList##flag)
|
||||
#define test_and_clear_nino_al_flag(ni, flag) \
|
||||
test_and_clear_nino_flag(ni, AttrList##flag)
|
||||
|
||||
#define NInoAttrListDirty(ni) test_nino_al_flag(ni, Dirty)
|
||||
#define NInoAttrListSetDirty(ni) set_nino_al_flag(ni, Dirty)
|
||||
#define NInoAttrListClearDirty(ni) clear_nino_al_flag(ni, Dirty)
|
||||
#define NInoAttrListTestAndSetDirty(ni) test_and_set_nino_al_flag(ni, Dirty)
|
||||
#define NInoAttrListTestAndClearDirty(ni) test_and_clear_nino_al_flag(ni, Dirty)
|
||||
|
||||
#define NInoFileNameDirty(ni) \
|
||||
test_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameSetDirty(ni) \
|
||||
set_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameClearDirty(ni) \
|
||||
clear_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameTestAndSetDirty(ni) \
|
||||
test_and_set_nino_flag(ni, FileNameDirty)
|
||||
#define NInoFileNameTestAndClearDirty(ni) \
|
||||
test_and_clear_nino_flag(ni, FileNameDirty)
|
||||
|
||||
/**
|
||||
* struct _ntfs_inode - The NTFS in-memory inode structure.
|
||||
*
|
||||
* It is just used as an extension to the fields already provided in the VFS
|
||||
* inode.
|
||||
*/
|
||||
struct _ntfs_inode {
|
||||
u64 mft_no; /* Inode / mft record number. */
|
||||
MFT_RECORD *mrec; /* The actual mft record of the inode. */
|
||||
ntfs_volume *vol; /* Pointer to the ntfs volume of this inode. */
|
||||
unsigned long state; /* NTFS specific flags describing this inode.
|
||||
See ntfs_inode_state_bits above. */
|
||||
FILE_ATTR_FLAGS flags; /* Flags describing the file.
|
||||
(Copy from STANDARD_INFORMATION) */
|
||||
/*
|
||||
* Attribute list support (for use by the attribute lookup functions).
|
||||
* Setup during ntfs_open_inode() for all inodes with attribute lists.
|
||||
* Only valid if NI_AttrList is set in state.
|
||||
*/
|
||||
u32 attr_list_size; /* Length of attribute list value in bytes. */
|
||||
u8 *attr_list; /* Attribute list value itself. */
|
||||
/* Below fields are always valid. */
|
||||
s32 nr_extents; /* For a base mft record, the number of
|
||||
attached extent inodes (0 if none), for
|
||||
extent records this is -1. */
|
||||
union { /* This union is only used if nr_extents != 0. */
|
||||
ntfs_inode **extent_nis;/* For nr_extents > 0, array of the
|
||||
ntfs inodes of the extent mft
|
||||
records belonging to this base
|
||||
inode which have been loaded. */
|
||||
ntfs_inode *base_ni; /* For nr_extents == -1, the ntfs
|
||||
inode of the base mft record. */
|
||||
};
|
||||
|
||||
/* Temp: for directory handling */
|
||||
void *private_data; /* ntfs_dt containing this inode */
|
||||
int ref_count;
|
||||
|
||||
/* Below fields are valid only for base inode. */
|
||||
s64 data_size; /* Data size stored in the filename index. */
|
||||
s64 allocated_size; /* Allocated size stored in the filename
|
||||
index. (NOTE: Equal to allocated size of
|
||||
the unnamed data attribute for normal or
|
||||
encrypted files and to compressed size
|
||||
of the unnamed data attribute for sparse or
|
||||
compressed files.) */
|
||||
|
||||
time_t creation_time;
|
||||
time_t last_data_change_time;
|
||||
time_t last_mft_change_time;
|
||||
time_t last_access_time;
|
||||
};
|
||||
|
||||
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 ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni,
|
||||
const MFT_REF mref);
|
||||
|
||||
extern int ntfs_inode_attach_all_extents(ntfs_inode *ni);
|
||||
|
||||
extern void ntfs_inode_mark_dirty(ntfs_inode *ni);
|
||||
|
||||
extern void ntfs_inode_update_atime(ntfs_inode *ni);
|
||||
extern void ntfs_inode_update_time(ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_inode_sync(ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_inode_add_attrlist(ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_inode_free_space(ntfs_inode *ni, int size);
|
||||
|
||||
extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a);
|
||||
|
||||
#endif /* defined _NTFS_INODE_H */
|
2664
include/ntfs-3g/layout.h
Normal file
2664
include/ntfs-3g/layout.h
Normal file
File diff suppressed because it is too large
Load Diff
50
include/ntfs-3g/lcnalloc.h
Normal file
50
include/ntfs-3g/lcnalloc.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* lcnalloc.h - Exports for cluster (de)allocation. Originated from the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2002 Anton Altaparmakov
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
*
|
||||
* 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_LCNALLOC_H
|
||||
#define _NTFS_LCNALLOC_H
|
||||
|
||||
#include "types.h"
|
||||
#include "runlist.h"
|
||||
#include "volume.h"
|
||||
|
||||
/**
|
||||
* enum NTFS_CLUSTER_ALLOCATION_ZONES -
|
||||
*/
|
||||
typedef enum {
|
||||
FIRST_ZONE = 0, /* For sanity checking. */
|
||||
MFT_ZONE = 0, /* Allocate from $MFT zone. */
|
||||
DATA_ZONE = 1, /* Allocate from $DATA zone. */
|
||||
LAST_ZONE = 1, /* For sanity checking. */
|
||||
} NTFS_CLUSTER_ALLOCATION_ZONES;
|
||||
|
||||
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(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn,
|
||||
s64 count);
|
||||
|
||||
#endif /* defined _NTFS_LCNALLOC_H */
|
||||
|
192
include/ntfs-3g/list.h
Normal file
192
include/ntfs-3g/list.h
Normal file
@ -0,0 +1,192 @@
|
||||
/*
|
||||
* list.h - Linked list implementation. Originated from 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 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_LIST_H
|
||||
#define _NTFS_LIST_H
|
||||
|
||||
/**
|
||||
* struct 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 list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* __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 void __list_add(struct list_head * new,
|
||||
struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* __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 __list_del(struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
*
|
||||
* Note: list_empty on entry does not return true after this, the entry is in
|
||||
* an undefined state.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static __inline__ void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static void list_splice(struct list_head *list,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define 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 */
|
||||
|
394
include/ntfs-3g/logfile.h
Normal file
394
include/ntfs-3g/logfile.h
Normal file
@ -0,0 +1,394 @@
|
||||
/*
|
||||
* logfile.h - Exports for $LogFile handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2005 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_LOGFILE_H
|
||||
#define _NTFS_LOGFILE_H
|
||||
|
||||
#include "types.h"
|
||||
#include "endians.h"
|
||||
#include "layout.h"
|
||||
|
||||
/*
|
||||
* Journal ($LogFile) organization:
|
||||
*
|
||||
* Two restart areas present in the first two pages (restart pages, one restart
|
||||
* area in each page). When the volume is dismounted they should be identical,
|
||||
* except for the update sequence array which usually has a different update
|
||||
* sequence number.
|
||||
*
|
||||
* These are followed by log records organized in pages headed by a log record
|
||||
* header going up to log file size. Not all pages contain log records when a
|
||||
* volume is first formatted, but as the volume ages, all records will be used.
|
||||
* When the log file fills up, the records at the beginning are purged (by
|
||||
* modifying the oldest_lsn to a higher value presumably) and writing begins
|
||||
* at the beginning of the file. Effectively, the log file is viewed as a
|
||||
* circular entity.
|
||||
*
|
||||
* NOTE: Windows NT, 2000, and XP all use log file version 1.1 but they accept
|
||||
* versions <= 1.x, including 0.-1. (Yes, that is a minus one in there!) We
|
||||
* probably only want to support 1.1 as this seems to be the current version
|
||||
* and we don't know how that differs from the older versions. The only
|
||||
* exception is if the journal is clean as marked by the two restart pages
|
||||
* then it doesn't matter whether we are on an earlier version. We can just
|
||||
* reinitialize the logfile and start again with version 1.1.
|
||||
*/
|
||||
|
||||
/* Some $LogFile related constants. */
|
||||
#define MaxLogFileSize 0x100000000ULL
|
||||
#define DefaultLogPageSize 4096
|
||||
#define MinLogRecordPages 48
|
||||
|
||||
/**
|
||||
* struct RESTART_PAGE_HEADER - Log file restart page header.
|
||||
*
|
||||
* Begins the restart area.
|
||||
*/
|
||||
typedef struct {
|
||||
/*Ofs*/
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
/* 0*/ NTFS_RECORD_TYPES magic;/* The magic is "RSTR". */
|
||||
/* 4*/ le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
When creating, set this to be immediately
|
||||
after this header structure (without any
|
||||
alignment). */
|
||||
/* 6*/ le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
|
||||
/* 8*/ leLSN chkdsk_lsn; /* The last log file sequence number found by
|
||||
chkdsk. Only used when the magic is changed
|
||||
to "CHKD". Otherwise this is zero. */
|
||||
/* 16*/ le32 system_page_size; /* Byte size of system pages when the log file
|
||||
was created, has to be >= 512 and a power of
|
||||
2. Use this to calculate the required size
|
||||
of the usa (usa_count) and add it to usa_ofs.
|
||||
Then verify that the result is less than the
|
||||
value of the restart_area_offset. */
|
||||
/* 20*/ le32 log_page_size; /* Byte size of log file pages, has to be >=
|
||||
512 and a power of 2. The default is 4096
|
||||
and is used when the system page size is
|
||||
between 4096 and 8192. Otherwise this is
|
||||
set to the system page size instead. */
|
||||
/* 24*/ le16 restart_area_offset;/* Byte offset from the start of this header to
|
||||
the RESTART_AREA. Value has to be aligned
|
||||
to 8-byte boundary. When creating, set this
|
||||
to be after the usa. */
|
||||
/* 26*/ sle16 minor_ver; /* Log file minor version. Only check if major
|
||||
version is 1. */
|
||||
/* 28*/ sle16 major_ver; /* Log file major version. We only support
|
||||
version 1.1. */
|
||||
/* sizeof() = 30 (0x1e) bytes */
|
||||
} __attribute__((__packed__)) RESTART_PAGE_HEADER;
|
||||
|
||||
/*
|
||||
* Constant for the log client indices meaning that there are no client records
|
||||
* 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
|
||||
|
||||
/*
|
||||
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
||||
* information about the log file in which they are present.
|
||||
*/
|
||||
enum {
|
||||
RESTART_VOLUME_IS_CLEAN = const_cpu_to_le16(0x0002),
|
||||
RESTART_SPACE_FILLER = 0xffff, /* gcc: Force enum bit width to 16. */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
typedef le16 RESTART_AREA_FLAGS;
|
||||
|
||||
/**
|
||||
* struct RESTART_AREA - Log file restart area record.
|
||||
*
|
||||
* The offset of this record is found by adding the offset of the
|
||||
* RESTART_PAGE_HEADER to the restart_area_offset value found in it.
|
||||
* See notes at restart_area_offset above.
|
||||
*/
|
||||
typedef struct {
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN current_lsn; /* The current, i.e. last LSN inside the log
|
||||
when the restart area was last written.
|
||||
This happens often but what is the interval?
|
||||
Is it just fixed time or is it every time a
|
||||
check point is written or something else?
|
||||
On create set to 0. */
|
||||
/* 8*/ le16 log_clients; /* Number of log client records in the array of
|
||||
log client records which follows this
|
||||
restart area. Must be 1. */
|
||||
/* 10*/ le16 client_free_list; /* The index of the first free log client record
|
||||
in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means that there are no
|
||||
free log client records in the array.
|
||||
If != LOGFILE_NO_CLIENT, check that
|
||||
log_clients > client_free_list. On Win2k
|
||||
and presumably earlier, on a clean volume
|
||||
this is != LOGFILE_NO_CLIENT, and it should
|
||||
be 0, i.e. the first (and only) client
|
||||
record is free and thus the logfile is
|
||||
closed and hence clean. A dirty volume
|
||||
would have left the logfile open and hence
|
||||
this would be LOGFILE_NO_CLIENT. On WinXP
|
||||
and presumably later, the logfile is always
|
||||
open, even on clean shutdown so this should
|
||||
always be LOGFILE_NO_CLIENT. */
|
||||
/* 12*/ le16 client_in_use_list;/* The index of the first in-use log client
|
||||
record in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means that there are no
|
||||
in-use log client records in the array. If
|
||||
!= LOGFILE_NO_CLIENT check that log_clients
|
||||
> client_in_use_list. On Win2k and
|
||||
presumably earlier, on a clean volume this
|
||||
is LOGFILE_NO_CLIENT, i.e. there are no
|
||||
client records in use and thus the logfile
|
||||
is closed and hence clean. A dirty volume
|
||||
would have left the logfile open and hence
|
||||
this would be != LOGFILE_NO_CLIENT, and it
|
||||
should be 0, i.e. the first (and only)
|
||||
client record is in use. On WinXP and
|
||||
presumably later, the logfile is always
|
||||
open, even on clean shutdown so this should
|
||||
always be 0. */
|
||||
/* 14*/ RESTART_AREA_FLAGS flags;/* Flags modifying LFS behaviour. On Win2k
|
||||
and presumably earlier this is always 0. On
|
||||
WinXP and presumably later, if the logfile
|
||||
was shutdown cleanly, the second bit,
|
||||
RESTART_VOLUME_IS_CLEAN, is set. This bit
|
||||
is cleared when the volume is mounted by
|
||||
WinXP and set when the volume is dismounted,
|
||||
thus if the logfile is dirty, this bit is
|
||||
clear. Thus we don't need to check the
|
||||
Windows version to determine if the logfile
|
||||
is clean. Instead if the logfile is closed,
|
||||
we know it must be clean. If it is open and
|
||||
this bit is set, we also know it must be
|
||||
clean. If on the other hand the logfile is
|
||||
open and this bit is clear, we can be almost
|
||||
certain that the logfile is dirty. */
|
||||
/* 16*/ le32 seq_number_bits; /* How many bits to use for the sequence
|
||||
number. This is calculated as 67 - the
|
||||
number of bits required to store the logfile
|
||||
size in bytes and this can be used in with
|
||||
the specified file_size as a consistency
|
||||
check. */
|
||||
/* 20*/ le16 restart_area_length;/* Length of the restart area including the
|
||||
client array. Following checks required if
|
||||
version matches. Otherwise, skip them.
|
||||
restart_area_offset + restart_area_length
|
||||
has to be <= system_page_size. Also,
|
||||
restart_area_length has to be >=
|
||||
client_array_offset + (log_clients *
|
||||
sizeof(log client record)). */
|
||||
/* 22*/ le16 client_array_offset;/* Offset from the start of this record to
|
||||
the first log client record if versions are
|
||||
matched. When creating, set this to be
|
||||
after this restart area structure, aligned
|
||||
to 8-bytes boundary. If the versions do not
|
||||
match, this is ignored and the offset is
|
||||
assumed to be (sizeof(RESTART_AREA) + 7) &
|
||||
~7, i.e. rounded up to first 8-byte
|
||||
boundary. Either way, client_array_offset
|
||||
has to be aligned to an 8-byte boundary.
|
||||
Also, restart_area_offset +
|
||||
client_array_offset has to be <= 510.
|
||||
Finally, client_array_offset + (log_clients
|
||||
* sizeof(log client record)) has to be <=
|
||||
system_page_size. On Win2k and presumably
|
||||
earlier, this is 0x30, i.e. immediately
|
||||
following this record. On WinXP and
|
||||
presumably later, this is 0x40, i.e. there
|
||||
are 16 extra bytes between this record and
|
||||
the client array. This probably means that
|
||||
the RESTART_AREA record is actually bigger
|
||||
in WinXP and later. */
|
||||
/* 24*/ sle64 file_size; /* Usable byte size of the log file. If the
|
||||
restart_area_offset + the offset of the
|
||||
file_size are > 510 then corruption has
|
||||
occurred. This is the very first check when
|
||||
starting with the restart_area as if it
|
||||
fails it means that some of the above values
|
||||
will be corrupted by the multi sector
|
||||
transfer protection. The file_size has to
|
||||
be rounded down to be a multiple of the
|
||||
log_page_size in the RESTART_PAGE_HEADER and
|
||||
then it has to be at least big enough to
|
||||
store the two restart pages and 48 (0x30)
|
||||
log record pages. */
|
||||
/* 32*/ le32 last_lsn_data_length;/* Length of data of last LSN, not including
|
||||
the log record header. On create set to
|
||||
0. */
|
||||
/* 36*/ le16 log_record_header_length;/* Byte size of the log record header.
|
||||
If the version matches then check that the
|
||||
value of log_record_header_length is a
|
||||
multiple of 8, i.e.
|
||||
(log_record_header_length + 7) & ~7 ==
|
||||
log_record_header_length. When creating set
|
||||
it to sizeof(LOG_RECORD_HEADER), aligned to
|
||||
8 bytes. */
|
||||
/* 38*/ le16 log_page_data_offset;/* Offset to the start of data in a log record
|
||||
page. Must be a multiple of 8. On create
|
||||
set it to immediately after the update
|
||||
sequence array of the log record page. */
|
||||
/* 40*/ le32 restart_log_open_count;/* A counter that gets incremented every
|
||||
time the logfile is restarted which happens
|
||||
at mount time when the logfile is opened.
|
||||
When creating set to a random value. Win2k
|
||||
sets it to the low 32 bits of the current
|
||||
system time in NTFS format (see time.h). */
|
||||
/* 44*/ le32 reserved; /* Reserved/alignment to 8-byte boundary. */
|
||||
/* sizeof() = 48 (0x30) bytes */
|
||||
} __attribute__((__packed__)) RESTART_AREA;
|
||||
|
||||
/**
|
||||
* struct LOG_CLIENT_RECORD - Log client record.
|
||||
*
|
||||
* The offset of this record is found by adding the offset of the
|
||||
* RESTART_AREA to the client_array_offset value found in it.
|
||||
*/
|
||||
typedef struct {
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||
set to 0. */
|
||||
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
||||
the volume, i.e. the current position within
|
||||
the log file. At present, if clean this
|
||||
should = current_lsn in restart area but it
|
||||
probably also = current_lsn when dirty most
|
||||
of the time. At create set to 0. */
|
||||
/* 16*/ le16 prev_client; /* The offset to the previous log client record
|
||||
in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means there is no previous
|
||||
client record, i.e. this is the first one.
|
||||
This is always LOGFILE_NO_CLIENT. */
|
||||
/* 18*/ le16 next_client; /* The offset to the next log client record in
|
||||
the array of log client records.
|
||||
LOGFILE_NO_CLIENT means there are no next
|
||||
client records, i.e. this is the last one.
|
||||
This is always LOGFILE_NO_CLIENT. */
|
||||
/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set
|
||||
to zero every time the logfile is restarted
|
||||
and it is incremented when the logfile is
|
||||
closed at dismount time. Thus it is 0 when
|
||||
dirty and 1 when clean. On WinXP and
|
||||
presumably later, this is always 0. */
|
||||
/* 22*/ u8 reserved[6]; /* Reserved/alignment. */
|
||||
/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should
|
||||
always be 8. */
|
||||
/* 32*/ ntfschar client_name[64];/* Name of the client in Unicode. Should
|
||||
always be "NTFS" with the remaining bytes
|
||||
set to 0. */
|
||||
/* sizeof() = 160 (0xa0) bytes */
|
||||
} __attribute__((__packed__)) LOG_CLIENT_RECORD;
|
||||
|
||||
/**
|
||||
* struct RECORD_PAGE_HEADER - Log page record page header.
|
||||
*
|
||||
* Each log page begins with this header and is followed by several LOG_RECORD
|
||||
* structures, starting at offset 0x40 (the size of this structure and the
|
||||
* following update sequence array and then aligned to 8 byte boundary, but is
|
||||
* this specified anywhere?).
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
|
||||
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
|
||||
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
|
||||
When creating, set this to be immediately
|
||||
after this header structure (without any
|
||||
alignment). */
|
||||
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
|
||||
|
||||
union {
|
||||
LSN last_lsn;
|
||||
s64 file_offset;
|
||||
} __attribute__((__packed__)) copy;
|
||||
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.
|
||||
*
|
||||
* (Or is it log record pages?)
|
||||
*/
|
||||
typedef enum {
|
||||
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */
|
||||
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. */
|
||||
} __attribute__((__packed__)) LOG_RECORD_FLAGS;
|
||||
|
||||
/**
|
||||
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
|
||||
*/
|
||||
typedef struct {
|
||||
u16 seq_number;
|
||||
u16 client_index;
|
||||
} __attribute__((__packed__)) LOG_CLIENT_ID;
|
||||
|
||||
/**
|
||||
* struct LOG_RECORD - Log record header.
|
||||
*
|
||||
* Each log record seems to have a constant size of 0x70 bytes.
|
||||
*/
|
||||
typedef struct {
|
||||
LSN this_lsn;
|
||||
LSN client_previous_lsn;
|
||||
LSN client_undo_next_lsn;
|
||||
u32 client_data_length;
|
||||
LOG_CLIENT_ID client_id;
|
||||
u32 record_type;
|
||||
u32 transaction_id;
|
||||
u16 flags;
|
||||
u16 reserved_or_alignment[3];
|
||||
/* Now are at ofs 0x30 into struct. */
|
||||
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. */
|
||||
u16 record_offset;
|
||||
u16 attribute_offset;
|
||||
u32 alignment_or_reserved;
|
||||
VCN target_vcn;
|
||||
/* Now at ofs 0x50. */
|
||||
struct { /* Only present if lcns_to_follow
|
||||
is not 0. */
|
||||
LCN lcn;
|
||||
} __attribute__((__packed__)) lcn_list[0];
|
||||
} __attribute__((__packed__)) LOG_RECORD;
|
||||
|
||||
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);
|
||||
|
||||
#endif /* defined _NTFS_LOGFILE_H */
|
111
include/ntfs-3g/logging.h
Normal file
111
include/ntfs-3g/logging.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* logging.h - Centralised logging. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2005 Richard Russon
|
||||
*
|
||||
* 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 _LOGGING_H_
|
||||
#define _LOGGING_H_
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* Function prototype for the logging handlers */
|
||||
typedef int (ntfs_log_handler)(const char *function, const char *file, int line,
|
||||
u32 level, void *data, const char *format, va_list args);
|
||||
|
||||
/* Set the logging handler from one of the functions, below. */
|
||||
void ntfs_log_set_handler(ntfs_log_handler *handler);
|
||||
|
||||
/* Logging handlers */
|
||||
ntfs_log_handler ntfs_log_handler_syslog __attribute__((format(printf, 6, 0)));
|
||||
ntfs_log_handler ntfs_log_handler_fprintf __attribute__((format(printf, 6, 0)));
|
||||
ntfs_log_handler ntfs_log_handler_null __attribute__((format(printf, 6, 0)));
|
||||
ntfs_log_handler ntfs_log_handler_stdout __attribute__((format(printf, 6, 0)));
|
||||
ntfs_log_handler ntfs_log_handler_outerr __attribute__((format(printf, 6, 0)));
|
||||
ntfs_log_handler ntfs_log_handler_stderr __attribute__((format(printf, 6, 0)));
|
||||
|
||||
/* Enable/disable certain log levels */
|
||||
u32 ntfs_log_set_levels(u32 levels);
|
||||
u32 ntfs_log_clear_levels(u32 levels);
|
||||
u32 ntfs_log_get_levels(void);
|
||||
|
||||
/* Enable/disable certain log flags */
|
||||
u32 ntfs_log_set_flags(u32 flags);
|
||||
u32 ntfs_log_clear_flags(u32 flags);
|
||||
u32 ntfs_log_get_flags(void);
|
||||
|
||||
/* Turn command-line options into logging flags */
|
||||
BOOL ntfs_log_parse_option(const char *option);
|
||||
|
||||
int ntfs_log_redirect(const char *function, const char *file, int line,
|
||||
u32 level, void *data, const char *format, ...)
|
||||
__attribute__((format(printf, 6, 7)));
|
||||
|
||||
/* Logging levels - Determine what gets logged */
|
||||
#define NTFS_LOG_LEVEL_DEBUG (1 << 0) /* x = 42 */
|
||||
#define NTFS_LOG_LEVEL_TRACE (1 << 1) /* Entering function x() */
|
||||
#define NTFS_LOG_LEVEL_QUIET (1 << 2) /* Quietable output */
|
||||
#define NTFS_LOG_LEVEL_INFO (1 << 3) /* Volume needs defragmenting */
|
||||
#define NTFS_LOG_LEVEL_VERBOSE (1 << 4) /* Forced to continue */
|
||||
#define NTFS_LOG_LEVEL_PROGRESS (1 << 5) /* 54% complete */
|
||||
#define NTFS_LOG_LEVEL_WARNING (1 << 6) /* You should backup before starting */
|
||||
#define NTFS_LOG_LEVEL_ERROR (1 << 7) /* Operation failed, no damage done */
|
||||
#define NTFS_LOG_LEVEL_PERROR (1 << 8) /* Message : standard error description */
|
||||
#define NTFS_LOG_LEVEL_CRITICAL (1 << 9) /* Operation failed,damage may have occurred */
|
||||
|
||||
/* Logging style flags - Manage the style of the output */
|
||||
#define NTFS_LOG_FLAG_PREFIX (1 << 0) /* Prefix messages with "ERROR: ", etc */
|
||||
#define NTFS_LOG_FLAG_FILENAME (1 << 1) /* Show the file origin of the message */
|
||||
#define NTFS_LOG_FLAG_LINE (1 << 2) /* Show the line number of the message */
|
||||
#define NTFS_LOG_FLAG_FUNCTION (1 << 3) /* Show the function name containing the message */
|
||||
#define NTFS_LOG_FLAG_ONLYNAME (1 << 4) /* Only display the filename, not the pathname */
|
||||
#define NTFS_LOG_FLAG_COLOUR (1 << 5) /* Colour highlight some messages */
|
||||
|
||||
/* Macros to simplify logging. One for each level defined above.
|
||||
* Note, ntfs_log_debug/trace have effect only if DEBUG is defined.
|
||||
*/
|
||||
#define ntfs_log_critical(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_CRITICAL,NULL,FORMAT,##ARGS)
|
||||
#define ntfs_log_error(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_ERROR,NULL,FORMAT,##ARGS)
|
||||
#define ntfs_log_info(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_INFO,NULL,FORMAT,##ARGS)
|
||||
#define ntfs_log_perror(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_PERROR,NULL,FORMAT,##ARGS)
|
||||
#define ntfs_log_progress(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_PROGRESS,NULL,FORMAT,##ARGS)
|
||||
#define ntfs_log_quiet(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_QUIET,NULL,FORMAT,##ARGS)
|
||||
#define ntfs_log_verbose(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_VERBOSE,NULL,FORMAT,##ARGS)
|
||||
#define ntfs_log_warning(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_WARNING,NULL,FORMAT,##ARGS)
|
||||
|
||||
/* By default debug and trace messages are compiled into the program,
|
||||
* but not displayed.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#define ntfs_log_debug(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_DEBUG,NULL,FORMAT,##ARGS)
|
||||
#define ntfs_log_trace(FORMAT, ARGS...) ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__,NTFS_LOG_LEVEL_TRACE,NULL,FORMAT,##ARGS)
|
||||
#else
|
||||
#define ntfs_log_debug(FORMAT, ARGS...)do {} while (0)
|
||||
#define ntfs_log_trace(FORMAT, ARGS...)do {} while (0)
|
||||
#endif /* DEBUG */
|
||||
|
||||
#endif /* _LOGGING_H_ */
|
||||
|
118
include/ntfs-3g/mft.h
Normal file
118
include/ntfs-3g/mft.h
Normal file
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* mft.h - Exports for MFT record handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2002 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_MFT_H
|
||||
#define _NTFS_MFT_H
|
||||
|
||||
#include "volume.h"
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
|
||||
extern int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||
const s64 count, MFT_RECORD *b);
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_read - read a record from the mft
|
||||
* @vol: volume to read from
|
||||
* @mref: mft record number to read
|
||||
* @b: output data buffer
|
||||
*
|
||||
* Read the mft record specified by @mref from volume @vol into buffer @b.
|
||||
* Return 0 on success or -1 on error, with errno set to the error code.
|
||||
*
|
||||
* The read mft record is mst deprotected and is hence ready to use. The caller
|
||||
* should check the record with is_baad_record() in case mst deprotection
|
||||
* failed.
|
||||
*
|
||||
* NOTE: @b has to be at least of size vol->mft_record_size.
|
||||
*/
|
||||
static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol,
|
||||
const MFT_REF mref, MFT_RECORD *b)
|
||||
{
|
||||
return ntfs_mft_records_read(vol, mref, 1, b);
|
||||
}
|
||||
|
||||
extern int ntfs_file_record_read(const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD **mrec, ATTR_RECORD **attr);
|
||||
|
||||
extern int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
||||
const s64 count, MFT_RECORD *b);
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_write - write an mft record to disk
|
||||
* @vol: volume to write to
|
||||
* @mref: mft record number to write
|
||||
* @b: data buffer containing the mft record to write
|
||||
*
|
||||
* Write the mft record specified by @mref from buffer @b to volume @vol.
|
||||
* Return 0 on success or -1 on error, with errno set to the error code.
|
||||
*
|
||||
* Before the mft record is written, it is mst protected. After the write, it
|
||||
* is deprotected again, thus resulting in an increase in the update sequence
|
||||
* number inside the buffer @b.
|
||||
*
|
||||
* NOTE: @b has to be at least of size vol->mft_record_size.
|
||||
*/
|
||||
static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol,
|
||||
const MFT_REF mref, MFT_RECORD *b)
|
||||
{
|
||||
return ntfs_mft_records_write(vol, mref, 1, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mft_record_get_data_size - return number of bytes used in mft record @b
|
||||
* @m: mft record to get the data size of
|
||||
*
|
||||
* Takes the mft record @m and returns the number of bytes used in the record
|
||||
* or 0 on error (i.e. @m is not a valid mft record). Zero is not a valid size
|
||||
* for an mft record as it at least has to have the MFT_RECORD itself and a
|
||||
* zero length attribute of type AT_END, thus making the minimum size 56 bytes.
|
||||
*
|
||||
* Aside: The size is independent of NTFS versions 1.x/3.x because the 8-byte
|
||||
* alignment of the first attribute mask the difference in MFT_RECORD size
|
||||
* between NTFS 1.x and 3.x. Also, you would expect every mft record to
|
||||
* contain an update sequence array as well but that could in theory be
|
||||
* non-existent (don't know if Windows' NTFS driver/chkdsk wouldn't view this
|
||||
* as corruption in itself though).
|
||||
*/
|
||||
static __inline__ u32 ntfs_mft_record_get_data_size(const MFT_RECORD *m)
|
||||
{
|
||||
if (!m || !ntfs_is_mft_record(m->magic))
|
||||
return 0;
|
||||
/* Get the number of used bytes and return it. */
|
||||
return le32_to_cpu(m->bytes_in_use);
|
||||
}
|
||||
|
||||
extern int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
|
||||
MFT_RECORD *mrec);
|
||||
|
||||
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 int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_mft_usn_dec(MFT_RECORD *mrec);
|
||||
|
||||
#endif /* defined _NTFS_MFT_H */
|
||||
|
8
include/ntfs-3g/misc.h
Normal file
8
include/ntfs-3g/misc.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _NTFS_MISC_H_
|
||||
#define _NTFS_MISC_H_
|
||||
|
||||
void *ntfs_calloc(size_t size);
|
||||
void *ntfs_malloc(size_t size);
|
||||
|
||||
#endif /* _NTFS_MISC_H_ */
|
||||
|
34
include/ntfs-3g/mst.h
Normal file
34
include/ntfs-3g/mst.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* mst.h - Exports for multi sector transfer fixup functions.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2002 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_MST_H
|
||||
#define _NTFS_MST_H
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
|
||||
extern int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size);
|
||||
extern int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size);
|
||||
extern void ntfs_mst_post_write_fixup(NTFS_RECORD *b);
|
||||
|
||||
#endif /* defined _NTFS_MST_H */
|
||||
|
69
include/ntfs-3g/ntfstime.h
Normal file
69
include/ntfs-3g/ntfstime.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* ntfstime.h - NTFS time related functions. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2005 Anton Altaparmakov
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
*
|
||||
* 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_NTFSTIME_H
|
||||
#define _NTFS_NTFSTIME_H
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
|
||||
|
||||
/**
|
||||
* 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: n A Unix time (number of seconds since 1970)
|
||||
*/
|
||||
static __inline__ time_t ntfs2utc(s64 ntfs_time)
|
||||
{
|
||||
return (sle64_to_cpu(ntfs_time) - (NTFS_TIME_OFFSET)) / 10000000;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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: n An NTFS time (100ns units since Jan 1601)
|
||||
*/
|
||||
static __inline__ s64 utc2ntfs(time_t utc_time)
|
||||
{
|
||||
/* 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 */
|
87
include/ntfs-3g/runlist.h
Normal file
87
include/ntfs-3g/runlist.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* runlist.h - Exports for runlist handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* 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_RUNLIST_H
|
||||
#define _NTFS_RUNLIST_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/* Forward declarations */
|
||||
typedef struct _runlist_element runlist_element;
|
||||
typedef runlist_element runlist;
|
||||
|
||||
#include "attrib.h"
|
||||
#include "volume.h"
|
||||
|
||||
/**
|
||||
* struct _runlist_element - in memory vcn to lcn mapping array element.
|
||||
* @vcn: starting vcn of the current array element
|
||||
* @lcn: starting lcn of the current array element
|
||||
* @length: length in clusters of the current array element
|
||||
*
|
||||
* The last vcn (in fact the last vcn + 1) is reached when length == 0.
|
||||
*
|
||||
* When lcn == -1 this means that the count vcns starting at vcn are not
|
||||
* physically allocated (i.e. this is a hole / data is sparse).
|
||||
*/
|
||||
struct _runlist_element {/* In memory vcn to lcn mapping structure element. */
|
||||
VCN vcn; /* vcn = Starting virtual cluster number. */
|
||||
LCN lcn; /* lcn = Starting logical cluster number. */
|
||||
s64 length; /* Run length in clusters. */
|
||||
};
|
||||
|
||||
extern LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn);
|
||||
|
||||
extern s64 ntfs_rl_pread(const ntfs_volume *vol, const runlist_element *rl,
|
||||
const s64 pos, s64 count, void *b);
|
||||
extern s64 ntfs_rl_pwrite(const ntfs_volume *vol, const runlist_element *rl,
|
||||
const s64 pos, s64 count, void *b);
|
||||
|
||||
extern runlist_element *ntfs_runlists_merge(runlist_element *drl,
|
||||
runlist_element *srl);
|
||||
|
||||
extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol,
|
||||
const ATTR_RECORD *attr, runlist_element *old_rl);
|
||||
|
||||
extern int ntfs_get_nr_significant_bytes(const s64 n);
|
||||
|
||||
extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
|
||||
const runlist_element *rl, const VCN start_vcn);
|
||||
|
||||
extern int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max,
|
||||
const s64 n);
|
||||
|
||||
extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
|
||||
const int dst_len, const runlist_element *rl,
|
||||
const VCN start_vcn, VCN *const stop_vcn);
|
||||
|
||||
extern int ntfs_rl_truncate(runlist **arl, const VCN start_vcn);
|
||||
|
||||
extern int ntfs_rl_sparse(runlist *rl);
|
||||
extern s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl);
|
||||
|
||||
#ifdef NTFS_TEST
|
||||
int test_rl_main(int argc, char *argv[]);
|
||||
#endif
|
||||
|
||||
#endif /* defined _NTFS_RUNLIST_H */
|
||||
|
58
include/ntfs-3g/security.h
Normal file
58
include/ntfs-3g/security.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* security.h - Exports for handling security/ACLs in NTFS.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2005-2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_SECURITY_H
|
||||
#define _NTFS_SECURITY_H
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
|
||||
extern const GUID *const zero_guid;
|
||||
|
||||
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);
|
||||
extern void ntfs_generate_guid(GUID *guid);
|
||||
extern int ntfs_sd_add_everyone(ntfs_inode *ni);
|
||||
|
||||
#endif /* defined _NTFS_SECURITY_H */
|
85
include/ntfs-3g/support.h
Normal file
85
include/ntfs-3g/support.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* support.h - Useful definitions and macros. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_SUPPORT_H
|
||||
#define _NTFS_SUPPORT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDDEF_H
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Our mailing list. Use this define to prevent typos in email address.
|
||||
*/
|
||||
#define NTFS_DEV_LIST "ntfs-3g-devel@lists.sf.net"
|
||||
|
||||
/*
|
||||
* Generic macro to convert pointers to values for comparison purposes.
|
||||
*/
|
||||
#ifndef p2n
|
||||
#define p2n(p) ((ptrdiff_t)((ptrdiff_t*)(p)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The classic min and max macros.
|
||||
*/
|
||||
#ifndef min
|
||||
#define min(a,b) ((a) <= (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a) >= (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Useful macro for determining the offset of a struct member.
|
||||
*/
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simple bit operation macros. NOTE: These are NOT atomic.
|
||||
*/
|
||||
#define test_bit(bit, var) ((var) & (1 << (bit)))
|
||||
#define set_bit(bit, var) (var) |= 1 << (bit)
|
||||
#define clear_bit(bit, var) (var) &= ~(1 << (bit))
|
||||
|
||||
#define test_and_set_bit(bit, var) \
|
||||
({ \
|
||||
const BOOL old_state = test_bit(bit, var); \
|
||||
set_bit(bit, var); \
|
||||
old_state; \
|
||||
})
|
||||
|
||||
#define test_and_clear_bit(bit, var) \
|
||||
({ \
|
||||
const BOOL old_state = test_bit(bit, var); \
|
||||
clear_bit(bit, var); \
|
||||
old_state; \
|
||||
})
|
||||
|
||||
#endif /* defined _NTFS_SUPPORT_H */
|
||||
|
124
include/ntfs-3g/types.h
Normal file
124
include/ntfs-3g/types.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* types.h - Misc type definitions not related to on-disk structure.
|
||||
* Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_TYPES_H
|
||||
#define _NTFS_TYPES_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if HAVE_STDINT_H || !HAVE_CONFIG_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
typedef uint8_t u8; /* Unsigned types of an exact size */
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef int8_t s8; /* Signed types of an exact size */
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
|
||||
typedef u16 le16;
|
||||
typedef u32 le32;
|
||||
typedef u64 le64;
|
||||
|
||||
/*
|
||||
* 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 ntfschar; /* 2-byte Unicode character type. */
|
||||
#define UCHAR_T_SIZE_BITS 1
|
||||
|
||||
/*
|
||||
* Clusters are signed 64-bit values on NTFS volumes. We define two types, LCN
|
||||
* and VCN, to allow for type checking and better code readability.
|
||||
*/
|
||||
typedef s64 VCN;
|
||||
typedef sle64 leVCN;
|
||||
typedef s64 LCN;
|
||||
typedef sle64 leLCN;
|
||||
|
||||
/*
|
||||
* The NTFS journal $LogFile uses log sequence numbers which are signed 64-bit
|
||||
* values. We define our own type LSN, to allow for type checking and better
|
||||
* code readability.
|
||||
*/
|
||||
typedef s64 LSN;
|
||||
typedef sle64 leLSN;
|
||||
|
||||
/*
|
||||
* Cygwin has a collision between our BOOL and <windef.h>'s
|
||||
* As long as this file will be included after <windows.h> were fine.
|
||||
*/
|
||||
#ifndef _WINDEF_H
|
||||
/**
|
||||
* enum BOOL - These are just to make the code more readable...
|
||||
*/
|
||||
typedef enum {
|
||||
#ifndef FALSE
|
||||
FALSE = 0,
|
||||
#endif
|
||||
#ifndef NO
|
||||
NO = 0,
|
||||
#endif
|
||||
#ifndef ZERO
|
||||
ZERO = 0,
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
TRUE = 1,
|
||||
#endif
|
||||
#ifndef YES
|
||||
YES = 1,
|
||||
#endif
|
||||
#ifndef ONE
|
||||
ONE = 1,
|
||||
#endif
|
||||
} BOOL;
|
||||
#endif /* defined _WINDEF_H */
|
||||
|
||||
/**
|
||||
* enum IGNORE_CASE_BOOL -
|
||||
*/
|
||||
typedef enum {
|
||||
CASE_SENSITIVE = 0,
|
||||
IGNORE_CASE = 1,
|
||||
} IGNORE_CASE_BOOL;
|
||||
|
||||
#define STATUS_OK (0)
|
||||
#define STATUS_ERROR (-1)
|
||||
#define STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT (-2)
|
||||
#define STATUS_KEEP_SEARCHING (-3)
|
||||
#define STATUS_NOT_FOUND (-4)
|
||||
|
||||
#endif /* defined _NTFS_TYPES_H */
|
||||
|
69
include/ntfs-3g/unistr.h
Normal file
69
include/ntfs-3g/unistr.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* unistr.h - Exports for Unicode string handling. Originated from the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 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
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_UNISTR_H
|
||||
#define _NTFS_UNISTR_H
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
|
||||
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_collate(const ntfschar *name1, const u32 name1_len,
|
||||
const ntfschar *name2, const u32 name2_len,
|
||||
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);
|
||||
|
||||
extern int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
|
||||
const ntfschar *upcase, const u32 upcase_size);
|
||||
|
||||
extern u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen);
|
||||
|
||||
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_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, int outs_len);
|
||||
|
||||
extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len);
|
||||
|
||||
extern ntfschar *ntfs_str2ucs(const char *s, int *len);
|
||||
|
||||
extern void ntfs_ucsfree(ntfschar *ucs);
|
||||
|
||||
#endif /* defined _NTFS_UNISTR_H */
|
||||
|
29
include/ntfs-3g/version.h
Normal file
29
include/ntfs-3g/version.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* version.h - Info about the NTFS library. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2005 Anton Altaparmakov
|
||||
* Copyright (c) 2005 Richard Russon
|
||||
*
|
||||
* 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_VERSION_H_
|
||||
#define _NTFS_VERSION_H_
|
||||
|
||||
extern const char *ntfs_libntfs_version(void);
|
||||
|
||||
#endif /* _NTFS_VERSION_H_ */
|
||||
|
233
include/ntfs-3g/volume.h
Normal file
233
include/ntfs-3g/volume.h
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* volume.h - Exports for NTFS volume handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* Copyright (c) 2005-2006 Yura Pakhuchiy
|
||||
* Copyright (c) 2005-2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_VOLUME_H
|
||||
#define _NTFS_VOLUME_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#ifdef HAVE_MNTENT_H
|
||||
#include <mntent.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Under Cygwin, DJGPP and FreeBSD we do not have MS_RDONLY and MS_NOATIME,
|
||||
* so we define them ourselves.
|
||||
*/
|
||||
#ifndef MS_RDONLY
|
||||
#define MS_RDONLY 1
|
||||
#endif
|
||||
/*
|
||||
* Solaris defines MS_RDONLY but not MS_NOATIME thus we need to carefully
|
||||
* define MS_NOATIME.
|
||||
*/
|
||||
#ifndef MS_NOATIME
|
||||
#if (MS_RDONLY != 1)
|
||||
# define MS_NOATIME 1
|
||||
#else
|
||||
# define MS_NOATIME 2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct _ntfs_volume ntfs_volume;
|
||||
|
||||
#include "types.h"
|
||||
#include "support.h"
|
||||
#include "device.h"
|
||||
#include "inode.h"
|
||||
#include "attrib.h"
|
||||
|
||||
/**
|
||||
* enum ntfs_mount_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_mount_flags;
|
||||
|
||||
extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags);
|
||||
|
||||
/**
|
||||
* enum ntfs_volume_state_bits -
|
||||
*
|
||||
* Defined bits for the state field in the ntfs_volume structure.
|
||||
*/
|
||||
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_NoATime, /* 1: Do not update access time. */
|
||||
} ntfs_volume_state_bits;
|
||||
|
||||
#define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state)
|
||||
#define set_nvol_flag(nv, flag) set_bit(NV_##flag, (nv)->state)
|
||||
#define clear_nvol_flag(nv, flag) clear_bit(NV_##flag, (nv)->state)
|
||||
|
||||
#define NVolReadOnly(nv) test_nvol_flag(nv, ReadOnly)
|
||||
#define NVolSetReadOnly(nv) set_nvol_flag(nv, ReadOnly)
|
||||
#define NVolClearReadOnly(nv) clear_nvol_flag(nv, ReadOnly)
|
||||
|
||||
#define NVolCaseSensitive(nv) test_nvol_flag(nv, CaseSensitive)
|
||||
#define NVolSetCaseSensitive(nv) set_nvol_flag(nv, CaseSensitive)
|
||||
#define NVolClearCaseSensitive(nv) clear_nvol_flag(nv, CaseSensitive)
|
||||
|
||||
#define NVolLogFileEmpty(nv) test_nvol_flag(nv, LogFileEmpty)
|
||||
#define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty)
|
||||
#define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty)
|
||||
|
||||
#define NVolNoATime(nv) test_nvol_flag(nv, NoATime)
|
||||
#define NVolSetNoATime(nv) set_nvol_flag(nv, NoATime)
|
||||
#define NVolClearNoATime(nv) clear_nvol_flag(nv, NoATime)
|
||||
|
||||
/*
|
||||
* NTFS version 1.1 and 1.2 are used by Windows NT4.
|
||||
* NTFS version 2.x is used by Windows 2000 Beta
|
||||
* NTFS version 3.0 is used by Windows 2000.
|
||||
* NTFS version 3.1 is used by Windows XP, 2003 and Vista.
|
||||
*/
|
||||
|
||||
#define NTFS_V1_1(major, minor) ((major) == 1 && (minor) == 1)
|
||||
#define NTFS_V1_2(major, minor) ((major) == 1 && (minor) == 2)
|
||||
#define NTFS_V2_X(major, minor) ((major) == 2)
|
||||
#define NTFS_V3_0(major, minor) ((major) == 3 && (minor) == 0)
|
||||
#define NTFS_V3_1(major, minor) ((major) == 3 && (minor) == 1)
|
||||
|
||||
#define NTFS_BUF_SIZE 8192
|
||||
|
||||
/**
|
||||
* struct _ntfs_volume - structure describing an open volume in memory.
|
||||
*/
|
||||
struct _ntfs_volume {
|
||||
union {
|
||||
struct ntfs_device *dev; /* NTFS device associated with
|
||||
the volume. */
|
||||
void *sb; /* For kernel porting compatibility. */
|
||||
};
|
||||
char *vol_name; /* Name of the volume. */
|
||||
unsigned long state; /* NTFS specific flags describing this volume.
|
||||
See ntfs_volume_state_bits above. */
|
||||
|
||||
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. */
|
||||
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. */
|
||||
u32 cluster_size; /* Byte size of a cluster. */
|
||||
u32 mft_record_size; /* Byte size of a mft record. */
|
||||
u32 indx_record_size; /* Byte size of a INDX record. */
|
||||
u8 cluster_size_bits; /* Log(2) of the byte size of a cluster. */
|
||||
u8 mft_record_size_bits;/* Log(2) of the byte size of a mft record. */
|
||||
u8 indx_record_size_bits;/* Log(2) of the byte size of a INDX record. */
|
||||
|
||||
/* Variables used by the cluster and mft allocators. */
|
||||
u8 mft_zone_multiplier; /* Initial mft zone multiplier. */
|
||||
s64 mft_data_pos; /* Mft record number at which to allocate the
|
||||
next mft record. */
|
||||
LCN mft_zone_start; /* First cluster of the mft zone. */
|
||||
LCN mft_zone_end; /* First cluster beyond the mft zone. */
|
||||
LCN mft_zone_pos; /* Current position in the mft zone. */
|
||||
LCN data1_zone_pos; /* Current position in the first data zone. */
|
||||
LCN data2_zone_pos; /* Current position in the second data zone. */
|
||||
|
||||
s64 nr_clusters; /* Volume size in clusters, hence also the
|
||||
number of bits in lcn_bitmap. */
|
||||
ntfs_inode *lcnbmp_ni; /* ntfs_inode structure for FILE_Bitmap. */
|
||||
ntfs_attr *lcnbmp_na; /* ntfs_attr structure for the data attribute
|
||||
of FILE_Bitmap. Each bit represents a
|
||||
cluster on the volume, bit 0 representing
|
||||
lcn 0 and so on. A set bit means that the
|
||||
cluster and vice versa. */
|
||||
|
||||
LCN mft_lcn; /* Logical cluster number of the data attribute
|
||||
for FILE_MFT. */
|
||||
ntfs_inode *mft_ni; /* ntfs_inode structure for FILE_MFT. */
|
||||
ntfs_attr *mft_na; /* ntfs_attr structure for the data attribute
|
||||
of FILE_MFT. */
|
||||
ntfs_attr *mftbmp_na; /* ntfs_attr structure for the bitmap attribute
|
||||
of FILE_MFT. Each bit represents an mft
|
||||
record in the $DATA attribute, bit 0
|
||||
representing mft record 0 and so on. A set
|
||||
bit means that the mft record is in use and
|
||||
vice versa. */
|
||||
|
||||
int mftmirr_size; /* Size of the FILE_MFTMirr in mft records. */
|
||||
LCN mftmirr_lcn; /* Logical cluster number of the data attribute
|
||||
for FILE_MFTMirr. */
|
||||
ntfs_inode *mftmirr_ni; /* ntfs_inode structure for FILE_MFTMirr. */
|
||||
ntfs_attr *mftmirr_na; /* ntfs_attr structure for the data attribute
|
||||
of FILE_MFTMirr. */
|
||||
|
||||
ntfschar *upcase; /* Upper case equivalents of all 65536 2-byte
|
||||
Unicode characters. Obtained from
|
||||
FILE_UpCase. */
|
||||
u32 upcase_len; /* Length in Unicode characters of the upcase
|
||||
table. */
|
||||
|
||||
ATTR_DEF *attrdef; /* Attribute definitions. Obtained from
|
||||
FILE_AttrDef. */
|
||||
s32 attrdef_len; /* Size of the attribute definition table in
|
||||
bytes. */
|
||||
|
||||
/* Temp: for directory handling */
|
||||
void *private_data; /* ntfs_dir for . */
|
||||
void *private_bmp1; /* ntfs_bmp for $MFT/$BITMAP */
|
||||
void *private_bmp2; /* ntfs_bmp for $Bitmap */
|
||||
};
|
||||
|
||||
extern ntfs_volume *ntfs_volume_alloc(void);
|
||||
|
||||
extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
|
||||
unsigned long flags);
|
||||
|
||||
extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
|
||||
unsigned long flags);
|
||||
extern int ntfs_device_umount(ntfs_volume *vol, const BOOL force);
|
||||
|
||||
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_logfile_reset(ntfs_volume *vol);
|
||||
|
||||
extern int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags);
|
||||
|
||||
#endif /* defined _NTFS_VOLUME_H */
|
||||
|
64
libntfs-3g/Makefile.am
Normal file
64
libntfs-3g/Makefile.am
Normal file
@ -0,0 +1,64 @@
|
||||
#
|
||||
# Before making a release, the LTVERSION string should be modified.
|
||||
# The string is of the form CURRENT:REVISION:AGE.
|
||||
#
|
||||
# CURRENT (C)
|
||||
# The most recent interface number that this library implements.
|
||||
#
|
||||
# REVISION (R)
|
||||
# The implementation number that this library implements.
|
||||
#
|
||||
# AGE (A)
|
||||
# The difference between the newest and oldest interfaces that this
|
||||
# library implements. In other works, the library implements all the
|
||||
# interface numbers in the range from number 'CURRENT - AGE' to
|
||||
# 'CURRENT'.
|
||||
#
|
||||
# This means that:
|
||||
#
|
||||
# - If interfaces have been changed or added, but binary compatibility has
|
||||
# been preserved, change to C+1:0:A+1
|
||||
#
|
||||
# - If binary compatibility has been broken (eg removed or changed
|
||||
# interfaces) change to C+1:0:0
|
||||
#
|
||||
# - If the interface is the same as the previous version, change to C:R+1:A
|
||||
#
|
||||
|
||||
linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs-3g
|
||||
|
||||
lib_LTLIBRARIES = libntfs-3g.la
|
||||
libntfs_3g_la_CFLAGS = $(LIBNTFS_3G_CFLAGS)
|
||||
libntfs_3g_la_SOURCES = \
|
||||
attrib.c \
|
||||
attrlist.c \
|
||||
bitmap.c \
|
||||
bootsect.c \
|
||||
collate.c \
|
||||
compat.c \
|
||||
compress.c \
|
||||
debug.c \
|
||||
device.c \
|
||||
device_io.c \
|
||||
dir.c \
|
||||
index.c \
|
||||
inode.c \
|
||||
lcnalloc.c \
|
||||
logfile.c \
|
||||
logging.c \
|
||||
mft.c \
|
||||
misc.c \
|
||||
mst.c \
|
||||
runlist.c \
|
||||
security.c \
|
||||
unistr.c \
|
||||
version.c \
|
||||
volume.c
|
||||
|
||||
AM_CPPFLAGS = $(linux_ntfsincludedir) $(all_includes)
|
||||
|
||||
EXTRA_DIST = unix_io.c
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
libs: $(lib_LTLIBRARIES)
|
4928
libntfs-3g/attrib.c
Normal file
4928
libntfs-3g/attrib.c
Normal file
File diff suppressed because it is too large
Load Diff
315
libntfs-3g/attrlist.c
Normal file
315
libntfs-3g/attrlist.c
Normal file
@ -0,0 +1,315 @@
|
||||
/**
|
||||
* attrlist.c - Attribute list attribute handling code. Originated from the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "attrib.h"
|
||||
#include "attrlist.h"
|
||||
#include "debug.h"
|
||||
#include "unistr.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_need - check whether inode need attribute list
|
||||
* @ni: opened ntfs inode for which perform check
|
||||
*
|
||||
* Check whether all are attributes belong to one MFT record, in that case
|
||||
* attribute list is not needed.
|
||||
*
|
||||
* Return 1 if inode need attribute list, 0 if not, -1 on error with errno set
|
||||
* to the error code. If function succeed errno set to 0. The following error
|
||||
* codes are defined:
|
||||
* EINVAL - Invalid arguments passed to function or attribute haven't got
|
||||
* attribute list.
|
||||
*/
|
||||
int ntfs_attrlist_need(ntfs_inode *ni)
|
||||
{
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
|
||||
if (!ni) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
|
||||
|
||||
if (!NInoAttrList(ni)) {
|
||||
ntfs_log_trace("Inode haven't got attribute list.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ni->attr_list) {
|
||||
ntfs_log_trace("Corrupt in-memory struct.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
ale = (ATTR_LIST_ENTRY *)ni->attr_list;
|
||||
while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
|
||||
if (MREF_LE(ale->mft_reference) != ni->mft_no)
|
||||
return 1;
|
||||
ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_entry_add - add an attribute list attribute entry
|
||||
* @ni: opened ntfs inode, which contains that attribute
|
||||
* @attr: attribute record to add to attribute list
|
||||
*
|
||||
* Return 0 on success and -1 on error with errno set to the error code. The
|
||||
* following error codes are defined:
|
||||
* EINVAL - Invalid arguments passed to function.
|
||||
* ENOMEM - Not enough memory to allocate necessary buffers.
|
||||
* EIO - I/O error occurred or damaged filesystem.
|
||||
* EEXIST - Such attribute already present in attribute list.
|
||||
*/
|
||||
int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
|
||||
{
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
MFT_REF mref;
|
||||
ntfs_attr *na = NULL;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
u8 *new_al;
|
||||
int entry_len, entry_offset, err;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
|
||||
(long long) ni->mft_no,
|
||||
(unsigned) le32_to_cpu(attr->type));
|
||||
|
||||
if (!ni || !attr) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mref = MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));
|
||||
|
||||
if (ni->nr_extents == -1)
|
||||
ni = ni->base_ni;
|
||||
|
||||
if (!NInoAttrList(ni)) {
|
||||
ntfs_log_trace("Attribute list isn't present.\n");
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Determine size and allocate memory for new attribute list. */
|
||||
entry_len = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
|
||||
attr->name_length + 7) & ~7;
|
||||
new_al = ntfs_calloc(ni->attr_list_size + entry_len);
|
||||
if (!new_al)
|
||||
return -1;
|
||||
|
||||
/* Find place for the new entry. */
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to obtain attribute search context.\n");
|
||||
goto err_out;
|
||||
}
|
||||
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) ? 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)) {
|
||||
/* Found some extent, check it to be before new extent. */
|
||||
if (ctx->al_entry->lowest_vcn == attr->lowest_vcn) {
|
||||
err = EEXIST;
|
||||
ntfs_log_trace("Such attribute already present in the "
|
||||
"attribute list.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto err_out;
|
||||
}
|
||||
/* Add new entry after this extent. */
|
||||
ale = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
|
||||
le16_to_cpu(ctx->al_entry->length));
|
||||
} else {
|
||||
/* Check for real errors. */
|
||||
if (errno != ENOENT) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Attribute lookup failed.\n");
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
goto err_out;
|
||||
}
|
||||
/* No previous extents found. */
|
||||
ale = ctx->al_entry;
|
||||
}
|
||||
/* Don't need it anymore, @ctx->al_entry points to @ni->attr_list. */
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
|
||||
/* Determine new entry offset. */
|
||||
entry_offset = ((u8 *)ale - ni->attr_list);
|
||||
/* Set pointer to new entry. */
|
||||
ale = (ATTR_LIST_ENTRY *)(new_al + entry_offset);
|
||||
/* Zero it to fix valgrind warning. */
|
||||
memset(ale, 0, entry_len);
|
||||
/* Form new entry. */
|
||||
ale->type = attr->type;
|
||||
ale->length = cpu_to_le16(entry_len);
|
||||
ale->name_length = attr->name_length;
|
||||
ale->name_offset = offsetof(ATTR_LIST_ENTRY, name);
|
||||
if (attr->non_resident)
|
||||
ale->lowest_vcn = attr->lowest_vcn;
|
||||
else
|
||||
ale->lowest_vcn = 0;
|
||||
ale->mft_reference = mref;
|
||||
ale->instance = attr->instance;
|
||||
memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
|
||||
attr->name_length * sizeof(ntfschar));
|
||||
|
||||
/* Resize $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, ni->attr_list_size + entry_len)) {
|
||||
err = errno;
|
||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Copy entries from old attribute list to new. */
|
||||
memcpy(new_al, ni->attr_list, entry_offset);
|
||||
memcpy(new_al + entry_offset + entry_len, ni->attr_list +
|
||||
entry_offset, ni->attr_list_size - entry_offset);
|
||||
|
||||
/* Set new runlist. */
|
||||
free(ni->attr_list);
|
||||
ni->attr_list = new_al;
|
||||
ni->attr_list_size = ni->attr_list_size + entry_len;
|
||||
NInoAttrListSetDirty(ni);
|
||||
/* Done! */
|
||||
ntfs_attr_close(na);
|
||||
return 0;
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_attrlist_entry_rm - remove an attribute list attribute entry
|
||||
* @ctx: attribute search context describing the attribute list entry
|
||||
*
|
||||
* Remove the attribute list entry @ctx->al_entry from the attribute list.
|
||||
*
|
||||
* Return 0 on success and -1 on error with errno set to the error code.
|
||||
*/
|
||||
int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
u8 *new_al;
|
||||
int new_al_len;
|
||||
ntfs_inode *base_ni;
|
||||
ntfs_attr *na;
|
||||
ATTR_LIST_ENTRY *ale;
|
||||
int err;
|
||||
|
||||
if (!ctx || !ctx->ntfs_ino || !ctx->al_entry) {
|
||||
ntfs_log_trace("Invalid arguments.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->base_ntfs_ino)
|
||||
base_ni = ctx->base_ntfs_ino;
|
||||
else
|
||||
base_ni = ctx->ntfs_ino;
|
||||
ale = ctx->al_entry;
|
||||
|
||||
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) le64_to_cpu(ctx->al_entry->lowest_vcn));
|
||||
|
||||
if (!NInoAttrList(base_ni)) {
|
||||
ntfs_log_trace("Attribute list isn't present.\n");
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate memory for new attribute list. */
|
||||
new_al_len = base_ni->attr_list_size - le16_to_cpu(ale->length);
|
||||
new_al = ntfs_calloc(new_al_len);
|
||||
if (!new_al)
|
||||
return -1;
|
||||
|
||||
/* Reisze $ATTRIBUTE_LIST to new length. */
|
||||
na = ntfs_attr_open(base_ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
err = errno;
|
||||
ntfs_log_trace("Failed to open $ATTRIBUTE_LIST attribute.\n");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_attr_truncate(na, new_al_len)) {
|
||||
err = errno;
|
||||
ntfs_log_trace("$ATTRIBUTE_LIST resize failed.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Copy entries from old attribute list to new. */
|
||||
memcpy(new_al, base_ni->attr_list, (u8*)ale - base_ni->attr_list);
|
||||
memcpy(new_al + ((u8*)ale - base_ni->attr_list), (u8*)ale + le16_to_cpu(
|
||||
ale->length), new_al_len - ((u8*)ale - base_ni->attr_list));
|
||||
|
||||
/* Set new runlist. */
|
||||
free(base_ni->attr_list);
|
||||
base_ni->attr_list = new_al;
|
||||
base_ni->attr_list_size = new_al_len;
|
||||
NInoAttrListSetDirty(base_ni);
|
||||
/* Done! */
|
||||
ntfs_attr_close(na);
|
||||
return 0;
|
||||
err_out:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
free(new_al);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
289
libntfs-3g/bitmap.c
Normal file
289
libntfs-3g/bitmap.c
Normal file
@ -0,0 +1,289 @@
|
||||
/**
|
||||
* bitmap.c - Bitmap handling code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Richard Russon
|
||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
#include "bitmap.h"
|
||||
#include "debug.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
/**
|
||||
* ntfs_bit_set - set a bit in a field of bits
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to set
|
||||
* @new_value: value to set bit to (0 or 1)
|
||||
*
|
||||
* Set the bit @bit in the @bitmap to @new_value. Ignore all errors.
|
||||
*/
|
||||
void ntfs_bit_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
||||
{
|
||||
if (!bitmap || new_value > 1)
|
||||
return;
|
||||
if (!new_value)
|
||||
bitmap[bit >> 3] &= ~(1 << (bit & 7));
|
||||
else
|
||||
bitmap[bit >> 3] |= (1 << (bit & 7));
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bit_get - get value of a bit in a field of bits
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to get
|
||||
*
|
||||
* Get and return the value of the bit @bit in @bitmap (0 or 1).
|
||||
* Return -1 on error.
|
||||
*/
|
||||
char ntfs_bit_get(const u8 *bitmap, const u64 bit)
|
||||
{
|
||||
if (!bitmap)
|
||||
return -1;
|
||||
return (bitmap[bit >> 3] >> (bit & 7)) & 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bit_get_and_set - get value of a bit in a field of bits and set it
|
||||
* @bitmap: field of bits
|
||||
* @bit: bit to get/set
|
||||
* @new_value: value to set bit to (0 or 1)
|
||||
*
|
||||
* Return the value of the bit @bit and set it to @new_value (0 or 1).
|
||||
* Return -1 on error.
|
||||
*/
|
||||
char ntfs_bit_get_and_set(u8 *bitmap, const u64 bit, const u8 new_value)
|
||||
{
|
||||
register u8 old_bit, shift;
|
||||
|
||||
if (!bitmap || new_value > 1)
|
||||
return -1;
|
||||
shift = bit & 7;
|
||||
old_bit = (bitmap[bit >> 3] >> shift) & 1;
|
||||
if (new_value != old_bit)
|
||||
bitmap[bit >> 3] ^= 1 << shift;
|
||||
return old_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
* @count: number of bits to set
|
||||
* @value: value to set the bits to (i.e. 0 or 1)
|
||||
*
|
||||
* Set @count bits starting at bit @start_bit in the bitmap described by the
|
||||
* attribute @na to @value, where @value is either 0 or 1.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
static int ntfs_bitmap_set_bits_in_run(ntfs_attr *na, s64 start_bit,
|
||||
s64 count, int value)
|
||||
{
|
||||
s64 bufsize, br;
|
||||
u8 *buf, *lastbyte_buf;
|
||||
int bit, firstbyte, lastbyte, lastbyte_pos, tmp, err;
|
||||
|
||||
if (!na || start_bit < 0 || count < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bit = start_bit & 7;
|
||||
if (bit)
|
||||
firstbyte = 1;
|
||||
else
|
||||
firstbyte = 0;
|
||||
|
||||
/* Calculate the required buffer size in bytes, capping it at 8kiB. */
|
||||
bufsize = ((count - (bit ? 8 - bit : 0) + 7) >> 3) + firstbyte;
|
||||
if (bufsize > 8192)
|
||||
bufsize = 8192;
|
||||
|
||||
buf = ntfs_malloc(bufsize);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
/* Depending on @value, zero or set all bits in the allocated buffer. */
|
||||
memset(buf, value ? 0xff : 0, bufsize);
|
||||
|
||||
/* If there is a first partial byte... */
|
||||
if (bit) {
|
||||
/* read it in... */
|
||||
br = ntfs_attr_pread(na, start_bit >> 3, 1, buf);
|
||||
if (br != 1) {
|
||||
free(buf);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
/* and set or clear the appropriate bits in it. */
|
||||
while ((bit & 7) && count--) {
|
||||
if (value)
|
||||
*buf |= 1 << bit++;
|
||||
else
|
||||
*buf &= ~(1 << bit++);
|
||||
}
|
||||
/* Update @start_bit to the new position. */
|
||||
start_bit = (start_bit + 7) & ~7;
|
||||
}
|
||||
|
||||
/* Loop until @count reaches zero. */
|
||||
lastbyte = 0;
|
||||
lastbyte_buf = NULL;
|
||||
bit = count & 7;
|
||||
do {
|
||||
/* If there is a last partial byte... */
|
||||
if (count > 0 && bit) {
|
||||
lastbyte_pos = ((count + 7) >> 3) + firstbyte;
|
||||
if (!lastbyte_pos) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_trace("Eeek! lastbyte is zero. Leaving "
|
||||
"inconsistent metadata.\n");
|
||||
err = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and it is in the currently loaded bitmap window... */
|
||||
if (lastbyte_pos <= bufsize) {
|
||||
lastbyte_buf = buf + lastbyte_pos - 1;
|
||||
|
||||
/* read the byte in... */
|
||||
br = ntfs_attr_pread(na, (start_bit + count) >>
|
||||
3, 1, lastbyte_buf);
|
||||
if (br != 1) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_trace("Eeek! Read of last byte "
|
||||
"failed. Leaving "
|
||||
"inconsistent metadata.\n");
|
||||
err = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
/* and set/clear the appropriate bits in it. */
|
||||
while (bit && count--) {
|
||||
if (value)
|
||||
*lastbyte_buf |= 1 << --bit;
|
||||
else
|
||||
*lastbyte_buf &= ~(1 << --bit);
|
||||
}
|
||||
/* We don't want to come back here... */
|
||||
bit = 0;
|
||||
/* We have a last byte that we have handled. */
|
||||
lastbyte = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the prepared buffer to disk. */
|
||||
tmp = (start_bit >> 3) - firstbyte;
|
||||
br = ntfs_attr_pwrite(na, tmp, bufsize, buf);
|
||||
if (br != bufsize) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_trace("Eeek! Failed to write buffer to bitmap. "
|
||||
"Leaving inconsistent metadata.\n");
|
||||
err = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
|
||||
/* Update counters. */
|
||||
tmp = (bufsize - firstbyte - lastbyte) << 3;
|
||||
if (firstbyte) {
|
||||
firstbyte = 0;
|
||||
/*
|
||||
* Re-set the partial first byte so a subsequent write
|
||||
* of the buffer does not have stale, incorrect bits.
|
||||
*/
|
||||
*buf = value ? 0xff : 0;
|
||||
}
|
||||
start_bit += tmp;
|
||||
count -= tmp;
|
||||
if (bufsize > (tmp = (count + 7) >> 3))
|
||||
bufsize = tmp;
|
||||
|
||||
if (lastbyte && count != 0) {
|
||||
// FIXME: Eeek! BUG!
|
||||
ntfs_log_trace("Eeek! Last buffer but count is not zero (= "
|
||||
"%lli). Leaving inconsistent metadata.\n",
|
||||
(long long)count);
|
||||
err = EIO;
|
||||
goto free_err_out;
|
||||
}
|
||||
} while (count > 0);
|
||||
|
||||
/* Done! */
|
||||
free(buf);
|
||||
return 0;
|
||||
|
||||
free_err_out:
|
||||
free(buf);
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_set_run - set a run of bits in a bitmap
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to set
|
||||
* @count: number of bits to set
|
||||
*
|
||||
* Set @count bits starting at bit @start_bit in the bitmap described by the
|
||||
* attribute @na.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_bitmap_set_run(ntfs_attr *na, s64 start_bit, s64 count)
|
||||
{
|
||||
return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_bitmap_clear_run - clear a run of bits in a bitmap
|
||||
* @na: attribute containing the bitmap
|
||||
* @start_bit: first bit to clear
|
||||
* @count: number of bits to clear
|
||||
*
|
||||
* Clear @count bits starting at bit @start_bit in the bitmap described by the
|
||||
* attribute @na.
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_bitmap_clear_run(ntfs_attr *na, s64 start_bit, s64 count)
|
||||
{
|
||||
ntfs_log_trace("Dealloc from bit 0x%llx, count 0x%llx.\n",
|
||||
(long long)start_bit, (long long)count);
|
||||
|
||||
return ntfs_bitmap_set_bits_in_run(na, start_bit, count, 0);
|
||||
}
|
||||
|
273
libntfs-3g/bootsect.c
Normal file
273
libntfs-3g/bootsect.c
Normal file
@ -0,0 +1,273 @@
|
||||
/**
|
||||
* bootsect.c - Boot sector handling code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2003-2004 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
*
|
||||
* 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_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
#include "bootsect.h"
|
||||
#include "debug.h"
|
||||
#include "logging.h"
|
||||
|
||||
/**
|
||||
* ntfs_boot_sector_is_ntfs - check if buffer contains a valid ntfs boot sector
|
||||
* @b: buffer containing putative boot sector to analyze
|
||||
* @silent: if zero, output progress messages to stderr
|
||||
*
|
||||
* Check if the buffer @b contains a valid ntfs boot sector. The buffer @b
|
||||
* must be at least 512 bytes in size.
|
||||
*
|
||||
* If @silent is zero, output progress messages to stderr. Otherwise, do not
|
||||
* output any messages (except when configured with --enable-debug in which
|
||||
* case warning/debug messages may be displayed).
|
||||
*
|
||||
* Return TRUE if @b contains a valid ntfs boot sector and FALSE if not.
|
||||
*/
|
||||
BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b, const BOOL silent __attribute__((unused)))
|
||||
{
|
||||
u32 i;
|
||||
|
||||
ntfs_log_debug("\nBeginning bootsector check...\n");
|
||||
|
||||
/* Calculate the checksum. Note, this is just a simple addition of
|
||||
all u32 values in the bootsector starting at the beginning and
|
||||
finishing at the offset of the checksum itself (i.e. not including
|
||||
the checksum...). */
|
||||
if ((void*)b < (void*)&b->checksum) {
|
||||
u32 *u = (u32 *)b;
|
||||
u32 *bi = (u32 *)(&b->checksum);
|
||||
|
||||
ntfs_log_debug("Calculating bootsector checksum... ");
|
||||
|
||||
for (i = 0; u < bi; ++u)
|
||||
i += le32_to_cpup(u);
|
||||
|
||||
if (le32_to_cpu(b->checksum) && le32_to_cpu(b->checksum) != i)
|
||||
goto not_ntfs;
|
||||
ntfs_log_debug("OK\n");
|
||||
}
|
||||
|
||||
/* Check OEMidentifier is "NTFS " */
|
||||
ntfs_log_debug("Checking OEMid... ");
|
||||
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) /* "NTFS " */
|
||||
goto not_ntfs;
|
||||
ntfs_log_debug("OK\n");
|
||||
|
||||
/* Check bytes per sector value is between 256 and 4096. */
|
||||
ntfs_log_debug("Checking bytes per sector... ");
|
||||
if (le16_to_cpu(b->bpb.bytes_per_sector) < 0x100 ||
|
||||
le16_to_cpu(b->bpb.bytes_per_sector) > 0x1000)
|
||||
goto not_ntfs;
|
||||
ntfs_log_debug("OK\n");
|
||||
|
||||
/* Check sectors per cluster value is valid. */
|
||||
ntfs_log_debug("Checking sectors per cluster... ");
|
||||
switch (b->bpb.sectors_per_cluster) {
|
||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
|
||||
break;
|
||||
default:
|
||||
goto not_ntfs;
|
||||
}
|
||||
ntfs_log_debug("OK\n");
|
||||
|
||||
/* Check the cluster size is not above 65536 bytes. */
|
||||
ntfs_log_debug("Checking cluster size... ");
|
||||
if ((u32)le16_to_cpu(b->bpb.bytes_per_sector) *
|
||||
b->bpb.sectors_per_cluster > 0x10000)
|
||||
goto not_ntfs;
|
||||
ntfs_log_debug("OK\n");
|
||||
|
||||
/* Check reserved/unused fields are really zero. */
|
||||
ntfs_log_debug("Checking reserved fields are zero... ");
|
||||
if (le16_to_cpu(b->bpb.reserved_sectors) ||
|
||||
le16_to_cpu(b->bpb.root_entries) ||
|
||||
le16_to_cpu(b->bpb.sectors) ||
|
||||
le16_to_cpu(b->bpb.sectors_per_fat) ||
|
||||
le32_to_cpu(b->bpb.large_sectors) ||
|
||||
b->bpb.fats)
|
||||
goto not_ntfs;
|
||||
ntfs_log_debug("OK\n");
|
||||
|
||||
/* Check clusters per file mft record value is valid. */
|
||||
ntfs_log_debug("Checking clusters per mft record... ");
|
||||
if ((u8)b->clusters_per_mft_record < 0xe1 ||
|
||||
(u8)b->clusters_per_mft_record > 0xf7) {
|
||||
switch (b->clusters_per_mft_record) {
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
break;
|
||||
default:
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
ntfs_log_debug("OK\n");
|
||||
|
||||
/* Check clusters per index block value is valid. */
|
||||
ntfs_log_debug("Checking clusters per index block... ");
|
||||
if ((u8)b->clusters_per_index_record < 0xe1 ||
|
||||
(u8)b->clusters_per_index_record > 0xf7) {
|
||||
switch (b->clusters_per_index_record) {
|
||||
case 1: case 2: case 4: case 8: case 0x10: case 0x20: case 0x40:
|
||||
break;
|
||||
default:
|
||||
goto not_ntfs;
|
||||
}
|
||||
}
|
||||
ntfs_log_debug("OK\n");
|
||||
|
||||
if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
|
||||
ntfs_log_debug("Warning: Bootsector has invalid end of sector marker.\n");
|
||||
|
||||
ntfs_log_debug("Bootsector check completed successfully.\n");
|
||||
|
||||
return TRUE;
|
||||
not_ntfs:
|
||||
ntfs_log_debug("FAILED\n");
|
||||
ntfs_log_debug("Bootsector check failed. Aborting...\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_boot_sector_parse - setup an ntfs volume from an ntfs boot sector
|
||||
* @vol: ntfs_volume to setup
|
||||
* @bs: buffer containing ntfs boot sector to parse
|
||||
*
|
||||
* Parse the ntfs bootsector @bs and setup the ntfs volume @vol with the
|
||||
* obtained values.
|
||||
*
|
||||
* Return 0 on success or -1 on error with errno set to the error code EINVAL.
|
||||
*/
|
||||
int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
|
||||
{
|
||||
u8 sectors_per_cluster;
|
||||
s8 c;
|
||||
|
||||
/* We return -1 with errno = EINVAL on error. */
|
||||
errno = EINVAL;
|
||||
|
||||
vol->sector_size = le16_to_cpu(bs->bpb.bytes_per_sector);
|
||||
vol->sector_size_bits = ffs(vol->sector_size) - 1;
|
||||
ntfs_log_debug("SectorSize = 0x%x\n", vol->sector_size);
|
||||
ntfs_log_debug("SectorSizeBits = %u\n", vol->sector_size_bits);
|
||||
/*
|
||||
* The bounds checks on mft_lcn and mft_mirr_lcn (i.e. them being
|
||||
* 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.
|
||||
*/
|
||||
sectors_per_cluster = bs->bpb.sectors_per_cluster;
|
||||
ntfs_log_debug("NumberOfSectors = %lli\n", sle64_to_cpu(bs->number_of_sectors));
|
||||
ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
|
||||
if (sectors_per_cluster & (sectors_per_cluster - 1)) {
|
||||
ntfs_log_debug("Error: %s is not a valid NTFS partition! "
|
||||
"sectors_per_cluster is not a power of 2.\n",
|
||||
vol->dev->d_name);
|
||||
return -1;
|
||||
}
|
||||
vol->nr_clusters = sle64_to_cpu(bs->number_of_sectors) >>
|
||||
(ffs(sectors_per_cluster) - 1);
|
||||
|
||||
vol->mft_lcn = sle64_to_cpu(bs->mft_lcn);
|
||||
vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
|
||||
ntfs_log_debug("MFT LCN = 0x%llx\n", vol->mft_lcn);
|
||||
ntfs_log_debug("MFTMirr LCN = 0x%llx\n", vol->mftmirr_lcn);
|
||||
if (vol->mft_lcn > vol->nr_clusters ||
|
||||
vol->mftmirr_lcn > vol->nr_clusters) {
|
||||
ntfs_log_debug("Error: %s is not a valid NTFS partition!\n",
|
||||
vol->dev->d_name);
|
||||
ntfs_log_debug("($Mft LCN or $MftMirr LCN is greater than the "
|
||||
"number of clusters!)\n");
|
||||
return -1;
|
||||
}
|
||||
vol->cluster_size = sectors_per_cluster * vol->sector_size;
|
||||
if (vol->cluster_size & (vol->cluster_size - 1)) {
|
||||
ntfs_log_debug("Error: %s is not a valid NTFS partition! "
|
||||
"cluster_size is not a power of 2.\n",
|
||||
vol->dev->d_name);
|
||||
return -1;
|
||||
}
|
||||
vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
|
||||
/*
|
||||
* Need to get the clusters per mft record and handle it if it is
|
||||
* negative. Then calculate the mft_record_size. A value of 0x80 is
|
||||
* illegal, thus signed char is actually ok!
|
||||
*/
|
||||
c = bs->clusters_per_mft_record;
|
||||
ntfs_log_debug("ClusterSize = 0x%x\n", (unsigned)vol->cluster_size);
|
||||
ntfs_log_debug("ClusterSizeBits = %u\n", vol->cluster_size_bits);
|
||||
ntfs_log_debug("ClustersPerMftRecord = 0x%x\n", c);
|
||||
/*
|
||||
* When clusters_per_mft_record is negative, it means that it is to
|
||||
* be taken to be the negative base 2 logarithm of the mft_record_size
|
||||
* min bytes. Then:
|
||||
* mft_record_size = 2^(-clusters_per_mft_record) bytes.
|
||||
*/
|
||||
if (c < 0)
|
||||
vol->mft_record_size = 1 << -c;
|
||||
else
|
||||
vol->mft_record_size = c << vol->cluster_size_bits;
|
||||
if (vol->mft_record_size & (vol->mft_record_size - 1)) {
|
||||
ntfs_log_debug("Error: %s is not a valid NTFS partition! "
|
||||
"mft_record_size is not a power of 2.\n",
|
||||
vol->dev->d_name);
|
||||
return -1;
|
||||
}
|
||||
vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
|
||||
ntfs_log_debug("MftRecordSize = 0x%x\n", (unsigned)vol->mft_record_size);
|
||||
ntfs_log_debug("MftRecordSizeBits = %u\n", vol->mft_record_size_bits);
|
||||
/* Same as above for INDX record. */
|
||||
c = bs->clusters_per_index_record;
|
||||
ntfs_log_debug("ClustersPerINDXRecord = 0x%x\n", c);
|
||||
if (c < 0)
|
||||
vol->indx_record_size = 1 << -c;
|
||||
else
|
||||
vol->indx_record_size = c << vol->cluster_size_bits;
|
||||
vol->indx_record_size_bits = ffs(vol->indx_record_size) - 1;
|
||||
ntfs_log_debug("INDXRecordSize = 0x%x\n", (unsigned)vol->indx_record_size);
|
||||
ntfs_log_debug("INDXRecordSizeBits = %u\n", vol->indx_record_size_bits);
|
||||
/*
|
||||
* Work out the size of the MFT mirror in number of mft records. If the
|
||||
* cluster size is less than or equal to the size taken by four mft
|
||||
* records, the mft mirror stores the first four mft records. If the
|
||||
* cluster size is bigger than the size taken by four mft records, the
|
||||
* mft mirror contains as many mft records as will fit into one
|
||||
* cluster.
|
||||
*/
|
||||
if (vol->cluster_size <= 4 * vol->mft_record_size)
|
||||
vol->mftmirr_size = 4;
|
||||
else
|
||||
vol->mftmirr_size = vol->cluster_size / vol->mft_record_size;
|
||||
return 0;
|
||||
}
|
221
libntfs-3g/collate.c
Normal file
221
libntfs-3g/collate.c
Normal file
@ -0,0 +1,221 @@
|
||||
/**
|
||||
* collate.c - NTFS collation handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
*
|
||||
* 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_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "collate.h"
|
||||
#include "debug.h"
|
||||
#include "unistr.h"
|
||||
#include "logging.h"
|
||||
|
||||
BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* FIXME: At the moment we only support COLLATION_BINARY,
|
||||
* COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME so we return false
|
||||
* for everything else.
|
||||
*/
|
||||
if (cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG &&
|
||||
cr != COLLATION_FILE_NAME)
|
||||
return FALSE;
|
||||
i = le32_to_cpu(cr);
|
||||
if (((i >= 0) && (i <= 0x02)) ||
|
||||
((i >= 0x10) && (i <= 0x13)))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_collate_binary - Which of two binary objects should be listed first
|
||||
* @vol: unused
|
||||
* @data1:
|
||||
* @data1_len:
|
||||
* @data2:
|
||||
* @data2_len:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
rc = memcmp(data1, data2, min(data1_len, data2_len));
|
||||
if (!rc && (data1_len != data2_len)) {
|
||||
if (data1_len < data2_len)
|
||||
rc = -1;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_collate_ntofs_ulong - Which of two long ints should be listed first
|
||||
* @vol: unused
|
||||
* @data1:
|
||||
* @data1_len:
|
||||
* @data2:
|
||||
* @data2_len:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
{
|
||||
int rc;
|
||||
u32 d1, d2;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (data1_len != data2_len || data1_len != 4) {
|
||||
ntfs_log_error("data1_len or/and data2_len not equal to 4.\n");
|
||||
return NTFS_COLLATION_ERROR;
|
||||
}
|
||||
d1 = le32_to_cpup(data1);
|
||||
d2 = le32_to_cpup(data2);
|
||||
if (d1 < d2)
|
||||
rc = -1;
|
||||
else {
|
||||
if (d1 == d2)
|
||||
rc = 0;
|
||||
else
|
||||
rc = 1;
|
||||
}
|
||||
ntfs_log_trace("Done, returning %i.\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_collate_file_name - Which of two filenames should be listed first
|
||||
* @vol:
|
||||
* @data1:
|
||||
* @data1_len: unused
|
||||
* @data2:
|
||||
* @data2_len: unused
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
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)))
|
||||
{
|
||||
int rc;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
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;
|
||||
}
|
||||
|
||||
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*/,
|
||||
NULL/*ntfs_collate_ntofs_security_hash*/,
|
||||
NULL/*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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr,
|
||||
const void *data1, const int data1_len,
|
||||
const void *data2, const int data2_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* FIXME: At the moment we only support COLLATION_BINARY,
|
||||
* COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME so we return error
|
||||
* for everything else.
|
||||
*/
|
||||
if (cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG &&
|
||||
cr != COLLATION_FILE_NAME)
|
||||
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;
|
||||
}
|
73
libntfs-3g/compat.c
Normal file
73
libntfs-3g/compat.c
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* compat.c - Tweaks for Windows compatibility
|
||||
*
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
* Copyright (c) 2002-2004 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
|
||||
*/
|
||||
|
||||
#ifdef WINDOWS
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
/* TODO: Add check for FFS in the configure script... (AIA) */
|
||||
|
||||
#ifndef HAVE_FFS
|
||||
/**
|
||||
* ffs - Find the first set bit in an int
|
||||
* @x:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
int ffs(int x)
|
||||
{
|
||||
int r = 1;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff)) {
|
||||
x >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
if (!(x & 0xff)) {
|
||||
x >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
if (!(x & 0xf)) {
|
||||
x >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
if (!(x & 3)) {
|
||||
x >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
if (!(x & 1)) {
|
||||
x >>= 1;
|
||||
r += 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif /* HAVE_FFS */
|
||||
|
||||
#endif /* WINDOWS */
|
||||
|
552
libntfs-3g/compress.c
Normal file
552
libntfs-3g/compress.c
Normal file
@ -0,0 +1,552 @@
|
||||
/**
|
||||
* compress.c - Compressed attribute handling code. Originated from the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
*
|
||||
* 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_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "attrib.h"
|
||||
#include "debug.h"
|
||||
#include "volume.h"
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "runlist.h"
|
||||
#include "compress.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
/**
|
||||
* enum ntfs_compression_constants - constants used in the compression code
|
||||
*/
|
||||
typedef enum {
|
||||
/* Token types and access mask. */
|
||||
NTFS_SYMBOL_TOKEN = 0,
|
||||
NTFS_PHRASE_TOKEN = 1,
|
||||
NTFS_TOKEN_MASK = 1,
|
||||
|
||||
/* Compression sub-block constants. */
|
||||
NTFS_SB_SIZE_MASK = 0x0fff,
|
||||
NTFS_SB_SIZE = 0x1000,
|
||||
NTFS_SB_IS_COMPRESSED = 0x8000,
|
||||
} ntfs_compression_constants;
|
||||
|
||||
/**
|
||||
* ntfs_decompress - decompress a compression block into an array of pages
|
||||
* @dest: buffer to which to write the decompressed data
|
||||
* @dest_size: size of buffer @dest in bytes
|
||||
* @cb_start: compression block to decompress
|
||||
* @cb_size: size of compression block @cb_start in bytes
|
||||
*
|
||||
* This decompresses the compression block @cb_start into the destination
|
||||
* buffer @dest.
|
||||
*
|
||||
* @cb_start is a pointer to the compression block which needs decompressing
|
||||
* and @cb_size is the size of @cb_start in bytes (8-64kiB).
|
||||
*
|
||||
* Return 0 if success or -EOVERFLOW on error in the compressed stream.
|
||||
*/
|
||||
static int ntfs_decompress(u8 *dest, const u32 dest_size,
|
||||
u8 *const cb_start, const u32 cb_size)
|
||||
{
|
||||
/*
|
||||
* Pointers into the compressed data, i.e. the compression block (cb),
|
||||
* and the therein contained sub-blocks (sb).
|
||||
*/
|
||||
u8 *cb_end = cb_start + cb_size; /* End of cb. */
|
||||
u8 *cb = cb_start; /* Current position in cb. */
|
||||
u8 *cb_sb_start = cb; /* Beginning of the current sb in the cb. */
|
||||
u8 *cb_sb_end; /* End of current sb / beginning of next sb. */
|
||||
/* Variables for uncompressed data / destination. */
|
||||
u8 *dest_end = dest + dest_size; /* End of dest buffer. */
|
||||
u8 *dest_sb_start; /* Start of current sub-block in dest. */
|
||||
u8 *dest_sb_end; /* End of current sb in dest. */
|
||||
/* Variables for tag and token parsing. */
|
||||
u8 tag; /* Current tag. */
|
||||
int token; /* Loop counter for the eight tokens in tag. */
|
||||
|
||||
ntfs_log_trace("Entering, cb_size = 0x%x.\n", (unsigned)cb_size);
|
||||
do_next_sb:
|
||||
ntfs_log_debug("Beginning sub-block at offset = 0x%x in the cb.\n",
|
||||
cb - cb_start);
|
||||
/*
|
||||
* Have we reached the end of the compression block or the end of the
|
||||
* decompressed data? The latter can happen for example if the current
|
||||
* position in the compression block is one byte before its end so the
|
||||
* first two checks do not detect it.
|
||||
*/
|
||||
if (cb == cb_end || !le16_to_cpup((u16*)cb) || dest == dest_end) {
|
||||
ntfs_log_debug("Completed. Returning success (0).\n");
|
||||
return 0;
|
||||
}
|
||||
/* Setup offset for the current sub-block destination. */
|
||||
dest_sb_start = dest;
|
||||
dest_sb_end = dest + NTFS_SB_SIZE;
|
||||
/* Check that we are still within allowed boundaries. */
|
||||
if (dest_sb_end > dest_end)
|
||||
goto return_overflow;
|
||||
/* Does the minimum size of a compressed sb overflow valid range? */
|
||||
if (cb + 6 > cb_end)
|
||||
goto return_overflow;
|
||||
/* Setup the current sub-block source pointers and validate range. */
|
||||
cb_sb_start = cb;
|
||||
cb_sb_end = cb_sb_start + (le16_to_cpup((u16*)cb) & NTFS_SB_SIZE_MASK)
|
||||
+ 3;
|
||||
if (cb_sb_end > cb_end)
|
||||
goto return_overflow;
|
||||
/* Now, we are ready to process the current sub-block (sb). */
|
||||
if (!(le16_to_cpup((u16*)cb) & NTFS_SB_IS_COMPRESSED)) {
|
||||
ntfs_log_debug("Found uncompressed sub-block.\n");
|
||||
/* This sb is not compressed, just copy it into destination. */
|
||||
/* Advance source position to first data byte. */
|
||||
cb += 2;
|
||||
/* An uncompressed sb must be full size. */
|
||||
if (cb_sb_end - cb != NTFS_SB_SIZE)
|
||||
goto return_overflow;
|
||||
/* Copy the block and advance the source position. */
|
||||
memcpy(dest, cb, NTFS_SB_SIZE);
|
||||
cb += NTFS_SB_SIZE;
|
||||
/* Advance destination position to next sub-block. */
|
||||
dest += NTFS_SB_SIZE;
|
||||
goto do_next_sb;
|
||||
}
|
||||
ntfs_log_debug("Found compressed sub-block.\n");
|
||||
/* This sb is compressed, decompress it into destination. */
|
||||
/* Forward to the first tag in the sub-block. */
|
||||
cb += 2;
|
||||
do_next_tag:
|
||||
if (cb == cb_sb_end) {
|
||||
/* Check if the decompressed sub-block was not full-length. */
|
||||
if (dest < dest_sb_end) {
|
||||
int nr_bytes = dest_sb_end - dest;
|
||||
|
||||
ntfs_log_debug("Filling incomplete sub-block with zeroes.\n");
|
||||
/* Zero remainder and update destination position. */
|
||||
memset(dest, 0, nr_bytes);
|
||||
dest += nr_bytes;
|
||||
}
|
||||
/* We have finished the current sub-block. */
|
||||
goto do_next_sb;
|
||||
}
|
||||
/* Check we are still in range. */
|
||||
if (cb > cb_sb_end || dest > dest_sb_end)
|
||||
goto return_overflow;
|
||||
/* Get the next tag and advance to first token. */
|
||||
tag = *cb++;
|
||||
/* Parse the eight tokens described by the tag. */
|
||||
for (token = 0; token < 8; token++, tag >>= 1) {
|
||||
u16 lg, pt, length, max_non_overlap;
|
||||
register u16 i;
|
||||
u8 *dest_back_addr;
|
||||
|
||||
/* Check if we are done / still in range. */
|
||||
if (cb >= cb_sb_end || dest > dest_sb_end)
|
||||
break;
|
||||
/* Determine token type and parse appropriately.*/
|
||||
if ((tag & NTFS_TOKEN_MASK) == NTFS_SYMBOL_TOKEN) {
|
||||
/*
|
||||
* We have a symbol token, copy the symbol across, and
|
||||
* advance the source and destination positions.
|
||||
*/
|
||||
*dest++ = *cb++;
|
||||
/* Continue with the next token. */
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* We have a phrase token. Make sure it is not the first tag in
|
||||
* the sb as this is illegal and would confuse the code below.
|
||||
*/
|
||||
if (dest == dest_sb_start)
|
||||
goto return_overflow;
|
||||
/*
|
||||
* Determine the number of bytes to go back (p) and the number
|
||||
* of bytes to copy (l). We use an optimized algorithm in which
|
||||
* we first calculate log2(current destination position in sb),
|
||||
* which allows determination of l and p in O(1) rather than
|
||||
* O(n). We just need an arch-optimized log2() function now.
|
||||
*/
|
||||
lg = 0;
|
||||
for (i = dest - dest_sb_start - 1; i >= 0x10; i >>= 1)
|
||||
lg++;
|
||||
/* Get the phrase token into i. */
|
||||
pt = le16_to_cpup((u16*)cb);
|
||||
/*
|
||||
* Calculate starting position of the byte sequence in
|
||||
* the destination using the fact that p = (pt >> (12 - lg)) + 1
|
||||
* and make sure we don't go too far back.
|
||||
*/
|
||||
dest_back_addr = dest - (pt >> (12 - lg)) - 1;
|
||||
if (dest_back_addr < dest_sb_start)
|
||||
goto return_overflow;
|
||||
/* Now calculate the length of the byte sequence. */
|
||||
length = (pt & (0xfff >> lg)) + 3;
|
||||
/* Verify destination is in range. */
|
||||
if (dest + length > dest_sb_end)
|
||||
goto return_overflow;
|
||||
/* The number of non-overlapping bytes. */
|
||||
max_non_overlap = dest - dest_back_addr;
|
||||
if (length <= max_non_overlap) {
|
||||
/* The byte sequence doesn't overlap, just copy it. */
|
||||
memcpy(dest, dest_back_addr, length);
|
||||
/* Advance destination pointer. */
|
||||
dest += length;
|
||||
} else {
|
||||
/*
|
||||
* The byte sequence does overlap, copy non-overlapping
|
||||
* part and then do a slow byte by byte copy for the
|
||||
* overlapping part. Also, advance the destination
|
||||
* pointer.
|
||||
*/
|
||||
memcpy(dest, dest_back_addr, max_non_overlap);
|
||||
dest += max_non_overlap;
|
||||
dest_back_addr += max_non_overlap;
|
||||
length -= max_non_overlap;
|
||||
while (length--)
|
||||
*dest++ = *dest_back_addr++;
|
||||
}
|
||||
/* Advance source position and continue with the next token. */
|
||||
cb += 2;
|
||||
}
|
||||
/* No tokens left in the current tag. Continue with the next tag. */
|
||||
goto do_next_tag;
|
||||
return_overflow:
|
||||
errno = EOVERFLOW;
|
||||
ntfs_log_perror("Failed to decompress file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_is_cb_compressed - internal function, do not use
|
||||
*
|
||||
* This is a very specialised function determining if a cb is compressed or
|
||||
* uncompressed. It is assumed that checking for a sparse cb has already been
|
||||
* performed and that the cb is not sparse. It makes all sorts of other
|
||||
* assumptions as well and hence it is not useful anywhere other than where it
|
||||
* is used at the moment. Please, do not make this function available for use
|
||||
* outside of compress.c as it is bound to confuse people and not do what they
|
||||
* want.
|
||||
*
|
||||
* Return TRUE on errors so that the error will be detected later on in the
|
||||
* code. Might be a bit confusing to debug but there really should never be
|
||||
* errors coming from here.
|
||||
*/
|
||||
static BOOL ntfs_is_cb_compressed(ntfs_attr *na, runlist_element *rl,
|
||||
VCN cb_start_vcn, int cb_clusters)
|
||||
{
|
||||
/*
|
||||
* The simplest case: the run starting at @cb_start_vcn contains
|
||||
* @cb_clusters clusters which are all not sparse, thus the cb is not
|
||||
* compressed.
|
||||
*/
|
||||
restart:
|
||||
cb_clusters -= rl->length - (cb_start_vcn - rl->vcn);
|
||||
while (cb_clusters > 0) {
|
||||
/* Go to the next run. */
|
||||
rl++;
|
||||
/* Map the next runlist fragment if it is not mapped. */
|
||||
if (rl->lcn < LCN_HOLE || !rl->length) {
|
||||
cb_start_vcn = rl->vcn;
|
||||
rl = ntfs_attr_find_vcn(na, rl->vcn);
|
||||
if (!rl || rl->lcn < LCN_HOLE || !rl->length)
|
||||
return TRUE;
|
||||
/*
|
||||
* If the runs were merged need to deal with the
|
||||
* resulting partial run so simply restart.
|
||||
*/
|
||||
if (rl->vcn < cb_start_vcn)
|
||||
goto restart;
|
||||
}
|
||||
/* If the current run is sparse, the cb is compressed. */
|
||||
if (rl->lcn == LCN_HOLE)
|
||||
return TRUE;
|
||||
/* If the whole cb is not sparse, it is not compressed. */
|
||||
if (rl->length >= cb_clusters)
|
||||
return FALSE;
|
||||
cb_clusters -= rl->length;
|
||||
};
|
||||
/* All cb_clusters were not sparse thus the cb is not compressed. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_compressed_attr_pread - read from a compressed attribute
|
||||
* @na: ntfs attribute to read from
|
||||
* @pos: byte position in the attribute to begin reading from
|
||||
* @count: number of bytes to read
|
||||
* @b: output data buffer
|
||||
*
|
||||
* NOTE: You probably want to be using attrib.c::ntfs_attr_pread() instead.
|
||||
*
|
||||
* This function will read @count bytes starting at offset @pos from the
|
||||
* compressed ntfs attribute @na into the data buffer @b.
|
||||
*
|
||||
* On success, return the number of successfully read bytes. If this number
|
||||
* is lower than @count this means that the read reached end of file or that
|
||||
* an error was encountered during the read so that the read is partial.
|
||||
* 0 means end of file or nothing was read (also return 0 when @count is 0).
|
||||
*
|
||||
* On error and nothing has been read, return -1 with errno set appropriately
|
||||
* to the return code of ntfs_pread(), or to EINVAL in case of invalid
|
||||
* arguments.
|
||||
*/
|
||||
s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count, void *b)
|
||||
{
|
||||
s64 br, to_read, ofs, total, total2;
|
||||
u64 cb_size_mask;
|
||||
VCN start_vcn, vcn, end_vcn;
|
||||
ntfs_volume *vol;
|
||||
runlist_element *rl;
|
||||
u8 *dest, *cb, *cb_pos, *cb_end;
|
||||
u32 cb_size;
|
||||
int err;
|
||||
unsigned int nr_cbs, cb_clusters;
|
||||
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count 0x%llx.\n",
|
||||
(unsigned long long)na->ni->mft_no, na->type,
|
||||
(long long)pos, (long long)count);
|
||||
if (!na || !NAttrCompressed(na) || !na->ni || !na->ni->vol || !b ||
|
||||
pos < 0 || count < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Encrypted attributes are not supported. We return access denied,
|
||||
* which is what Windows NT4 does, too.
|
||||
*/
|
||||
if (NAttrEncrypted(na)) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
if (!count)
|
||||
return 0;
|
||||
/* Truncate reads beyond end of attribute. */
|
||||
if (pos + count > na->data_size) {
|
||||
if (pos >= na->data_size) {
|
||||
return 0;
|
||||
}
|
||||
count = na->data_size - pos;
|
||||
}
|
||||
/* If it is a resident attribute, simply use ntfs_attr_pread(). */
|
||||
if (!NAttrNonResident(na))
|
||||
return ntfs_attr_pread(na, pos, count, b);
|
||||
total = total2 = 0;
|
||||
/* Zero out reads beyond initialized size. */
|
||||
if (pos + count > na->initialized_size) {
|
||||
if (pos >= na->initialized_size) {
|
||||
memset(b, 0, count);
|
||||
return count;
|
||||
}
|
||||
total2 = pos + count - na->initialized_size;
|
||||
count -= total2;
|
||||
memset((u8*)b + count, 0, total2);
|
||||
}
|
||||
vol = na->ni->vol;
|
||||
cb_size = na->compression_block_size;
|
||||
cb_size_mask = cb_size - 1UL;
|
||||
cb_clusters = na->compression_block_clusters;
|
||||
|
||||
/* Need a temporary buffer for each loaded compression block. */
|
||||
cb = ntfs_malloc(cb_size);
|
||||
if (!cb)
|
||||
return -1;
|
||||
|
||||
/* Need a temporary buffer for each uncompressed block. */
|
||||
dest = ntfs_malloc(cb_size);
|
||||
if (!dest) {
|
||||
free(cb);
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* The first vcn in the first compression block (cb) which we need to
|
||||
* decompress.
|
||||
*/
|
||||
start_vcn = (pos & ~cb_size_mask) >> vol->cluster_size_bits;
|
||||
/* Offset in the uncompressed cb at which to start reading data. */
|
||||
ofs = pos & cb_size_mask;
|
||||
/*
|
||||
* The first vcn in the cb after the last cb which we need to
|
||||
* decompress.
|
||||
*/
|
||||
end_vcn = ((pos + count + cb_size - 1) & ~cb_size_mask) >>
|
||||
vol->cluster_size_bits;
|
||||
/* Number of compression blocks (cbs) in the wanted vcn range. */
|
||||
nr_cbs = (end_vcn - start_vcn) << vol->cluster_size_bits >>
|
||||
na->compression_block_size_bits;
|
||||
cb_end = cb + cb_size;
|
||||
do_next_cb:
|
||||
nr_cbs--;
|
||||
cb_pos = cb;
|
||||
vcn = start_vcn;
|
||||
start_vcn += cb_clusters;
|
||||
|
||||
/* Check whether the compression block is sparse. */
|
||||
rl = ntfs_attr_find_vcn(na, vcn);
|
||||
if (!rl || rl->lcn < LCN_HOLE) {
|
||||
free(cb);
|
||||
free(dest);
|
||||
if (total)
|
||||
return total;
|
||||
/* FIXME: Do we want EIO or the error code? (AIA) */
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (rl->lcn == LCN_HOLE) {
|
||||
/* Sparse cb, zero out destination range overlapping the cb. */
|
||||
ntfs_log_debug("Found sparse compression block.\n");
|
||||
to_read = min(count, cb_size - ofs);
|
||||
memset(b, 0, to_read);
|
||||
ofs = 0;
|
||||
total += to_read;
|
||||
count -= to_read;
|
||||
b = (u8*)b + to_read;
|
||||
} else if (!ntfs_is_cb_compressed(na, rl, vcn, cb_clusters)) {
|
||||
s64 tdata_size, tinitialized_size;
|
||||
/*
|
||||
* Uncompressed cb, read it straight into the destination range
|
||||
* overlapping the cb.
|
||||
*/
|
||||
ntfs_log_debug("Found uncompressed compression block.\n");
|
||||
/*
|
||||
* Read the uncompressed data into the destination buffer.
|
||||
* NOTE: We cheat a little bit here by marking the attribute as
|
||||
* not compressed in the ntfs_attr structure so that we can
|
||||
* read the data by simply using ntfs_attr_pread(). (-8
|
||||
* NOTE: we have to modify data_size and initialized_size
|
||||
* temporarily as well...
|
||||
*/
|
||||
to_read = min(count, cb_size - ofs);
|
||||
ofs += vcn << vol->cluster_size_bits;
|
||||
NAttrClearCompressed(na);
|
||||
tdata_size = na->data_size;
|
||||
tinitialized_size = na->initialized_size;
|
||||
na->data_size = na->initialized_size = na->allocated_size;
|
||||
do {
|
||||
br = ntfs_attr_pread(na, ofs, to_read, b);
|
||||
if (br < 0) {
|
||||
err = errno;
|
||||
na->data_size = tdata_size;
|
||||
na->initialized_size = tinitialized_size;
|
||||
NAttrSetCompressed(na);
|
||||
free(cb);
|
||||
free(dest);
|
||||
if (total)
|
||||
return total;
|
||||
errno = err;
|
||||
return br;
|
||||
}
|
||||
total += br;
|
||||
count -= br;
|
||||
b = (u8*)b + br;
|
||||
to_read -= br;
|
||||
ofs += br;
|
||||
} while (to_read > 0);
|
||||
na->data_size = tdata_size;
|
||||
na->initialized_size = tinitialized_size;
|
||||
NAttrSetCompressed(na);
|
||||
ofs = 0;
|
||||
} else {
|
||||
s64 tdata_size, tinitialized_size;
|
||||
|
||||
/*
|
||||
* Compressed cb, decompress it into the temporary buffer, then
|
||||
* copy the data to the destination range overlapping the cb.
|
||||
*/
|
||||
ntfs_log_debug("Found compressed compression block.\n");
|
||||
/*
|
||||
* Read the compressed data into the temporary buffer.
|
||||
* NOTE: We cheat a little bit here by marking the attribute as
|
||||
* not compressed in the ntfs_attr structure so that we can
|
||||
* read the raw, compressed data by simply using
|
||||
* ntfs_attr_pread(). (-8
|
||||
* NOTE: We have to modify data_size and initialized_size
|
||||
* temporarily as well...
|
||||
*/
|
||||
to_read = cb_size;
|
||||
NAttrClearCompressed(na);
|
||||
tdata_size = na->data_size;
|
||||
tinitialized_size = na->initialized_size;
|
||||
na->data_size = na->initialized_size = na->allocated_size;
|
||||
do {
|
||||
br = ntfs_attr_pread(na,
|
||||
(vcn << vol->cluster_size_bits) +
|
||||
(cb_pos - cb), to_read, cb_pos);
|
||||
if (br < 0) {
|
||||
err = errno;
|
||||
na->data_size = tdata_size;
|
||||
na->initialized_size = tinitialized_size;
|
||||
NAttrSetCompressed(na);
|
||||
free(cb);
|
||||
free(dest);
|
||||
if (total)
|
||||
return total;
|
||||
errno = err;
|
||||
return br;
|
||||
}
|
||||
cb_pos += br;
|
||||
to_read -= br;
|
||||
} while (to_read > 0);
|
||||
na->data_size = tdata_size;
|
||||
na->initialized_size = tinitialized_size;
|
||||
NAttrSetCompressed(na);
|
||||
/* Just a precaution. */
|
||||
if (cb_pos + 2 <= cb_end)
|
||||
*(u16*)cb_pos = 0;
|
||||
ntfs_log_debug("Successfully read the compression block.\n");
|
||||
if (ntfs_decompress(dest, cb_size, cb, cb_size) < 0) {
|
||||
err = errno;
|
||||
free(cb);
|
||||
free(dest);
|
||||
if (total)
|
||||
return total;
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
to_read = min(count, cb_size - ofs);
|
||||
memcpy(b, dest + ofs, to_read);
|
||||
total += to_read;
|
||||
count -= to_read;
|
||||
b = (u8*)b + to_read;
|
||||
ofs = 0;
|
||||
}
|
||||
/* Do we have more work to do? */
|
||||
if (nr_cbs)
|
||||
goto do_next_cb;
|
||||
/* We no longer need the buffers. */
|
||||
free(cb);
|
||||
free(dest);
|
||||
/* Return number of bytes read. */
|
||||
return total + total2;
|
||||
}
|
73
libntfs-3g/debug.c
Normal file
73
libntfs-3g/debug.c
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* debug.c - Debugging output functions. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "runlist.h"
|
||||
#include "debug.h"
|
||||
#include "logging.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* ntfs_debug_runlist_dump - Dump a runlist.
|
||||
* @rl:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void ntfs_debug_runlist_dump(const runlist_element *rl)
|
||||
{
|
||||
int i = 0;
|
||||
const char *lcn_str[5] = { "LCN_HOLE ", "LCN_RL_NOT_MAPPED",
|
||||
"LCN_ENOENT ", "LCN_EINVAL ",
|
||||
"LCN_unknown " };
|
||||
|
||||
ntfs_log_debug("NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
|
||||
if (!rl) {
|
||||
ntfs_log_debug("Run list not present.\n");
|
||||
return;
|
||||
}
|
||||
ntfs_log_debug("VCN LCN Run length\n");
|
||||
do {
|
||||
LCN lcn = (rl + i)->lcn;
|
||||
|
||||
if (lcn < (LCN)0) {
|
||||
int idx = -lcn - 1;
|
||||
|
||||
if (idx > -LCN_EINVAL - 1)
|
||||
idx = 4;
|
||||
ntfs_log_debug("%-16llx %s %-16llx%s\n", rl[i].vcn, lcn_str[idx], rl[i].length, rl[i].length ? "" : " (runlist end)");
|
||||
} else
|
||||
ntfs_log_debug("%-16llx %-16llx %-16llx%s\n", rl[i].vcn, rl[i].lcn, rl[i].length, rl[i].length ? "" : " (runlist end)");
|
||||
} while (rl[i++].length);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
734
libntfs-3g/device.c
Normal file
734
libntfs-3g/device.c
Normal file
@ -0,0 +1,734 @@
|
||||
/**
|
||||
* device.c - Low level device io functions. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_UNISTD_H
|
||||
#include <unistd.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
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FD_H
|
||||
#include <linux/fd.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_HDREG_H
|
||||
#include <linux/hdreg.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "mst.h"
|
||||
#include "debug.h"
|
||||
#include "device.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if defined(linux) && defined(_IO) && !defined(BLKGETSIZE)
|
||||
#define BLKGETSIZE _IO(0x12,96) /* Get device size in 512-byte blocks. */
|
||||
#endif
|
||||
#if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64)
|
||||
#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* Get device size in bytes. */
|
||||
#endif
|
||||
#if defined(linux) && !defined(HDIO_GETGEO)
|
||||
#define HDIO_GETGEO 0x0301 /* Get device geometry. */
|
||||
#endif
|
||||
#if defined(linux) && defined(_IO) && !defined(BLKSSZGET)
|
||||
# define BLKSSZGET _IO(0x12,104) /* Get device sector size in bytes. */
|
||||
#endif
|
||||
#if defined(linux) && defined(_IO) && !defined(BLKBSZSET)
|
||||
# define BLKBSZSET _IOW(0x12,113,size_t) /* Set device block size in bytes. */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it
|
||||
* @name: name of the device (must be present)
|
||||
* @state: initial device state (usually zero)
|
||||
* @dops: ntfs device operations to use with the device (must be present)
|
||||
* @priv_data: pointer to private data (optional)
|
||||
*
|
||||
* Allocate an ntfs device structure and pre-initialize it with the user-
|
||||
* specified device operations @dops, device state @state, device name @name,
|
||||
* and optional private data @priv_data.
|
||||
*
|
||||
* Note, @name is copied and can hence be freed after this functions returns.
|
||||
*
|
||||
* On success return a pointer to the allocated ntfs device structure and on
|
||||
* error return NULL with errno set to the error code returned by ntfs_malloc().
|
||||
*/
|
||||
struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
|
||||
struct ntfs_device_operations *dops, void *priv_data)
|
||||
{
|
||||
struct ntfs_device *dev;
|
||||
|
||||
if (!name) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = ntfs_malloc(sizeof(struct ntfs_device));
|
||||
if (dev) {
|
||||
if (!(dev->d_name = strdup(name))) {
|
||||
int eo = errno;
|
||||
free(dev);
|
||||
errno = eo;
|
||||
return NULL;
|
||||
}
|
||||
dev->d_ops = dops;
|
||||
dev->d_state = state;
|
||||
dev->d_private = priv_data;
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_free - free an ntfs device structure
|
||||
* @dev: ntfs device structure to free
|
||||
*
|
||||
* Free the ntfs device structure @dev.
|
||||
*
|
||||
* Return 0 on success or -1 on error with errno set to the error code. The
|
||||
* following error codes are defined:
|
||||
* EINVAL Invalid pointer @dev.
|
||||
* EBUSY Device is still open. Close it before freeing it!
|
||||
*/
|
||||
int ntfs_device_free(struct ntfs_device *dev)
|
||||
{
|
||||
if (!dev) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (NDevOpen(dev)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
free(dev->d_name);
|
||||
free(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_pread - positioned read from disk
|
||||
* @dev: device to read from
|
||||
* @pos: position in device to read from
|
||||
* @count: number of bytes to read
|
||||
* @b: output data buffer
|
||||
*
|
||||
* This function will read @count bytes from device @dev at position @pos into
|
||||
* the data buffer @b.
|
||||
*
|
||||
* On success, return the number of successfully read bytes. If this number is
|
||||
* lower than @count this means that we have either reached end of file or
|
||||
* encountered an error during the read so that the read is partial. 0 means
|
||||
* end of file or nothing to read (@count is 0).
|
||||
*
|
||||
* On error and nothing has been read, return -1 with errno set appropriately
|
||||
* to the return code of either seek, read, or set to EINVAL in case of
|
||||
* invalid arguments.
|
||||
*/
|
||||
s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
|
||||
{
|
||||
s64 br, total;
|
||||
struct ntfs_device_operations *dops;
|
||||
|
||||
ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!count)
|
||||
return 0;
|
||||
dops = dev->d_ops;
|
||||
/* Locate to position. */
|
||||
if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
|
||||
ntfs_log_perror("ntfs_pread: device seek to 0x%llx returned error",
|
||||
pos);
|
||||
return -1;
|
||||
}
|
||||
/* Read the data. */
|
||||
for (total = 0; count; count -= br, total += br) {
|
||||
br = dops->read(dev, (char*)b + total, count);
|
||||
/* If everything ok, continue. */
|
||||
if (br > 0)
|
||||
continue;
|
||||
/* If EOF or error return number of bytes read. */
|
||||
if (!br || total)
|
||||
return total;
|
||||
/* Nothing read and error, return error status. */
|
||||
return br;
|
||||
}
|
||||
/* Finally, return the number of bytes read. */
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_pwrite - positioned write to disk
|
||||
* @dev: device to write to
|
||||
* @pos: position in file descriptor to write to
|
||||
* @count: number of bytes to write
|
||||
* @b: data buffer to write to disk
|
||||
*
|
||||
* This function will write @count bytes from data buffer @b to the device @dev
|
||||
* at position @pos.
|
||||
*
|
||||
* On success, return the number of successfully written bytes. If this number
|
||||
* is lower than @count this means that the write has been interrupted in
|
||||
* flight or that an error was encountered during the write so that the write
|
||||
* is partial. 0 means nothing was written (also return 0 when @count is 0).
|
||||
*
|
||||
* On error and nothing has been written, return -1 with errno set
|
||||
* appropriately to the return code of either seek, write, or set
|
||||
* to EINVAL in case of invalid arguments.
|
||||
*/
|
||||
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const void *b)
|
||||
{
|
||||
s64 written, total, ret = -1;
|
||||
struct ntfs_device_operations *dops;
|
||||
|
||||
ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
|
||||
if (!b || count < 0 || pos < 0) {
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (!count)
|
||||
return 0;
|
||||
if (NDevReadOnly(dev)) {
|
||||
errno = EROFS;
|
||||
goto out;
|
||||
}
|
||||
dops = dev->d_ops;
|
||||
/* Locate to position. */
|
||||
if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
|
||||
ntfs_log_perror("ntfs_pwrite: seek to 0x%llx returned error",
|
||||
pos);
|
||||
goto out;
|
||||
}
|
||||
NDevSetDirty(dev);
|
||||
for (total = 0; count; count -= written, total += written) {
|
||||
written = dops->write(dev, (const char*)b + total, count);
|
||||
/* If everything ok, continue. */
|
||||
if (written > 0)
|
||||
continue;
|
||||
/*
|
||||
* If nothing written or error return number of bytes written.
|
||||
*/
|
||||
if (!written || total)
|
||||
break;
|
||||
/* Nothing written and error, return error status. */
|
||||
total = written;
|
||||
break;
|
||||
}
|
||||
ret = total;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mst_pread - multi sector transfer (mst) positioned read
|
||||
* @dev: device to read from
|
||||
* @pos: position in file descriptor to read from
|
||||
* @count: number of blocks to read
|
||||
* @bksize: size of each block that needs mst deprotecting
|
||||
* @b: output data buffer
|
||||
*
|
||||
* Multi sector transfer (mst) positioned read. This function will read @count
|
||||
* blocks of size @bksize bytes each from device @dev at position @pos into the
|
||||
* the data buffer @b.
|
||||
*
|
||||
* On success, return the number of successfully read blocks. If this number is
|
||||
* lower than @count this means that we have reached end of file, that the read
|
||||
* was interrupted, or that an error was encountered during the read so that
|
||||
* the read is partial. 0 means end of file or nothing was read (also return 0
|
||||
* when @count or @bksize are 0).
|
||||
*
|
||||
* On error and nothing was read, return -1 with errno set appropriately to the
|
||||
* return code of either seek, read, or set to EINVAL in case of invalid
|
||||
* arguments.
|
||||
*
|
||||
* NOTE: If an incomplete multi sector transfer has been detected the magic
|
||||
* will have been changed to magic_BAAD but no error will be returned. Thus it
|
||||
* is possible that we return count blocks as being read but that any number
|
||||
* (between zero and count!) of these blocks is actually subject to a multi
|
||||
* sector transfer error. This should be detected by the caller by checking for
|
||||
* the magic being "BAAD".
|
||||
*/
|
||||
s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b)
|
||||
{
|
||||
s64 br, i;
|
||||
|
||||
if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Do the read. */
|
||||
br = ntfs_pread(dev, pos, count * bksize, b);
|
||||
if (br < 0)
|
||||
return br;
|
||||
/*
|
||||
* Apply fixups to successfully read data, disregarding any errors
|
||||
* returned from the MST fixup function. This is because we want to
|
||||
* fixup everything possible and we rely on the fact that the "BAAD"
|
||||
* magic will be detected later on.
|
||||
*/
|
||||
count = br / bksize;
|
||||
for (i = 0; i < count; ++i)
|
||||
ntfs_mst_post_read_fixup((NTFS_RECORD*)
|
||||
((u8*)b + i * bksize), bksize);
|
||||
/* Finally, return the number of complete blocks read. */
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mst_pwrite - multi sector transfer (mst) positioned write
|
||||
* @dev: device to write to
|
||||
* @pos: position in file descriptor to write to
|
||||
* @count: number of blocks to write
|
||||
* @bksize: size of each block that needs mst protecting
|
||||
* @b: data buffer to write to disk
|
||||
*
|
||||
* Multi sector transfer (mst) positioned write. This function will write
|
||||
* @count blocks of size @bksize bytes each from data buffer @b to the device
|
||||
* @dev at position @pos.
|
||||
*
|
||||
* On success, return the number of successfully written blocks. If this number
|
||||
* is lower than @count this means that the write has been interrupted or that
|
||||
* an error was encountered during the write so that the write is partial. 0
|
||||
* means nothing was written (also return 0 when @count or @bksize are 0).
|
||||
*
|
||||
* On error and nothing has been written, return -1 with errno set
|
||||
* appropriately to the return code of either seek, write, or set
|
||||
* to EINVAL in case of invalid arguments.
|
||||
*
|
||||
* NOTE: We mst protect the data, write it, then mst deprotect it using a quick
|
||||
* deprotect algorithm (no checking). This saves us from making a copy before
|
||||
* the write and at the same time causes the usn to be incremented in the
|
||||
* buffer. This conceptually fits in better with the idea that cached data is
|
||||
* always deprotected and protection is performed when the data is actually
|
||||
* going to hit the disk and the cache is immediately deprotected again
|
||||
* simulating an mst read on the written data. This way cache coherency is
|
||||
* achieved.
|
||||
*/
|
||||
s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
|
||||
const u32 bksize, void *b)
|
||||
{
|
||||
s64 written, i;
|
||||
|
||||
if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (!count)
|
||||
return 0;
|
||||
/* Prepare data for writing. */
|
||||
for (i = 0; i < count; ++i) {
|
||||
int err;
|
||||
|
||||
err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
|
||||
((u8*)b + i * bksize), bksize);
|
||||
if (err < 0) {
|
||||
/* Abort write at this position. */
|
||||
if (!i)
|
||||
return err;
|
||||
count = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Write the prepared data. */
|
||||
written = ntfs_pwrite(dev, pos, count * bksize, b);
|
||||
/* Quickly deprotect the data again. */
|
||||
for (i = 0; i < count; ++i)
|
||||
ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
|
||||
if (written <= 0)
|
||||
return written;
|
||||
/* Finally, return the number of complete blocks written. */
|
||||
return written / bksize;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_cluster_read - read ntfs clusters
|
||||
* @vol: volume to read from
|
||||
* @lcn: starting logical cluster number
|
||||
* @count: number of clusters to read
|
||||
* @b: output data buffer
|
||||
*
|
||||
* Read @count ntfs clusters starting at logical cluster number @lcn from
|
||||
* volume @vol into buffer @b. Return number of clusters read or -1 on error,
|
||||
* with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
|
||||
void *b)
|
||||
{
|
||||
s64 br;
|
||||
|
||||
if (!vol || lcn < 0 || count < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (vol->nr_clusters < lcn + count) {
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror("Trying to read outside of volume "
|
||||
"(%lld < %lld)", vol->nr_clusters, lcn + count);
|
||||
return -1;
|
||||
}
|
||||
br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits,
|
||||
count << vol->cluster_size_bits, b);
|
||||
if (br < 0) {
|
||||
ntfs_log_perror("Error reading cluster(s)");
|
||||
return br;
|
||||
}
|
||||
return br >> vol->cluster_size_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_cluster_write - write ntfs clusters
|
||||
* @vol: volume to write to
|
||||
* @lcn: starting logical cluster number
|
||||
* @count: number of clusters to write
|
||||
* @b: data buffer to write to disk
|
||||
*
|
||||
* Write @count ntfs clusters starting at logical cluster number @lcn from
|
||||
* buffer @b to volume @vol. Return the number of clusters written or -1 on
|
||||
* error, with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
|
||||
const s64 count, const void *b)
|
||||
{
|
||||
s64 bw;
|
||||
|
||||
if (!vol || lcn < 0 || count < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (vol->nr_clusters < lcn + count) {
|
||||
errno = ESPIPE;
|
||||
ntfs_log_perror("Trying to write outside of volume "
|
||||
"(%lld < %lld)", vol->nr_clusters, lcn + count);
|
||||
return -1;
|
||||
}
|
||||
if (!NVolReadOnly(vol))
|
||||
bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits,
|
||||
count << vol->cluster_size_bits, b);
|
||||
else
|
||||
bw = count << vol->cluster_size_bits;
|
||||
if (bw < 0) {
|
||||
ntfs_log_perror("Error writing cluster(s)");
|
||||
return bw;
|
||||
}
|
||||
return bw >> vol->cluster_size_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_offset_valid - test if a device offset is valid
|
||||
* @dev: open device
|
||||
* @ofs: offset to test for validity
|
||||
*
|
||||
* Test if the offset @ofs is an existing location on the device described
|
||||
* by the open device structure @dev.
|
||||
*
|
||||
* Return 0 if it is valid and -1 if it is not valid.
|
||||
*/
|
||||
static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
|
||||
{
|
||||
char ch;
|
||||
|
||||
if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
|
||||
dev->d_ops->read(dev, &ch, 1) == 1)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_size_get - return the size of a device in blocks
|
||||
* @dev: open device
|
||||
* @block_size: block size in bytes in which to return the result
|
||||
*
|
||||
* Return the number of @block_size sized blocks in the device described by the
|
||||
* open device @dev.
|
||||
*
|
||||
* Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
|
||||
*
|
||||
* On error return -1 with errno set to the error code.
|
||||
*/
|
||||
s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
||||
{
|
||||
s64 high, low;
|
||||
|
||||
if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKGETSIZE64
|
||||
{ u64 size;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
|
||||
ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
|
||||
(unsigned long long)size,
|
||||
(unsigned long long)size);
|
||||
return (s64)size / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef BLKGETSIZE
|
||||
{ unsigned long size;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
|
||||
ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
|
||||
size, size);
|
||||
return (s64)size * 512 / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef FDGETPRM
|
||||
{ struct floppy_struct this_floppy;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
|
||||
ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
|
||||
(unsigned long)this_floppy.size,
|
||||
(unsigned long)this_floppy.size);
|
||||
return (s64)this_floppy.size * 512 / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* We couldn't figure it out by using a specialized ioctl,
|
||||
* so do binary search to find the size of the device.
|
||||
*/
|
||||
low = 0LL;
|
||||
for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
|
||||
low = high;
|
||||
while (low < high - 1LL) {
|
||||
const s64 mid = (low + high) / 2;
|
||||
|
||||
if (!ntfs_device_offset_valid(dev, mid))
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
dev->d_ops->seek(dev, 0LL, SEEK_SET);
|
||||
return (low + 1LL) / block_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_partition_start_sector_get - get starting sector of a partition
|
||||
* @dev: open device
|
||||
*
|
||||
* On success, return the starting sector of the partition @dev in the parent
|
||||
* block device of @dev. On error return -1 with errno set to the error code.
|
||||
*
|
||||
* The following error codes are defined:
|
||||
* EINVAL Input parameter error
|
||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||
*/
|
||||
s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
|
||||
{
|
||||
if (!dev) {
|
||||
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 start_sect = %lu (0x%lx)\n",
|
||||
geo.start, geo.start);
|
||||
return geo.start;
|
||||
}
|
||||
}
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_heads_get - get number of heads of device
|
||||
* @dev: open device
|
||||
*
|
||||
* On success, return the number of heads on the device @dev. On error return
|
||||
* -1 with errno set to the error code.
|
||||
*
|
||||
* The following error codes are defined:
|
||||
* EINVAL Input parameter error
|
||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||
*/
|
||||
int ntfs_device_heads_get(struct ntfs_device *dev)
|
||||
{
|
||||
if (!dev) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_sectors_per_track_get - get number of sectors per track of device
|
||||
* @dev: open device
|
||||
*
|
||||
* On success, return the number of sectors per track on the device @dev. On
|
||||
* error return -1 with errno set to the error code.
|
||||
*
|
||||
* The following error codes are defined:
|
||||
* EINVAL Input parameter error
|
||||
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
|
||||
*/
|
||||
int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
|
||||
{
|
||||
if (!dev) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_sector_size_get - get sector size of a device
|
||||
* @dev: open device
|
||||
*
|
||||
* On success, return the sector size in bytes of the device @dev.
|
||||
* On error return -1 with errno set to the error code.
|
||||
*
|
||||
* The following error codes are defined:
|
||||
* EINVAL Input parameter error
|
||||
* EOPNOTSUPP System does not support BLKSSZGET ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting BLKSSZGET
|
||||
*/
|
||||
int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
||||
{
|
||||
if (!dev) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKSSZGET
|
||||
{
|
||||
int sect_size = 0;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) {
|
||||
ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
|
||||
sect_size);
|
||||
return sect_size;
|
||||
}
|
||||
}
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_block_size_set - set block size of a device
|
||||
* @dev: open device
|
||||
* @block_size: block size to set @dev to
|
||||
*
|
||||
* On success, return 0.
|
||||
* On error return -1 with errno set to the error code.
|
||||
*
|
||||
* The following error codes are defined:
|
||||
* EINVAL Input parameter error
|
||||
* EOPNOTSUPP System does not support BLKBSZSET ioctl
|
||||
* ENOTTY @dev is a file or a device not supporting BLKBSZSET
|
||||
*/
|
||||
int ntfs_device_block_size_set(struct ntfs_device *dev,
|
||||
int block_size __attribute__((unused)))
|
||||
{
|
||||
if (!dev) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#ifdef BLKBSZSET
|
||||
{
|
||||
size_t s_block_size = block_size;
|
||||
if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
|
||||
ntfs_log_debug("Used BLKBSZSET to set block size to "
|
||||
"%d bytes.\n", block_size);
|
||||
return 0;
|
||||
}
|
||||
/* If not a block device, pretend it was successful. */
|
||||
if (!NDevBlock(dev))
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/* If not a block device, pretend it was successful. */
|
||||
if (!NDevBlock(dev))
|
||||
return 0;
|
||||
errno = EOPNOTSUPP;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
38
libntfs-3g/device_io.c
Normal file
38
libntfs-3g/device_io.c
Normal 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 */
|
1655
libntfs-3g/dir.c
Normal file
1655
libntfs-3g/dir.c
Normal file
File diff suppressed because it is too large
Load Diff
1836
libntfs-3g/index.c
Normal file
1836
libntfs-3g/index.c
Normal file
File diff suppressed because it is too large
Load Diff
1157
libntfs-3g/inode.c
Normal file
1157
libntfs-3g/inode.c
Normal file
File diff suppressed because it is too large
Load Diff
858
libntfs-3g/lcnalloc.c
Normal file
858
libntfs-3g/lcnalloc.c
Normal file
@ -0,0 +1,858 @@
|
||||
/**
|
||||
* lcnalloc.c - Cluster (de)allocation code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004 Yura Pakhuchiy
|
||||
*
|
||||
* 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_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
#include "bitmap.h"
|
||||
#include "debug.h"
|
||||
#include "runlist.h"
|
||||
#include "volume.h"
|
||||
#include "lcnalloc.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
/**
|
||||
* ntfs_cluster_alloc - allocate clusters on an ntfs volume
|
||||
* @vol: mounted ntfs volume on which to allocate the clusters
|
||||
* @start_vcn: vcn to use for the first allocated cluster
|
||||
* @count: number of clusters to allocate
|
||||
* @start_lcn: starting lcn at which to allocate the clusters (or -1 if none)
|
||||
* @zone: zone from which to allocate the clusters
|
||||
*
|
||||
* Allocate @count clusters preferably starting at cluster @start_lcn or at the
|
||||
* current allocator position if @start_lcn is -1, on the mounted ntfs volume
|
||||
* @vol. @zone is either DATA_ZONE for allocation of normal clusters and
|
||||
* MFT_ZONE for allocation of clusters for the master file table, i.e. the
|
||||
* $MFT/$DATA attribute.
|
||||
*
|
||||
* On success return a runlist describing the allocated cluster(s).
|
||||
*
|
||||
* On error return NULL with errno set to the error code.
|
||||
*
|
||||
* Notes on the allocation algorithm
|
||||
* =================================
|
||||
*
|
||||
* There are two data zones. First is the area between the end of the mft zone
|
||||
* and the end of the volume, and second is the area between the start of the
|
||||
* volume and the start of the mft zone. On unmodified/standard NTFS 1.x
|
||||
* volumes, the second data zone doesn't exist due to the mft zone being
|
||||
* expanded to cover the start of the volume in order to reserve space for the
|
||||
* mft bitmap attribute.
|
||||
*
|
||||
* This is not the prettiest function but the complexity stems from the need of
|
||||
* implementing the mft vs data zoned approach and from the fact that we have
|
||||
* access to the lcn bitmap in portions of up to 8192 bytes at a time, so we
|
||||
* need to cope with crossing over boundaries of two buffers. Further, the fact
|
||||
* that the allocator allows for caller supplied hints as to the location of
|
||||
* where allocation should begin and the fact that the allocator keeps track of
|
||||
* where in the data zones the next natural allocation should occur, contribute
|
||||
* to the complexity of the function. But it should all be worthwhile, because
|
||||
* this allocator should: 1) be a full implementation of the MFT zone approach
|
||||
* used by Windows, 2) cause reduction in fragmentation as much as possible,
|
||||
* and 3) be speedy in allocations (the code is not optimized for speed, but
|
||||
* the algorithm is, so further speed improvements are probably possible).
|
||||
*
|
||||
* FIXME: We should be monitoring cluster allocation and increment the MFT zone
|
||||
* size dynamically but this is something for the future. We will just cause
|
||||
* heavier fragmentation by not doing it and I am not even sure Windows would
|
||||
* grow the MFT zone dynamically, so it might even be correct not to do this.
|
||||
* The overhead in doing dynamic MFT zone expansion would be very large and
|
||||
* unlikely worth the effort. (AIA)
|
||||
*
|
||||
* TODO: I have added in double the required zone position pointer wrap around
|
||||
* logic which can be optimized to having only one of the two logic sets.
|
||||
* However, having the double logic will work fine, but if we have only one of
|
||||
* the sets and we get it wrong somewhere, then we get into trouble, so
|
||||
* removing the duplicate logic requires _very_ careful consideration of _all_
|
||||
* possible code paths. So at least for now, I am leaving the double logic -
|
||||
* better safe than sorry... (AIA)
|
||||
*/
|
||||
runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
|
||||
LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone)
|
||||
{
|
||||
LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
|
||||
LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
|
||||
s64 clusters, br;
|
||||
runlist *rl = NULL, *trl;
|
||||
u8 *buf, *byte;
|
||||
int err = 0, rlpos, rlsize, buf_size;
|
||||
u8 pass, done_zones, search_zone, need_writeback, bit;
|
||||
|
||||
ntfs_log_trace("Entering with count = 0x%llx, start_lcn = 0x%llx, zone = "
|
||||
"%s_ZONE.\n", (long long)count, (long long)start_lcn,
|
||||
zone == MFT_ZONE ? "MFT" : "DATA");
|
||||
if (!vol || count < 0 || start_lcn < -1 || !vol->lcnbmp_na ||
|
||||
(s8)zone < FIRST_ZONE || zone > LAST_ZONE) {
|
||||
ntfs_log_trace("Invalid arguments!\n");
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return empty runlist if @count == 0 */
|
||||
if (!count) {
|
||||
rl = ntfs_malloc(0x1000);
|
||||
if (!rl)
|
||||
return NULL;
|
||||
rl[0].vcn = start_vcn;
|
||||
rl[0].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[0].length = 0;
|
||||
return rl;
|
||||
}
|
||||
|
||||
/* Allocate memory. */
|
||||
buf = ntfs_malloc(8192);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
/*
|
||||
* If no specific @start_lcn was requested, use the current data zone
|
||||
* position, otherwise use the requested @start_lcn but make sure it
|
||||
* lies outside the mft zone. Also set done_zones to 0 (no zones done)
|
||||
* and pass depending on whether we are starting inside a zone (1) or
|
||||
* at the beginning of a zone (2). If requesting from the MFT_ZONE,
|
||||
* we either start at the current position within the mft zone or at
|
||||
* the specified position. If the latter is out of bounds then we start
|
||||
* at the beginning of the MFT_ZONE.
|
||||
*/
|
||||
done_zones = 0;
|
||||
pass = 1;
|
||||
/*
|
||||
* zone_start and zone_end are the current search range. search_zone
|
||||
* is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of
|
||||
* volume) and 4 for data zone 2 (start of volume till start of mft
|
||||
* zone).
|
||||
*/
|
||||
zone_start = start_lcn;
|
||||
if (zone_start < 0) {
|
||||
if (zone == DATA_ZONE)
|
||||
zone_start = vol->data1_zone_pos;
|
||||
else
|
||||
zone_start = vol->mft_zone_pos;
|
||||
if (!zone_start) {
|
||||
/*
|
||||
* Zone starts at beginning of volume which means a
|
||||
* single pass is sufficient.
|
||||
*/
|
||||
pass = 2;
|
||||
}
|
||||
} else if (zone == DATA_ZONE && zone_start >= vol->mft_zone_start &&
|
||||
zone_start < vol->mft_zone_end) {
|
||||
zone_start = vol->mft_zone_end;
|
||||
/*
|
||||
* Starting at beginning of data1_zone which means a single
|
||||
* pass in this zone is sufficient.
|
||||
*/
|
||||
pass = 2;
|
||||
} else if (zone == MFT_ZONE && (zone_start < vol->mft_zone_start ||
|
||||
zone_start >= vol->mft_zone_end)) {
|
||||
zone_start = vol->mft_lcn;
|
||||
if (!vol->mft_zone_end)
|
||||
zone_start = 0;
|
||||
/*
|
||||
* Starting at beginning of volume which means a single pass
|
||||
* is sufficient.
|
||||
*/
|
||||
pass = 2;
|
||||
}
|
||||
if (zone == MFT_ZONE) {
|
||||
zone_end = vol->mft_zone_end;
|
||||
search_zone = 1;
|
||||
} else /* if (zone == DATA_ZONE) */ {
|
||||
/* Skip searching the mft zone. */
|
||||
done_zones |= 1;
|
||||
if (zone_start >= vol->mft_zone_end) {
|
||||
zone_end = vol->nr_clusters;
|
||||
search_zone = 2;
|
||||
} else {
|
||||
zone_end = vol->mft_zone_start;
|
||||
search_zone = 4;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* bmp_pos is the current bit position inside the bitmap. We use
|
||||
* bmp_initial_pos to determine whether or not to do a zone switch.
|
||||
*/
|
||||
bmp_pos = bmp_initial_pos = zone_start;
|
||||
|
||||
/* Loop until all clusters are allocated, i.e. clusters == 0. */
|
||||
clusters = count;
|
||||
rlpos = rlsize = 0;
|
||||
while (1) {
|
||||
ntfs_log_trace("Start of outer while loop: done_zones = 0x%x, "
|
||||
"search_zone = %i, pass = %i, zone_start = "
|
||||
"0x%llx, zone_end = 0x%llx, bmp_initial_pos = "
|
||||
"0x%llx, bmp_pos = 0x%llx, rlpos = %i, rlsize = "
|
||||
"%i.\n", done_zones, search_zone, pass,
|
||||
(long long)zone_start, (long long)zone_end,
|
||||
(long long)bmp_initial_pos, (long long)bmp_pos,
|
||||
rlpos, rlsize);
|
||||
/* Loop until we run out of free clusters. */
|
||||
last_read_pos = bmp_pos >> 3;
|
||||
ntfs_log_trace("last_read_pos = 0x%llx.\n", (long long)last_read_pos);
|
||||
br = ntfs_attr_pread(vol->lcnbmp_na, last_read_pos, 8192, buf);
|
||||
if (br <= 0) {
|
||||
if (!br) {
|
||||
/* Reached end of attribute. */
|
||||
ntfs_log_trace("End of attribute reached. Skipping "
|
||||
"to zone_pass_done.\n");
|
||||
goto zone_pass_done;
|
||||
}
|
||||
err = errno;
|
||||
ntfs_log_trace("ntfs_attr_pread() failed. Aborting.\n");
|
||||
goto err_ret;
|
||||
}
|
||||
/*
|
||||
* We might have read less than 8192 bytes if we are close to
|
||||
* the end of the attribute.
|
||||
*/
|
||||
buf_size = (int)br << 3;
|
||||
lcn = bmp_pos & 7;
|
||||
bmp_pos &= ~7;
|
||||
need_writeback = 0;
|
||||
ntfs_log_trace("Before inner while loop: buf_size = %i, lcn = "
|
||||
"0x%llx, bmp_pos = 0x%llx, need_writeback = %i.\n",
|
||||
buf_size, (long long)lcn, (long long)bmp_pos,
|
||||
need_writeback);
|
||||
while (lcn < buf_size && lcn + bmp_pos < zone_end) {
|
||||
byte = buf + (lcn >> 3);
|
||||
ntfs_log_trace("In inner while loop: buf_size = %i, lcn = "
|
||||
"0x%llx, bmp_pos = 0x%llx, "
|
||||
"need_writeback = %i, byte ofs = 0x%x, "
|
||||
"*byte = 0x%x.\n", buf_size,
|
||||
(long long)lcn, (long long)bmp_pos,
|
||||
need_writeback, (unsigned int)(lcn >> 3),
|
||||
(unsigned int)*byte);
|
||||
/* Skip full bytes. */
|
||||
if (*byte == 0xff) {
|
||||
lcn = (lcn + 8) & ~7;
|
||||
ntfs_log_trace("continuing while loop 1.\n");
|
||||
continue;
|
||||
}
|
||||
bit = 1 << (lcn & 7);
|
||||
ntfs_log_trace("bit = %i.\n", bit);
|
||||
/* If the bit is already set, go onto the next one. */
|
||||
if (*byte & bit) {
|
||||
lcn++;
|
||||
ntfs_log_trace("continuing while loop 2.\n");
|
||||
continue;
|
||||
}
|
||||
/* Reallocate memory if necessary. */
|
||||
if ((rlpos + 2) * (int)sizeof(runlist) >= rlsize) {
|
||||
ntfs_log_trace("Reallocating space.\n");
|
||||
if (!rl)
|
||||
ntfs_log_trace("First free bit is at LCN = "
|
||||
"0x%llx.\n", (long long)(lcn + bmp_pos));
|
||||
rlsize += 4096;
|
||||
trl = (runlist*)realloc(rl, rlsize);
|
||||
if (!trl) {
|
||||
err = ENOMEM;
|
||||
ntfs_log_trace("Failed to allocate memory, "
|
||||
"going to wb_err_ret.\n");
|
||||
goto wb_err_ret;
|
||||
}
|
||||
rl = trl;
|
||||
ntfs_log_trace("Reallocated memory, rlsize = "
|
||||
"0x%x.\n", rlsize);
|
||||
}
|
||||
/* Allocate the bitmap bit. */
|
||||
*byte |= bit;
|
||||
/* We need to write this bitmap buffer back to disk! */
|
||||
need_writeback = 1;
|
||||
ntfs_log_trace("*byte = 0x%x, need_writeback is set.\n",
|
||||
(unsigned int)*byte);
|
||||
/*
|
||||
* Coalesce with previous run if adjacent LCNs.
|
||||
* Otherwise, append a new run.
|
||||
*/
|
||||
ntfs_log_trace("Adding run (lcn 0x%llx, len 0x%llx), "
|
||||
"prev_lcn = 0x%llx, lcn = 0x%llx, "
|
||||
"bmp_pos = 0x%llx, prev_run_len = "
|
||||
"0x%llx, rlpos = %i.\n",
|
||||
(long long)(lcn + bmp_pos), 1LL,
|
||||
(long long)prev_lcn, (long long)lcn,
|
||||
(long long)bmp_pos,
|
||||
(long long)prev_run_len, rlpos);
|
||||
if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) {
|
||||
ntfs_log_trace("Coalescing to run (lcn 0x%llx, len "
|
||||
"0x%llx).\n",
|
||||
(long long)rl[rlpos - 1].lcn,
|
||||
(long long) rl[rlpos - 1].length);
|
||||
rl[rlpos - 1].length = ++prev_run_len;
|
||||
ntfs_log_trace("Run now (lcn 0x%llx, len 0x%llx), "
|
||||
"prev_run_len = 0x%llx.\n",
|
||||
(long long)rl[rlpos - 1].lcn,
|
||||
(long long)rl[rlpos - 1].length,
|
||||
(long long)prev_run_len);
|
||||
} else {
|
||||
if (rlpos) {
|
||||
ntfs_log_trace("Adding new run, (previous "
|
||||
"run lcn 0x%llx, len 0x%llx).\n",
|
||||
(long long) rl[rlpos - 1].lcn,
|
||||
(long long) rl[rlpos - 1].length);
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn +
|
||||
prev_run_len;
|
||||
} else {
|
||||
ntfs_log_trace("Adding new run, is first run.\n");
|
||||
rl[rlpos].vcn = start_vcn;
|
||||
}
|
||||
rl[rlpos].lcn = prev_lcn = lcn + bmp_pos;
|
||||
rl[rlpos].length = prev_run_len = 1;
|
||||
rlpos++;
|
||||
}
|
||||
/* Done? */
|
||||
if (!--clusters) {
|
||||
LCN tc;
|
||||
/*
|
||||
* Update the current zone position. Positions
|
||||
* of already scanned zones have been updated
|
||||
* during the respective zone switches.
|
||||
*/
|
||||
tc = lcn + bmp_pos + 1;
|
||||
ntfs_log_trace("Done. Updating current zone "
|
||||
"position, tc = 0x%llx, search_zone = %i.\n",
|
||||
(long long)tc, search_zone);
|
||||
switch (search_zone) {
|
||||
case 1:
|
||||
ntfs_log_trace("Before checks, vol->mft_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->mft_zone_pos);
|
||||
if (tc >= vol->mft_zone_end) {
|
||||
vol->mft_zone_pos =
|
||||
vol->mft_lcn;
|
||||
if (!vol->mft_zone_end)
|
||||
vol->mft_zone_pos = 0;
|
||||
} else if ((bmp_initial_pos >=
|
||||
vol->mft_zone_pos ||
|
||||
tc > vol->mft_zone_pos)
|
||||
&& tc >= vol->mft_lcn)
|
||||
vol->mft_zone_pos = tc;
|
||||
ntfs_log_trace("After checks, vol->mft_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->mft_zone_pos);
|
||||
break;
|
||||
case 2:
|
||||
ntfs_log_trace("Before checks, vol->data1_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->data1_zone_pos);
|
||||
if (tc >= vol->nr_clusters)
|
||||
vol->data1_zone_pos =
|
||||
vol->mft_zone_end;
|
||||
else if ((bmp_initial_pos >=
|
||||
vol->data1_zone_pos ||
|
||||
tc > vol->data1_zone_pos)
|
||||
&& tc >= vol->mft_zone_end)
|
||||
vol->data1_zone_pos = tc;
|
||||
ntfs_log_trace("After checks, vol->data1_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->data1_zone_pos);
|
||||
break;
|
||||
case 4:
|
||||
ntfs_log_trace("Before checks, vol->data2_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->data2_zone_pos);
|
||||
if (tc >= vol->mft_zone_start)
|
||||
vol->data2_zone_pos = 0;
|
||||
else if (bmp_initial_pos >=
|
||||
vol->data2_zone_pos ||
|
||||
tc > vol->data2_zone_pos)
|
||||
vol->data2_zone_pos = tc;
|
||||
ntfs_log_trace("After checks, vol->data2_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->data2_zone_pos);
|
||||
break;
|
||||
default:
|
||||
free(rl);
|
||||
free(buf);
|
||||
NTFS_BUG("switch (search_zone) 1");
|
||||
return NULL;
|
||||
}
|
||||
ntfs_log_trace("Going to done_ret.\n");
|
||||
goto done_ret;
|
||||
}
|
||||
lcn++;
|
||||
}
|
||||
bmp_pos += buf_size;
|
||||
ntfs_log_trace("After inner while loop: buf_size = 0x%x, lcn = "
|
||||
"0x%llx, bmp_pos = 0x%llx, need_writeback = %i.\n",
|
||||
buf_size, (long long)lcn,
|
||||
(long long)bmp_pos, need_writeback);
|
||||
if (need_writeback) {
|
||||
s64 bw;
|
||||
ntfs_log_trace("Writing back.\n");
|
||||
need_writeback = 0;
|
||||
bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos,
|
||||
br, buf);
|
||||
if (bw != br) {
|
||||
if (bw == -1)
|
||||
err = errno;
|
||||
else
|
||||
err = EIO;
|
||||
ntfs_log_trace("Bitmap writeback failed in read next "
|
||||
"buffer code path with error code %i.\n", err);
|
||||
goto err_ret;
|
||||
}
|
||||
}
|
||||
if (bmp_pos < zone_end) {
|
||||
ntfs_log_trace("Continuing outer while loop, bmp_pos = "
|
||||
"0x%llx, zone_end = 0x%llx.\n",
|
||||
(long long)bmp_pos,
|
||||
(long long)zone_end);
|
||||
continue;
|
||||
}
|
||||
zone_pass_done: /* Finished with the current zone pass. */
|
||||
ntfs_log_trace("At zone_pass_done, pass = %i.\n", pass);
|
||||
if (pass == 1) {
|
||||
/*
|
||||
* Now do pass 2, scanning the first part of the zone
|
||||
* we omitted in pass 1.
|
||||
*/
|
||||
pass = 2;
|
||||
zone_end = zone_start;
|
||||
switch (search_zone) {
|
||||
case 1: /* mft_zone */
|
||||
zone_start = vol->mft_zone_start;
|
||||
break;
|
||||
case 2: /* data1_zone */
|
||||
zone_start = vol->mft_zone_end;
|
||||
break;
|
||||
case 4: /* data2_zone */
|
||||
zone_start = 0;
|
||||
break;
|
||||
default:
|
||||
NTFS_BUG("switch (search_zone) 2");
|
||||
}
|
||||
/* Sanity check. */
|
||||
if (zone_end < zone_start)
|
||||
zone_end = zone_start;
|
||||
bmp_pos = zone_start;
|
||||
ntfs_log_trace("Continuing outer while loop, pass = 2, "
|
||||
"zone_start = 0x%llx, zone_end = "
|
||||
"0x%llx, bmp_pos = 0x%llx.\n",
|
||||
zone_start, zone_end, bmp_pos);
|
||||
continue;
|
||||
} /* pass == 2 */
|
||||
done_zones_check:
|
||||
ntfs_log_trace("At done_zones_check, search_zone = %i, done_zones "
|
||||
"before = 0x%x, done_zones after = 0x%x.\n",
|
||||
search_zone, done_zones, done_zones | search_zone);
|
||||
done_zones |= search_zone;
|
||||
if (done_zones < 7) {
|
||||
ntfs_log_trace("Switching zone.\n");
|
||||
/* Now switch to the next zone we haven't done yet. */
|
||||
pass = 1;
|
||||
switch (search_zone) {
|
||||
case 1:
|
||||
ntfs_log_trace("Switching from mft zone to data1 "
|
||||
"zone.\n");
|
||||
/* Update mft zone position. */
|
||||
if (rlpos) {
|
||||
LCN tc;
|
||||
ntfs_log_trace("Before checks, vol->mft_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->mft_zone_pos);
|
||||
tc = rl[rlpos - 1].lcn +
|
||||
rl[rlpos - 1].length;
|
||||
if (tc >= vol->mft_zone_end) {
|
||||
vol->mft_zone_pos =
|
||||
vol->mft_lcn;
|
||||
if (!vol->mft_zone_end)
|
||||
vol->mft_zone_pos = 0;
|
||||
} else if ((bmp_initial_pos >=
|
||||
vol->mft_zone_pos ||
|
||||
tc > vol->mft_zone_pos)
|
||||
&& tc >= vol->mft_lcn)
|
||||
vol->mft_zone_pos = tc;
|
||||
ntfs_log_trace("After checks, vol->mft_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->mft_zone_pos);
|
||||
}
|
||||
/* Switch from mft zone to data1 zone. */
|
||||
switch_to_data1_zone: search_zone = 2;
|
||||
zone_start = bmp_initial_pos =
|
||||
vol->data1_zone_pos;
|
||||
zone_end = vol->nr_clusters;
|
||||
if (zone_start == vol->mft_zone_end)
|
||||
pass = 2;
|
||||
if (zone_start >= zone_end) {
|
||||
vol->data1_zone_pos = zone_start =
|
||||
vol->mft_zone_end;
|
||||
pass = 2;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
ntfs_log_trace("Switching from data1 zone to data2 "
|
||||
"zone.\n");
|
||||
/* Update data1 zone position. */
|
||||
if (rlpos) {
|
||||
LCN tc;
|
||||
ntfs_log_trace("Before checks, vol->data1_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->data1_zone_pos);
|
||||
tc = rl[rlpos - 1].lcn +
|
||||
rl[rlpos - 1].length;
|
||||
if (tc >= vol->nr_clusters)
|
||||
vol->data1_zone_pos =
|
||||
vol->mft_zone_end;
|
||||
else if ((bmp_initial_pos >=
|
||||
vol->data1_zone_pos ||
|
||||
tc > vol->data1_zone_pos)
|
||||
&& tc >= vol->mft_zone_end)
|
||||
vol->data1_zone_pos = tc;
|
||||
ntfs_log_trace("After checks, vol->data1_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->data1_zone_pos);
|
||||
}
|
||||
/* Switch from data1 zone to data2 zone. */
|
||||
search_zone = 4;
|
||||
zone_start = bmp_initial_pos =
|
||||
vol->data2_zone_pos;
|
||||
zone_end = vol->mft_zone_start;
|
||||
if (!zone_start)
|
||||
pass = 2;
|
||||
if (zone_start >= zone_end) {
|
||||
vol->data2_zone_pos = zone_start =
|
||||
bmp_initial_pos = 0;
|
||||
pass = 2;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
ntfs_log_debug("Switching from data2 zone to data1 "
|
||||
"zone.\n");
|
||||
/* Update data2 zone position. */
|
||||
if (rlpos) {
|
||||
LCN tc;
|
||||
ntfs_log_trace("Before checks, vol->data2_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->data2_zone_pos);
|
||||
tc = rl[rlpos - 1].lcn +
|
||||
rl[rlpos - 1].length;
|
||||
if (tc >= vol->mft_zone_start)
|
||||
vol->data2_zone_pos = 0;
|
||||
else if (bmp_initial_pos >=
|
||||
vol->data2_zone_pos ||
|
||||
tc > vol->data2_zone_pos)
|
||||
vol->data2_zone_pos = tc;
|
||||
ntfs_log_trace("After checks, vol->data2_zone_pos = 0x%llx.\n",
|
||||
(long long) vol->data2_zone_pos);
|
||||
}
|
||||
/* Switch from data2 zone to data1 zone. */
|
||||
goto switch_to_data1_zone; /* See above. */
|
||||
default:
|
||||
NTFS_BUG("switch (search_zone) 3");
|
||||
}
|
||||
ntfs_log_trace("After zone switch, search_zone = %i, pass = "
|
||||
"%i, bmp_initial_pos = 0x%llx, "
|
||||
"zone_start = 0x%llx, zone_end = "
|
||||
"0x%llx.\n", search_zone, pass,
|
||||
(long long)bmp_initial_pos,
|
||||
(long long)zone_start,
|
||||
(long long)zone_end);
|
||||
bmp_pos = zone_start;
|
||||
if (zone_start == zone_end) {
|
||||
ntfs_log_trace("Empty zone, going to "
|
||||
"done_zones_check.\n");
|
||||
/* Empty zone. Don't bother searching it. */
|
||||
goto done_zones_check;
|
||||
}
|
||||
ntfs_log_trace("Continuing outer while loop.\n");
|
||||
continue;
|
||||
} /* done_zones == 7 */
|
||||
ntfs_log_trace("All zones are finished.\n");
|
||||
/*
|
||||
* All zones are finished! If DATA_ZONE, shrink mft zone. If
|
||||
* MFT_ZONE, we have really run out of space.
|
||||
*/
|
||||
mft_zone_size = vol->mft_zone_end - vol->mft_zone_start;
|
||||
ntfs_log_trace("vol->mft_zone_start = 0x%llx, vol->mft_zone_end = "
|
||||
"0x%llx, mft_zone_size = 0x%llx.\n",
|
||||
(long long)vol->mft_zone_start,
|
||||
(long long)vol->mft_zone_end,
|
||||
(long long)mft_zone_size);
|
||||
if (zone == MFT_ZONE || mft_zone_size <= 0) {
|
||||
ntfs_log_trace("No free clusters left, going to err_ret.\n");
|
||||
/* Really no more space left on device. */
|
||||
err = ENOSPC;
|
||||
goto err_ret;
|
||||
} /* zone == DATA_ZONE && mft_zone_size > 0 */
|
||||
ntfs_log_trace("Shrinking mft zone.\n");
|
||||
zone_end = vol->mft_zone_end;
|
||||
mft_zone_size >>= 1;
|
||||
if (mft_zone_size > 0)
|
||||
vol->mft_zone_end = vol->mft_zone_start + mft_zone_size;
|
||||
else /* mft zone and data2 zone no longer exist. */
|
||||
vol->data2_zone_pos = vol->mft_zone_start =
|
||||
vol->mft_zone_end = 0;
|
||||
if (vol->mft_zone_pos >= vol->mft_zone_end) {
|
||||
vol->mft_zone_pos = vol->mft_lcn;
|
||||
if (!vol->mft_zone_end)
|
||||
vol->mft_zone_pos = 0;
|
||||
}
|
||||
bmp_pos = zone_start = bmp_initial_pos =
|
||||
vol->data1_zone_pos = vol->mft_zone_end;
|
||||
search_zone = 2;
|
||||
pass = 2;
|
||||
done_zones &= ~2;
|
||||
ntfs_log_trace("After shrinking mft zone, mft_zone_size = 0x%llx, "
|
||||
"vol->mft_zone_start = 0x%llx, "
|
||||
"vol->mft_zone_end = 0x%llx, vol->mft_zone_pos "
|
||||
"= 0x%llx, search_zone = 2, pass = 2, "
|
||||
"dones_zones = 0x%x, zone_start = 0x%llx, "
|
||||
"zone_end = 0x%llx, vol->data1_zone_pos = "
|
||||
"0x%llx, continuing outer while loop.\n",
|
||||
(long long)mft_zone_size,
|
||||
(long long)vol->mft_zone_start,
|
||||
(long long)vol->mft_zone_end,
|
||||
(long long)vol->mft_zone_pos,
|
||||
done_zones,
|
||||
(long long)zone_start,
|
||||
(long long)zone_end,
|
||||
(long long)vol->data1_zone_pos);
|
||||
}
|
||||
ntfs_log_debug("After outer while loop.\n");
|
||||
done_ret:
|
||||
ntfs_log_debug("At done_ret.\n");
|
||||
/* Add runlist terminator element. */
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[rlpos].length = 0;
|
||||
if (need_writeback) {
|
||||
s64 bw;
|
||||
ntfs_log_trace("Writing back.\n");
|
||||
need_writeback = 0;
|
||||
bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos, br, buf);
|
||||
if (bw != br) {
|
||||
if (bw < 0)
|
||||
err = errno;
|
||||
else
|
||||
err = EIO;
|
||||
ntfs_log_trace("Bitmap writeback failed in done code path "
|
||||
"with error code %i.\n", err);
|
||||
goto err_ret;
|
||||
}
|
||||
}
|
||||
done_err_ret:
|
||||
ntfs_log_debug("At done_err_ret (follows done_ret).\n");
|
||||
free(buf);
|
||||
/* Done! */
|
||||
if (!err)
|
||||
return rl;
|
||||
ntfs_log_trace("Failed to allocate clusters. Returning with error code "
|
||||
"%i.\n", err);
|
||||
errno = err;
|
||||
return NULL;
|
||||
wb_err_ret:
|
||||
ntfs_log_trace("At wb_err_ret.\n");
|
||||
if (need_writeback) {
|
||||
s64 bw;
|
||||
ntfs_log_trace("Writing back.\n");
|
||||
need_writeback = 0;
|
||||
bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos, br, buf);
|
||||
if (bw != br) {
|
||||
if (bw < 0)
|
||||
err = errno;
|
||||
else
|
||||
err = EIO;
|
||||
ntfs_log_trace("Bitmap writeback failed in error code path "
|
||||
"with error code %i.\n", err);
|
||||
}
|
||||
}
|
||||
err_ret:
|
||||
ntfs_log_trace("At err_ret.\n");
|
||||
if (rl) {
|
||||
if (err == ENOSPC) {
|
||||
ntfs_log_trace("err = ENOSPC, first free lcn = 0x%llx, could "
|
||||
"allocate up to = 0x%llx clusters.\n",
|
||||
(long long)rl[0].lcn,
|
||||
(long long)count - clusters);
|
||||
}
|
||||
/* Add runlist terminator element. */
|
||||
rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length;
|
||||
rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
|
||||
rl[rlpos].length = 0;
|
||||
/* Deallocate all allocated clusters. */
|
||||
ntfs_log_trace("Deallocating allocated clusters.\n");
|
||||
ntfs_cluster_free_from_rl(vol, rl);
|
||||
/* Free the runlist. */
|
||||
free(rl);
|
||||
rl = NULL;
|
||||
} else {
|
||||
if (err == ENOSPC) {
|
||||
ntfs_log_trace("No space left at all, err = ENOSPC, first "
|
||||
"free lcn = 0x%llx.\n",
|
||||
(long long)vol->data1_zone_pos);
|
||||
}
|
||||
}
|
||||
ntfs_log_trace("rl = NULL, going to done_err_ret.\n");
|
||||
goto done_err_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_cluster_free_from_rl - free clusters from runlist
|
||||
* @vol: mounted ntfs volume on which to free the clusters
|
||||
* @rl: runlist from which deallocate clusters
|
||||
*
|
||||
* On success return 0 and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
|
||||
{
|
||||
ntfs_log_trace("Entering.\n");
|
||||
|
||||
for (; rl->length; rl++) {
|
||||
|
||||
ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
|
||||
(long long)rl->lcn, (long long)rl->length);
|
||||
|
||||
if (rl->lcn >= 0 && ntfs_bitmap_clear_run(vol->lcnbmp_na,
|
||||
rl->lcn, rl->length)) {
|
||||
int eo = errno;
|
||||
ntfs_log_trace("Eeek! Deallocation of clusters failed.\n");
|
||||
errno = eo;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_cluster_free - free clusters on an ntfs volume
|
||||
* @vol: mounted ntfs volume on which to free the clusters
|
||||
* @na: attribute whose runlist describes the clusters to free
|
||||
* @start_vcn: vcn in @rl at which to start freeing clusters
|
||||
* @count: number of clusters to free or -1 for all clusters
|
||||
*
|
||||
* Free @count clusters starting at the cluster @start_vcn in the runlist
|
||||
* described by the attribute @na from the mounted ntfs volume @vol.
|
||||
*
|
||||
* If @count is -1, all clusters from @start_vcn to the end of the runlist
|
||||
* are deallocated.
|
||||
*
|
||||
* On success return the number of deallocated clusters (not counting sparse
|
||||
* clusters) and on error return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
|
||||
{
|
||||
runlist *rl;
|
||||
s64 nr_freed, delta, to_free;
|
||||
|
||||
if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
|
||||
(count < 0 && count != -1)) {
|
||||
ntfs_log_trace("Invalid arguments!\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
|
||||
"vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no,
|
||||
na->type, (long long)count, (long long)start_vcn);
|
||||
|
||||
rl = ntfs_attr_find_vcn(na, start_vcn);
|
||||
if (!rl) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Find the starting cluster inside the run that needs freeing. */
|
||||
delta = start_vcn - rl->vcn;
|
||||
|
||||
/* The number of clusters in this run that need freeing. */
|
||||
to_free = rl->length - delta;
|
||||
if (count >= 0 && to_free > count)
|
||||
to_free = count;
|
||||
|
||||
if (rl->lcn != LCN_HOLE) {
|
||||
/* Do the actual freeing of the clusters in this run. */
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
|
||||
to_free))
|
||||
return -1;
|
||||
/* We have freed @to_free real clusters. */
|
||||
nr_freed = to_free;
|
||||
} else {
|
||||
/* No real clusters were freed. */
|
||||
nr_freed = 0;
|
||||
}
|
||||
|
||||
/* Go to the next run and adjust the number of clusters left to free. */
|
||||
++rl;
|
||||
if (count >= 0)
|
||||
count -= to_free;
|
||||
|
||||
/*
|
||||
* Loop over the remaining runs, using @count as a capping value, and
|
||||
* free them.
|
||||
*/
|
||||
for (; rl->length && count != 0; ++rl) {
|
||||
// FIXME: Need to try ntfs_attr_map_runlist() for attribute
|
||||
// list support! (AIA)
|
||||
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_trace("Eeek! invalid lcn (= %lli). Should attempt "
|
||||
"to map runlist! Leaving inconsistent "
|
||||
"metadata!\n", (long long)rl->lcn);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The number of clusters in this run that need freeing. */
|
||||
to_free = rl->length;
|
||||
if (count >= 0 && to_free > count)
|
||||
to_free = count;
|
||||
|
||||
if (rl->lcn != LCN_HOLE) {
|
||||
/* Do the actual freeing of the clusters in the run. */
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
|
||||
to_free)) {
|
||||
int eo = errno;
|
||||
|
||||
// FIXME: Eeek! We need rollback! (AIA)
|
||||
ntfs_log_trace("Eeek! bitmap clear run failed. "
|
||||
"Leaving inconsistent metadata!\n");
|
||||
errno = eo;
|
||||
return -1;
|
||||
}
|
||||
/* We have freed @to_free real clusters. */
|
||||
nr_freed += to_free;
|
||||
}
|
||||
|
||||
if (count >= 0)
|
||||
count -= to_free;
|
||||
}
|
||||
|
||||
if (count != -1 && count != 0) {
|
||||
// FIXME: Eeek! BUG()
|
||||
ntfs_log_trace("Eeek! count still not zero (= %lli). Leaving "
|
||||
"inconsistent metadata!\n", (long long)count);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Done. Return the number of actual clusters that were freed. */
|
||||
return nr_freed;
|
||||
}
|
762
libntfs-3g/logfile.c
Normal file
762
libntfs-3g/logfile.c
Normal file
@ -0,0 +1,762 @@
|
||||
/**
|
||||
* logfile.c - NTFS journal handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2005-2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "attrib.h"
|
||||
#include "debug.h"
|
||||
#include "logfile.h"
|
||||
#include "volume.h"
|
||||
#include "mst.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
/**
|
||||
* ntfs_check_restart_page_header - check the page header for consistency
|
||||
* @rp: restart page header to check
|
||||
* @pos: position in logfile at which the restart page header resides
|
||||
*
|
||||
* Check the restart page header @rp for consistency and return TRUE if it is
|
||||
* consistent and FALSE otherwise.
|
||||
*
|
||||
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
||||
* require the full restart page.
|
||||
*/
|
||||
static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
||||
{
|
||||
u32 logfile_system_page_size, logfile_log_page_size;
|
||||
u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
|
||||
BOOL have_usa = TRUE;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
/*
|
||||
* If the system or log page sizes are smaller than the ntfs block size
|
||||
* or either is not a power of 2 we cannot handle this log file.
|
||||
*/
|
||||
logfile_system_page_size = le32_to_cpu(rp->system_page_size);
|
||||
logfile_log_page_size = le32_to_cpu(rp->log_page_size);
|
||||
if (logfile_system_page_size < NTFS_BLOCK_SIZE ||
|
||||
logfile_log_page_size < NTFS_BLOCK_SIZE ||
|
||||
logfile_system_page_size &
|
||||
(logfile_system_page_size - 1) ||
|
||||
logfile_log_page_size & (logfile_log_page_size - 1)) {
|
||||
ntfs_log_error("$LogFile uses unsupported page size.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* We must be either at !pos (1st restart page) or at pos = system page
|
||||
* size (2nd restart page).
|
||||
*/
|
||||
if (pos && pos != logfile_system_page_size) {
|
||||
ntfs_log_error("Found restart area in incorrect "
|
||||
"position in $LogFile.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* 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. (This driver supports version "
|
||||
"1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver),
|
||||
(int)sle16_to_cpu(rp->minor_ver));
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* If chkdsk has been run the restart page may not be protected by an
|
||||
* update sequence array.
|
||||
*/
|
||||
if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
|
||||
have_usa = FALSE;
|
||||
goto skip_usa_checks;
|
||||
}
|
||||
/* Verify the size of the update sequence array. */
|
||||
usa_count = 1 + (logfile_system_page_size >> NTFS_BLOCK_SIZE_BITS);
|
||||
if (usa_count != le16_to_cpu(rp->usa_count)) {
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent update sequence array count.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* Verify the position of the update sequence array. */
|
||||
usa_ofs = le16_to_cpu(rp->usa_ofs);
|
||||
usa_end = usa_ofs + usa_count * sizeof(u16);
|
||||
if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
|
||||
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent update sequence array offset.\n");
|
||||
return FALSE;
|
||||
}
|
||||
skip_usa_checks:
|
||||
/*
|
||||
* Verify the position of the restart area. It must be:
|
||||
* - aligned to 8-byte boundary,
|
||||
* - after the update sequence array, and
|
||||
* - within the system page size.
|
||||
*/
|
||||
ra_ofs = le16_to_cpu(rp->restart_area_offset);
|
||||
if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
|
||||
ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
|
||||
ra_ofs > logfile_system_page_size) {
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent restart area offset.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
|
||||
* set.
|
||||
*/
|
||||
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
|
||||
ntfs_log_error("$LogFile restart page is not modified "
|
||||
"by chkdsk but a chkdsk LSN is specified.\n");
|
||||
return FALSE;
|
||||
}
|
||||
ntfs_log_trace("Done.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_check_restart_area - check the restart area for consistency
|
||||
* @rp: restart page whose restart area to check
|
||||
*
|
||||
* Check the restart area of the restart page @rp for consistency and return
|
||||
* TRUE if it is consistent and FALSE otherwise.
|
||||
*
|
||||
* This function assumes that the restart page header has already been
|
||||
* consistency checked.
|
||||
*
|
||||
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
||||
* require the full restart page.
|
||||
*/
|
||||
static BOOL ntfs_check_restart_area(RESTART_PAGE_HEADER *rp)
|
||||
{
|
||||
u64 file_size;
|
||||
RESTART_AREA *ra;
|
||||
u16 ra_ofs, ra_len, ca_ofs;
|
||||
u8 fs_bits;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
ra_ofs = le16_to_cpu(rp->restart_area_offset);
|
||||
ra = (RESTART_AREA*)((u8*)rp + ra_ofs);
|
||||
/*
|
||||
* Everything before ra->file_size must be before the first word
|
||||
* protected by an update sequence number. This ensures that it is
|
||||
* safe to access ra->client_array_offset.
|
||||
*/
|
||||
if (ra_ofs + offsetof(RESTART_AREA, file_size) >
|
||||
NTFS_BLOCK_SIZE - sizeof(u16)) {
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent file offset.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* Now that we can access ra->client_array_offset, make sure everything
|
||||
* up to the log client array is before the first word protected by an
|
||||
* update sequence number. This ensures we can access all of the
|
||||
* restart area elements safely. Also, the client array offset must be
|
||||
* aligned to an 8-byte boundary.
|
||||
*/
|
||||
ca_ofs = le16_to_cpu(ra->client_array_offset);
|
||||
if (((ca_ofs + 7) & ~7) != ca_ofs ||
|
||||
ra_ofs + ca_ofs > (u16)(NTFS_BLOCK_SIZE -
|
||||
sizeof(u16))) {
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent client array offset.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* The restart area must end within the system page size both when
|
||||
* calculated manually and as specified by ra->restart_area_length.
|
||||
* Also, the calculated length must not exceed the specified length.
|
||||
*/
|
||||
ra_len = ca_ofs + le16_to_cpu(ra->log_clients) *
|
||||
sizeof(LOG_CLIENT_RECORD);
|
||||
if ((u32)(ra_ofs + ra_len) > le32_to_cpu(rp->system_page_size) ||
|
||||
(u32)(ra_ofs + le16_to_cpu(ra->restart_area_length)) >
|
||||
le32_to_cpu(rp->system_page_size) ||
|
||||
ra_len > le16_to_cpu(ra->restart_area_length)) {
|
||||
ntfs_log_error("$LogFile restart area is out of bounds "
|
||||
"of the system page size specified by the "
|
||||
"restart page header and/or the specified "
|
||||
"restart area length is inconsistent.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* The ra->client_free_list and ra->client_in_use_list must be either
|
||||
* LOGFILE_NO_CLIENT or less than ra->log_clients or they are
|
||||
* overflowing the client array.
|
||||
*/
|
||||
if ((ra->client_free_list != LOGFILE_NO_CLIENT &&
|
||||
le16_to_cpu(ra->client_free_list) >=
|
||||
le16_to_cpu(ra->log_clients)) ||
|
||||
(ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||
le16_to_cpu(ra->client_in_use_list) >=
|
||||
le16_to_cpu(ra->log_clients))) {
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"overflowing client free and/or in use lists.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* Check ra->seq_number_bits against ra->file_size for consistency.
|
||||
* We cannot just use ffs() because the file size is not a power of 2.
|
||||
*/
|
||||
file_size = (u64)sle64_to_cpu(ra->file_size);
|
||||
fs_bits = 0;
|
||||
while (file_size) {
|
||||
file_size >>= 1;
|
||||
fs_bits++;
|
||||
}
|
||||
if (le32_to_cpu(ra->seq_number_bits) != (u32)(67 - fs_bits)) {
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent sequence number bits.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* The log record header length must be a multiple of 8. */
|
||||
if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
|
||||
le16_to_cpu(ra->log_record_header_length)) {
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent log record header length.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* Ditto for the log page data offset. */
|
||||
if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
|
||||
le16_to_cpu(ra->log_page_data_offset)) {
|
||||
ntfs_log_error("$LogFile restart area specifies "
|
||||
"inconsistent log page data offset.\n");
|
||||
return FALSE;
|
||||
}
|
||||
ntfs_log_trace("Done.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_check_log_client_array - check the log client array for consistency
|
||||
* @rp: restart page whose log client array to check
|
||||
*
|
||||
* Check the log client array of the restart page @rp for consistency and
|
||||
* return TRUE if it is consistent and FALSE otherwise.
|
||||
*
|
||||
* This function assumes that the restart page header and the restart area have
|
||||
* already been consistency checked.
|
||||
*
|
||||
* Unlike ntfs_check_restart_page_header() and ntfs_check_restart_area(), this
|
||||
* function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
|
||||
* restart page and the page must be multi sector transfer deprotected.
|
||||
*/
|
||||
static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
|
||||
{
|
||||
RESTART_AREA *ra;
|
||||
LOG_CLIENT_RECORD *ca, *cr;
|
||||
u16 nr_clients, idx;
|
||||
BOOL in_free_list, idx_is_first;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
||||
ca = (LOG_CLIENT_RECORD*)((u8*)ra +
|
||||
le16_to_cpu(ra->client_array_offset));
|
||||
/*
|
||||
* Check the ra->client_free_list first and then check the
|
||||
* ra->client_in_use_list. Check each of the log client records in
|
||||
* each of the lists and check that the array does not overflow the
|
||||
* ra->log_clients value. Also keep track of the number of records
|
||||
* visited as there cannot be more than ra->log_clients records and
|
||||
* that way we detect eventual loops in within a list.
|
||||
*/
|
||||
nr_clients = le16_to_cpu(ra->log_clients);
|
||||
idx = le16_to_cpu(ra->client_free_list);
|
||||
in_free_list = TRUE;
|
||||
check_list:
|
||||
for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
|
||||
idx = le16_to_cpu(cr->next_client)) {
|
||||
if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
|
||||
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. */
|
||||
if (idx_is_first) {
|
||||
if (cr->prev_client != LOGFILE_NO_CLIENT)
|
||||
goto err_out;
|
||||
idx_is_first = FALSE;
|
||||
}
|
||||
}
|
||||
/* Switch to and check the in use list if we just did the free list. */
|
||||
if (in_free_list) {
|
||||
in_free_list = FALSE;
|
||||
idx = le16_to_cpu(ra->client_in_use_list);
|
||||
goto check_list;
|
||||
}
|
||||
ntfs_log_trace("Done.\n");
|
||||
return TRUE;
|
||||
err_out:
|
||||
ntfs_log_error("$LogFile log client array is corrupt.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_check_and_load_restart_page - check the restart page for consistency
|
||||
* @log_na: opened ntfs attribute for journal $LogFile
|
||||
* @rp: restart page to check
|
||||
* @pos: position in @log_na at which the restart page resides
|
||||
* @wrp: [OUT] copy of the multi sector transfer deprotected restart page
|
||||
* @lsn: [OUT] set to the current logfile lsn on success
|
||||
*
|
||||
* Check the restart page @rp for consistency and return 0 if it is consistent
|
||||
* and errno otherwise. The restart page may have been modified by chkdsk in
|
||||
* which case its magic is CHKD instead of RSTR.
|
||||
*
|
||||
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
|
||||
* require the full restart page.
|
||||
*
|
||||
* If @wrp is not NULL, on success, *@wrp will point to a buffer containing a
|
||||
* copy of the complete multi sector transfer deprotected page. On failure,
|
||||
* *@wrp is undefined.
|
||||
*
|
||||
* Similarly, if @lsn is not NULL, on success *@lsn will be set to the current
|
||||
* logfile lsn according to this restart page. On failure, *@lsn is undefined.
|
||||
*
|
||||
* The following error codes are defined:
|
||||
* EINVAL - The restart page is inconsistent.
|
||||
* ENOMEM - Not enough memory to load the restart page.
|
||||
* EIO - Failed to reading from $LogFile.
|
||||
*/
|
||||
static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
|
||||
RESTART_PAGE_HEADER *rp, s64 pos, RESTART_PAGE_HEADER **wrp,
|
||||
LSN *lsn)
|
||||
{
|
||||
RESTART_AREA *ra;
|
||||
RESTART_PAGE_HEADER *trp;
|
||||
int err;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
/* Check the restart page header for consistency. */
|
||||
if (!ntfs_check_restart_page_header(rp, pos)) {
|
||||
/* Error output already done inside the function. */
|
||||
return EINVAL;
|
||||
}
|
||||
/* Check the restart area for consistency. */
|
||||
if (!ntfs_check_restart_area(rp)) {
|
||||
/* Error output already done inside the function. */
|
||||
return EINVAL;
|
||||
}
|
||||
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
||||
/*
|
||||
* Allocate a buffer to store the whole restart page so we can multi
|
||||
* sector transfer deprotect it.
|
||||
*/
|
||||
trp = ntfs_malloc(le32_to_cpu(rp->system_page_size));
|
||||
if (!trp)
|
||||
return errno;
|
||||
/*
|
||||
* Read the whole of the restart page into the buffer. If it fits
|
||||
* completely inside @rp, just copy it from there. Otherwise read it
|
||||
* from disk.
|
||||
*/
|
||||
if (le32_to_cpu(rp->system_page_size) <= NTFS_BLOCK_SIZE)
|
||||
memcpy(trp, rp, le32_to_cpu(rp->system_page_size));
|
||||
else if (ntfs_attr_pread(log_na, pos,
|
||||
le32_to_cpu(rp->system_page_size), trp) !=
|
||||
le32_to_cpu(rp->system_page_size)) {
|
||||
err = errno;
|
||||
ntfs_log_error("Failed to read whole restart page into the "
|
||||
"buffer.\n");
|
||||
if (err != ENOMEM)
|
||||
err = EIO;
|
||||
goto err_out;
|
||||
}
|
||||
/*
|
||||
* Perform the multi sector transfer deprotection on the buffer if the
|
||||
* restart page is protected.
|
||||
*/
|
||||
if ((!ntfs_is_chkd_record(trp->magic) || le16_to_cpu(trp->usa_count))
|
||||
&& ntfs_mst_post_read_fixup((NTFS_RECORD*)trp,
|
||||
le32_to_cpu(rp->system_page_size))) {
|
||||
/*
|
||||
* A multi sector tranfer error was detected. We only need to
|
||||
* abort if the restart page contents exceed the multi sector
|
||||
* transfer fixup of the first sector.
|
||||
*/
|
||||
if (le16_to_cpu(rp->restart_area_offset) +
|
||||
le16_to_cpu(ra->restart_area_length) >
|
||||
NTFS_BLOCK_SIZE - (int)sizeof(u16)) {
|
||||
ntfs_log_error("Multi sector transfer error "
|
||||
"detected in $LogFile restart page.\n");
|
||||
err = EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If the restart page is modified by chkdsk or there are no active
|
||||
* logfile clients, the logfile is consistent. Otherwise, need to
|
||||
* check the log client records for consistency, too.
|
||||
*/
|
||||
err = 0;
|
||||
if (ntfs_is_rstr_record(rp->magic) &&
|
||||
ra->client_in_use_list != LOGFILE_NO_CLIENT) {
|
||||
if (!ntfs_check_log_client_array(trp)) {
|
||||
err = EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
if (lsn) {
|
||||
if (ntfs_is_rstr_record(rp->magic))
|
||||
*lsn = sle64_to_cpu(ra->current_lsn);
|
||||
else /* if (ntfs_is_chkd_record(rp->magic)) */
|
||||
*lsn = sle64_to_cpu(rp->chkdsk_lsn);
|
||||
}
|
||||
ntfs_log_trace("Done.\n");
|
||||
if (wrp)
|
||||
*wrp = trp;
|
||||
else {
|
||||
err_out:
|
||||
free(trp);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_check_logfile - check in the journal if the volume is consistent
|
||||
* @log_na: ntfs attribute of loaded journal $LogFile to check
|
||||
* @rp: [OUT] on success this is a copy of the current restart page
|
||||
*
|
||||
* Check the $LogFile journal for consistency and return TRUE if it is
|
||||
* consistent and FALSE if not. On success, the current restart page is
|
||||
* returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it.
|
||||
*
|
||||
* At present we only check the two restart pages and ignore the log record
|
||||
* pages.
|
||||
*
|
||||
* Note that the MstProtected flag is not set on the $LogFile inode and hence
|
||||
* when reading pages they are not deprotected. This is because we do not know
|
||||
* if the $LogFile was created on a system with a different page size to ours
|
||||
* yet and mst deprotection would fail if our page size is smaller.
|
||||
*/
|
||||
BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
|
||||
{
|
||||
s64 size, pos;
|
||||
LSN rstr1_lsn, rstr2_lsn;
|
||||
ntfs_volume *vol = log_na->ni->vol;
|
||||
u8 *kaddr = NULL;
|
||||
RESTART_PAGE_HEADER *rstr1_ph = NULL;
|
||||
RESTART_PAGE_HEADER *rstr2_ph = NULL;
|
||||
int log_page_size, log_page_mask, err;
|
||||
BOOL logfile_is_empty = TRUE;
|
||||
u8 log_page_bits;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
/* An empty $LogFile must have been clean before it got emptied. */
|
||||
if (NVolLogFileEmpty(vol))
|
||||
goto is_empty;
|
||||
size = log_na->data_size;
|
||||
/* Make sure the file doesn't exceed the maximum allowed size. */
|
||||
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.
|
||||
*/
|
||||
log_page_bits = ffs(log_page_size) - 1;
|
||||
size &= ~(log_page_size - 1);
|
||||
|
||||
/*
|
||||
* Ensure the log file is big enough to store at least the two restart
|
||||
* pages and the minimum number of log record pages.
|
||||
*/
|
||||
if (size < log_page_size * 2 || (size - log_page_size * 2) >>
|
||||
log_page_bits < MinLogRecordPages) {
|
||||
ntfs_log_error("$LogFile is too small.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* Allocate memory for restart page. */
|
||||
kaddr = ntfs_malloc(NTFS_BLOCK_SIZE);
|
||||
if (!kaddr)
|
||||
return FALSE;
|
||||
/*
|
||||
* Read through the file looking for a restart page. Since the restart
|
||||
* page header is at the beginning of a page we only need to search at
|
||||
* what could be the beginning of a page (for each page size) rather
|
||||
* than scanning the whole file byte by byte. If all potential places
|
||||
* contain empty and uninitialized records, the log file can be assumed
|
||||
* to be empty.
|
||||
*/
|
||||
for (pos = 0; pos < size; pos <<= 1) {
|
||||
/*
|
||||
* Read first NTFS_BLOCK_SIZE bytes of potential restart page.
|
||||
*/
|
||||
if (ntfs_attr_pread(log_na, pos, NTFS_BLOCK_SIZE, kaddr) !=
|
||||
NTFS_BLOCK_SIZE) {
|
||||
ntfs_log_error("Failed to read first NTFS_BLOCK_SIZE "
|
||||
"bytes of potential restart page.\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* A non-empty block means the logfile is not empty while an
|
||||
* empty block after a non-empty block has been encountered
|
||||
* means we are done.
|
||||
*/
|
||||
if (!ntfs_is_empty_recordp((le32*)kaddr))
|
||||
logfile_is_empty = FALSE;
|
||||
else if (!logfile_is_empty)
|
||||
break;
|
||||
/*
|
||||
* A log record page means there cannot be a restart page after
|
||||
* this so no need to continue searching.
|
||||
*/
|
||||
if (ntfs_is_rcrd_recordp((le32*)kaddr))
|
||||
break;
|
||||
/* If not a (modified by chkdsk) restart page, continue. */
|
||||
if (!ntfs_is_rstr_recordp((le32*)kaddr) &&
|
||||
!ntfs_is_chkd_recordp((le32*)kaddr)) {
|
||||
if (!pos)
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Check the (modified by chkdsk) restart page for consistency
|
||||
* and get a copy of the complete multi sector transfer
|
||||
* deprotected restart page.
|
||||
*/
|
||||
err = ntfs_check_and_load_restart_page(log_na,
|
||||
(RESTART_PAGE_HEADER*)kaddr, pos,
|
||||
!rstr1_ph ? &rstr1_ph : &rstr2_ph,
|
||||
!rstr1_ph ? &rstr1_lsn : &rstr2_lsn);
|
||||
if (!err) {
|
||||
/*
|
||||
* If we have now found the first (modified by chkdsk)
|
||||
* restart page, continue looking for the second one.
|
||||
*/
|
||||
if (!pos) {
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* We have now found the second (modified by chkdsk)
|
||||
* restart page, so we can stop looking.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Error output already done inside the function. Note, we do
|
||||
* not abort if the restart page was invalid as we might still
|
||||
* find a valid one further in the file.
|
||||
*/
|
||||
if (err != EINVAL)
|
||||
goto err_out;
|
||||
/* Continue looking. */
|
||||
if (!pos)
|
||||
pos = NTFS_BLOCK_SIZE >> 1;
|
||||
}
|
||||
if (kaddr) {
|
||||
free(kaddr);
|
||||
kaddr = NULL;
|
||||
}
|
||||
if (logfile_is_empty) {
|
||||
NVolSetLogFileEmpty(vol);
|
||||
is_empty:
|
||||
ntfs_log_trace("Done. ($LogFile is empty.)\n");
|
||||
return TRUE;
|
||||
}
|
||||
if (!rstr1_ph) {
|
||||
if (rstr2_ph)
|
||||
ntfs_log_error("BUG: rstr2_ph isn't NULL!\n");
|
||||
ntfs_log_error("Did not find any restart pages in "
|
||||
"$LogFile and it was not empty.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* If both restart pages were found, use the more recent one. */
|
||||
if (rstr2_ph) {
|
||||
/*
|
||||
* If the second restart area is more recent, switch to it.
|
||||
* Otherwise just throw it away.
|
||||
*/
|
||||
if (rstr2_lsn > rstr1_lsn) {
|
||||
ntfs_log_debug("Using second restart page as it is more "
|
||||
"recent.\n");
|
||||
free(rstr1_ph);
|
||||
rstr1_ph = rstr2_ph;
|
||||
/* rstr1_lsn = rstr2_lsn; */
|
||||
} else {
|
||||
ntfs_log_debug("Using first restart page as it is more "
|
||||
"recent.\n");
|
||||
free(rstr2_ph);
|
||||
}
|
||||
rstr2_ph = NULL;
|
||||
}
|
||||
/* All consistency checks passed. */
|
||||
if (rp)
|
||||
*rp = rstr1_ph;
|
||||
else
|
||||
free(rstr1_ph);
|
||||
ntfs_log_trace("Done.\n");
|
||||
return TRUE;
|
||||
err_out:
|
||||
free(kaddr);
|
||||
free(rstr1_ph);
|
||||
free(rstr2_ph);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_is_logfile_clean - check in the journal if the volume is clean
|
||||
* @log_na: ntfs attribute of loaded journal $LogFile to check
|
||||
* @rp: copy of the current restart page
|
||||
*
|
||||
* Analyze the $LogFile journal and return TRUE if it indicates the volume was
|
||||
* shutdown cleanly and FALSE if not.
|
||||
*
|
||||
* At present we only look at the two restart pages and ignore the log record
|
||||
* pages. This is a little bit crude in that there will be a very small number
|
||||
* of cases where we think that a volume is dirty when in fact it is clean.
|
||||
* This should only affect volumes that have not been shutdown cleanly but did
|
||||
* not have any pending, non-check-pointed i/o, i.e. they were completely idle
|
||||
* at least for the five seconds preceding the unclean shutdown.
|
||||
*
|
||||
* This function assumes that the $LogFile journal has already been consistency
|
||||
* checked by a call to ntfs_check_logfile() and in particular if the $LogFile
|
||||
* is empty this function requires that NVolLogFileEmpty() is true otherwise an
|
||||
* empty volume will be reported as dirty.
|
||||
*/
|
||||
BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp)
|
||||
{
|
||||
RESTART_AREA *ra;
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
/* An empty $LogFile must have been clean before it got emptied. */
|
||||
if (NVolLogFileEmpty(log_na->ni->vol)) {
|
||||
ntfs_log_trace("Done. ($LogFile is empty.)\n");
|
||||
return TRUE;
|
||||
}
|
||||
if (!rp) {
|
||||
ntfs_log_error("Restart page header is NULL.\n");
|
||||
return FALSE;
|
||||
}
|
||||
if (!ntfs_is_rstr_record(rp->magic) &&
|
||||
!ntfs_is_chkd_record(rp->magic)) {
|
||||
ntfs_log_error("Restart page buffer is invalid. This is "
|
||||
"probably a bug in that the $LogFile should "
|
||||
"have been consistency checked before calling "
|
||||
"this function.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
|
||||
/*
|
||||
* If the $LogFile has active clients, i.e. it is open, and we do not
|
||||
* have the RESTART_VOLUME_IS_CLEAN bit set in the restart area flags,
|
||||
* we assume there was an unclean shutdown.
|
||||
*/
|
||||
if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
|
||||
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
|
||||
ntfs_log_debug("Done. $LogFile indicates a dirty shutdown.\n");
|
||||
return FALSE;
|
||||
}
|
||||
/* $LogFile indicates a clean shutdown. */
|
||||
ntfs_log_trace("Done. $LogFile indicates a clean shutdown.\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_empty_logfile - empty the contents of the $LogFile journal
|
||||
* @na: ntfs attribute of journal $LogFile to empty
|
||||
*
|
||||
* Empty the contents of the $LogFile journal @na and return 0 on success and
|
||||
* -1 on error.
|
||||
*
|
||||
* This function assumes that the $LogFile journal has already been consistency
|
||||
* checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
|
||||
* has been used to ensure that the $LogFile is clean.
|
||||
*/
|
||||
int ntfs_empty_logfile(ntfs_attr *na)
|
||||
{
|
||||
s64 len, pos, count;
|
||||
char buf[NTFS_BUF_SIZE];
|
||||
|
||||
ntfs_log_trace("Entering.\n");
|
||||
if (NVolLogFileEmpty(na->ni->vol))
|
||||
return 0;
|
||||
|
||||
/* The $DATA attribute of the $LogFile has to be non-resident. */
|
||||
if (!NAttrNonResident(na)) {
|
||||
errno = EIO;
|
||||
ntfs_log_perror("$LogFile $DATA attribute is resident!?!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get length of $LogFile contents. */
|
||||
len = na->data_size;
|
||||
if (!len) {
|
||||
ntfs_log_debug("$LogFile has zero length, no disk write "
|
||||
"needed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read $LogFile until its end. We do this as a check for correct
|
||||
length thus making sure we are decompressing the mapping pairs
|
||||
array correctly and hence writing below is safe as well. */
|
||||
pos = 0;
|
||||
while ((count = ntfs_attr_pread(na, pos, NTFS_BUF_SIZE, buf)) > 0)
|
||||
pos += count;
|
||||
|
||||
if (count == -1 || pos != len) {
|
||||
ntfs_log_error("Amount of $LogFile data read does not "
|
||||
"correspond to expected length!\n");
|
||||
if (count != -1)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill the buffer with 0xff's. */
|
||||
memset(buf, -1, NTFS_BUF_SIZE);
|
||||
|
||||
/* Set the $DATA attribute. */
|
||||
pos = 0;
|
||||
while ((count = len - pos) > 0) {
|
||||
if (count > NTFS_BUF_SIZE)
|
||||
count = NTFS_BUF_SIZE;
|
||||
|
||||
if ((count = ntfs_attr_pwrite(na, pos, count, buf)) <= 0) {
|
||||
ntfs_log_perror("Failed to set the $LogFile attribute "
|
||||
"value.\n");
|
||||
if (count != -1)
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
pos += count;
|
||||
}
|
||||
|
||||
/* Set the flag so we do not have to do it again on remount. */
|
||||
NVolSetLogFileEmpty(na->ni->vol);
|
||||
return 0;
|
||||
}
|
634
libntfs-3g/logging.c
Normal file
634
libntfs-3g/logging.c
Normal file
@ -0,0 +1,634 @@
|
||||
/**
|
||||
* logging.c - Centralised logging. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2005 Richard Russon
|
||||
* Copyright (c) 2005-2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
#ifndef PATH_SEP
|
||||
#define PATH_SEP '/'
|
||||
#endif
|
||||
|
||||
/* Colour prefixes and a suffix */
|
||||
static const char *col_green = "\e[32m";
|
||||
static const char *col_cyan = "\e[36m";
|
||||
static const char *col_yellow = "\e[01;33m";
|
||||
static const char *col_red = "\e[01;31m";
|
||||
static const char *col_redinv = "\e[01;07;31m";
|
||||
static const char *col_end = "\e[0m";
|
||||
|
||||
/**
|
||||
* struct ntfs_logging - Control info for the logging system
|
||||
* @levels: Bitfield of logging levels
|
||||
* @flags: Flags which affect the output style
|
||||
* @handler: Function to perform the actual logging
|
||||
*/
|
||||
struct ntfs_logging {
|
||||
u32 levels;
|
||||
u32 flags;
|
||||
ntfs_log_handler *handler;
|
||||
};
|
||||
|
||||
/**
|
||||
* ntfs_log
|
||||
* This struct controls all the logging within the library and tools.
|
||||
*/
|
||||
static struct ntfs_logging ntfs_log = {
|
||||
#ifdef DEBUG
|
||||
NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE |
|
||||
#endif
|
||||
NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_WARNING |
|
||||
NTFS_LOG_LEVEL_ERROR | NTFS_LOG_LEVEL_PERROR | NTFS_LOG_LEVEL_CRITICAL |
|
||||
NTFS_LOG_LEVEL_PROGRESS,
|
||||
NTFS_LOG_FLAG_ONLYNAME,
|
||||
#ifdef DEBUG
|
||||
ntfs_log_handler_outerr
|
||||
#else
|
||||
ntfs_log_handler_null
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_get_levels - Get a list of the current logging levels
|
||||
*
|
||||
* Find out which logging levels are enabled.
|
||||
*
|
||||
* Returns: Log levels in a 32-bit field
|
||||
*/
|
||||
u32 ntfs_log_get_levels(void)
|
||||
{
|
||||
return ntfs_log.levels;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_set_levels - Enable extra logging levels
|
||||
* @levels: 32-bit field of log levels to set
|
||||
*
|
||||
* Enable one or more logging levels.
|
||||
* The logging levels are named: NTFS_LOG_LEVEL_*.
|
||||
*
|
||||
* Returns: Log levels that were enabled before the call
|
||||
*/
|
||||
u32 ntfs_log_set_levels(u32 levels)
|
||||
{
|
||||
u32 old;
|
||||
old = ntfs_log.levels;
|
||||
ntfs_log.levels |= levels;
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_clear_levels - Disable some logging levels
|
||||
* @levels: 32-bit field of log levels to clear
|
||||
*
|
||||
* Disable one or more logging levels.
|
||||
* The logging levels are named: NTFS_LOG_LEVEL_*.
|
||||
*
|
||||
* Returns: Log levels that were enabled before the call
|
||||
*/
|
||||
u32 ntfs_log_clear_levels(u32 levels)
|
||||
{
|
||||
u32 old;
|
||||
old = ntfs_log.levels;
|
||||
ntfs_log.levels &= (~levels);
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_get_flags - Get a list of logging style flags
|
||||
*
|
||||
* Find out which logging flags are enabled.
|
||||
*
|
||||
* Returns: Logging flags in a 32-bit field
|
||||
*/
|
||||
u32 ntfs_log_get_flags(void)
|
||||
{
|
||||
return ntfs_log.flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_set_flags - Enable extra logging style flags
|
||||
* @flags: 32-bit field of logging flags to set
|
||||
*
|
||||
* Enable one or more logging flags.
|
||||
* The log flags are named: NTFS_LOG_LEVEL_*.
|
||||
*
|
||||
* Returns: Logging flags that were enabled before the call
|
||||
*/
|
||||
u32 ntfs_log_set_flags(u32 flags)
|
||||
{
|
||||
u32 old;
|
||||
old = ntfs_log.flags;
|
||||
ntfs_log.flags |= flags;
|
||||
return old;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_clear_flags - Disable some logging styles
|
||||
* @flags: 32-bit field of logging flags to clear
|
||||
*
|
||||
* Disable one or more logging flags.
|
||||
* The log flags are named: NTFS_LOG_LEVEL_*.
|
||||
*
|
||||
* Returns: Logging flags that were enabled before the call
|
||||
*/
|
||||
u32 ntfs_log_clear_flags(u32 flags)
|
||||
{
|
||||
u32 old;
|
||||
old = ntfs_log.flags;
|
||||
ntfs_log.flags &= (~flags);
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_get_stream - Default output streams for logging levels
|
||||
* @level: Log level
|
||||
*
|
||||
* By default, urgent messages are sent to "stderr".
|
||||
* Other messages are sent to "stdout".
|
||||
*
|
||||
* Returns: "string" Prefix to be used
|
||||
*/
|
||||
static FILE * ntfs_log_get_stream(u32 level)
|
||||
{
|
||||
FILE *stream;
|
||||
|
||||
switch (level) {
|
||||
case NTFS_LOG_LEVEL_INFO:
|
||||
case NTFS_LOG_LEVEL_QUIET:
|
||||
case NTFS_LOG_LEVEL_PROGRESS:
|
||||
case NTFS_LOG_LEVEL_VERBOSE:
|
||||
stream = stdout;
|
||||
break;
|
||||
|
||||
case NTFS_LOG_LEVEL_DEBUG:
|
||||
case NTFS_LOG_LEVEL_TRACE:
|
||||
case NTFS_LOG_LEVEL_WARNING:
|
||||
case NTFS_LOG_LEVEL_ERROR:
|
||||
case NTFS_LOG_LEVEL_CRITICAL:
|
||||
case NTFS_LOG_LEVEL_PERROR:
|
||||
default:
|
||||
stream = stderr;
|
||||
break;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_get_prefix - Default prefixes for logging levels
|
||||
* @level: Log level to be prefixed
|
||||
*
|
||||
* Prefixing the logging output can make it easier to parse.
|
||||
*
|
||||
* Returns: "string" Prefix to be used
|
||||
*/
|
||||
static const char * ntfs_log_get_prefix(u32 level)
|
||||
{
|
||||
const char *prefix;
|
||||
|
||||
switch (level) {
|
||||
case NTFS_LOG_LEVEL_DEBUG:
|
||||
prefix = "DEBUG: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_TRACE:
|
||||
prefix = "TRACE: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_QUIET:
|
||||
prefix = "QUIET: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_INFO:
|
||||
prefix = "INFO: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_VERBOSE:
|
||||
prefix = "VERBOSE: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_PROGRESS:
|
||||
prefix = "PROGRESS: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_WARNING:
|
||||
prefix = "WARNING: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_ERROR:
|
||||
prefix = "ERROR: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_PERROR:
|
||||
prefix = "ERROR: ";
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_CRITICAL:
|
||||
prefix = "CRITICAL: ";
|
||||
break;
|
||||
default:
|
||||
prefix = "";
|
||||
break;
|
||||
}
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_set_handler - Provide an alternate logging handler
|
||||
* @handler: function to perform the logging
|
||||
*
|
||||
* This alternate handler will be called for all future logging requests.
|
||||
* If no @handler is specified, logging will revert to the default handler.
|
||||
*/
|
||||
void ntfs_log_set_handler(ntfs_log_handler *handler)
|
||||
{
|
||||
if (handler) {
|
||||
ntfs_log.handler = handler;
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
if (handler == ntfs_log_handler_syslog)
|
||||
openlog("libntfs", LOG_PID, LOG_USER);
|
||||
#endif
|
||||
} else
|
||||
ntfs_log.handler = ntfs_log_handler_null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_redirect - Pass on the request to the real handler
|
||||
* @function: Function in which the log line occurred
|
||||
* @file: File in which the log line occurred
|
||||
* @line: Line number on which the log line occurred
|
||||
* @level: Level at which the line is logged
|
||||
* @data: User specified data, possibly specific to a handler
|
||||
* @format: printf-style formatting string
|
||||
* @...: Arguments to be formatted
|
||||
*
|
||||
* This is just a redirector function. The arguments are simply passed to the
|
||||
* main logging handler (as defined in the global logging struct @ntfs_log).
|
||||
*
|
||||
* Returns: -1 Error occurred
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_redirect(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, ...)
|
||||
{
|
||||
int olderr = errno;
|
||||
int ret;
|
||||
va_list args;
|
||||
|
||||
if (!(ntfs_log.levels & level)) /* Don't log this message */
|
||||
return 0;
|
||||
|
||||
va_start(args, format);
|
||||
errno = olderr;
|
||||
ret = ntfs_log.handler(function, file, line, level, data, format, args);
|
||||
va_end(args);
|
||||
|
||||
errno = olderr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_syslog - syslog logging handler
|
||||
* @function: Function in which the log line occurred
|
||||
* @file: File in which the log line occurred
|
||||
* @line: Line number on which the log line occurred
|
||||
* @level: Level at which the line is logged
|
||||
* @data: User specified data, possibly specific to a handler
|
||||
* @format: printf-style formatting string
|
||||
* @args: Arguments to be formatted
|
||||
*
|
||||
* A simple syslog logging handler. Ignores colors.
|
||||
*
|
||||
* Returns: -1 Error occurred
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
int ntfs_log_handler_syslog(const char *function __attribute__((unused)),
|
||||
const char *file, __attribute__((unused)) int line, u32 level,
|
||||
void *data __attribute__((unused)), const char *format, va_list args)
|
||||
{
|
||||
int ret = 0;
|
||||
int olderr = errno;
|
||||
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
file = strrchr(file, PATH_SEP) + 1;
|
||||
#if 0 /* FIXME: Implement this all. */
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) /* Prefix the output */
|
||||
ret += fprintf(stream, "%s", ntfs_log_get_prefix(level));
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_FILENAME) /* Source filename */
|
||||
ret += fprintf(stream, "%s ", file);
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_LINE) /* Source line number */
|
||||
ret += fprintf(stream, "(%d) ", line);
|
||||
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
|
||||
(level & NTFS_LOG_LEVEL_TRACE))
|
||||
ret += fprintf(stream, "%s(): ", function);
|
||||
|
||||
ret += vfprintf(stream, format, args);
|
||||
|
||||
if (level & NTFS_LOG_LEVEL_PERROR) {
|
||||
if (reason)
|
||||
ret += fprintf(stream, ": %s\n", reason);
|
||||
else
|
||||
ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||
}
|
||||
#endif
|
||||
vsyslog(LOG_NOTICE, format, args);
|
||||
ret = 1; /* FIXME: caclulate how many bytes had been written. */
|
||||
|
||||
errno = olderr;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_fprintf - Basic logging handler
|
||||
* @function: Function in which the log line occurred
|
||||
* @file: File in which the log line occurred
|
||||
* @line: Line number on which the log line occurred
|
||||
* @level: Level at which the line is logged
|
||||
* @data: User specified data, possibly specific to a handler
|
||||
* @format: printf-style formatting string
|
||||
* @args: Arguments to be formatted
|
||||
*
|
||||
* A simple logging handler. This is where the log line is finally displayed.
|
||||
* It is more likely that you will want to set the handler to either
|
||||
* ntfs_log_handler_outerr or ntfs_log_handler_stderr.
|
||||
*
|
||||
* Note: For this handler, @data is a pointer to a FILE output stream.
|
||||
* If @data is NULL, nothing will be displayed.
|
||||
*
|
||||
* Returns: -1 Error occurred
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_fprintf(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
int ret = 0;
|
||||
int olderr = errno;
|
||||
FILE *stream;
|
||||
const char *col_prefix = NULL;
|
||||
const char *col_suffix = NULL;
|
||||
|
||||
if (!data) /* Interpret data as a FILE stream. */
|
||||
return 0; /* If it's NULL, we can't do anything. */
|
||||
stream = (FILE*)data;
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_COLOUR) {
|
||||
/* Pick a colour determined by the log level */
|
||||
switch (level) {
|
||||
case NTFS_LOG_LEVEL_DEBUG:
|
||||
col_prefix = col_green;
|
||||
col_suffix = col_end;
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_TRACE:
|
||||
col_prefix = col_cyan;
|
||||
col_suffix = col_end;
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_WARNING:
|
||||
col_prefix = col_yellow;
|
||||
col_suffix = col_end;
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_ERROR:
|
||||
case NTFS_LOG_LEVEL_PERROR:
|
||||
col_prefix = col_red;
|
||||
col_suffix = col_end;
|
||||
break;
|
||||
case NTFS_LOG_LEVEL_CRITICAL:
|
||||
col_prefix = col_redinv;
|
||||
col_suffix = col_end;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (col_prefix)
|
||||
ret += fprintf(stream, col_prefix);
|
||||
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_ONLYNAME) &&
|
||||
(strchr(file, PATH_SEP))) /* Abbreviate the filename */
|
||||
file = strrchr(file, PATH_SEP) + 1;
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_PREFIX) /* Prefix the output */
|
||||
ret += fprintf(stream, "%s", ntfs_log_get_prefix(level));
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_FILENAME) /* Source filename */
|
||||
ret += fprintf(stream, "%s ", file);
|
||||
|
||||
if (ntfs_log.flags & NTFS_LOG_FLAG_LINE) /* Source line number */
|
||||
ret += fprintf(stream, "(%d) ", line);
|
||||
|
||||
if ((ntfs_log.flags & NTFS_LOG_FLAG_FUNCTION) || /* Source function */
|
||||
(level & NTFS_LOG_LEVEL_TRACE))
|
||||
ret += fprintf(stream, "%s(): ", function);
|
||||
|
||||
ret += vfprintf(stream, format, args);
|
||||
|
||||
if (level & NTFS_LOG_LEVEL_PERROR)
|
||||
ret += fprintf(stream, ": %s\n", strerror(olderr));
|
||||
|
||||
if (col_suffix)
|
||||
ret += fprintf(stream, col_suffix);
|
||||
|
||||
|
||||
fflush(stream);
|
||||
errno = olderr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_null - Null logging handler (no output)
|
||||
* @function: Function in which the log line occurred
|
||||
* @file: File in which the log line occurred
|
||||
* @line: Line number on which the log line occurred
|
||||
* @level: Level at which the line is logged
|
||||
* @data: User specified data, possibly specific to a handler
|
||||
* @format: printf-style formatting string
|
||||
* @args: Arguments to be formatted
|
||||
*
|
||||
* This handler produces no output. It provides a way to temporarily disable
|
||||
* logging, without having to change the levels and flags.
|
||||
*
|
||||
* Returns: 0 Message wasn't logged
|
||||
*/
|
||||
int ntfs_log_handler_null(const char *function __attribute__((unused)), const char *file __attribute__((unused)),
|
||||
int line __attribute__((unused)), u32 level __attribute__((unused)), void *data __attribute__((unused)),
|
||||
const char *format __attribute__((unused)), va_list args __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_stdout - All logs go to stdout
|
||||
* @function: Function in which the log line occurred
|
||||
* @file: File in which the log line occurred
|
||||
* @line: Line number on which the log line occurred
|
||||
* @level: Level at which the line is logged
|
||||
* @data: User specified data, possibly specific to a handler
|
||||
* @format: printf-style formatting string
|
||||
* @args: Arguments to be formatted
|
||||
*
|
||||
* Display a log message to stdout.
|
||||
*
|
||||
* Note: For this handler, @data is a pointer to a FILE output stream.
|
||||
* If @data is NULL, then stdout will be used.
|
||||
*
|
||||
* Note: This function calls ntfs_log_handler_fprintf to do the main work.
|
||||
*
|
||||
* Returns: -1 Error occurred
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_stdout(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
if (!data)
|
||||
data = stdout;
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_outerr - Logs go to stdout/stderr depending on level
|
||||
* @function: Function in which the log line occurred
|
||||
* @file: File in which the log line occurred
|
||||
* @line: Line number on which the log line occurred
|
||||
* @level: Level at which the line is logged
|
||||
* @data: User specified data, possibly specific to a handler
|
||||
* @format: printf-style formatting string
|
||||
* @args: Arguments to be formatted
|
||||
*
|
||||
* Display a log message. The output stream will be determined by the log
|
||||
* level.
|
||||
*
|
||||
* Note: For this handler, @data is a pointer to a FILE output stream.
|
||||
* If @data is NULL, the function ntfs_log_get_stream will be called
|
||||
*
|
||||
* Note: This function calls ntfs_log_handler_fprintf to do the main work.
|
||||
*
|
||||
* Returns: -1 Error occurred
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_outerr(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
if (!data)
|
||||
data = ntfs_log_get_stream(level);
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_log_handler_stderr - All logs go to stderr
|
||||
* @function: Function in which the log line occurred
|
||||
* @file: File in which the log line occurred
|
||||
* @line: Line number on which the log line occurred
|
||||
* @level: Level at which the line is logged
|
||||
* @data: User specified data, possibly specific to a handler
|
||||
* @format: printf-style formatting string
|
||||
* @args: Arguments to be formatted
|
||||
*
|
||||
* Display a log message to stderr.
|
||||
*
|
||||
* Note: For this handler, @data is a pointer to a FILE output stream.
|
||||
* If @data is NULL, then stdout will be used.
|
||||
*
|
||||
* Note: This function calls ntfs_log_handler_fprintf to do the main work.
|
||||
*
|
||||
* Returns: -1 Error occurred
|
||||
* 0 Message wasn't logged
|
||||
* num Number of output characters
|
||||
*/
|
||||
int ntfs_log_handler_stderr(const char *function, const char *file,
|
||||
int line, u32 level, void *data, const char *format, va_list args)
|
||||
{
|
||||
if (!data)
|
||||
data = stderr;
|
||||
|
||||
return ntfs_log_handler_fprintf(function, file, line, level, data, format, args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ntfs_log_parse_option - Act upon command line options
|
||||
* @option: Option flag
|
||||
*
|
||||
* Delegate some of the work of parsing the command line. All the options begin
|
||||
* with "--log-". Options cause log levels to be enabled in @ntfs_log (the
|
||||
* global logging structure).
|
||||
*
|
||||
* Note: The "colour" option changes the logging handler.
|
||||
*
|
||||
* Returns: TRUE Option understood
|
||||
* FALSE Invalid log option
|
||||
*/
|
||||
BOOL ntfs_log_parse_option(const char *option)
|
||||
{
|
||||
if (strcmp(option, "--log-debug") == 0) {
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-verbose") == 0) {
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-quiet") == 0) {
|
||||
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
|
||||
return TRUE;
|
||||
} else if (strcmp(option, "--log-trace") == 0) {
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
return TRUE;
|
||||
} else if ((strcmp(option, "--log-colour") == 0) ||
|
||||
(strcmp(option, "--log-color") == 0)) {
|
||||
ntfs_log_set_flags(NTFS_LOG_FLAG_COLOUR);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Unknown logging option '%s'\n", option);
|
||||
return FALSE;
|
||||
}
|
||||
|
1576
libntfs-3g/mft.c
Normal file
1576
libntfs-3g/mft.c
Normal file
File diff suppressed because it is too large
Load Diff
36
libntfs-3g/misc.c
Normal file
36
libntfs-3g/misc.c
Normal file
@ -0,0 +1,36 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "misc.h"
|
||||
#include "logging.h"
|
||||
|
||||
/**
|
||||
* ntfs_calloc
|
||||
*
|
||||
* Return a pointer to the allocated memory or NULL if the request fails.
|
||||
*/
|
||||
void *ntfs_calloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = calloc(1, size);
|
||||
if (!p)
|
||||
ntfs_log_perror("Failed to calloc %lld bytes", (long long)size);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *ntfs_malloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = malloc(size);
|
||||
if (!p)
|
||||
ntfs_log_perror("Failed to malloc %lld bytes", (long long)size);
|
||||
return p;
|
||||
}
|
||||
|
222
libntfs-3g/mst.c
Normal file
222
libntfs-3g/mst.c
Normal file
@ -0,0 +1,222 @@
|
||||
/**
|
||||
* mst.c - Multi sector fixup handling code. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "mst.h"
|
||||
#include "logging.h"
|
||||
|
||||
/**
|
||||
* ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data
|
||||
* @b: pointer to the data to deprotect
|
||||
* @size: size in bytes of @b
|
||||
*
|
||||
* Perform the necessary post read multi sector transfer fixups and detect the
|
||||
* presence of incomplete multi sector transfers. - In that case, overwrite the
|
||||
* magic of the ntfs record header being processed with "BAAD" (in memory only!)
|
||||
* and abort processing.
|
||||
*
|
||||
* Return 0 on success and -1 on error, with errno set to the error code. The
|
||||
* following error codes are defined:
|
||||
* EINVAL Invalid arguments or invalid NTFS record in buffer @b.
|
||||
* 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(NTFS_RECORD *b, const u32 size)
|
||||
{
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* Setup the variables. */
|
||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Position of usn in update sequence array. */
|
||||
usa_pos = (u16*)b + usa_ofs/sizeof(u16);
|
||||
/*
|
||||
* The update sequence number which has to be equal to each of the
|
||||
* u16 values before they are fixed up. Note no need to care for
|
||||
* endianness since we are comparing and moving data for on disk
|
||||
* structures which means the data is consistent. - If it is
|
||||
* consistency the wrong endianness it doesn't make any difference.
|
||||
*/
|
||||
usn = *usa_pos;
|
||||
/*
|
||||
* Position in protected data of first u16 that needs fixing up.
|
||||
*/
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
/*
|
||||
* Check for incomplete multi sector transfer(s).
|
||||
*/
|
||||
while (usa_count--) {
|
||||
if (*data_pos != usn) {
|
||||
/*
|
||||
* Incomplete multi sector transfer detected! )-:
|
||||
* Set the magic to "BAAD" and return failure.
|
||||
* Note that magic_BAAD is already converted to le32.
|
||||
*/
|
||||
b->magic = magic_BAAD;
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
/* Re-setup the variables. */
|
||||
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--) {
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
*/
|
||||
*data_pos = *(++usa_pos);
|
||||
/* Increment position in data as well. */
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mst_pre_write_fixup - apply multi sector transfer protection
|
||||
* @b: pointer to the data to protect
|
||||
* @size: size in bytes of @b
|
||||
*
|
||||
* Perform the necessary pre write multi sector transfer fixup on the data
|
||||
* pointer to by @b of @size.
|
||||
*
|
||||
* Return 0 if fixups applied successfully or -1 if no fixups were performed
|
||||
* due to errors. In that case errno i set to the error code (EINVAL).
|
||||
*
|
||||
* NOTE: We consider the absence / invalidity of an update sequence array to
|
||||
* mean error. This means that you have to create a valid update sequence
|
||||
* array header in the ntfs record before calling this function, otherwise it
|
||||
* will fail (the header needs to contain the position of the update sequence
|
||||
* array together with the number of elements in the array). You also need to
|
||||
* initialise the update sequence number before calling this function
|
||||
* otherwise a random word will be used (whatever was in the record at that
|
||||
* position at that time).
|
||||
*/
|
||||
int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
||||
{
|
||||
u16 usa_ofs, usa_count, usn;
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* Sanity check + only fixup if it makes sense. */
|
||||
if (!b || ntfs_is_baad_record(b->magic) ||
|
||||
ntfs_is_hole_record(b->magic)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Setup the variables. */
|
||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Position of usn in update sequence array. */
|
||||
usa_pos = (u16*)((u8*)b + usa_ofs);
|
||||
/*
|
||||
* Cyclically increment the update sequence number
|
||||
* (skipping 0 and -1, i.e. 0xffff).
|
||||
*/
|
||||
usn = le16_to_cpup(usa_pos) + 1;
|
||||
if (usn == 0xffff || !usn)
|
||||
usn = 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--) {
|
||||
/*
|
||||
* 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 = usn;
|
||||
/* Increment position in data as well. */
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mst_post_write_fixup - deprotect multi sector transfer protected data
|
||||
* @b: pointer to the data to deprotect
|
||||
*
|
||||
* Perform the necessary post write multi sector transfer fixup, not checking
|
||||
* for any errors, because we assume we have just used
|
||||
* ntfs_mst_pre_write_fixup(), thus the data will be fine or we would never
|
||||
* have gotten here.
|
||||
*/
|
||||
void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
||||
{
|
||||
u16 *usa_pos, *data_pos;
|
||||
|
||||
u16 usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
u16 usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
/* Position of usn in update sequence array. */
|
||||
usa_pos = (u16*)b + usa_ofs/sizeof(u16);
|
||||
|
||||
/* Position in protected data of first u16 that needs fixing up. */
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
*/
|
||||
*data_pos = *(++usa_pos);
|
||||
|
||||
/* Increment position in data as well. */
|
||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
}
|
||||
|
2136
libntfs-3g/runlist.c
Normal file
2136
libntfs-3g/runlist.c
Normal file
File diff suppressed because it is too large
Load Diff
340
libntfs-3g/security.c
Normal file
340
libntfs-3g/security.c
Normal file
@ -0,0 +1,340 @@
|
||||
/**
|
||||
* security.c - Handling security/ACLs in NTFS. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2005-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2006 Yura Pakhuchiy
|
||||
*
|
||||
* 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_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "attrib.h"
|
||||
#include "security.h"
|
||||
#include "misc.h"
|
||||
|
||||
/*
|
||||
* The zero GUID.
|
||||
*/
|
||||
static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
|
||||
const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
|
||||
const GUID *const zero_guid = &__zero_guid;
|
||||
|
||||
/**
|
||||
* ntfs_guid_is_zero - check if a GUID is zero
|
||||
* @guid: [IN] guid to check
|
||||
*
|
||||
* Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
|
||||
* and FALSE otherwise.
|
||||
*/
|
||||
BOOL ntfs_guid_is_zero(const GUID *guid)
|
||||
{
|
||||
return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_guid_to_mbs - convert a GUID to a multi byte string
|
||||
* @guid: [IN] guid to convert
|
||||
* @guid_str: [OUT] string in which to return the GUID (optional)
|
||||
*
|
||||
* Convert the GUID pointed to by @guid to a multi byte string of the form
|
||||
* "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". Therefore, @guid_str (if not NULL)
|
||||
* needs to be able to store at least 37 bytes.
|
||||
*
|
||||
* If @guid_str is not NULL it will contain the converted GUID on return. If
|
||||
* it is NULL a string will be allocated and this will be returned. The caller
|
||||
* is responsible for free()ing the string in that case.
|
||||
*
|
||||
* On success return the converted string and on failure return NULL with errno
|
||||
* set to the error code.
|
||||
*/
|
||||
char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
|
||||
{
|
||||
char *_guid_str;
|
||||
int res;
|
||||
|
||||
if (!guid) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
_guid_str = guid_str;
|
||||
if (!_guid_str) {
|
||||
_guid_str = ntfs_malloc(37);
|
||||
if (!_guid_str)
|
||||
return _guid_str;
|
||||
}
|
||||
res = snprintf(_guid_str, 37,
|
||||
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
(unsigned int)le32_to_cpu(guid->data1),
|
||||
le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
|
||||
guid->data4[0], guid->data4[1],
|
||||
guid->data4[2], guid->data4[3], guid->data4[4],
|
||||
guid->data4[5], guid->data4[6], guid->data4[7]);
|
||||
if (res == 36)
|
||||
return _guid_str;
|
||||
if (!guid_str)
|
||||
free(_guid_str);
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
|
||||
* @sid: [IN] SID for which to determine the maximum string size
|
||||
*
|
||||
* Determine the maximum multi byte string size in bytes which is needed to
|
||||
* store the standard textual representation of the SID pointed to by @sid.
|
||||
* See ntfs_sid_to_mbs(), below.
|
||||
*
|
||||
* On success return the maximum number of bytes needed to store the multi byte
|
||||
* string and on failure return -1 with errno set to the error code.
|
||||
*/
|
||||
int ntfs_sid_to_mbs_size(const SID *sid)
|
||||
{
|
||||
int size, i;
|
||||
|
||||
if (!ntfs_sid_is_valid(sid)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
/* Start with "S-". */
|
||||
size = 2;
|
||||
/*
|
||||
* Add the SID_REVISION. Hopefully the compiler will optimize this
|
||||
* away as SID_REVISION is a constant.
|
||||
*/
|
||||
for (i = SID_REVISION; i > 0; i /= 10)
|
||||
size++;
|
||||
/* Add the "-". */
|
||||
size++;
|
||||
/*
|
||||
* Add the identifier authority. If it needs to be in decimal, the
|
||||
* maximum is 2^32-1 = 4294967295 = 10 characters. If it needs to be
|
||||
* in hexadecimal, then maximum is 0x665544332211 = 14 characters.
|
||||
*/
|
||||
if (!sid->identifier_authority.high_part)
|
||||
size += 10;
|
||||
else
|
||||
size += 14;
|
||||
/*
|
||||
* Finally, add the sub authorities. For each we have a "-" followed
|
||||
* by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
|
||||
*/
|
||||
size += (1 + 10) * sid->sub_authority_count;
|
||||
/* We need the zero byte at the end, too. */
|
||||
size++;
|
||||
return size * sizeof(char);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_sid_to_mbs - convert a SID to a multi byte string
|
||||
* @sid: [IN] SID to convert
|
||||
* @sid_str: [OUT] string in which to return the SID (optional)
|
||||
* @sid_str_size: [IN] size in bytes of @sid_str
|
||||
*
|
||||
* Convert the SID pointed to by @sid to its standard textual representation.
|
||||
* @sid_str (if not NULL) needs to be able to store at least
|
||||
* ntfs_sid_to_mbs_size() bytes. @sid_str_size is the size in bytes of
|
||||
* @sid_str if @sid_str is not NULL.
|
||||
*
|
||||
* The standard textual representation of the SID is of the form:
|
||||
* S-R-I-S-S...
|
||||
* Where:
|
||||
* - The first "S" is the literal character 'S' identifying the following
|
||||
* digits as a SID.
|
||||
* - R is the revision level of the SID expressed as a sequence of digits
|
||||
* in decimal.
|
||||
* - I is the 48-bit identifier_authority, expressed as digits in decimal,
|
||||
* if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
|
||||
* - S... is one or more sub_authority values, expressed as digits in
|
||||
* decimal.
|
||||
*
|
||||
* If @sid_str is not NULL it will contain the converted SUID on return. If it
|
||||
* is NULL a string will be allocated and this will be returned. The caller is
|
||||
* responsible for free()ing the string in that case.
|
||||
*
|
||||
* On success return the converted string and on failure return NULL with errno
|
||||
* set to the error code.
|
||||
*/
|
||||
char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
|
||||
{
|
||||
u64 u;
|
||||
char *s;
|
||||
int i, j, cnt;
|
||||
|
||||
/*
|
||||
* No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
|
||||
* check @sid, too. 8 is the minimum SID string size.
|
||||
*/
|
||||
if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
/* Allocate string if not provided. */
|
||||
if (!sid_str) {
|
||||
cnt = ntfs_sid_to_mbs_size(sid);
|
||||
if (cnt < 0)
|
||||
return NULL;
|
||||
s = ntfs_malloc(cnt);
|
||||
if (!s)
|
||||
return s;
|
||||
sid_str = s;
|
||||
/* So we know we allocated it. */
|
||||
sid_str_size = 0;
|
||||
} else {
|
||||
s = sid_str;
|
||||
cnt = sid_str_size;
|
||||
}
|
||||
/* Start with "S-R-". */
|
||||
i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
|
||||
if (i < 0 || i >= cnt)
|
||||
goto err_out;
|
||||
s += i;
|
||||
cnt -= i;
|
||||
/* Add the identifier authority. */
|
||||
for (u = i = 0, j = 40; i < 6; i++, j -= 8)
|
||||
u += (u64)sid->identifier_authority.value[i] << j;
|
||||
if (!sid->identifier_authority.high_part)
|
||||
i = snprintf(s, cnt, "%lu", (unsigned long)u);
|
||||
else
|
||||
i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
|
||||
if (i < 0 || i >= cnt)
|
||||
goto err_out;
|
||||
s += i;
|
||||
cnt -= i;
|
||||
/* Finally, add the sub authorities. */
|
||||
for (j = 0; j < sid->sub_authority_count; j++) {
|
||||
i = snprintf(s, cnt, "-%u", (unsigned int)
|
||||
le32_to_cpu(sid->sub_authority[j]));
|
||||
if (i < 0 || i >= cnt)
|
||||
goto err_out;
|
||||
s += i;
|
||||
cnt -= i;
|
||||
}
|
||||
return sid_str;
|
||||
err_out:
|
||||
if (i >= cnt)
|
||||
i = EMSGSIZE;
|
||||
else
|
||||
i = errno;
|
||||
if (!sid_str_size)
|
||||
free(sid_str);
|
||||
errno = i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_generate_guid - generatates a random current guid.
|
||||
* @guid: [OUT] pointer to a GUID struct to hold the generated guid.
|
||||
*
|
||||
* perhaps not a very good random number generator though...
|
||||
*/
|
||||
void ntfs_generate_guid(GUID *guid)
|
||||
{
|
||||
unsigned int i;
|
||||
u8 *p = (u8 *)guid;
|
||||
|
||||
for (i = 0; i < sizeof(GUID); i++) {
|
||||
p[i] = (u8)(random() & 0xFF);
|
||||
if (i == 7)
|
||||
p[7] = (p[7] & 0x0F) | 0x40;
|
||||
if (i == 8)
|
||||
p[8] = (p[8] & 0x3F) | 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
int ntfs_sd_add_everyone(ntfs_inode *ni)
|
||||
{
|
||||
SECURITY_DESCRIPTOR_ATTR *sd;
|
||||
ACL *acl;
|
||||
ACCESS_ALLOWED_ACE *ace;
|
||||
SID *sid;
|
||||
int ret, sd_len;
|
||||
|
||||
/* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
|
||||
/*
|
||||
* Calculate security descriptor length. We have 2 sub-authorities in
|
||||
* owner and group SIDs, but structure SID contain only one, so add
|
||||
* 4 bytes to every SID.
|
||||
*/
|
||||
sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
|
||||
sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE);
|
||||
sd = ntfs_calloc(sd_len);
|
||||
if (!sd)
|
||||
return -1;
|
||||
|
||||
sd->revision = 1;
|
||||
sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
|
||||
|
||||
sid = (SID *)((u8 *)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
|
||||
sid->revision = 1;
|
||||
sid->sub_authority_count = 2;
|
||||
sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sd->owner = cpu_to_le32((u8 *)sid - (u8 *)sd);
|
||||
|
||||
sid = (SID *)((u8 *)sid + sizeof(SID) + 4);
|
||||
sid->revision = 1;
|
||||
sid->sub_authority_count = 2;
|
||||
sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sd->group = cpu_to_le32((u8 *)sid - (u8 *)sd);
|
||||
|
||||
acl = (ACL *)((u8 *)sid + sizeof(SID) + 4);
|
||||
acl->revision = 2;
|
||||
acl->size = cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
|
||||
acl->ace_count = cpu_to_le16(1);
|
||||
sd->dacl = cpu_to_le32((u8 *)acl - (u8 *)sd);
|
||||
|
||||
ace = (ACCESS_ALLOWED_ACE *)((u8 *)acl + sizeof(ACL));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
|
||||
ace->size = cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
|
||||
ace->mask = cpu_to_le32(0x1f01ff); /* FIXME */
|
||||
ace->sid.revision = 1;
|
||||
ace->sid.sub_authority_count = 1;
|
||||
ace->sid.sub_authority[0] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 1;
|
||||
|
||||
ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8 *)sd,
|
||||
sd_len);
|
||||
if (ret)
|
||||
ntfs_log_perror("Failed to add SECURITY_DESCRIPTOR\n");
|
||||
|
||||
free(sd);
|
||||
return ret;
|
||||
}
|
||||
|
757
libntfs-3g/unistr.c
Normal file
757
libntfs-3g/unistr.c
Normal file
@ -0,0 +1,757 @@
|
||||
/**
|
||||
* unistr.c - Unicode string handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2002-2006 Szabolcs Szakacsits
|
||||
*
|
||||
* 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_WCHAR_H
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "attrib.h"
|
||||
#include "types.h"
|
||||
#include "unistr.h"
|
||||
#include "debug.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
/*
|
||||
* IMPORTANT
|
||||
* =========
|
||||
*
|
||||
* All these routines assume that the Unicode characters are in little endian
|
||||
* encoding inside the strings!!!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is used by the name collation functions to quickly determine what
|
||||
* characters are (in)valid.
|
||||
*/
|
||||
#if 0
|
||||
static const u8 legal_ansi_char_array[0x40] = {
|
||||
0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
|
||||
0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17,
|
||||
0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00,
|
||||
|
||||
0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
|
||||
0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ntfs_names_are_equal - compare two Unicode names for equality
|
||||
* @s1: name to compare to @s2
|
||||
* @s1_len: length in Unicode characters of @s1
|
||||
* @s2: name to compare to @s1
|
||||
* @s2_len: length in Unicode characters of @s2
|
||||
* @ic: ignore case bool
|
||||
* @upcase: upcase table (only if @ic == IGNORE_CASE)
|
||||
* @upcase_size: length in Unicode characters of @upcase (if present)
|
||||
*
|
||||
* Compare the names @s1 and @s2 and return TRUE (1) if the names are
|
||||
* identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE,
|
||||
* the @upcase table is used to perform a case insensitive comparison.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
if (s1_len != s2_len)
|
||||
return FALSE;
|
||||
if (!s1_len)
|
||||
return TRUE;
|
||||
if (ic == CASE_SENSITIVE)
|
||||
return ntfs_ucsncmp(s1, s2, s1_len) ? FALSE: TRUE;
|
||||
return ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size) ? FALSE:
|
||||
TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_names_collate - collate two Unicode names
|
||||
* @name1: first Unicode name to compare
|
||||
* @name1_len: length of first Unicode name to compare
|
||||
* @name2: second Unicode name to compare
|
||||
* @name2_len: length of second Unicode name to compare
|
||||
* @err_val: if @name1 contains an invalid character return this value
|
||||
* @ic: either CASE_SENSITIVE or IGNORE_CASE
|
||||
* @upcase: upcase table (ignored if @ic is CASE_SENSITIVE)
|
||||
* @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE)
|
||||
*
|
||||
* ntfs_names_collate() collates two Unicode names and returns:
|
||||
*
|
||||
* -1 if the first name collates before the second one,
|
||||
* 0 if the names match,
|
||||
* 1 if the second name collates before the first one, or
|
||||
* @err_val if an invalid character is found in @name1 during the comparison.
|
||||
*
|
||||
* The following characters are considered invalid: '"', '*', '<', '>' and '?'.
|
||||
*/
|
||||
int ntfs_names_collate(const ntfschar *name1, const u32 name1_len,
|
||||
const ntfschar *name2, const u32 name2_len,
|
||||
const int err_val __attribute__((unused)),
|
||||
const IGNORE_CASE_BOOL ic, const ntfschar *upcase,
|
||||
const u32 upcase_len)
|
||||
{
|
||||
u32 cnt;
|
||||
ntfschar c1, c2;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) {
|
||||
ntfs_log_debug("ntfs_names_collate received NULL pointer!\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
for (cnt = 0; cnt < min(name1_len, name2_len); ++cnt) {
|
||||
c1 = le16_to_cpu(*name1);
|
||||
name1++;
|
||||
c2 = le16_to_cpu(*name2);
|
||||
name2++;
|
||||
if (ic) {
|
||||
if (c1 < upcase_len)
|
||||
c1 = le16_to_cpu(upcase[c1]);
|
||||
if (c2 < upcase_len)
|
||||
c2 = le16_to_cpu(upcase[c2]);
|
||||
}
|
||||
#if 0
|
||||
if (c1 < 64 && legal_ansi_char_array[c1] & 8)
|
||||
return err_val;
|
||||
#endif
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
if (c1 > c2)
|
||||
return 1;
|
||||
}
|
||||
if (name1_len < name2_len)
|
||||
return -1;
|
||||
if (name1_len == name2_len)
|
||||
return 0;
|
||||
/* name1_len > name2_len */
|
||||
#if 0
|
||||
c1 = le16_to_cpu(*name1);
|
||||
if (c1 < 64 && legal_ansi_char_array[c1] & 8)
|
||||
return err_val;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucsncmp - compare two little endian Unicode strings
|
||||
* @s1: first string
|
||||
* @s2: second string
|
||||
* @n: maximum unicode characters to compare
|
||||
*
|
||||
* Compare the first @n characters of the Unicode strings @s1 and @s2,
|
||||
* The strings in little endian format and appropriate le16_to_cpu()
|
||||
* conversion is performed on non-little endian machines.
|
||||
*
|
||||
* The function returns an integer less than, equal to, or greater than zero
|
||||
* if @s1 (or the first @n Unicode characters thereof) is found, respectively,
|
||||
* to be less than, to match, or be greater than @s2.
|
||||
*/
|
||||
int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
|
||||
{
|
||||
ntfschar c1, c2;
|
||||
size_t i;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!s1 || !s2) {
|
||||
ntfs_log_debug("ntfs_wcsncmp() received NULL pointer!\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < n; ++i) {
|
||||
c1 = le16_to_cpu(s1[i]);
|
||||
c2 = le16_to_cpu(s2[i]);
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
if (c1 > c2)
|
||||
return 1;
|
||||
if (!c1)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucsncasecmp - compare two little endian Unicode strings, ignoring case
|
||||
* @s1: first string
|
||||
* @s2: second string
|
||||
* @n: maximum unicode characters to compare
|
||||
* @upcase: upcase table
|
||||
* @upcase_size: upcase table size in Unicode characters
|
||||
*
|
||||
* Compare the first @n characters of the Unicode strings @s1 and @s2,
|
||||
* ignoring case. The strings in little endian format and appropriate
|
||||
* le16_to_cpu() conversion is performed on non-little endian machines.
|
||||
*
|
||||
* Each character is uppercased using the @upcase table before the comparison.
|
||||
*
|
||||
* The function returns an integer less than, equal to, or greater than zero
|
||||
* if @s1 (or the first @n Unicode characters thereof) is found, respectively,
|
||||
* to be less than, to match, or be greater than @s2.
|
||||
*/
|
||||
int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
|
||||
const ntfschar *upcase, const u32 upcase_size)
|
||||
{
|
||||
ntfschar c1, c2;
|
||||
size_t i;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!s1 || !s2 || !upcase) {
|
||||
ntfs_log_debug("ntfs_wcsncasecmp() received NULL pointer!\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < n; ++i) {
|
||||
if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
|
||||
c1 = le16_to_cpu(upcase[c1]);
|
||||
if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
|
||||
c2 = le16_to_cpu(upcase[c2]);
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
if (c1 > c2)
|
||||
return 1;
|
||||
if (!c1)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucsnlen - determine the length of a little endian Unicode string
|
||||
* @s: pointer to Unicode string
|
||||
* @maxlen: maximum length of string @s
|
||||
*
|
||||
* Return the number of Unicode characters in the little endian Unicode
|
||||
* string @s up to a maximum of maxlen Unicode characters, not including
|
||||
* the terminating (ntfschar)'\0'. If there is no (ntfschar)'\0' between @s
|
||||
* and @s + @maxlen, @maxlen is returned.
|
||||
*
|
||||
* This function never looks beyond @s + @maxlen.
|
||||
*/
|
||||
u32 ntfs_ucsnlen(const ntfschar *s, u32 maxlen)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
if (!le16_to_cpu(s[i]))
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucsndup - duplicate little endian Unicode string
|
||||
* @s: pointer to Unicode string
|
||||
* @maxlen: maximum length of string @s
|
||||
*
|
||||
* Return a pointer to a new little endian Unicode string which is a duplicate
|
||||
* of the string s. Memory for the new string is obtained with ntfs_malloc(3),
|
||||
* and can be freed with free(3).
|
||||
*
|
||||
* A maximum of @maxlen Unicode characters are copied and a terminating
|
||||
* (ntfschar)'\0' little endian Unicode character is added.
|
||||
*
|
||||
* This function never looks beyond @s + @maxlen.
|
||||
*
|
||||
* Return a pointer to the new little endian Unicode string on success and NULL
|
||||
* on failure with errno set to the error code.
|
||||
*/
|
||||
ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen)
|
||||
{
|
||||
ntfschar *dst;
|
||||
u32 len;
|
||||
|
||||
len = ntfs_ucsnlen(s, maxlen);
|
||||
dst = ntfs_malloc((len + 1) * sizeof(ntfschar));
|
||||
if (dst) {
|
||||
memcpy(dst, s, len * sizeof(ntfschar));
|
||||
dst[len] = cpu_to_le16(L'\0');
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_name_upcase - Map an Unicode name to its uppercase equivalent
|
||||
* @name:
|
||||
* @name_len:
|
||||
* @upcase:
|
||||
* @upcase_len:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void ntfs_name_upcase(ntfschar *name, u32 name_len, const ntfschar *upcase,
|
||||
const u32 upcase_len)
|
||||
{
|
||||
u32 i;
|
||||
ntfschar u;
|
||||
|
||||
for (i = 0; i < name_len; i++)
|
||||
if ((u = le16_to_cpu(name[i])) < upcase_len)
|
||||
name[i] = upcase[u];
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_file_value_upcase - Convert a filename to upper case
|
||||
* @file_name_attr:
|
||||
* @upcase:
|
||||
* @upcase_len:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
|
||||
const ntfschar *upcase, const u32 upcase_len)
|
||||
{
|
||||
ntfs_name_upcase((ntfschar*)&file_name_attr->file_name,
|
||||
file_name_attr->file_name_length, upcase, upcase_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_file_values_compare - Which of two filenames should be listed first
|
||||
* @file_name_attr1:
|
||||
* @file_name_attr2:
|
||||
* @err_val:
|
||||
* @ic:
|
||||
* @upcase:
|
||||
* @upcase_len:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
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)
|
||||
{
|
||||
return ntfs_names_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,
|
||||
err_val, ic, upcase, upcase_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucstombs - convert a little endian Unicode string to a multibyte string
|
||||
* @ins: input Unicode string buffer
|
||||
* @ins_len: length of input string in Unicode characters
|
||||
* @outs: on return contains the (allocated) output multibyte string
|
||||
* @outs_len: length of output buffer in bytes
|
||||
*
|
||||
* Convert the input little endian, 2-byte Unicode string @ins, of length
|
||||
* @ins_len into the multibyte string format dictated by the current locale.
|
||||
*
|
||||
* If *@outs is NULL, the function allocates the string and the caller is
|
||||
* responsible for calling free(*@outs); when finished with it.
|
||||
*
|
||||
* On success the function returns the number of bytes written to the output
|
||||
* string *@outs (>= 0), not counting the terminating NULL byte. If the output
|
||||
* string buffer was allocated, *@outs is set to it.
|
||||
*
|
||||
* On error, -1 is returned, and errno is set to the error code. The following
|
||||
* error codes can be expected:
|
||||
* EINVAL Invalid arguments (e.g. @ins or @outs is NULL).
|
||||
* EILSEQ The input string cannot be represented as a multibyte
|
||||
* sequence according to the current locale.
|
||||
* ENAMETOOLONG Destination buffer is too small for input string.
|
||||
* ENOMEM Not enough memory to allocate destination buffer.
|
||||
*/
|
||||
int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
|
||||
int outs_len)
|
||||
{
|
||||
char *mbs;
|
||||
wchar_t wc;
|
||||
int i, o, mbs_len;
|
||||
int cnt = 0;
|
||||
#ifdef HAVE_MBSINIT
|
||||
mbstate_t mbstate;
|
||||
#endif
|
||||
|
||||
if (!ins || !outs) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
mbs = *outs;
|
||||
mbs_len = outs_len;
|
||||
if (mbs && !mbs_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
if (!mbs) {
|
||||
mbs_len = (ins_len + 1) * MB_CUR_MAX;
|
||||
mbs = ntfs_malloc(mbs_len);
|
||||
if (!mbs)
|
||||
return -1;
|
||||
}
|
||||
#ifdef HAVE_MBSINIT
|
||||
memset(&mbstate, 0, sizeof(mbstate));
|
||||
#else
|
||||
wctomb(NULL, 0);
|
||||
#endif
|
||||
for (i = o = 0; i < ins_len; i++) {
|
||||
/* Reallocate memory if necessary or abort. */
|
||||
if ((int)(o + MB_CUR_MAX) > mbs_len) {
|
||||
char *tc;
|
||||
if (mbs == *outs) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
tc = ntfs_malloc((mbs_len + 64) & ~63);
|
||||
if (!tc)
|
||||
goto err_out;
|
||||
memcpy(tc, mbs, mbs_len);
|
||||
mbs_len = (mbs_len + 64) & ~63;
|
||||
free(mbs);
|
||||
mbs = tc;
|
||||
}
|
||||
/* Convert the LE Unicode character to a CPU wide character. */
|
||||
wc = (wchar_t)le16_to_cpu(ins[i]);
|
||||
if (!wc)
|
||||
break;
|
||||
/* Convert the CPU endian wide character to multibyte. */
|
||||
#ifdef HAVE_MBSINIT
|
||||
cnt = wcrtomb(mbs + o, wc, &mbstate);
|
||||
#else
|
||||
cnt = wctomb(mbs + o, wc);
|
||||
#endif
|
||||
if (cnt == -1)
|
||||
goto err_out;
|
||||
if (cnt <= 0) {
|
||||
ntfs_log_debug("Eeek. cnt <= 0, cnt = %i\n", cnt);
|
||||
errno = EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
o += cnt;
|
||||
}
|
||||
#ifdef HAVE_MBSINIT
|
||||
/* Make sure we are back in the initial state. */
|
||||
if (!mbsinit(&mbstate)) {
|
||||
ntfs_log_debug("Eeek. mbstate not in initial state!\n");
|
||||
errno = EILSEQ;
|
||||
goto err_out;
|
||||
}
|
||||
#endif
|
||||
/* Now write the NULL character. */
|
||||
mbs[o] = '\0';
|
||||
if (*outs != mbs)
|
||||
*outs = mbs;
|
||||
return o;
|
||||
err_out:
|
||||
if (mbs != *outs) {
|
||||
int eo = errno;
|
||||
free(mbs);
|
||||
errno = eo;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mbstoucs - convert a multibyte string to a little endian Unicode string
|
||||
* @ins: input multibyte string buffer
|
||||
* @outs: on return contains the (allocated) output Unicode string
|
||||
* @outs_len: length of output buffer in Unicode characters
|
||||
*
|
||||
* Convert the input multibyte string @ins, from the current locale into the
|
||||
* corresponding little endian, 2-byte Unicode string.
|
||||
*
|
||||
* If *@outs is NULL, the function allocates the string and the caller is
|
||||
* responsible for calling free(*@outs); when finished with it.
|
||||
*
|
||||
* On success the function returns the number of Unicode characters written to
|
||||
* the output string *@outs (>= 0), not counting the terminating Unicode NULL
|
||||
* character. If the output string buffer was allocated, *@outs is set to it.
|
||||
*
|
||||
* On error, -1 is returned, and errno is set to the error code. The following
|
||||
* error codes can be expected:
|
||||
* EINVAL Invalid arguments (e.g. @ins or @outs is NULL).
|
||||
* EILSEQ The input string cannot be represented as a Unicode
|
||||
* string according to the current locale.
|
||||
* ENAMETOOLONG Destination buffer is too small for input string.
|
||||
* ENOMEM Not enough memory to allocate destination buffer.
|
||||
*/
|
||||
int ntfs_mbstoucs(const char *ins, ntfschar **outs, int outs_len)
|
||||
{
|
||||
ntfschar *ucs;
|
||||
const char *s;
|
||||
wchar_t wc;
|
||||
int i, o, cnt, ins_len, ucs_len, ins_size;
|
||||
#ifdef HAVE_MBSINIT
|
||||
mbstate_t mbstate;
|
||||
#endif
|
||||
|
||||
if (!ins || !outs) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
ucs = *outs;
|
||||
ucs_len = outs_len;
|
||||
if (ucs && !ucs_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
/* Determine the size of the multi-byte string in bytes. */
|
||||
ins_size = strlen(ins);
|
||||
/* Determine the length of the multi-byte string. */
|
||||
s = ins;
|
||||
#if defined(HAVE_MBSINIT)
|
||||
memset(&mbstate, 0, sizeof(mbstate));
|
||||
ins_len = mbsrtowcs(NULL, (const char **)&s, 0, &mbstate);
|
||||
#ifdef __CYGWIN32__
|
||||
if (!ins_len && *ins) {
|
||||
/* Older Cygwin had broken mbsrtowcs() implementation. */
|
||||
ins_len = strlen(ins);
|
||||
}
|
||||
#endif
|
||||
#elif !defined(DJGPP)
|
||||
ins_len = mbstowcs(NULL, s, 0);
|
||||
#else
|
||||
/* Eeek!!! DJGPP has broken mbstowcs() implementation!!! */
|
||||
ins_len = strlen(ins);
|
||||
#endif
|
||||
if (ins_len == -1)
|
||||
return ins_len;
|
||||
#ifdef HAVE_MBSINIT
|
||||
if ((s != ins) || !mbsinit(&mbstate)) {
|
||||
#else
|
||||
if (s != ins) {
|
||||
#endif
|
||||
errno = EILSEQ;
|
||||
return -1;
|
||||
}
|
||||
/* Add the NULL terminator. */
|
||||
ins_len++;
|
||||
if (!ucs) {
|
||||
ucs_len = ins_len;
|
||||
ucs = ntfs_malloc(ucs_len * sizeof(ntfschar));
|
||||
if (!ucs)
|
||||
return -1;
|
||||
}
|
||||
#ifdef HAVE_MBSINIT
|
||||
memset(&mbstate, 0, sizeof(mbstate));
|
||||
#else
|
||||
mbtowc(NULL, NULL, 0);
|
||||
#endif
|
||||
for (i = o = cnt = 0; i < ins_size; i += cnt, o++) {
|
||||
/* Reallocate memory if necessary or abort. */
|
||||
if (o >= ucs_len) {
|
||||
ntfschar *tc;
|
||||
if (ucs == *outs) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* We will never get here but hey, it's only a bit of
|
||||
* extra code...
|
||||
*/
|
||||
ucs_len = (ucs_len * sizeof(ntfschar) + 64) & ~63;
|
||||
tc = (ntfschar*)realloc(ucs, ucs_len);
|
||||
if (!tc)
|
||||
goto err_out;
|
||||
ucs = tc;
|
||||
ucs_len /= sizeof(ntfschar);
|
||||
}
|
||||
/* Convert the multibyte character to a wide character. */
|
||||
#ifdef HAVE_MBSINIT
|
||||
cnt = mbrtowc(&wc, ins + i, ins_size - i, &mbstate);
|
||||
#else
|
||||
cnt = mbtowc(&wc, ins + i, ins_size - i);
|
||||
#endif
|
||||
if (!cnt)
|
||||
break;
|
||||
if (cnt == -1)
|
||||
goto err_out;
|
||||
if (cnt < -1) {
|
||||
ntfs_log_trace("Eeek. cnt = %i\n", cnt);
|
||||
errno = EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
/* Make sure we are not overflowing the NTFS Unicode set. */
|
||||
if ((unsigned long)wc >= (unsigned long)(1 <<
|
||||
(8 * sizeof(ntfschar)))) {
|
||||
errno = EILSEQ;
|
||||
goto err_out;
|
||||
}
|
||||
/* Convert the CPU wide character to a LE Unicode character. */
|
||||
ucs[o] = cpu_to_le16(wc);
|
||||
}
|
||||
#ifdef HAVE_MBSINIT
|
||||
/* Make sure we are back in the initial state. */
|
||||
if (!mbsinit(&mbstate)) {
|
||||
ntfs_log_trace("Eeek. mbstate not in initial state!\n");
|
||||
errno = EILSEQ;
|
||||
goto err_out;
|
||||
}
|
||||
#endif
|
||||
/* Now write the NULL character. */
|
||||
ucs[o] = cpu_to_le16(L'\0');
|
||||
if (*outs != ucs)
|
||||
*outs = ucs;
|
||||
return o;
|
||||
err_out:
|
||||
if (ucs != *outs) {
|
||||
int eo = errno;
|
||||
free(ucs);
|
||||
errno = eo;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_upcase_table_build - build the default upcase table for NTFS
|
||||
* @uc: destination buffer where to store the built table
|
||||
* @uc_len: size of destination buffer in bytes
|
||||
*
|
||||
* ntfs_upcase_table_build() builds the default upcase table for NTFS and
|
||||
* stores it in the caller supplied buffer @uc of size @uc_len.
|
||||
*
|
||||
* Note, @uc_len must be at least 128kiB in size or bad things will happen!
|
||||
*/
|
||||
void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
||||
{
|
||||
static int uc_run_table[][3] = { /* Start, End, Add */
|
||||
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
|
||||
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
|
||||
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
|
||||
{0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128},
|
||||
{0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112},
|
||||
{0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126},
|
||||
{0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8},
|
||||
{0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8},
|
||||
{0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8},
|
||||
{0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7},
|
||||
{0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16},
|
||||
{0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26},
|
||||
{0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32},
|
||||
{0}
|
||||
};
|
||||
static int uc_dup_table[][2] = { /* Start, End */
|
||||
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
|
||||
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
|
||||
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
|
||||
{0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9},
|
||||
{0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95},
|
||||
{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
|
||||
{0}
|
||||
};
|
||||
static int uc_byte_table[][2] = { /* Offset, Value */
|
||||
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
|
||||
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
|
||||
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
|
||||
{0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F},
|
||||
{0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9},
|
||||
{0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE},
|
||||
{0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7},
|
||||
{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
|
||||
{0}
|
||||
};
|
||||
int i, r;
|
||||
|
||||
memset((char*)uc, 0, uc_len);
|
||||
uc_len >>= 1;
|
||||
if (uc_len > 65536)
|
||||
uc_len = 65536;
|
||||
for (i = 0; (u32)i < uc_len; i++)
|
||||
uc[i] = i;
|
||||
for (r = 0; uc_run_table[r][0]; r++)
|
||||
for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
|
||||
uc[i] += uc_run_table[r][2];
|
||||
for (r = 0; uc_dup_table[r][0]; r++)
|
||||
for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
|
||||
uc[i + 1]--;
|
||||
for (r = 0; uc_byte_table[r][0]; r++)
|
||||
uc[uc_byte_table[r][0]] = uc_byte_table[r][1];
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_str2ucs - convert a string to a valid NTFS file name
|
||||
* @s: input string
|
||||
* @len: length of output buffer in Unicode characters
|
||||
*
|
||||
* Convert the input @s string into the corresponding little endian,
|
||||
* 2-byte Unicode string. The length of the converted string is less
|
||||
* or equal to the maximum length allowed by the NTFS format (255).
|
||||
*
|
||||
* If @s is NULL then return AT_UNNAMED.
|
||||
*
|
||||
* On success the function returns the Unicode string in an allocated
|
||||
* buffer and the caller is responsible to free it when it's not needed
|
||||
* anymore.
|
||||
*
|
||||
* On error NULL is returned and errno is set to the error code.
|
||||
*/
|
||||
ntfschar *ntfs_str2ucs(const char *s, int *len)
|
||||
{
|
||||
ntfschar *ucs = NULL;
|
||||
|
||||
if (s && ((*len = ntfs_mbstoucs(s, &ucs, 0)) == -1)) {
|
||||
ntfs_log_perror("Couldn't convert '%s' to Unicode", s);
|
||||
return NULL;
|
||||
}
|
||||
if (*len > NTFS_MAX_NAME_LEN) {
|
||||
free(ucs);
|
||||
errno = ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
if (!ucs || !*len) {
|
||||
ucs = AT_UNNAMED;
|
||||
*len = 0;
|
||||
}
|
||||
return ucs;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ucsfree - free memory allocated by ntfs_str2ucs()
|
||||
* @ucs input string to be freed
|
||||
*
|
||||
* Free memory at @ucs and which was allocated by ntfs_str2ucs.
|
||||
*
|
||||
* Return value: none.
|
||||
*/
|
||||
void ntfs_ucsfree(ntfschar *ucs)
|
||||
{
|
||||
if (ucs && (ucs != AT_UNNAMED))
|
||||
free(ucs);
|
||||
}
|
||||
|
327
libntfs-3g/unix_io.c
Normal file
327
libntfs-3g/unix_io.c
Normal file
@ -0,0 +1,327 @@
|
||||
/**
|
||||
* unix_io.c - Unix style disk io functions. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* 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
|
||||
* 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_UNISTD_H
|
||||
#include <unistd.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
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FD_H
|
||||
#include <linux/fd.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "mst.h"
|
||||
#include "debug.h"
|
||||
#include "device.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define DEV_FD(dev) (*(int *)dev->d_private)
|
||||
|
||||
/* Define to nothing if not present on this system. */
|
||||
#ifndef O_EXCL
|
||||
# define O_EXCL 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_open - Open a device and lock it exclusively
|
||||
* @dev:
|
||||
* @flags:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
|
||||
{
|
||||
struct flock flk;
|
||||
struct stat sbuf;
|
||||
int err;
|
||||
|
||||
if (NDevOpen(dev)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
dev->d_private = ntfs_malloc(sizeof(int));
|
||||
if (!dev->d_private)
|
||||
return -1;
|
||||
/*
|
||||
* Open the device/file obtaining the file descriptor for exclusive
|
||||
* access (but only if mounting r/w).
|
||||
*/
|
||||
if ((flags & O_RDWR) == O_RDWR)
|
||||
flags |= O_EXCL;
|
||||
*(int*)dev->d_private = open(dev->d_name, flags);
|
||||
if (*(int*)dev->d_private == -1) {
|
||||
err = errno;
|
||||
goto err_out;
|
||||
}
|
||||
/* Setup our read-only flag. */
|
||||
if ((flags & O_RDWR) != O_RDWR)
|
||||
NDevSetReadOnly(dev);
|
||||
/* Acquire exclusive (mandatory) lock on the whole device. */
|
||||
memset(&flk, 0, sizeof(flk));
|
||||
if (NDevReadOnly(dev))
|
||||
flk.l_type = F_RDLCK;
|
||||
else
|
||||
flk.l_type = F_WRLCK;
|
||||
flk.l_whence = SEEK_SET;
|
||||
flk.l_start = flk.l_len = 0LL;
|
||||
if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
|
||||
err = errno;
|
||||
ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s for %s\n",
|
||||
dev->d_name, NDevReadOnly(dev) ? "reading" : "writing");
|
||||
if (close(DEV_FD(dev)))
|
||||
ntfs_log_perror("ntfs_device_unix_io_open: Warning: Could not "
|
||||
"close %s", dev->d_name);
|
||||
goto err_out;
|
||||
}
|
||||
/* Determine if device is a block device or not, ignoring errors. */
|
||||
if (!fstat(DEV_FD(dev), &sbuf) && S_ISBLK(sbuf.st_mode))
|
||||
NDevSetBlock(dev);
|
||||
/* Set our open flag. */
|
||||
NDevSetOpen(dev);
|
||||
return 0;
|
||||
err_out:
|
||||
free(dev->d_private);
|
||||
dev->d_private = NULL;
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_close - Close the device, releasing the lock
|
||||
* @dev:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_device_unix_io_close(struct ntfs_device *dev)
|
||||
{
|
||||
struct flock flk;
|
||||
|
||||
if (!NDevOpen(dev)) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
if (NDevDirty(dev))
|
||||
fsync(DEV_FD(dev));
|
||||
/* Release exclusive (mandatory) lock on the whole device. */
|
||||
memset(&flk, 0, sizeof(flk));
|
||||
flk.l_type = F_UNLCK;
|
||||
flk.l_whence = SEEK_SET;
|
||||
flk.l_start = flk.l_len = 0LL;
|
||||
if (fcntl(DEV_FD(dev), F_SETLK, &flk))
|
||||
ntfs_log_perror("ntfs_device_unix_io_close: Warning: Could not "
|
||||
"unlock %s", dev->d_name);
|
||||
/* Close the file descriptor and clear our open flag. */
|
||||
if (close(DEV_FD(dev)))
|
||||
return -1;
|
||||
NDevClearOpen(dev);
|
||||
free(dev->d_private);
|
||||
dev->d_private = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_seek - Seek to a place on the device
|
||||
* @dev:
|
||||
* @offset:
|
||||
* @whence:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset,
|
||||
int whence)
|
||||
{
|
||||
return lseek(DEV_FD(dev), offset, whence);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_read - Read from the device, from the current location
|
||||
* @dev:
|
||||
* @buf:
|
||||
* @count:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static s64 ntfs_device_unix_io_read(struct ntfs_device *dev, void *buf,
|
||||
s64 count)
|
||||
{
|
||||
return read(DEV_FD(dev), buf, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_write - Write to the device, at the current location
|
||||
* @dev:
|
||||
* @buf:
|
||||
* @count:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf,
|
||||
s64 count)
|
||||
{
|
||||
if (NDevReadOnly(dev)) {
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
NDevSetDirty(dev);
|
||||
return write(DEV_FD(dev), buf, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_pread - Perform a positioned read from the device
|
||||
* @dev:
|
||||
* @buf:
|
||||
* @count:
|
||||
* @offset:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf,
|
||||
s64 count, s64 offset)
|
||||
{
|
||||
return ntfs_pread(dev, offset, count, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_pwrite - Perform a positioned write to the device
|
||||
* @dev:
|
||||
* @buf:
|
||||
* @count:
|
||||
* @offset:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
|
||||
s64 count, s64 offset)
|
||||
{
|
||||
if (NDevReadOnly(dev)) {
|
||||
errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
NDevSetDirty(dev);
|
||||
return ntfs_pwrite(dev, offset, count, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_sync - Flush any buffered changes to the device
|
||||
* @dev:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_device_unix_io_sync(struct ntfs_device *dev)
|
||||
{
|
||||
if (!NDevReadOnly(dev) && NDevDirty(dev)) {
|
||||
int res = fsync(DEV_FD(dev));
|
||||
if (!res)
|
||||
NDevClearDirty(dev);
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_stat - Get information about the device
|
||||
* @dev:
|
||||
* @buf:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf)
|
||||
{
|
||||
return fstat(DEV_FD(dev), buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_unix_io_ioctl - Perform an ioctl on the device
|
||||
* @dev:
|
||||
* @request:
|
||||
* @argp:
|
||||
*
|
||||
* Description...
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request,
|
||||
void *argp)
|
||||
{
|
||||
return ioctl(DEV_FD(dev), request, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Device operations for working with unix style devices and files.
|
||||
*/
|
||||
struct ntfs_device_operations ntfs_device_unix_io_ops = {
|
||||
.open = ntfs_device_unix_io_open,
|
||||
.close = ntfs_device_unix_io_close,
|
||||
.seek = ntfs_device_unix_io_seek,
|
||||
.read = ntfs_device_unix_io_read,
|
||||
.write = ntfs_device_unix_io_write,
|
||||
.pread = ntfs_device_unix_io_pread,
|
||||
.pwrite = ntfs_device_unix_io_pwrite,
|
||||
.sync = ntfs_device_unix_io_sync,
|
||||
.stat = ntfs_device_unix_io_stat,
|
||||
.ioctl = ntfs_device_unix_io_ioctl,
|
||||
};
|
40
libntfs-3g/version.c
Normal file
40
libntfs-3g/version.c
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* version.c - Info about the NTFS library. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2005 Anton Altaparmakov
|
||||
* Copyright (c) 2005 Richard Russon
|
||||
*
|
||||
* 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
|
||||
|
||||
#include "version.h"
|
||||
|
||||
/* FIXME: merge libntfs into the user space NTFS driver */
|
||||
static const char *libntfs_version_string = "22:0:0";
|
||||
|
||||
/**
|
||||
* ntfs_libntfs_version - query version number of the ntfs library libntfs
|
||||
*
|
||||
* Returns pointer to a text string representing the version of libntfs.
|
||||
*/
|
||||
const char *ntfs_libntfs_version(void)
|
||||
{
|
||||
return libntfs_version_string;
|
||||
}
|
1526
libntfs-3g/volume.c
Normal file
1526
libntfs-3g/volume.c
Normal file
File diff suppressed because it is too large
Load Diff
1473
libntfs-3g/win32_io.c
Normal file
1473
libntfs-3g/win32_io.c
Normal file
File diff suppressed because it is too large
Load Diff
50
src/Makefile.am
Normal file
50
src/Makefile.am
Normal file
@ -0,0 +1,50 @@
|
||||
if REALLYSTATIC
|
||||
AM_LIBS = $(top_builddir)/libntfs-3g/.libs/libntfs-3g.a
|
||||
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)
|
||||
|
||||
man_MANS = ntfs-3g.8
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs
|
||||
|
||||
bin_PROGRAMS = ntfs-3g
|
||||
|
||||
# Set the include path.
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include/ntfs-3g $(all_includes)
|
||||
|
||||
ntfs_3g_SOURCES = ntfs-3g.c utils.c utils.h
|
||||
ntfs_3g_LDADD = $(AM_LIBS) $(FUSE_MODULE_LIBS)
|
||||
ntfs_3g_LDFLAGS = $(AM_LFLAGS)
|
||||
ntfs_3g_CFLAGS = $(FUSE_MODULE_CFLAGS) -DFUSE_USE_VERSION=25
|
||||
|
||||
# Extra targets
|
||||
|
||||
strip: $(bin_PROGRAMS)
|
||||
$(STRIP) $^
|
||||
|
||||
libs:
|
||||
(cd ../libntfs-3g && $(MAKE) libs) || exit 1;
|
||||
|
||||
install-exec-hook:
|
||||
$(INSTALL) -d $(DESTDIR)/sbin
|
||||
$(LN_S) -f $(bindir)/ntfs-3g $(DESTDIR)/sbin/mount.ntfs-3g
|
||||
ldconfig
|
||||
|
||||
install-data-hook:
|
||||
$(INSTALL) -d $(DESTDIR)$(man8dir)
|
||||
$(LN_S) -f ntfs-3g.8 $(DESTDIR)$(man8dir)/mount.ntfs-3g.8
|
||||
|
||||
uninstall-local:
|
||||
$(RM) -f $(DESTDIR)/sbin/mount.ntfs-3g
|
||||
$(RM) -f $(DESTDIR)$(man8dir)/mount.ntfs-3g.8
|
||||
|
198
src/ntfs-3g.8.in
Normal file
198
src/ntfs-3g.8.in
Normal file
@ -0,0 +1,198 @@
|
||||
.\" Copyright (c) 2005-2006 Yura Pakhuchiy.
|
||||
.\" Copyright (c) 2005 Richard Russon.
|
||||
.\" Copyright (c) 2006 Szabolcs Szakacsits.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFS-3G 8 "October 2006" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
ntfs-3g \- Third Generation NTFS Driver
|
||||
.SH SYNOPSIS
|
||||
.B ntfs-3g
|
||||
.I device mount_point
|
||||
[\fB\-o options\fR]
|
||||
.SH DESCRIPTION
|
||||
\fBntfs-3g\fR is an NTFS driver, which can
|
||||
create, remove, rename files, directories, hard links, and
|
||||
streams; it can read and write files, including
|
||||
streams and sparse files; it can handle special files like
|
||||
symbolic links, devices, and FIFOs; moreover it can also read
|
||||
compressed files.
|
||||
.SH OPTIONS
|
||||
Below is a summary of the options that \fBntfs-3g\fR accepts.
|
||||
.TP
|
||||
.B uid=, gid=, umask=
|
||||
Provide default owner, group, and access mode mask.
|
||||
These options work as documented in mount(8). By
|
||||
default, the files and directories are owned by the user who
|
||||
mounted the volume but everybody has full read, write and
|
||||
executable access, moreover browse permission to any directory.
|
||||
If you want to use the currently limited permission
|
||||
handling then use these options together with the
|
||||
.B default_permissions,
|
||||
.B fmask
|
||||
and
|
||||
.B dmask
|
||||
options. The usage of the
|
||||
.B default_permissions
|
||||
option is a must in such cases.
|
||||
.TP
|
||||
.B default_permissions
|
||||
By default FUSE doesn't check file access permissions, the
|
||||
filesystem is free to implement its access policy or leave it to
|
||||
the underlying file access mechanism (e.g. in case of network
|
||||
filesystems). This option enables permission checking, restricting
|
||||
accesses based on file modes. This option is usually useful
|
||||
together with the
|
||||
.B allow_other
|
||||
mount option.
|
||||
.TP
|
||||
.B fmask=, dmask=
|
||||
Instead of specifying umask which applies both to
|
||||
files and directories, fmask applies only to files and
|
||||
mask only to directories.
|
||||
.TP
|
||||
.B ro
|
||||
Mount filesystem read\-only.
|
||||
.TP
|
||||
.B locale=
|
||||
You can set locale with this option which is often required to make
|
||||
visible files with national charaters. It's useful if locale
|
||||
environment variables are not set before partitions had been mounted
|
||||
from /etc/fstab.
|
||||
.TP
|
||||
.B force
|
||||
Force mount even if the volume is scheduled for consistency check.
|
||||
Use this option with caution and preferably with the
|
||||
.B ro
|
||||
option.
|
||||
.TP
|
||||
.B show_sys_files
|
||||
Show the system files in directory listings.
|
||||
Otherwise the default behaviour is to hide the system files.
|
||||
Please note that even when this option is specified, "$MFT"
|
||||
may not be visible due to a glibc bug.
|
||||
Furthermore, irrespectively of show_sys_files, all
|
||||
files are accessible by name, for example you can always do
|
||||
"ls \-l '$UpCase'".
|
||||
.TP
|
||||
.B allow_other
|
||||
This option overrides the security measure restricting file access
|
||||
to the user mounting the filesystem. This option is by default only
|
||||
allowed to root, but this restriction can be removed with a
|
||||
configuration option described in the previous section.
|
||||
.TP
|
||||
.B large_read
|
||||
Issue large read requests. This can improve performance for some
|
||||
filesystems, but can also degrade performance. This option is mostly
|
||||
useful on 2.4.X kernels, as on 2.6 kernels requests size is
|
||||
automatically determined for optimum performance.
|
||||
.TP
|
||||
.B max_read=
|
||||
With this option the maximum size of read operations can be set.
|
||||
The default is infinite. Note that the size of read requests is
|
||||
limited anyway to 32 pages (which is 128kbyte on i386).
|
||||
.TP
|
||||
.B silent
|
||||
Do nothing on chmod and chown operations, but do not return error.
|
||||
This option is on by default.
|
||||
.TP
|
||||
.B no_def_opts
|
||||
By default ntfs-3g acts as "silent,allow_other" was passed to it,
|
||||
this option cancel this behaviour.
|
||||
.TP
|
||||
.B streams_interface=
|
||||
This option controls how the user can access Alternate Data Streams (ADS)
|
||||
or in other words, named data streams. It can be set
|
||||
to, one of \fBnone\fR, \fBwindows\fR or \fBxattr\fR. If the option is set to
|
||||
\fBnone\fR, the user will have no access to the named data streams. If it's set
|
||||
to \fBwindows\fR, then the user can access them just like in Windows (eg. cat
|
||||
file:stream). If it's set to \fBxattr\fR, then the named data streams are
|
||||
mapped to xattrs and user can manipulate them using \fB{get,set}fattr\fR
|
||||
utilities. The default is \fBnone\fR.
|
||||
.TP
|
||||
.B debug
|
||||
Makes ntfs-3g to not detach from terminal and print a lot of debug output from
|
||||
libntfs-3g and FUSE.
|
||||
.TP
|
||||
.B no_detach
|
||||
Same as above but with less debug output.
|
||||
.SH ALTERNATE DATA STREAMS (ADS)
|
||||
All data on NTFS is stored in streams. Every file has exactly one unnamed
|
||||
data stream and can have many named data streams. The size of a file is the
|
||||
size of its unnamed data stream. By default, \fBntfs-3g\fR will only read
|
||||
the unnamed data stream.
|
||||
.PP
|
||||
By using the options "streams_interface=windows", you will be able to read
|
||||
any named data streams, simply by specifying the stream's name after a colon.
|
||||
For example:
|
||||
.RS
|
||||
.sp
|
||||
cat some.mp3:artist
|
||||
.sp
|
||||
.RE
|
||||
Named data streams act like normals files, so you can read from them, write to
|
||||
them and even delete them (using rm). You can list all the named data streams
|
||||
a file has by getting the "ntfs.streams.list" extended attribute.
|
||||
.SH EXAMPLES
|
||||
Mount /dev/hda1 to /mnt/windows:
|
||||
.RS
|
||||
.sp
|
||||
.B ntfs-3g /dev/hda1 /mnt/windows
|
||||
.sp
|
||||
.RE
|
||||
Read\-only mount /dev/hda5 to /home/user/mnt and make user with uid 1000
|
||||
to be the owner of all files:
|
||||
.RS
|
||||
.sp
|
||||
.B ntfs-3g /dev/hda5 /home/user/mnt \-o ro,uid=1000
|
||||
.sp
|
||||
.RE
|
||||
/etc/fstab entry for the above:
|
||||
.RS
|
||||
.sp
|
||||
.B /dev/hda5 /home/user/mnt ntfs\-3g ro,uid=1000 0 0
|
||||
.sp
|
||||
.RE
|
||||
Unmount /mnt/windows:
|
||||
.RS
|
||||
.sp
|
||||
.B umount /mnt/windows
|
||||
.sp
|
||||
.RE
|
||||
You can also unmount /mnt/windows with fusermount:
|
||||
.RS
|
||||
.sp
|
||||
.B fusermount \-u /mnt/windows
|
||||
.sp
|
||||
.RE
|
||||
.SH KNOWN ISSUES
|
||||
Please see
|
||||
.RS
|
||||
.sp
|
||||
http://www.ntfs-3g.org/support.html
|
||||
.sp
|
||||
.RE
|
||||
for all known issues.
|
||||
If you would find a new one in the latest release of
|
||||
this software then please send an email describing it
|
||||
according to the above page. You can also contact the
|
||||
development team on the ntfs\-3g\-devel@lists.sf.net email
|
||||
address anytime.
|
||||
.SH AUTHORS
|
||||
.B ntfs-3g
|
||||
was based on and a major improvement to ntfsmount and libntfs which were
|
||||
written by Yura Pakhuchiy and the Linux-NTFS team. The improvements were
|
||||
made, the ntfs-3g project was initiated and currently led by long time
|
||||
Linux-NTFS team developer Szabolcs Szakacsits (szaka@sienet.hu) to revive
|
||||
the stalled open source development and project management.
|
||||
|
||||
.SH THANKS
|
||||
Several people made heroic efforts, often over five or more
|
||||
years which resulted the ntfs-3g driver. Most importantly they are
|
||||
Anton Altaparmakov, Richard Russon, Szabolcs Szakacsits, Yura Pakhuchiy,
|
||||
Yuval Fedel, and the author of the groundbreaking FUSE filesystem development
|
||||
framework, Miklos Szeredi.
|
||||
.SH SEE ALSO
|
||||
.BR ntfsprogs (8),
|
||||
.BR attr (5),
|
||||
.BR getfattr (1)
|
2047
src/ntfs-3g.c
Normal file
2047
src/ntfs-3g.c
Normal file
File diff suppressed because it is too large
Load Diff
966
src/utils.c
Normal file
966
src/utils.c
Normal file
@ -0,0 +1,966 @@
|
||||
/**
|
||||
* utils.c - Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2005 Richard Russon
|
||||
* Copyright (c) 2003-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2003 Lode Leroy
|
||||
*
|
||||
* A set of shared functions for ntfs utilities
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBINTL_H
|
||||
#include <libintl.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_CTYPE_H
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
#include "debug.h"
|
||||
#include "dir.h"
|
||||
#include "version.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
const char *ntfs_home =
|
||||
"Ntfs-3g news, support and information: http://www.ntfs-3g.org\n";
|
||||
const char *ntfs_gpl = "This program is free software, released under the GNU "
|
||||
"General Public License\nand you are welcome to redistribute it under "
|
||||
"certain conditions. It comes with\nABSOLUTELY NO WARRANTY; for "
|
||||
"details read the GNU General Public License to be\nfound in the file "
|
||||
"\"COPYING\" distributed with this program, or online at:\n"
|
||||
"http://www.gnu.org/copyleft/gpl.html\n";
|
||||
|
||||
static const char *invalid_ntfs_msg =
|
||||
"The device '%s' doesn't have a valid NTFS.\n"
|
||||
"Maybe you selected the wrong device? Or the whole disk instead of a\n"
|
||||
"partition (e.g. /dev/hda, not /dev/hda1)? Or the other way around?\n";
|
||||
|
||||
static const char *corrupt_volume_msg =
|
||||
"NTFS is inconsistent. Run chkdsk /f on Windows then reboot it TWICE!\n"
|
||||
"The usage of the /f parameter is very IMPORTANT! No modification was\n"
|
||||
"made to NTFS by this software.\n";
|
||||
|
||||
static const char *hibernated_volume_msg =
|
||||
"The NTFS partition is hibernated. Please resume Windows and turned it \n"
|
||||
"off properly, so mounting could be done safely.\n";
|
||||
|
||||
static const char *unclean_journal_msg =
|
||||
"Mount is denied because the NTFS journal file is unclean. Choices are:\n"
|
||||
" A) Shutdown Windows properly.\n"
|
||||
" B) Click the 'Safely Remove Hardware' icon in the Windows taskbar\n"
|
||||
" notification area before disconnecting the device.\n"
|
||||
" C) Use 'Eject' from Windows Explorer to safely remove the device.\n"
|
||||
" D) If you ran chkdsk previously then boot Windows again which will\n"
|
||||
" automatically initialize the journal.\n"
|
||||
" E) Run 'ntfsfix' on Linux which will reset the NTFS journal.\n"
|
||||
" F) Mount the volume read-only by using the 'ro' mount option.\n";
|
||||
|
||||
static const char *opened_volume_msg =
|
||||
"Mount is denied because the NTFS volume is already exclusively opened.\n"
|
||||
"The volume may be already mounted, or another software may use it which\n"
|
||||
"could be identified for example by the help of the 'fuser' command.\n";
|
||||
|
||||
/**
|
||||
* utils_set_locale
|
||||
*/
|
||||
int utils_set_locale(void)
|
||||
{
|
||||
const char *locale;
|
||||
|
||||
locale = setlocale(LC_ALL, "");
|
||||
if (!locale) {
|
||||
locale = setlocale(LC_ALL, NULL);
|
||||
ntfs_log_error("Couldn't set local environment, using default '%s'.\n", locale);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ntfs_volume *utils_mount_volume(const char *volume, unsigned long flags,
|
||||
BOOL force)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
|
||||
vol = ntfs_mount(volume, flags);
|
||||
if (!vol) {
|
||||
|
||||
ntfs_log_perror("Failed to mount '%s'", volume);
|
||||
|
||||
if (errno == EINVAL)
|
||||
ntfs_log_error(invalid_ntfs_msg, volume);
|
||||
else if (errno == EIO)
|
||||
ntfs_log_error("%s", corrupt_volume_msg);
|
||||
else if (errno == EPERM)
|
||||
ntfs_log_error("%s", hibernated_volume_msg);
|
||||
else if (errno == EOPNOTSUPP)
|
||||
ntfs_log_error("%s", unclean_journal_msg);
|
||||
else if (errno == EBUSY)
|
||||
ntfs_log_error("%s", opened_volume_msg);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vol->flags & VOLUME_IS_DIRTY) {
|
||||
if (!force) {
|
||||
ntfs_log_error("Volume is scheduled for check.\nPlease "
|
||||
"boot into Windows TWICE, or use the "
|
||||
"'force' mount option.\n");
|
||||
ntfs_umount(vol, FALSE);
|
||||
|
||||
return NULL;
|
||||
} else
|
||||
ntfs_log_error("WARNING: Dirty volume mount was forced "
|
||||
"by the 'force' mount option.\n");
|
||||
}
|
||||
|
||||
return vol;
|
||||
}
|
||||
|
||||
/**
|
||||
* utils_parse_size - Convert a string representing a size
|
||||
* @value: String to be parsed
|
||||
* @size: Parsed size
|
||||
* @scale: Whether or not to allow a suffix to scale the value
|
||||
*
|
||||
* Read a string and convert it to a number. Strings may be suffixed to scale
|
||||
* them. Any number without a suffix is assumed to be in bytes.
|
||||
*
|
||||
* Suffix Description Multiple
|
||||
* [tT] Terabytes 10^12
|
||||
* [gG] Gigabytes 10^9
|
||||
* [mM] Megabytes 10^6
|
||||
* [kK] Kilobytes 10^3
|
||||
*
|
||||
* Notes:
|
||||
* Only the first character of the suffix is read.
|
||||
* The multipliers are decimal thousands, not binary: 1000, not 1024.
|
||||
* If parse_size fails, @size will not be changed
|
||||
*
|
||||
* Return: 1 Success
|
||||
* 0 Error, the string was malformed
|
||||
*/
|
||||
int utils_parse_size(const char *value, s64 *size, BOOL scale)
|
||||
{
|
||||
long long result;
|
||||
char *suffix = NULL;
|
||||
|
||||
if (!value || !size) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtoll(value, &suffix, 0);
|
||||
if (result < 0 || errno == ERANGE) {
|
||||
ntfs_log_error("Invalid size '%s'.\n", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!suffix) {
|
||||
ntfs_log_error("Internal error, strtoll didn't return a suffix.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (scale) {
|
||||
switch (suffix[0]) {
|
||||
case 't': case 'T': result *= 1000;
|
||||
case 'g': case 'G': result *= 1000;
|
||||
case 'm': case 'M': result *= 1000;
|
||||
case 'k': case 'K': result *= 1000;
|
||||
case '-': case 0:
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Invalid size suffix '%s'. Use T, G, M, or K.\n", suffix);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if ((suffix[0] != '-') && (suffix[0] != 0)) {
|
||||
ntfs_log_error("Invalid number '%.*s'.\n", (int)(suffix - value + 1), value);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
*size = result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* utils_parse_range - Convert a string representing a range of numbers
|
||||
* @string: The string to be parsed
|
||||
* @start: The beginning of the range will be stored here
|
||||
* @finish: The end of the range will be stored here
|
||||
*
|
||||
* Read a string of the form n-m. If the lower end is missing, zero will be
|
||||
* substituted. If the upper end is missing LONG_MAX will be used. If the
|
||||
* string cannot be parsed correctly, @start and @finish will not be changed.
|
||||
*
|
||||
* Return: 1 Success, a valid string was found
|
||||
* 0 Error, the string was not a valid range
|
||||
*/
|
||||
int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale)
|
||||
{
|
||||
s64 a, b;
|
||||
char *middle;
|
||||
|
||||
if (!string || !start || !finish) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
middle = strchr(string, '-');
|
||||
if (string == middle) {
|
||||
ntfs_log_debug("Range has no beginning, defaulting to 0.\n");
|
||||
a = 0;
|
||||
} else {
|
||||
if (!utils_parse_size(string, &a, scale))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (middle) {
|
||||
if (middle[1] == 0) {
|
||||
b = LONG_MAX; // XXX ULLONG_MAX
|
||||
ntfs_log_debug("Range has no end, defaulting to %lld.\n", b);
|
||||
} else {
|
||||
if (!utils_parse_size(middle+1, &b, scale))
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
b = a;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Range '%s' = %lld - %lld\n", string, a, b);
|
||||
|
||||
*start = a;
|
||||
*finish = b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_attribute - Find an attribute of the given type
|
||||
* @type: An attribute type, e.g. AT_FILE_NAME
|
||||
* @ctx: A search context, created using ntfs_get_attr_search_ctx
|
||||
*
|
||||
* Using the search context to keep track, find the first/next occurrence of a
|
||||
* given attribute type.
|
||||
*
|
||||
* N.B. This will return a pointer into @mft. As long as the search context
|
||||
* has been created without an inode, it won't overflow the buffer.
|
||||
*
|
||||
* Return: Pointer Success, an attribute was found
|
||||
* NULL Error, no matching attributes were found
|
||||
*/
|
||||
ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
if (!ctx) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ntfs_attr_lookup(type, NULL, 0, 0, 0, NULL, 0, ctx) != 0) {
|
||||
ntfs_log_debug("find_attribute didn't find an attribute of type: 0x%02x.\n", type);
|
||||
return NULL; /* None / no more of that type */
|
||||
}
|
||||
|
||||
ntfs_log_debug("find_attribute found an attribute of type: 0x%02x.\n", type);
|
||||
return ctx->attr;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_first_attribute - Find the first attribute of a given type
|
||||
* @type: An attribute type, e.g. AT_FILE_NAME
|
||||
* @mft: A buffer containing a raw MFT record
|
||||
*
|
||||
* Search through a raw MFT record for an attribute of a given type.
|
||||
* The return value is a pointer into the MFT record that was supplied.
|
||||
*
|
||||
* N.B. This will return a pointer into @mft. The pointer won't stray outside
|
||||
* the buffer, since we created the search context without an inode.
|
||||
*
|
||||
* Return: Pointer Success, an attribute was found
|
||||
* NULL Error, no matching attributes were found
|
||||
*/
|
||||
ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ATTR_RECORD *rec;
|
||||
|
||||
if (!mft) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(NULL, mft);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Couldn't create a search context.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rec = find_attribute(type, ctx);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
if (rec)
|
||||
ntfs_log_debug("find_first_attribute: found attr of type 0x%02x.\n", type);
|
||||
else
|
||||
ntfs_log_debug("find_first_attribute: didn't find attr of type 0x%02x.\n", type);
|
||||
return rec;
|
||||
}
|
||||
|
||||
/**
|
||||
* utils_inode_get_name
|
||||
*
|
||||
* using inode
|
||||
* get filename
|
||||
* add name to list
|
||||
* get parent
|
||||
* if parent is 5 (/) stop
|
||||
* get inode of parent
|
||||
*/
|
||||
int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize)
|
||||
{
|
||||
// XXX option: names = posix/win32 or dos
|
||||
// flags: path, filename, or both
|
||||
const int max_path = 20;
|
||||
|
||||
ntfs_volume *vol;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ATTR_RECORD *rec;
|
||||
FILE_NAME_ATTR *attr;
|
||||
int name_space;
|
||||
MFT_REF parent = FILE_root;
|
||||
char *names[max_path + 1];// XXX ntfs_malloc? and make max bigger?
|
||||
int i, len, offset = 0;
|
||||
|
||||
if (!inode || !buffer) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vol = inode->vol;
|
||||
|
||||
//ntfs_log_debug("sizeof(char*) = %d, sizeof(names) = %d\n", sizeof(char*), sizeof(names));
|
||||
memset(names, 0, sizeof(names));
|
||||
|
||||
for (i = 0; i < max_path; i++) {
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(inode, NULL);
|
||||
if (!ctx) {
|
||||
ntfs_log_error("Couldn't create a search context.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//ntfs_log_debug("i = %d, inode = %p (%lld)\n", i, inode, inode->mft_no);
|
||||
|
||||
name_space = 4;
|
||||
while ((rec = find_attribute(AT_FILE_NAME, ctx))) {
|
||||
/* We know this will always be resident. */
|
||||
attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset));
|
||||
|
||||
if (attr->file_name_type > name_space) { //XXX find the ...
|
||||
continue;
|
||||
}
|
||||
|
||||
name_space = attr->file_name_type;
|
||||
parent = le64_to_cpu(attr->parent_directory);
|
||||
|
||||
if (names[i]) {
|
||||
free(names[i]);
|
||||
names[i] = NULL;
|
||||
}
|
||||
|
||||
if (ntfs_ucstombs(attr->file_name, attr->file_name_length,
|
||||
&names[i], 0) < 0) {
|
||||
char *temp;
|
||||
ntfs_log_error("Couldn't translate filename to current locale.\n");
|
||||
temp = ntfs_malloc(30);
|
||||
if (!temp)
|
||||
return 0;
|
||||
snprintf(temp, 30, "<MFT%llu>", (unsigned
|
||||
long long)inode->mft_no);
|
||||
names[i] = temp;
|
||||
}
|
||||
|
||||
//ntfs_log_debug("names[%d] %s\n", i, names[i]);
|
||||
//ntfs_log_debug("parent = %lld\n", MREF(parent));
|
||||
}
|
||||
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
|
||||
if (i > 0) /* Don't close the original inode */
|
||||
ntfs_inode_close(inode);
|
||||
|
||||
if (MREF(parent) == FILE_root) { /* The root directory, stop. */
|
||||
//ntfs_log_debug("inode 5\n");
|
||||
break;
|
||||
}
|
||||
|
||||
inode = ntfs_inode_open(vol, parent);
|
||||
if (!inode) {
|
||||
ntfs_log_error("Couldn't open inode %llu.\n",
|
||||
(unsigned long long)MREF(parent));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= max_path) {
|
||||
/* If we get into an infinite loop, we'll end up here. */
|
||||
ntfs_log_error("The directory structure is too deep (over %d) nested directories.\n", max_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assemble the names in the correct order. */
|
||||
for (i = max_path; i >= 0; i--) {
|
||||
if (!names[i])
|
||||
continue;
|
||||
|
||||
len = snprintf(buffer + offset, bufsize - offset, "%c%s", PATH_SEP, names[i]);
|
||||
if (len >= (bufsize - offset)) {
|
||||
ntfs_log_error("Pathname was truncated.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
/* Free all the allocated memory */
|
||||
for (i = 0; i < max_path; i++)
|
||||
free(names[i]);
|
||||
|
||||
ntfs_log_debug("Pathname: %s\n", buffer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* utils_attr_get_name
|
||||
*/
|
||||
int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int bufsize)
|
||||
{
|
||||
int len, namelen;
|
||||
char *name;
|
||||
ATTR_DEF *attrdef;
|
||||
|
||||
// flags: attr, name, or both
|
||||
if (!attr || !buffer) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
attrdef = ntfs_attr_find_in_attrdef(vol, attr->type);
|
||||
if (attrdef) {
|
||||
name = NULL;
|
||||
namelen = ntfs_ucsnlen(attrdef->name, sizeof(attrdef->name));
|
||||
if (ntfs_ucstombs(attrdef->name, namelen, &name, 0) < 0) {
|
||||
ntfs_log_error("Couldn't translate attribute type to current locale.\n");
|
||||
// <UNKNOWN>?
|
||||
return 0;
|
||||
}
|
||||
len = snprintf(buffer, bufsize, "%s", name);
|
||||
} else {
|
||||
ntfs_log_error("Unknown attribute type 0x%02x\n", attr->type);
|
||||
len = snprintf(buffer, bufsize, "<UNKNOWN>");
|
||||
}
|
||||
|
||||
if (len >= bufsize) {
|
||||
ntfs_log_error("Attribute type was truncated.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!attr->name_length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer += len;
|
||||
bufsize -= len;
|
||||
|
||||
name = NULL;
|
||||
namelen = attr->name_length;
|
||||
if (ntfs_ucstombs((ntfschar *)((char *)attr + attr->name_offset),
|
||||
namelen, &name, 0) < 0) {
|
||||
ntfs_log_error("Couldn't translate attribute name to current locale.\n");
|
||||
// <UNKNOWN>?
|
||||
len = snprintf(buffer, bufsize, "<UNKNOWN>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = snprintf(buffer, bufsize, "(%s)", name);
|
||||
free(name);
|
||||
|
||||
if (len >= bufsize) {
|
||||
ntfs_log_error("Attribute name was truncated.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* utils_cluster_in_use - Determine if a cluster is in use
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
* @lcn: The Logical Cluster Number to test
|
||||
*
|
||||
* The metadata file $Bitmap has one binary bit representing each cluster on
|
||||
* disk. The bit will be set for each cluster that is in use. The function
|
||||
* reads the relevant part of $Bitmap into a buffer and tests the bit.
|
||||
*
|
||||
* This function has a static buffer in which it caches a section of $Bitmap.
|
||||
* If the lcn, being tested, lies outside the range, the buffer will be
|
||||
* refreshed.
|
||||
*
|
||||
* Return: 1 Cluster is in use
|
||||
* 0 Cluster is free space
|
||||
* -1 Error occurred
|
||||
*/
|
||||
int utils_cluster_in_use(ntfs_volume *vol, long long lcn)
|
||||
{
|
||||
static unsigned char buffer[512];
|
||||
static long long bmplcn = -sizeof(buffer) - 1; /* Which bit of $Bitmap is in the buffer */
|
||||
|
||||
int byte, bit;
|
||||
ntfs_attr *attr;
|
||||
|
||||
if (!vol) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Does lcn lie in the section of $Bitmap we already have cached? */
|
||||
if ((lcn < bmplcn) || (lcn >= (bmplcn + (sizeof(buffer) << 3)))) {
|
||||
ntfs_log_debug("Bit lies outside cache.\n");
|
||||
attr = ntfs_attr_open(vol->lcnbmp_ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!attr) {
|
||||
ntfs_log_perror("Couldn't open $Bitmap");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Mark the buffer as in use, in case the read is shorter. */
|
||||
memset(buffer, 0xFF, sizeof(buffer));
|
||||
bmplcn = lcn & (~((sizeof(buffer) << 3) - 1));
|
||||
|
||||
if (ntfs_attr_pread(attr, (bmplcn>>3), sizeof(buffer), buffer) < 0) {
|
||||
ntfs_log_perror("Couldn't read $Bitmap");
|
||||
ntfs_attr_close(attr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Reloaded bitmap buffer.\n");
|
||||
ntfs_attr_close(attr);
|
||||
}
|
||||
|
||||
bit = 1 << (lcn & 7);
|
||||
byte = (lcn >> 3) & (sizeof(buffer) - 1);
|
||||
ntfs_log_debug("cluster = %lld, bmplcn = %lld, byte = %d, bit = %d, in use %d\n", lcn, bmplcn, byte, bit, buffer[byte] & bit);
|
||||
|
||||
return (buffer[byte] & bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* utils_mftrec_in_use - Determine if a MFT Record is in use
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
* @mref: MFT Reference (inode number)
|
||||
*
|
||||
* The metadata file $BITMAP has one binary bit representing each record in the
|
||||
* MFT. The bit will be set for each record that is in use. The function
|
||||
* reads the relevant part of $BITMAP into a buffer and tests the bit.
|
||||
*
|
||||
* This function has a static buffer in which it caches a section of $BITMAP.
|
||||
* If the mref, being tested, lies outside the range, the buffer will be
|
||||
* refreshed.
|
||||
*
|
||||
* Return: 1 MFT Record is in use
|
||||
* 0 MFT Record is unused
|
||||
* -1 Error occurred
|
||||
*/
|
||||
int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref)
|
||||
{
|
||||
static u8 buffer[512];
|
||||
static s64 bmpmref = -sizeof(buffer) - 1; /* Which bit of $BITMAP is in the buffer */
|
||||
|
||||
int byte, bit;
|
||||
|
||||
if (!vol) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntfs_log_trace("entering\n");
|
||||
/* Does mref lie in the section of $Bitmap we already have cached? */
|
||||
if (((s64)MREF(mref) < bmpmref) || ((s64)MREF(mref) >= (bmpmref +
|
||||
(sizeof(buffer) << 3)))) {
|
||||
ntfs_log_debug("Bit lies outside cache.\n");
|
||||
|
||||
/* Mark the buffer as not in use, in case the read is shorter. */
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
bmpmref = mref & (~((sizeof(buffer) << 3) - 1));
|
||||
|
||||
if (ntfs_attr_pread(vol->mftbmp_na, (bmpmref>>3), sizeof(buffer), buffer) < 0) {
|
||||
ntfs_log_perror("Couldn't read $MFT/$BITMAP");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntfs_log_debug("Reloaded bitmap buffer.\n");
|
||||
}
|
||||
|
||||
bit = 1 << (mref & 7);
|
||||
byte = (mref >> 3) & (sizeof(buffer) - 1);
|
||||
ntfs_log_debug("cluster = %lld, bmpmref = %lld, byte = %d, bit = %d, in use %d\n", mref, bmpmref, byte, bit, buffer[byte] & bit);
|
||||
|
||||
return (buffer[byte] & bit);
|
||||
}
|
||||
|
||||
/**
|
||||
* __metadata
|
||||
*/
|
||||
static int __metadata(ntfs_volume *vol, u64 num)
|
||||
{
|
||||
if (num <= FILE_UpCase)
|
||||
return 1;
|
||||
if (!vol)
|
||||
return -1;
|
||||
if ((vol->major_ver == 3) && (num == FILE_Extend))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* utils_is_metadata - Determine if an inode represents a metadata file
|
||||
* @inode: An ntfs inode to be tested
|
||||
*
|
||||
* A handful of files in the volume contain filesystem data - metadata.
|
||||
* They can be identified by their inode number (offset in MFT/$DATA) or by
|
||||
* their parent.
|
||||
*
|
||||
* Return: 1 inode is a metadata file
|
||||
* 0 inode is not a metadata file
|
||||
* -1 Error occurred
|
||||
*/
|
||||
int utils_is_metadata(ntfs_inode *inode)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
ATTR_RECORD *rec;
|
||||
FILE_NAME_ATTR *attr;
|
||||
MFT_RECORD *file;
|
||||
u64 num;
|
||||
|
||||
if (!inode) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
vol = inode->vol;
|
||||
if (!vol)
|
||||
return -1;
|
||||
|
||||
num = inode->mft_no;
|
||||
if (__metadata(vol, num) == 1)
|
||||
return 1;
|
||||
|
||||
file = inode->mrec;
|
||||
if (file && (file->base_mft_record != 0)) {
|
||||
num = MREF(file->base_mft_record);
|
||||
if (__metadata(vol, num) == 1)
|
||||
return 1;
|
||||
}
|
||||
file = inode->mrec;
|
||||
|
||||
rec = find_first_attribute(AT_FILE_NAME, inode->mrec);
|
||||
if (!rec)
|
||||
return -1;
|
||||
|
||||
/* We know this will always be resident. */
|
||||
attr = (FILE_NAME_ATTR *) ((char *) rec + le16_to_cpu(rec->value_offset));
|
||||
|
||||
num = MREF(attr->parent_directory);
|
||||
if ((num != FILE_root) && (__metadata(vol, num) == 1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* utils_dump_mem - Display a block of memory in hex and ascii
|
||||
* @buf: Buffer to be displayed
|
||||
* @start: Offset into @buf to start from
|
||||
* @length: Number of bytes to display
|
||||
* @flags: Options to change the style of the output
|
||||
*
|
||||
* Display a block of memory in a tradition hex-dump manner.
|
||||
* Optionally the ascii part can be turned off.
|
||||
*
|
||||
* The flags, described fully in utils.h, default to 0 (DM_DEFAULTS).
|
||||
* Examples are: DM_INDENT (indent the output by one tab); DM_RED (colour the
|
||||
* output); DM_NO_ASCII (only print the hex values).
|
||||
*/
|
||||
void utils_dump_mem(void *buf, int start, int length, int flags)
|
||||
{
|
||||
int off, i, s, e, col;
|
||||
u8 *mem = buf;
|
||||
|
||||
s = start & ~15; // round down
|
||||
e = (start + length + 15) & ~15; // round up
|
||||
|
||||
for (off = s; off < e; off += 16) {
|
||||
col = 30;
|
||||
if (flags & DM_RED)
|
||||
col += 1;
|
||||
if (flags & DM_GREEN)
|
||||
col += 2;
|
||||
if (flags & DM_BLUE)
|
||||
col += 4;
|
||||
if (flags & DM_INDENT)
|
||||
ntfs_log_debug("\t");
|
||||
if (flags & DM_BOLD)
|
||||
ntfs_log_debug("\e[01m");
|
||||
if (flags & (DM_RED | DM_BLUE | DM_GREEN | DM_BOLD))
|
||||
ntfs_log_debug("\e[%dm", col);
|
||||
if (off == s)
|
||||
ntfs_log_debug("%6.6x ", start);
|
||||
else
|
||||
ntfs_log_debug("%6.6x ", off);
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if ((i == 8) && (!(flags & DM_NO_DIVIDER)))
|
||||
ntfs_log_debug(" -");
|
||||
if (((off+i) >= start) && ((off+i) < (start+length)))
|
||||
ntfs_log_debug(" %02X", mem[off+i]);
|
||||
else
|
||||
ntfs_log_debug(" ");
|
||||
}
|
||||
if (!(flags & DM_NO_ASCII)) {
|
||||
ntfs_log_debug(" ");
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (((off+i) < start) || ((off+i) >= (start+length)))
|
||||
ntfs_log_debug(" ");
|
||||
else if (isprint(mem[off + i]))
|
||||
ntfs_log_debug("%c", mem[off + i]);
|
||||
else
|
||||
ntfs_log_debug(".");
|
||||
}
|
||||
}
|
||||
if (flags & (DM_RED | DM_BLUE | DM_GREEN | DM_BOLD))
|
||||
ntfs_log_debug("\e[0m");
|
||||
ntfs_log_debug("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* mft_get_search_ctx
|
||||
*/
|
||||
struct mft_search_ctx * mft_get_search_ctx(ntfs_volume *vol)
|
||||
{
|
||||
struct mft_search_ctx *ctx;
|
||||
|
||||
if (!vol) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = calloc(1, sizeof *ctx);
|
||||
|
||||
ctx->mft_num = -1;
|
||||
ctx->vol = vol;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* mft_put_search_ctx
|
||||
*/
|
||||
void mft_put_search_ctx(struct mft_search_ctx *ctx)
|
||||
{
|
||||
if (!ctx)
|
||||
return;
|
||||
if (ctx->inode)
|
||||
ntfs_inode_close(ctx->inode);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* mft_next_record
|
||||
*/
|
||||
int mft_next_record(struct mft_search_ctx *ctx)
|
||||
{
|
||||
s64 nr_mft_records;
|
||||
ATTR_RECORD *attr10 = NULL;
|
||||
ATTR_RECORD *attr20 = NULL;
|
||||
ATTR_RECORD *attr80 = NULL;
|
||||
ntfs_attr_search_ctx *attr_ctx;
|
||||
|
||||
if (!ctx) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ctx->inode) {
|
||||
ntfs_inode_close(ctx->inode);
|
||||
ctx->inode = NULL;
|
||||
}
|
||||
|
||||
nr_mft_records = ctx->vol->mft_na->initialized_size >>
|
||||
ctx->vol->mft_record_size_bits;
|
||||
|
||||
for (ctx->mft_num++; (s64)ctx->mft_num < nr_mft_records; ctx->mft_num++) {
|
||||
int in_use;
|
||||
|
||||
ctx->flags_match = 0;
|
||||
in_use = utils_mftrec_in_use(ctx->vol, (MFT_REF) ctx->mft_num);
|
||||
if (in_use == -1) {
|
||||
ntfs_log_error("Error reading inode %llu. Aborting.\n",
|
||||
(unsigned long long)ctx->mft_num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (in_use) {
|
||||
ctx->flags_match |= FEMR_IN_USE;
|
||||
|
||||
ctx->inode = ntfs_inode_open(ctx->vol, (MFT_REF) ctx->mft_num);
|
||||
if (ctx->inode == NULL) {
|
||||
ntfs_log_error("Error reading inode %llu.\n", (unsigned
|
||||
long long) ctx->mft_num);
|
||||
continue;
|
||||
}
|
||||
|
||||
attr10 = find_first_attribute(AT_STANDARD_INFORMATION, ctx->inode->mrec);
|
||||
attr20 = find_first_attribute(AT_ATTRIBUTE_LIST, ctx->inode->mrec);
|
||||
attr80 = find_first_attribute(AT_DATA, ctx->inode->mrec);
|
||||
|
||||
if (attr10)
|
||||
ctx->flags_match |= FEMR_BASE_RECORD;
|
||||
else
|
||||
ctx->flags_match |= FEMR_NOT_BASE_RECORD;
|
||||
|
||||
if (attr20)
|
||||
ctx->flags_match |= FEMR_BASE_RECORD;
|
||||
|
||||
if (attr80)
|
||||
ctx->flags_match |= FEMR_FILE;
|
||||
|
||||
if (ctx->flags_search & FEMR_DIR) {
|
||||
attr_ctx = ntfs_attr_get_search_ctx(ctx->inode, NULL);
|
||||
if (attr_ctx) {
|
||||
if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, 0, 0, NULL, 0, attr_ctx) == 0)
|
||||
ctx->flags_match |= FEMR_DIR;
|
||||
|
||||
ntfs_attr_put_search_ctx(attr_ctx);
|
||||
} else {
|
||||
ntfs_log_error("Couldn't create a search context.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (utils_is_metadata(ctx->inode)) {
|
||||
case 1: ctx->flags_match |= FEMR_METADATA; break;
|
||||
case 0: ctx->flags_match |= FEMR_NOT_METADATA; break;
|
||||
default:
|
||||
ctx->flags_match |= FEMR_NOT_METADATA; break;
|
||||
//ntfs_log_error("Error reading inode %lld.\n", ctx->mft_num);
|
||||
//return -1;
|
||||
}
|
||||
|
||||
} else { // !in_use
|
||||
ntfs_attr *mft;
|
||||
|
||||
ctx->flags_match |= FEMR_NOT_IN_USE;
|
||||
|
||||
ctx->inode = calloc(1, sizeof(*ctx->inode));
|
||||
if (!ctx->inode) {
|
||||
ntfs_log_error("Out of memory. Aborting.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->inode->mft_no = ctx->mft_num;
|
||||
ctx->inode->vol = ctx->vol;
|
||||
ctx->inode->mrec = ntfs_malloc(ctx->vol->mft_record_size);
|
||||
if (!ctx->inode->mrec) {
|
||||
free(ctx->inode); // == ntfs_inode_close
|
||||
return -1;
|
||||
}
|
||||
|
||||
mft = ntfs_attr_open(ctx->vol->mft_ni, AT_DATA,
|
||||
AT_UNNAMED, 0);
|
||||
if (!mft) {
|
||||
ntfs_log_perror("Couldn't open $MFT/$DATA");
|
||||
// free / close
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ntfs_attr_pread(mft, ctx->vol->mft_record_size * ctx->mft_num, ctx->vol->mft_record_size, ctx->inode->mrec) < ctx->vol->mft_record_size) {
|
||||
ntfs_log_perror("Couldn't read MFT Record %llu",
|
||||
(unsigned long long) ctx->mft_num);
|
||||
// free / close
|
||||
ntfs_attr_close(mft);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntfs_attr_close(mft);
|
||||
}
|
||||
|
||||
if (ctx->flags_match & ctx->flags_search) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ntfs_inode_close(ctx->inode)) {
|
||||
ntfs_log_error("Error closing inode %llu.\n",
|
||||
(unsigned long long)ctx->mft_num);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ctx->inode = NULL;
|
||||
}
|
||||
|
||||
return (ctx->inode == NULL);
|
||||
}
|
||||
|
||||
|
99
src/utils.h
Normal file
99
src/utils.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* utils.h - Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2005 Richard Russon
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
*
|
||||
* A set of shared functions for ntfs utilities
|
||||
*
|
||||
* 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 _NTFS_UTILS_H_
|
||||
#define _NTFS_UTILS_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
extern const char *ntfs_home;
|
||||
extern const char *ntfs_gpl;
|
||||
|
||||
int utils_set_locale(void);
|
||||
int utils_parse_size(const char *value, s64 *size, BOOL scale);
|
||||
int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale);
|
||||
int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize);
|
||||
int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int bufsize);
|
||||
int utils_cluster_in_use(ntfs_volume *vol, long long lcn);
|
||||
int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref);
|
||||
int utils_is_metadata(ntfs_inode *inode);
|
||||
void utils_dump_mem(void *buf, int start, int length, int flags);
|
||||
|
||||
ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
|
||||
ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft);
|
||||
|
||||
int utils_valid_device(const char *name, int force);
|
||||
ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force);
|
||||
|
||||
/**
|
||||
* defines...
|
||||
* if *not in use* then the other flags are ignored?
|
||||
*/
|
||||
#define FEMR_IN_USE (1 << 0)
|
||||
#define FEMR_NOT_IN_USE (1 << 1)
|
||||
#define FEMR_FILE (1 << 2) // $DATA
|
||||
#define FEMR_DIR (1 << 3) // $INDEX_ROOT, "$I30"
|
||||
#define FEMR_METADATA (1 << 4)
|
||||
#define FEMR_NOT_METADATA (1 << 5)
|
||||
#define FEMR_BASE_RECORD (1 << 6)
|
||||
#define FEMR_NOT_BASE_RECORD (1 << 7)
|
||||
#define FEMR_ALL_RECORDS 0xFF
|
||||
|
||||
/**
|
||||
* struct mft_search_ctx
|
||||
*/
|
||||
struct mft_search_ctx {
|
||||
int flags_search;
|
||||
int flags_match;
|
||||
ntfs_inode *inode;
|
||||
ntfs_volume *vol;
|
||||
u64 mft_num;
|
||||
};
|
||||
|
||||
struct mft_search_ctx * mft_get_search_ctx(ntfs_volume *vol);
|
||||
void mft_put_search_ctx(struct mft_search_ctx *ctx);
|
||||
int mft_next_record(struct mft_search_ctx *ctx);
|
||||
|
||||
// Flags for dump mem
|
||||
#define DM_DEFAULTS 0
|
||||
#define DM_NO_ASCII (1 << 0)
|
||||
#define DM_NO_DIVIDER (1 << 1)
|
||||
#define DM_INDENT (1 << 2)
|
||||
#define DM_RED (1 << 3)
|
||||
#define DM_GREEN (1 << 4)
|
||||
#define DM_BLUE (1 << 5)
|
||||
#define DM_BOLD (1 << 6)
|
||||
|
||||
#endif /* _NTFS_UTILS_H_ */
|
Loading…
Reference in New Issue
Block a user