initial CVS import

This commit is contained in:
szaka 2006-10-30 22:32:48 +00:00
commit ba63b7daca
69 changed files with 32454 additions and 0 deletions

38
CREDITS Normal file
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
SUBDIRS = ntfs-3g
MAINTAINERCLEANFILES = Makefile.in

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

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

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

File diff suppressed because it is too large Load Diff

315
libntfs-3g/attrlist.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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, &sect_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
View File

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

1655
libntfs-3g/dir.c Normal file

File diff suppressed because it is too large Load Diff

1836
libntfs-3g/index.c Normal file

File diff suppressed because it is too large Load Diff

1157
libntfs-3g/inode.c Normal file

File diff suppressed because it is too large Load Diff

858
libntfs-3g/lcnalloc.c Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

36
libntfs-3g/misc.c Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

340
libntfs-3g/security.c Normal file
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

1473
libntfs-3g/win32_io.c Normal file

File diff suppressed because it is too large Load Diff

50
src/Makefile.am Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

966
src/utils.c Normal file
View 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
View 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_ */