Merge remote branch 'linux-ntfs/libntfs-3g_port' into PERMISSION_HANDLING_BRANCH

Conflicts:
	AUTHORS
	COPYING
	CREDITS
	ChangeLog
	Makefile.am
	NEWS
	README
	autogen.sh
	configure.ac
	include/Makefile.am
This commit is contained in:
Erik Larsson 2010-12-13 14:49:39 +01:00
commit 02bab2956c
108 changed files with 52000 additions and 3 deletions

24
.cvsignore Normal file
View File

@ -0,0 +1,24 @@
Makefile
Makefile.in
aclocal.m4
autom4te.cache
conf.libgnutlstest
config.guess
config.h
config.h.in
config.log
config.status
config.sub
configure
libtool
ntfsprogs.spec
stamp-h1
depcomp
ltmain.sh
mkinstalldirs
compile
install-sh
stamp-h.in
ltconfig
missing
INSTALL

20
CREDITS
View File

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

View File

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

37
README
View File

@ -66,3 +66,40 @@ line at the END(!) of the /etc/fstab file:
/dev/sda1 /mnt/windows ntfs-3g defaults 0 0
NTFS UTILITIES
==============
The ntfsprogs includes utilities for doing all required tasks to NTFS
partitions. In general, just run a utility without any command line
options to display the version number and usage syntax.
The following utilities are so far implemented:
ntfsfix - Attempt to fix an NTFS partition and force Windows to check NTFS.
mkntfs - Format a partition with the NTFS filesystem. See man 8 mkntfs for
command line options.
ntfslabel - Display/change the label of an NTFS partition. See man 8 ntfslabel
for details.
ntfsundelete - Recover deleted files from an NTFS volume. See man 8
ntfsundelete for more details.
ntfsresize - Resize NTFS volumes. See man 8 ntfsresize for details.
ntfsclone - Efficiently create/restore an image of an NTFS partition. See
man 8 ntfsclone for details.
ntfscluster - Locate the owner of any given sector or cluster on an NTFS
partition. See man 8 ntfscluster for details.
ntfsinfo - Show some information about an NTFS partition or one of the files
or directories within it. See man 8 ntfsinfo for details.
ntfsls - List information about files in a directory residing on an NTFS
partition. See man 8 ntfsls for details.
ntfscat - Concatenate files and print their contents on the standard output.
ntfscp - Overwrite files on an NTFS partition.

11
TODO.include Normal file
View File

@ -0,0 +1,11 @@
Add usnjrnl.h (copy from kernel driver):
- describe the $UsnJrnl on disk structures
Finish logfile.h: in particular, add:
- more about the $LogFile on disk structures
Remove ifdef HAVE_CONFIG_H and make config.h compulsory. Further, place
config.h in include/ntfs/config.h at least when distributing (make install,
make dist, make rpm).

65
TODO.libntfs Normal file
View File

@ -0,0 +1,65 @@
********************
* libntfs-gnomevfs *
********************
- be generic filter: provide ntfs_device_operations from parent GnomeVFSHandle
***********
* libntfs *
***********
*****************
* HIGH priority *
*****************
- complete ntfs_index_{add_filename,rm}
- move ntfsdecrypt to library.
- complete the implementation of ntfs_attr_truncate() (for compressed files)
- add write of compressed attributes
- detect presence of usnjrnl and if present and mounting rw, re-stamp it (see
current ntfs driver for example in 2.6.15 kernel)
- fix support for large sector sizes by changing the logical device block size
to the sector size in the ntfs volume (it ought to work without doing this as
we do byte-aligned i/o anyway) but it would be good to change in case a
previous mount left the block size to larger value and we expect 512 bytes as
that would be incredibly inefficient
*******************
* MEDIUM priority *
*******************
- create API reference book template (cf. linux kernel)
- enable automatic creation of API reference
- ntfs_index_add_filename to more generic ntfs_index_add
- write API for conventional high level file access.
- implement loads of utilities a-la ntfsrm, ntfsmkdir, etc...
- implement an ntfs shell where can use the above much faster with caching,
probably extending the library in the process
****************
* LOW priority *
****************
- Do we attach attributes (ntfs_attr) to the corresponding ntfs_inode? Now we
just atach the inode to the attribute and expect the user to not shoot
themselves in the foot.
- add ACL read/write support to library
- add MS BackupAPI to library
- add volume resizing support to library
- add defrag API to library
- write utilities for all of the above

128
TODO.ntfsprogs Normal file
View File

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

View File

@ -3,6 +3,7 @@
# compilation.
#
# Copyright (c) 2000-2006 Anton Altaparmakov
# Copyright (c) 2003 Jan Kratochvil
# Copyright (c) 2005-2009 Szabolcs Szakacsits
# Copyright (C) 2007-2008 Alon Bar-Lev
#
@ -127,6 +128,12 @@ AC_ARG_ENABLE(
[enable_device_default_io_ops="yes"]
)
AC_ARG_ENABLE(crypto,
AS_HELP_STRING(--enable-crypto,enable crypto related code and utilities
(default=no)), ,
enable_crypto=no
)
AC_ARG_ENABLE(
[nfconv],
[AS_HELP_STRING([--disable-nfconv],[disable the 'nfconv' patch, which adds support for Unicode normalization form conversion when built on Mac OS X @<:@default=enabled for Mac OS X@:>@])],
@ -153,6 +160,9 @@ ifdef(
[AC_PROG_LIBTOOL]
)
AC_PROG_INSTALL
PKG_PROG_PKG_CONFIG
AC_PATH_PROG([MV], [mv])
AC_PATH_PROG([RM], [rm])
AC_PATH_PROG([SED], [sed])
@ -256,6 +266,41 @@ else
FUSE_LIB_PATH=`$PKG_CONFIG --libs-only-L fuse | sed -e 's,/[/]*,/,g' -e 's,[ ]*$,,'`
fi
# Autodetect whether we can build crypto stuff or not.
compile_crypto=false
if test "$enable_crypto" != "no"; then
have_libgcrypt=false
AM_PATH_LIBGCRYPT(1.2.0, [ have_libgcrypt=true ],
[
if test "$enable_crypto" = "yes"; then
AC_MSG_ERROR([ntfsprogs crypto code requires the gcrypt library.])
else
AC_MSG_WARN([ntfsprogs crypto code requires the gcrypt library.])
fi
])
have_libgnutls=false
PKG_CHECK_MODULES(GNUTLS_MODULE, gnutls >= 1.2.8, [ have_libgnutls=true ],
[
if test "$enable_crypto" = "yes"; then
AC_MSG_ERROR([ntfsprogs crypto code requires the gnutls library.])
else
AC_MSG_WARN([ntfsprogs crypto code requires the gnutls library.])
fi
])
if test "$have_libgcrypt" = "true"; then
if test "$have_libgnutls" = "true"; then
compile_crypto=true
fi
fi
fi
AM_CONDITIONAL(ENABLE_CRYPTO, $compile_crypto)
# add --with-extra-includes and --with-extra-libs switch to ./configure
all_libraries="$all_libraries $USER_LDFLAGS"
all_includes="$all_includes $USER_INCLUDES"
AC_SUBST(all_includes)
AC_SUBST(all_libraries)
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
@ -264,7 +309,7 @@ AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
endian.h byteswap.h sys/byteorder.h sys/endian.h sys/param.h \
sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h sys/vfs.h \
sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h linux/hdreg.h \
machine/endian.h windows.h syslog.h])
machine/endian.h gcrypt.h windows.h gnutls/pkcs12.h syslog.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
@ -280,6 +325,7 @@ AC_C_BIGENDIAN(
]
,
)
AC_C_CONST
AC_C_INLINE
AC_TYPE_OFF_T
AC_TYPE_SIZE_T
@ -413,13 +459,29 @@ fi
# generate files
AC_CONFIG_FILES([
Makefile
doc/Makefile
include/Makefile
include/fuse-lite/Makefile
include/ntfs/Makefile
include/ntfs-3g/Makefile
libfuse-lite/Makefile
libntfs-3g/Makefile
libntfs-3g/libntfs-3g.pc
libntfs-3g/libntfs-3g.script.so
ntfsprogs/Makefile
ntfsprogs/mkntfs.8
ntfsprogs/ntfscat.8
ntfsprogs/ntfsclone.8
ntfsprogs/ntfscluster.8
ntfsprogs/ntfscmp.8
ntfsprogs/ntfscp.8
ntfsprogs/ntfsfix.8
ntfsprogs/ntfsinfo.8
ntfsprogs/ntfslabel.8
ntfsprogs/ntfsls.8
ntfsprogs/ntfsprogs.8
ntfsprogs/ntfsresize.8
ntfsprogs/ntfsundelete.8
src/Makefile
src/ntfs-3g.8
src/ntfs-3g.probe.8

2
doc/.cvsignore Normal file
View File

@ -0,0 +1,2 @@
Makefile
Makefile.in

24
doc/CodingStyle Normal file
View File

@ -0,0 +1,24 @@
The standard K&R coding style is used in this project and the guidelines
outlined in the Linux kernel CodingStyle document (found in the latest Linux
kernel main directory in Documentation/CodingStyle) should be adhered to as
strictly as possible.
Special notes:
Capitals are used when declaring NTFS on-disk structures which you
can't just go ahead modifying without getting killed (in a bug sense,
not literally...). In memory structures are named with lower case as
usual.
For styles that are not explicitly defined in the document or in the
kernel one, check/read the kernel and/or libntfs source. Some parts
of the kernel might use unwanted coding styles but usually, e.g.
linux/kernel/*
has what Linus prefers/writes and most developers follow.
The latest Linux kernel contains the script Lindent in the scripts/
directory which formats the source the most preferred way. Moreover,
the below patch will be applied to the official kernel tree as well:
http://lkml.org/lkml/2004/1/30/180
Check indent(1) for what the used/unused (default) parameters mean.

12
doc/Makefile.am Normal file
View File

@ -0,0 +1,12 @@
EXTRA_DIST = \
CodingStyle \
attribute_definitions \
attributes.txt \
compression.txt \
template.c \
template.h \
tunable_settings \
system_files.txt \
system_security_descriptors.txt
MAINTAINERCLEANFILES = Makefile.in

129
doc/attribute_definitions Normal file
View File

@ -0,0 +1,129 @@
/* All values are as in Windows NT4 SP6a. */
__u16 name[64] = "$STANDARD_INFORMATION"
__u32 type = 0x10
__u32 unknown[2] = 0, 0
__u32 flags = 0x40
__u64 min_size = 0x30
__u64 max_size = 0x30, in Win2k: 0x48
__u16 name[64] = "$ATTRIBUTE_LIST"
__u32 type = 0x20
__u32 unknown[2] = 0, 0
__u32 flags = 0x80
__u64 min_size = 0
__u64 max_size = -1
__u16 name[64] = "$FILE_NAME"
__u32 type = 0x30
__u32 unknown[2] = 0, 0
__u32 flags = 0x42
__u64 min_size = 0x44
__u64 max_size = 0x242
/* The $volume_version attribute has never been observed in the field. It
* probably never was used and was hence replaced by the $object_id in
* Windows 2000. */
__u16 name[64] = "$VOLUME_VERSION" in Win2k: "$OBJECT_ID"
__u32 type = 0x40
__u32 unknown[2] = 0, 0
__u32 flags = 0x40
__u64 min_size = 0x8 in Win2k: 0
__u64 max_size = 0x8 in Win2k: 0x100
__u16 name[64] = "$SECURITY_DESCRIPTOR"
__u32 type = 0x50
__u32 unknown[2] = 0, 0
__u32 flags = 0x80
__u64 min_size = 0
__u64 max_size = -1
__u16 name[64] = "$VOLUME_NAME"
__u32 type = 0x60
__u32 unknown[2] = 0,0
__u32 flags = 0x40
__u64 min_size = 0x2
__u64 max_size = 0x100
__u16 name[64] = "$VOLUME_INFORMATION"
__u32 type = 0x70
__u32 unknown[2] = 0, 0
__u32 flags = 0x40
__u64 min_size = 0xc
__u64 max_size = 0xc
__u16 name[64] = "$DATA"
__u32 type = 0x80
__u32 unknown[2] = 0, 0
__u32 flags = 0
__u64 min_size = 0
__u64 max_size = -1
__u16 name[64] = "$INDEX_ROOT"
__u32 type = 0x90
__u32 unknown[2] = 0, 0
__u32 flags = 0x40
__u64 min_size = 0
__u64 max_size = -1
__u16 name[64] = "$INDEX_ALLOCATION"
__u32 type = 0xa0
__u32 unknown[2] = 0,0
__u32 flags = 0x80
__u64 min_size = 0
__u64 max_size = -1
__u16 name[64] = "$BITMAP"
__u32 type = 0xb0
__u32 unknown[2] = 0, 0
__u32 flags = 0x80
__u64 min_size = 0
__u64 max_size = -1
/* The $symbolic_link attribute has never been observed in the field. It
* probably never was used and was hence replaced by the $reparse_point in
* Windows 2000. */
__u16 name[64] = "$SYMBOLIC_LINK" in Win2k: "$REPARSE_POINT"
__u32 type = 0xc0
__u32 unknown[2] = 0, 0
__u32 flags = 0x80
__u64 min_size = 0
__u64 max_size = -1 in Win2k: 0x4000
__u16 name[64] = "$EA_INFORMATION"
__u32 type = 0xd0
__u32 unknown[2] = 0, 0
__u32 flags = 0x40
__u64 min_size = 0x8
__u64 max_size = 0x8
__u16 name[64] = "$EA"
__u32 type = 0xe0
__u32 unknown[2] = 0, 0
__u32 flags = 0
__u64 min_size = 0
__u64 max_size = 0x10000
/*
* Sequence terminates here with a record all of whose fields are zero, even
* though the size of the $AttrDef data attribute is much larger (36000 bytes,
* i.e. in theory 225 attribute definitions of 160 bytes each but in practice
* only until we reach an all zero record).
*
* The following only applies to Windows 2000 and replaces the above comment.
*/
__u16 name[64] = "$LOGGED_UTILITY_STREAM"
__u32 type = 0x100
__u32 unknown[2] = 0, 0
__u32 flags = 0x80
__u64 min_size = 0
__u64 max_size = 0x10000
/*
* This is terminated by a single record all of whose fields are zero. This
* also finishes the $AttrDef data attribute, i.e. the attribute size is the
* correct size of the sequence of attribute definitions (2560 bytes, i.e.
* 16 attribute definitions of 160 bytes each).
*/

111
doc/attributes.txt Normal file
View File

@ -0,0 +1,111 @@
Notes on the storage of attributes.
===================================
Resident attributes
===================
Resident attributes are small enough to be stored in the mft record itself.
When an attribute becomes too big to fit in the mft record or when the number
of attributes grows so large that there is no more space in the mft record, the
largest attribute(s) is(are) made non-resident. (Note, that some attributes
cannot be non-resident.)
Non-resident attributes
=======================
Non-resident attributes contain only their non-resident attribute header in the
mft record and the actual attribute value is stored anywhere on the volume
(but not in other mft records).
The value of the attribute is saved as a sequence of clusters, named virtual
clusters, beginning at virtual cluster number (vcn) zero. Each vcn corresponds
to a cluster on the volume, or a logical cluster number (lcn). The lcns on the
volume begin with lcn zero for the very first cluster on the volume.
The location of the attribute value is described by the mapping pairs array
present in the non-resident attribute header structure. The mapping pairs array
contains, in compressed form, the mapping between the attribute's vcns and the
corresponding lcns on the volume.
When the mapping pairs array of a non-resident attribute becomes too large to
fit in the mft record or when there are so many attributes in the mft record
that, even though all attributes that can be non-resident have been made
non-resident, they still do not fit in the mft record, the larger non-resident
attributes are moved away from the mft record to make space.
This is done by moving whole non-resident attribute header structures to other
mft records and/or by splitting the mapping pairs array of attributes into
several non-resident attribute headers, each containing a chunk of the
original mapping pairs array. These non-resident attribute headers each
describing the same attribute value (but different parts of it) are called
extents.
Attribute list attribute
========================
The attribute list attribute is then added to the base mft record to describe
the location of each attribute.
The attribute list attribute lists all attributes that belong to this mft
record (with the exception of itself). Each entry in the attribute list
describes the attribute listed and in which mft record its attribute header can
be found. For resident attributes this will be the same number as the base mft
record in which the attribute list attribute is located itself. For non-resident
attributes, this will be another mft record, called an extension mft record.
Naturally, all extension mft records point back to their base mft record.
Only one attribute is stored in an extension mft record, even if the attribute
is very small. At least this is the case with Windows NT4 SP6a driver.
Should the mapping pairs array of an attribute become so large as to not fit
into an extenstion mft record, even though its attribute is the only attribute
in this extension record, then the attribute is splitt into several extents.
The first extent starts at vcn 0 and has its lowest vcn value set to zero and
continues up to its highest vcn value. This is determined by splitting up the
mapping pairs array into chunks which just fit into an extension mft record
each. Thus the first mapping pairs array chunk will determine the value of
the highest vcn for the first extent. The attribute list will contain an entry
for this extent. Then, a second extent is created which has its lowest vcn
value set to the highest vcn of the previous extent + 1 and the next chunk of
the mapping pairs array is inserted into this extent. Again, an entry for this
extent is placed into the attribute list, and so on, until the whole
non-resident attribute's mapping pairs array has been accomodated.
Should the attribute list become too big to fit inside the base mft record it
is made non-resident. However, it's maximum value size is determined by the
Windows cache manager to be 256kb (the size of a VACB). Also, the mapping pairs
array of the attribute list has to fit inside the base mft record, as an
attribute list can't be described by itself and attribute lists are not allowed to be nested.
Compressed attributes
=====================
The attribute value of each $DATA attribute can be compressed to save space.
If this is the case, the ATTR_IS_COMPRESSED flag is set.
See the discussion on compression in include/attrib.h for more details.
FIXME: The discussion belongs here! (AIA)
Sparse attributes (NTFS 3.0+)
=============================
The attribute value of each $DATA attribute can be sparse to save space.
If this is the case, the ATTR_IS_SPARSE flag is set. Note, that compressed
attributes are by definition sparse, as well as compressed, without having the
ATTR_IS_SPARSE flag set.
See the discussion on compression in include/attrib.h for more details.
FIXME: The discussion belongs here! (AIA)
Encrypted attributes (NTFS 3.0+)
================================
Since NTFS 3.0, the attribute value of each $DATA attribute can be encrypted,
to protect the contents from spying eyes. If this is the case, the
ATTR_IS_ENCRYPTED flag is set.
FIXME: Write notes on attribute encryption. The discussions from the articles
"Inside the Encrypting File System" in Windows NT magazine (?) are very good
starting points. (AIA)

153
doc/compression.txt Normal file
View File

@ -0,0 +1,153 @@
Description of the NTFS (de)compression algorithm (based on a modified LZ77
algorithm)
Copyright (c) 2001 Anton Altaparmakov
This document is published under the GNU General Public License.
Credits: This is based on notes taken from various places (most notably from
Regis Duchesne's NTFS documentation and from various LZ77 descriptions) and
further refined by looking at a few compressed streams to figure out some
uncertainties.
Note: You should also read the runlist description with regards to compression
in linux-ntfs/include/layout.h. Just search for "Attribute compression".
FIXME: Should merge the info from there into this document some time.
Compressed data is organized in logical "compression" blocks (cb). Each cb has
a size (cb_size) of 2^compression_unit clusters. In all versions of Windows,
NTFS (NT/2k/XP, NTFS 1.2-3.1), the only valid compression_unit is 4, IOW, each
cb is 2^4 = 16 clusters in size.
We detect and warn about a compression_unit != 4 but we try to decompress the
data anyway.
Compression is only supported for cluster sizes between 512 and 4096. Thus a
cb can be between 8 and 64kiB in size.
Each cb is independent of the other cbs and is thus the minimal unit we have
to parse even if we wanted to decompress only one byte.
Also, a cb can be totally uncompressed and this would be indicated as a sparse
cb in the runlist.
Thus, we need to look at the runlist of the compressed data stream, starting
at the beginning of the first cb overlapping @page. So we convert the page
offset into units of clusters (vcn), and round the vcn down to a mutliple of
cb_size clusters.
We then scan the runlist for the appropriate position. Based on what we find
there, we decide how to proceed.
If the cb is not compressed at all, and covers the whole of @page, we pretend
to be accessing an uncompressed file, so we fall back to what we do in
aops.c::ntfs_file_readpage(), i.e. we do:
return block_read_full_page(page, ntfs_file_get_block);
If the cb is completely sparse, and covers the whole of @page, we can just
zero out @page and complete the io (set @page up-to-date, unlock it, and
finally return 0).
In all other cases we initiate the decompression engine, but first some more
on the compression algorithm.
Before compression the data of each cb is further divided into 4kiB blocks, we
call them "sub compression" blocks (sb), each including a header specifying
its compressed length. So we could just scan the cb for the first sb
overlapping @page and skip the sbs before that, or we could decompress the
whole cb injecting the superfluous decompressed pages into the page cache as a
form of read ahead (this is what zisofs does for example).
In either case, we then need to read and decompress all sbs overlapping @page,
potentially having to decompress one or more other cbs, too.
As soon as @page is completed we could either stop or continue until we finish
the current cb, injecting pages as we go along (again following the zisofs
example).
Because the sbs follow each other directly, we need to actually read in the
whole cb in order to be able to scan through the cb to find the first sb
overlapping @page, so it does make sense to follow the zisofs approach of
decompressing the whole cb and injecting pages as we go along. So all
discussion from now on will assume that we are going to do that. Although it
might make sense not to decompress any sbs locate before @page because this
would be a kind of "read-behind" which is probably silly, unless someone is
reading the file backwards. Performing read-ahead by decompressing all sbs
following @page OTOH, is very likely to be a good idea.
So, we read the whole cb from disk and start at the first sb.
As mentioned above, each sb is started with a header. The header is 16 bits of
which the lower twelve bits (i.e. bits 0 to 11) are the length (L) - 3 of the
sb (including the two bytes for the header itself, or L - 1 not counting the
two bytes for the header). The higher four bits are set to 1011 (0xb) by the
compressor for a compressed block, or to 0000 for an uncompressed block, but
the decompressor only checks the most significant bit taking a 1 to signify a
compressed block, and a 0 an uncompressed block.
So from the header we know how many compressed bytes we need to decompress to
obtain the next 4kiB of uncompressed data and if we didn't want to decompress
this sb we could just seek to the next next one using the length read from the
header. We could then continue seeking until we reach the first sb overlapping
@page.
In either case, we will reach a sb which we want to decompress.
Having dealt with the 16-bit header of the sb, we now have length bytes of
compressed data to decompress. This compressed stream is further split into
tokens which are organized into groups of eight tokens. Each token group (tg)
starts with a tag byte, which is an eight bit bitmap, the bits specifying the
type of each of the following eight tokens. The least significant bit (LSB)
corresponds to the first token and the most significant bit (MSB) corresponds
to the last token.
The two types of tokens are symbol tokens, specified by a zero bit, and phrase
tokens, specified by a set bit.
A symbol token (st) is a single byte and is to be taken literally and copied
into the sliding window (the decompressed data).
A phrase token (pt) is a pointer back into the sliding window (in bytes),
together with a length (again in bytes), starting at the byte the back pointer
is pointing to. Thus a phrase token defines a sequence of bytes in the sliding
window which need to be copied at the current position into the sliding window
(the decompressed data stream).
Each pt consists of 2 bytes split into the back pointer (p) and the length (l),
each of variable bit width (but the sum of the widths of p and l is fixed at
16 bits). p is at least 4 bits and l is at most 12 bits.
The most significant bits contain the back pointer (p), while the least
significant bits contain the length (l).
l is actually stored as the number of bytes minus 3 (unsigned) as anything
shorter than that would be at least as long as the 2 bytes needed for the
actual pt, so no compression would be achieved.
p is stored as the positive number of bytes minus 1 (unsigned) as going zero
bytes back is meaningless.
Note that decompression has to occur byte by byte, as it is possible that some
of the bytes pointed to by the pt will only be generated in the sliding window
as the byte sequence pointed to by the pt is being copied into it!
To give a concrete example: a block full of the letter A would be compressed
by storing the byte A once as a symbol token, followed by a single phrase
token with back pointer -1 (p = 0, therefore go back by -(0 + 1) bytes) and
length 4095 (l=0xffc, therefore length 0xffc + 3 bytes).
The widths of p and l are determined from the current position within the
decompressed data (cur_pos). We don't actually care about the widths as such
however, but instead we want the mask (l_mask) with which to AND the pt to
obtain l, and the number of bits (p_shift) by which to right shift the pt to
obtain p. These are determined using the following algorithm:
for (i = cur_pos, l_mask = 0xfff, p_shift = 12; i >= 0x10; i >>= 1) {
l_mask >>= 1;
p_shift--;
}
Note, that as usual in NTFS, the sb header, as well as each pt, are stored in
little endian format.

0
doc/encryption.txt Normal file
View File

41
doc/system_files.txt Normal file
View File

@ -0,0 +1,41 @@
System files mft record numbers. All these files are always marked as used
in the bitmap attribute of the mft; presumably in order to avoid accidental
allocation for random other mft records. Also, the sequence number for each
of the system files is always equal to their mft record number and it is
never modified. (Only $MFT has a sequence number of 1, rather than 0.)
FILE_$MFT = 0, /* Master file table (mft). Data attribute
contains the entries and bitmap attribute
records which ones are in use (bit==1). */
FILE_$MFTMirr = 1, /* Mft mirror (copy of first four mft records)
in data attribute. */
FILE_$LogFile = 2, /* Journalling log in data attribute. */
FILE_$Volume = 3, /* Volume name attribute and volume information
attribute (flags and ntfs version). Windows
refers to this file as volume DASD (Direct
Access Storage Device). */
FILE_$AttrDef = 4, /* Array of attribute definitions in data
attribute. */
FILE_$root = 5, /* Root directory. */
FILE_$Bitmap = 6, /* Allocation bitmap of all clusters (lcns) in
data attribute. */
FILE_$Boot = 7, /* Boot sector (always at cluster 0) in data
attribute. */
FILE_$BadClus = 8, /* Contains all bad clusters in the non-resident
data attribute. */
FILE_$Secure = 9, /* Shared security descriptors in data attribute
and two indexes into the descriptors.
Appeared in Windows 2000. Before that, this
file was named $Quota but was unused. */
FILE_$UpCase = 10, /* Uppercase equivalents of all 65536 Unicode
characters in data attribute. */
FILE_$Extend = 11, /* Directory containing other system files (eg.
$ObjId, $Quota, $Reparse and $UsnJrnl). This
is new to NTFS3.0. */
FILE_reserved12 = 12, /* Reserved for future use (records 12-15). */
FILE_reserved13 = 13,
FILE_reserved14 = 14,
FILE_reserved15 = 15,
FILE_first_user = 16, /* First user file, used as test limit for
whether to allow opening a file or not. */

View File

@ -0,0 +1,33 @@
$SD attribute value for the system files on an NTFS 1.2 volume:
$MFT, $MFTMirr, $LogFile, $AttrDef, $Bitmap, $Boot, $BadClus, and $UpCase:
sd: 1, 0, 0x8004, 0x00000048, 0x00000058, 0x00000000, 0x00000014;
sd.dacl.acl: 2, 0, 0x0034, 0x0002, 0x0000;
sd.dacl.acl.ace1: 0, 0, 0x0014, 0x00120089;
sd.dacl.acl.ace1.sid: 1, 1, 0, 0, 0, 0, 0, 5, 0x00000012;
sd.dacl.acl.ace2: 0, 0, 0x0018, 0x00120089;
sd.dacl.acl.ace2.sid: 1, 2, 0, 0, 0, 0, 0, 5, 0x00000020, 0x00000220;
sd.owner.sid: 1, 2, 0, 0, 0, 0, 0, 5, 0x00000020, 0x00000220;
sd.group.sid: 1, 2, 0, 0, 0, 0, 0, 5, 0x00000020, 0x00000220;
$Volume, $Quota, and system files 0xb-0xf:
sd: 1, 0, 0x8004, 0x00000048, 0x00000058, 0x00000000, 0x00000014;
sd.dacl.acl: 2, 0, 0x0034, 0x0002, 0x0000;
sd.dacl.acl.ace1: 0, 0, 0x0014, 0x0012019f;
sd.dacl.acl.ace1.sid: 1, 1, 0, 0, 0, 0, 0, 5, 0x00000012;
sd.dacl.acl.ace2: 0, 0, 0x0018, 0x0012019f;
sd.dacl.acl.ace2.sid: 1, 2, 0, 0, 0, 0, 0, 5, 0x00000020, 0x00000220;
sd.owner.sid: 1, 2, 0, 0, 0, 0, 0, 5, 0x00000020, 0x00000220;
sd.group.sid: 1, 2, 0, 0, 0, 0, 0, 5, 0x00000020, 0x00000220;
. (root directory)
sd: 1, 0, 0x8004, 0x00000030, 0x00000040, 0x00000000, 0x00000014;
sd.dacl.acl: 2, 0, 0x001c, 0x0001, 0x0000;
sd.dacl.acl.ace1: 0, 3, 0x0014, 0x001f01ff;
sd.dacl.acl.ace1.sid: 1, 1, 0, 0, 0, 0, 0, 1, 0x00000000;
sd.owner.sid: 1, 2, 0, 0, 0, 0, 0, 5, 0x00000020, 0x00000220;
sd.group.sid: 1, 2, 0, 0, 0, 0, 0, 5, 0x00000020, 0x00000220;

47
doc/template.c Normal file
View File

@ -0,0 +1,47 @@
const char *EXEC_NAME = "";
const char *EXEC_VERSION= "0.0.1";
/*
* EXEC_NAME - Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2004 Anton Altaparmakov
*
* Short description here.
*
* Anton Altaparmakov <aia21@cantab.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program (in the main directory of the Linux-NTFS distribution
* in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* WARNING: This program might not work on architectures which do not allow
* unaligned access. For those, the program would need to start using
* get/put_unaligned macros (#include <asm/unaligned.h>), but not doing it yet,
* since NTFS really mostly applies to ia32 only, which does allow unaligned
* accesses. We might not actually have a problem though, since the structs are
* defined as being packed so that might be enough for gcc to insert the
* correct code.
*
* If anyone using a non-little endian and/or an aligned access only CPU tries
* this program please let me know whether it works or not!
*
* Anton Altaparmakov <aia21@cantab.net>
*/
int main(int argc, char **argv)
{
return 0;
}

26
doc/template.h Normal file
View File

@ -0,0 +1,26 @@
/*
* NAME.h - Description. Part of 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef NTFS_NAME_H
#define NTFS_NAME_H
#endif /* defined NTFS_NAME_H */

31
doc/tunable_settings Normal file
View File

@ -0,0 +1,31 @@
The following settings can be tuned in Windows NT in the registry under the key
\Registry\Machine\System\CurrentControlSet\Control\FileSystem.
NtfsDisable8dot3NameCreation default is to enable 8.3 creation
NtfsAllowExtendedCharacterIn8dot3Name default is to disallow extended chars
NtfsDisableLastAccessUpdate default is enable the last acc. update
__u32 NtfsMftZoneReservation:
If not present set the variable _NtfsMftZoneMultiplier to 1.
If = 0 or > 4, again set the variable _NtfsMftZoneMultiplier to 1.
Otherwise, set the variable _NtfsMftZoneMultiplier to the value of
NtfsMftZoneReservation.
Value = Space % of volume reserved for MftZone
1 = 12.5%
2 = 25%
3 = 37.5%
4 = 50%
The zone multiplier is ONLY read accessed when mount_volume is called and
when deallocate_clusters is called.
The zone multiplier is ONLY write accessed when the driver initializes.
Win2k adds:
NtfsQuotaNotifyRate ?
NtfsEncryptionService ?

27
getgccver Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
if test -z "$1"; then
echo "This program is only to be run by the ./configure script."
exit 1
fi
# Get the gcc version. Can't do this in configure.ac as automake refuses to
# preserve the square brackets while generating the configure script.
ver_str=`$1 -dumpversion 2> /dev/null | head -n 1`
case $2 in
version)
echo ${ver_str}
;;
major)
echo `echo ${ver_str} | cut -d'.' -f1 | sed s/"^\([0-9]*\).*$"/"\1"/`
;;
minor)
echo `echo ${ver_str} | cut -d'.' -f2 | sed s/"^\([0-9]*\).*$"/"\1"/`
;;
*)
echo "This program is only to be run by the ./configure script."
exit 1
;;
esac
exit 0

2
include/.cvsignore Normal file
View File

@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@ -1,4 +1,4 @@
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
SUBDIRS = ntfs-3g fuse-lite
SUBDIRS = ntfs ntfs-3g fuse-lite

2
include/ntfs/.cvsignore Normal file
View File

@ -0,0 +1,2 @@
Makefile
Makefile.in

11
include/ntfs/Makefile.am Normal file
View File

@ -0,0 +1,11 @@
linux_ntfsincludedir = $(includedir)/ntfs
noinst_HEADERS = \
gnome-vfs-method.h \
gnome-vfs-module.h \
list.h \
rich.h \
tree.h
MAINTAINERCLEANFILES = Makefile.in

View File

@ -0,0 +1,43 @@
/*
* gnome-vfs-method.h - Export for Gnome-VFS init/shutdown implementation of
* interface to libntfs. Par of the Linux-NTFS project.
*
* Copyright (c) 2002-2003 Jan Kratochvil <project-captive@jankratochvil.net>
* 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_GNOME_VFS_METHOD_H
#define _NTFS_GNOME_VFS_METHOD_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <libgnomevfs/gnome-vfs-method.h>
G_BEGIN_DECLS
GnomeVFSMethod *libntfs_gnomevfs_method_init(const gchar *method_name,
const gchar *args);
void libntfs_gnomevfs_method_shutdown(void);
G_END_DECLS
#endif /* _NTFS_GNOME_VFS_METHOD_H */

View File

@ -0,0 +1,42 @@
/*
* gnome-vfs-module.h - Exports for Gnome-VFS init/shutdown implementation of
* interface to libntfs. Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
* 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_GNOME_VFS_MODULE_H
#define _NTFS_GNOME_VFS_MODULE_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
G_BEGIN_DECLS
G_LOCK_EXTERN(libntfs);
#define libntfs_newn(objp, n) ((objp) = g_new(typeof(*(objp)), (n)))
#define libntfs_new(objp) (libntfs_newn((objp), 1))
#define LIBNTFS_MEMZERO(objp) (memset((objp), 0, sizeof(*(objp))))
G_END_DECLS
#endif /* _NTFS_GNOME_VFS_MODULE_H */

192
include/ntfs/list.h Normal file
View File

@ -0,0 +1,192 @@
/*
* list.h - Linked list implementation. Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2002 Anton Altaparmakov and others
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_LIST_H
#define _NTFS_LIST_H
/**
* struct 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 __inline__ 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 __inline__ 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 */

40
include/ntfs/rich.h Normal file
View File

@ -0,0 +1,40 @@
/*
* rich.h - Temporary junk file. Part of the Linux-NTFS project.
*
* 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_RICH_H_
#define _NTFS_RICH_H_
#include "layout.h"
#include "attrib.h"
#include "bitmap.h"
#define ROUND_UP(num,bound) (((num)+((bound)-1)) & ~((bound)-1))
#define ROUND_DOWN(num,bound) ((num) & ~((bound)-1))
#define ATTR_SIZE(s) ROUND_UP(s,8)
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_free_non_residents3(struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_RECORD *attr);
int utils_free_non_residents2(ntfs_inode *inode, struct ntfs_bmp *bmp);
void ntfs_name_print(ntfschar *name, int name_len);
#endif /* _NTFS_RICH_H_ */

82
include/ntfs/tree.h Normal file
View File

@ -0,0 +1,82 @@
/*
* tree.h - Directory tree handling code. Part of the Linux-NTFS project.
*
* 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_TREE_H_
#define _NTFS_TREE_H_
#include "layout.h"
#include "volume.h"
struct ntfs_dir;
/**
* struct ntfs_dt -
*/
struct ntfs_dt {
struct ntfs_dir *dir;
struct ntfs_dt *parent;
u8 *data;
int data_len;
int child_count;
INDEX_ENTRY **children;
struct ntfs_dt **sub_nodes;
ntfs_inode **inodes;
VCN vcn;
INDEX_HEADER *header;
BOOL changed;
};
void ntfs_dt_free(struct ntfs_dt *dt);
int ntfs_dt_rollback(struct ntfs_dt *dt);
int ntfs_dt_commit(struct ntfs_dt *dt);
BOOL ntfs_dt_create_children2(struct ntfs_dt *dt, int count);
BOOL ntfs_dt_resize_children3(struct ntfs_dt *dt, int new);
int ntfs_dt_root_count(struct ntfs_dt *dt);
int ntfs_dt_alloc_count(struct ntfs_dt *dt);
int ntfs_dt_initialise2(ntfs_volume *vol, struct ntfs_dt *dt);
struct ntfs_dt * ntfs_dt_create(struct ntfs_dir *dir, struct ntfs_dt *parent, VCN vcn);
MFT_REF ntfs_dt_find(struct ntfs_dt *dt, ntfschar *name, int name_len);
struct ntfs_dt * ntfs_dt_find2(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num);
struct ntfs_dt * ntfs_dt_find3(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num);
struct ntfs_dt * ntfs_dt_find4(struct ntfs_dt *dt, ntfschar *name, int name_len, int *index_num);
void ntfs_dt_find_all(struct ntfs_dt *dt);
int ntfs_dt_find_parent(struct ntfs_dt *dt);
BOOL ntfs_dt_isroot(struct ntfs_dt *dt);
int ntfs_dt_root_freespace(struct ntfs_dt *dt);
int ntfs_dt_alloc_freespace(struct ntfs_dt *dt);
int ntfs_dt_transfer(struct ntfs_dt *old, struct ntfs_dt *new, int start, int count);
int ntfs_dt_alloc_insert(struct ntfs_dt *dt, INDEX_ENTRY *first, int count);
INDEX_ENTRY * ntfs_dt_alloc_insert2(struct ntfs_dt *dt, int before, int count, int bytes);
int ntfs_dt_root_insert(struct ntfs_dt *dt, INDEX_ENTRY *first, int count);
int ntfs_dt_alloc_remove2(struct ntfs_dt *dt, int start, int count);
int ntfs_dt_root_remove2(struct ntfs_dt *dt, int start, int count);
int ntfs_dt_transfer2(struct ntfs_dt *old, struct ntfs_dt *new, int start, int count);
int ntfs_dt_root_replace(struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie);
BOOL ntfs_dt_alloc_replace(struct ntfs_dt *del, int del_num, INDEX_ENTRY *del_ie, INDEX_ENTRY *suc_ie);
BOOL ntfs_dt_root_remove(struct ntfs_dt *del, int del_num);
BOOL ntfs_dt_alloc_remove(struct ntfs_dt *del, int del_num);
int ntfs_dt_alloc_add(struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child);
int ntfs_dt_root_add(struct ntfs_dt *parent, int index_num, INDEX_ENTRY *ie, struct ntfs_dt *child);
int ntfs_dt_add2(INDEX_ENTRY *ie, struct ntfs_dt *suc, int suc_num, struct ntfs_dt *ded);
#endif /* _NTFS_TREE_H_ */

9
libntfs/.cvsignore Normal file
View File

@ -0,0 +1,9 @@
.deps
.libs
Makefile
Makefile.in
libntfs-gnomevfs.8
libntfs-gnomevfs.la
libntfs.conf
libntfs.la
*.lo

59
libntfs/Makefile.am Normal file
View File

@ -0,0 +1,59 @@
#
# 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
#
# For LTVERSION_LIBNTFS see configure.ac!
LTVERSION_LIBNTFS_GNOMEVFS = 1:0:0
linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs
if ENABLE_GNOME_VFS
gnomevfsmoduleslibdir = $(libdir)/gnome-vfs-2.0/modules
gnomevfsmoduleslib_LTLIBRARIES = libntfs-gnomevfs.la
gnomevfsmodulesconfdir = $(sysconfdir)/gnome-vfs-2.0/modules
gnomevfsmodulesconf_DATA = libntfs.conf
endif
libntfs_gnomevfs_la_LDFLAGS = -version-info $(LTVERSION_LIBNTFS_GNOMEVFS)
libntfs_gnomevfs_la_LIBS = $(NTFS_3G_MODULE_LIBS) $(LIBNTFS_GNOMEVFS_LIBS)
libntfs_gnomevfs_la_CFLAGS = $(NTFS_3G_MODULE_CFLAGS) $(LIBNTFS_GNOMEVFS_CFLAGS)
libntfs_gnomevfs_la_SOURCES = \
gnome-vfs-method.c \
gnome-vfs-module.c
man_MANS = libntfs-gnomevfs.8
AM_CPPFLAGS = $(linux_ntfsincludedir) $(all_includes)
EXTRA_DIST = libntfs.conf.in
MAINTAINERCLEANFILES = Makefile.in
libs: $(lib_LTLIBRARIES)

888
libntfs/gnome-vfs-method.c Normal file
View File

@ -0,0 +1,888 @@
/*
* gnome-vfs-method.c - Gnome-VFS init/shutdown implementation of interface to
* libntfs. Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
* Copyright (c) 2003-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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#undef FALSE
#undef TRUE
#include <ntfs-3g/types.h> /* for 'FALSE'/'TRUE' libntfs definition */
#define FALSE FALSE
#define TRUE TRUE
#include "gnome-vfs-method.h" /* self */
#include <libgnomevfs/gnome-vfs-method.h>
#include <glib/gmessages.h>
#include "gnome-vfs-module.h"
#include <glib/ghash.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <libgnomevfs/gnome-vfs-utils.h>
#include <ntfs-3g/volume.h>
#include <ntfs-3g/dir.h>
static GnomeVFSMethod GnomeVFSMethod_static;
G_LOCK_DEFINE_STATIC(GnomeVFSMethod_static);
/* map: (gchar *)method_name -> (struct method_name_info *) */
static GHashTable *method_name_hash;
G_LOCK_DEFINE_STATIC(method_name_hash);
struct method_name_info {
gchar *args;
};
static void method_name_hash_key_destroy_func(gchar *key)
{
g_return_if_fail(key != NULL);
g_free(key);
}
static void method_name_hash_value_destroy_func(struct method_name_info *value)
{
g_return_if_fail(value != NULL);
g_free(value->args);
g_free(value);
}
static void method_name_hash_init(void)
{
G_LOCK(method_name_hash);
if (!method_name_hash) {
method_name_hash = g_hash_table_new_full(
g_str_hash, /* hash_func */
g_str_equal, /* key_equal_func */
(GDestroyNotify) method_name_hash_key_destroy_func, /* key_destroy_func */
(GDestroyNotify) method_name_hash_value_destroy_func); /* value_destroy_func */
}
G_UNLOCK(method_name_hash);
}
/*
* map: (gchar *)uri_parent_string "method_name:uri_parent" -> (ntfs_volume *)
*/
static GHashTable *uri_parent_string_hash;
G_LOCK_DEFINE_STATIC(uri_parent_string_hash);
static void uri_parent_string_hash_key_destroy_func(gchar *key)
{
g_return_if_fail(key != NULL);
g_free(key);
}
static void uri_parent_string_hash_value_destroy_func(ntfs_volume *value)
{
g_return_if_fail(value != NULL);
ntfs_umount( /* errors ignored */
value, /* vol */
TRUE); /* force; possibly loose modifications */
}
static void uri_parent_string_hash_init(void)
{
G_LOCK(uri_parent_string_hash);
if (!uri_parent_string_hash) {
uri_parent_string_hash = g_hash_table_new_full(
g_str_hash, /* hash_func */
g_str_equal, /* key_equal_func */
(GDestroyNotify) uri_parent_string_hash_key_destroy_func, /* key_destroy_func */
(GDestroyNotify) uri_parent_string_hash_value_destroy_func); /* value_destroy_func */
}
G_UNLOCK(uri_parent_string_hash);
}
static GnomeVFSResult libntfs_gnomevfs_uri_parent_init(
ntfs_volume **volume_return, GnomeVFSURI *uri)
{
gchar *uri_parent_string;
gchar *uri_parent_string_parent;
ntfs_volume *volume;
g_return_val_if_fail(uri != NULL, GNOME_VFS_ERROR_INVALID_URI);
g_return_val_if_fail(volume_return != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
uri_parent_string_hash_init();
if (!uri->parent)
return GNOME_VFS_ERROR_INVALID_URI;
if (!uri->text) /* not needed here but we don't permit non-specific fs-image reference */
return GNOME_VFS_ERROR_INVALID_URI;
uri_parent_string_parent = gnome_vfs_uri_to_string(uri->parent,
GNOME_VFS_URI_HIDE_NONE);
g_assert(uri_parent_string_parent != NULL);
uri_parent_string = g_strdup_printf("%s:%s", uri->method_string,
uri_parent_string_parent);
g_assert(uri_parent_string != NULL);
G_LOCK(uri_parent_string_hash);
volume = g_hash_table_lookup(uri_parent_string_hash, uri_parent_string);
G_UNLOCK(uri_parent_string_hash);
if (!volume) {
struct method_name_info *method_name_info;
G_LOCK(method_name_hash);
method_name_info = g_hash_table_lookup(method_name_hash,
uri->method_string);
G_UNLOCK(method_name_hash);
if (!method_name_info) {
/* should not happend */
g_return_val_if_reached(GNOME_VFS_ERROR_INVALID_URI);
}
/* TODO: Generic GnomeVFS filter. */
if (strcmp(uri->parent->method_string, "file")) {
g_free(uri_parent_string);
return GNOME_VFS_ERROR_INVALID_URI;
}
if (!(volume = ntfs_mount(uri->parent->text, MS_RDONLY))) {
g_free(uri_parent_string);
return GNOME_VFS_ERROR_WRONG_FORMAT;
}
G_LOCK(uri_parent_string_hash);
g_hash_table_insert(uri_parent_string_hash,
g_strdup(uri_parent_string), volume);
G_UNLOCK(uri_parent_string_hash);
}
g_free(uri_parent_string);
*volume_return = volume;
return GNOME_VFS_OK;
}
static GnomeVFSResult inode_open_by_pathname(ntfs_inode **inode_return,
ntfs_volume *volume, const gchar *pathname)
{
MFT_REF mref;
ntfs_inode *inode;
gchar *pathname_parse, *pathname_next;
int errint;
g_return_val_if_fail(inode_return != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(volume != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(pathname != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
pathname = g_path_skip_root(pathname);
pathname_parse = g_alloca(strlen(pathname) + 1);
strcpy(pathname_parse, pathname);
mref = FILE_root;
for (;;) {
ntfschar *pathname_parse_ucs2;
gchar *pathname_parse_unescaped;
int i;
G_LOCK(libntfs);
inode = ntfs_inode_open(volume, mref);
G_UNLOCK(libntfs);
if (!inode)
return GNOME_VFS_ERROR_NOT_FOUND;
if (!*pathname_parse) {
*inode_return = inode;
return GNOME_VFS_OK;
}
for (pathname_next = pathname_parse; *pathname_next &&
*pathname_next != G_DIR_SEPARATOR; pathname_next++) ;
if (*pathname_next) {
/* terminate current path element */
*pathname_next++ = '\0';
}
while (*pathname_next == G_DIR_SEPARATOR)
pathname_next++;
/* FIXME: Is 'pathname' utf8? */
pathname_parse_unescaped = gnome_vfs_unescape_string(
pathname_parse, NULL); /* illegal_characters */
libntfs_newn(pathname_parse_ucs2,
strlen(pathname_parse_unescaped) + 1);
for (i = 0; pathname_parse_unescaped[i]; i++)
pathname_parse_ucs2[i] = pathname_parse_unescaped[i];
pathname_parse_ucs2[i] = 0;
g_free(pathname_parse_unescaped);
G_LOCK(libntfs);
mref = ntfs_inode_lookup_by_name(inode, pathname_parse_ucs2, i);
G_UNLOCK(libntfs);
g_free(pathname_parse_ucs2);
if ((MFT_REF)-1 == mref)
return GNOME_VFS_ERROR_NOT_FOUND;
G_LOCK(libntfs);
errint = ntfs_inode_close(inode);
G_UNLOCK(libntfs);
if (errint)
g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
pathname_parse = pathname_next;
}
/* NOTREACHED */
}
struct libntfs_directory {
ntfs_inode *inode;
GList *file_info_list; /* of (GnomeVFSFileInfo *); last item has ->data == NULL */
};
static GnomeVFSResult libntfs_gnomevfs_open_directory(GnomeVFSMethod *method,
GnomeVFSMethodHandle **method_handle, GnomeVFSURI *uri,
GnomeVFSFileInfoOptions options __attribute__((unused)),
GnomeVFSContext *context __attribute__((unused)))
{
GnomeVFSResult errvfsresult;
ntfs_volume *volume;
ntfs_inode *inode;
struct libntfs_directory *libntfs_directory;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(method_handle != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
if (GNOME_VFS_OK != (errvfsresult =
libntfs_gnomevfs_uri_parent_init(&volume, uri)))
return errvfsresult;
if (GNOME_VFS_OK != (errvfsresult = inode_open_by_pathname(&inode,
volume, uri->text)))
return errvfsresult;
libntfs_new(libntfs_directory);
libntfs_directory->inode = inode;
libntfs_directory->file_info_list = NULL;
*method_handle = (GnomeVFSMethodHandle *)libntfs_directory;
return errvfsresult;
}
static GnomeVFSResult libntfs_gnomevfs_close_directory(GnomeVFSMethod *method,
GnomeVFSMethodHandle *method_handle,
GnomeVFSContext *context __attribute__((unused)))
{
struct libntfs_directory *libntfs_directory;
int errint;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
libntfs_directory = (struct libntfs_directory *)method_handle;
g_return_val_if_fail(libntfs_directory != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
G_LOCK(libntfs);
errint = ntfs_inode_close(libntfs_directory->inode);
G_UNLOCK(libntfs);
if (errint)
g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
if (libntfs_directory->file_info_list) {
GList *last_l;
/*
* Prevent gnome_vfs_file_info_list_free() and its
* gnome_vfs_file_info_unref() on the last 'file_info_list'
* items as it is EOF with NULL '->data'.
*/
last_l = g_list_last(libntfs_directory->file_info_list);
g_assert(last_l->data == NULL);
libntfs_directory->file_info_list = g_list_delete_link(
libntfs_directory->file_info_list, last_l);
gnome_vfs_file_info_list_free(
libntfs_directory->file_info_list);
}
g_free(libntfs_directory);
return GNOME_VFS_OK;
}
static gchar *libntfs_ntfscharo_utf8(const ntfschar *name, const int name_len)
{
GString *gstring;
int i;
gstring = g_string_sized_new(name_len);
for (i = 0; i < name_len; i++)
gstring = g_string_append_unichar(gstring, name[i]);
return g_string_free(gstring, /* returns utf8-formatted string */
FALSE); /* free_segment */
}
/*
* Do not lock 'libntfs' here as we are already locked inside ntfs_readdir().
*/
static int libntfs_gnomevfs_read_directory_filldir(
struct libntfs_directory *libntfs_directory /* dirent */,
const ntfschar *name, const int name_len,
const int name_type __attribute__((unused)),
const s64 pos, const MFT_REF mref, const unsigned dt_type)
{
GnomeVFSFileInfo *file_info;
g_return_val_if_fail(libntfs_directory != NULL, -1);
g_return_val_if_fail(name != NULL, -1);
g_return_val_if_fail(name_len >= 0, -1);
g_return_val_if_fail(pos >= 0, -1);
/* system directory; FIXME: What is its proper identification? */
if (name_len > 0 && name[0] == '$')
return 0; /* continue traversal */
file_info = gnome_vfs_file_info_new();
file_info->name = libntfs_ntfscharo_utf8(name, name_len);
file_info->valid_fields = 0;
switch (dt_type) {
case NTFS_DT_FIFO:
file_info->type = GNOME_VFS_FILE_TYPE_FIFO;
break;
case NTFS_DT_CHR:
file_info->type = GNOME_VFS_FILE_TYPE_CHARACTER_DEVICE;
break;
case NTFS_DT_DIR:
file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
break;
case NTFS_DT_BLK:
file_info->type = GNOME_VFS_FILE_TYPE_BLOCK_DEVICE;
break;
case NTFS_DT_REG:
file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
break;
case NTFS_DT_LNK:
file_info->type = GNOME_VFS_FILE_TYPE_SYMBOLIC_LINK;
break;
case NTFS_DT_SOCK:
file_info->type = GNOME_VFS_FILE_TYPE_SOCKET;
break;
/* FIXME: What is 'NTFS_DT_WHT'? */
default:
file_info->type = GNOME_VFS_FILE_TYPE_UNKNOWN;
}
if (file_info->type != GNOME_VFS_FILE_TYPE_UNKNOWN)
file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_TYPE;
/* Detect 'file_info->size': */
if (file_info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
ntfs_inode *inode;
inode = ntfs_inode_open(libntfs_directory->inode->vol, mref);
/* FIXME: Check failed 'inode' open. */
if (inode) {
ntfs_attr *attr;
int errint;
attr = ntfs_attr_open(inode, /* ni */
AT_DATA, /* type */
AT_UNNAMED, /* name */
0); /* name_len */
/* FIXME: Check failed 'attr' open. */
if (attr) {
/* FIXME: Is 'data_size' the right field? */
file_info->size = attr->data_size;
file_info->valid_fields |=
GNOME_VFS_FILE_INFO_FIELDS_SIZE;
ntfs_attr_close(attr);
}
errint = ntfs_inode_close(inode);
/* FIXME: Check 'errint'. */
}
}
libntfs_directory->file_info_list = g_list_prepend(
libntfs_directory->file_info_list, file_info);
return 0; /* continue traversal */
}
static GnomeVFSResult libntfs_gnomevfs_read_directory(GnomeVFSMethod *method,
GnomeVFSMethodHandle *method_handle,
GnomeVFSFileInfo *file_info,
GnomeVFSContext *context __attribute__((unused)))
{
GnomeVFSResult errvfsresult;
struct libntfs_directory *libntfs_directory;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
libntfs_directory = (struct libntfs_directory *)method_handle;
g_return_val_if_fail(libntfs_directory != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
if (!libntfs_directory->file_info_list) {
int errint;
s64 pos;
pos = 0; /* read from the start; incl. "." and ".." entries */
G_LOCK(libntfs);
errint = ntfs_readdir(libntfs_directory->inode, /* dir_ni */
&pos, /* pos */
libntfs_directory, /* dirent */
(ntfs_filldir_t)libntfs_gnomevfs_read_directory_filldir); /* filldir */
G_UNLOCK(libntfs);
if (errint)
return GNOME_VFS_ERROR_INTERNAL;
libntfs_directory->file_info_list = g_list_prepend(
libntfs_directory->file_info_list, NULL); /* EOF */
libntfs_directory->file_info_list = g_list_reverse(
libntfs_directory->file_info_list);
}
if (!libntfs_directory->file_info_list->data) {
g_assert(libntfs_directory->file_info_list->next == NULL);
/*
* Do not clear the list to leave us stuck at EOF - GnomeVFS
* behaves that way.
*/
errvfsresult = GNOME_VFS_ERROR_EOF;
} else {
/* Cut first list item. */
gnome_vfs_file_info_copy(file_info, /* dest */
libntfs_directory->file_info_list->data); /* src */
gnome_vfs_file_info_unref(
libntfs_directory->file_info_list->data);
libntfs_directory->file_info_list = g_list_delete_link(
libntfs_directory->file_info_list,
libntfs_directory->file_info_list);
errvfsresult = GNOME_VFS_OK;
}
return errvfsresult;
}
struct libntfs_file {
ntfs_inode *inode;
ntfs_attr *attr;
s64 pos;
};
static GnomeVFSResult libntfs_open_attr(struct libntfs_file *libntfs_file)
{
g_return_val_if_fail(libntfs_file != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(libntfs_file->inode != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
if (!libntfs_file->attr) {
G_LOCK(libntfs);
libntfs_file->attr = ntfs_attr_open(
libntfs_file->inode, /* ni */
AT_DATA, /* type */
AT_UNNAMED, /* name */
0); /* name_len */
G_UNLOCK(libntfs);
if (!libntfs_file->attr)
return GNOME_VFS_ERROR_BAD_FILE;
libntfs_file->pos = 0;
}
return GNOME_VFS_OK;
}
static GnomeVFSResult libntfs_gnomevfs_open(GnomeVFSMethod *method,
GnomeVFSMethodHandle **method_handle_return, GnomeVFSURI *uri,
GnomeVFSOpenMode mode,
GnomeVFSContext *context __attribute__((unused)))
{
GnomeVFSResult errvfsresult;
ntfs_volume *volume;
ntfs_inode *inode;
struct libntfs_file *libntfs_file;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(method_handle_return != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
if (GNOME_VFS_OK != (errvfsresult =
libntfs_gnomevfs_uri_parent_init(&volume, uri)))
return errvfsresult;
if (mode & GNOME_VFS_OPEN_WRITE)
return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
if (GNOME_VFS_OK != (errvfsresult =
inode_open_by_pathname(&inode, volume, uri->text)))
return errvfsresult;
libntfs_new(libntfs_file);
libntfs_file->inode = inode;
libntfs_file->attr = NULL;
*method_handle_return = (GnomeVFSMethodHandle *)libntfs_file;
return errvfsresult;
}
static GnomeVFSResult libntfs_gnomevfs_create(GnomeVFSMethod *method,
GnomeVFSMethodHandle **method_handle_return, GnomeVFSURI *uri,
GnomeVFSOpenMode mode __attribute__((unused)),
gboolean exclusive __attribute__((unused)),
guint perm __attribute__((unused)),
GnomeVFSContext *context __attribute__((unused)))
{
GnomeVFSResult errvfsresult;
ntfs_volume *volume;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(method_handle_return != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
if (GNOME_VFS_OK != (errvfsresult =
libntfs_gnomevfs_uri_parent_init(&volume, uri)))
return errvfsresult;
return GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM;
}
static GnomeVFSResult libntfs_gnomevfs_close(GnomeVFSMethod *method,
GnomeVFSMethodHandle *method_handle,
GnomeVFSContext *context __attribute__((unused)))
{
struct libntfs_file *libntfs_file;
int errint;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
libntfs_file = (struct libntfs_file *) method_handle;
g_return_val_if_fail(libntfs_file != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
if (libntfs_file->attr) {
G_LOCK(libntfs);
ntfs_attr_close(libntfs_file->attr);
G_UNLOCK(libntfs);
}
G_LOCK(libntfs);
errint = ntfs_inode_close(libntfs_file->inode);
G_UNLOCK(libntfs);
if (errint)
g_return_val_if_reached(GNOME_VFS_ERROR_INTERNAL);
g_free(libntfs_file);
return GNOME_VFS_OK;
}
static GnomeVFSResult libntfs_gnomevfs_read(GnomeVFSMethod *method,
GnomeVFSMethodHandle *method_handle, gpointer buffer,
GnomeVFSFileSize num_bytes, GnomeVFSFileSize *bytes_read_return,
GnomeVFSContext *context __attribute__((unused)))
{
GnomeVFSResult errvfsresult;
struct libntfs_file *libntfs_file;
s64 count_s64, got;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
libntfs_file = (struct libntfs_file *)method_handle;
g_return_val_if_fail(libntfs_file != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(buffer != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(bytes_read_return != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
return errvfsresult;
count_s64 = num_bytes;
g_assert((GnomeVFSFileSize)count_s64 == num_bytes);
G_LOCK(libntfs);
got = ntfs_attr_pread(libntfs_file->attr, libntfs_file->pos, count_s64,
buffer);
G_UNLOCK(libntfs);
if (got == -1)
return GNOME_VFS_ERROR_IO;
libntfs_file->pos += got;
*bytes_read_return = got;
g_assert((s64)*bytes_read_return == got);
return GNOME_VFS_OK;
}
static GnomeVFSResult libntfs_gnomevfs_seek(GnomeVFSMethod *method,
GnomeVFSMethodHandle *method_handle,
GnomeVFSSeekPosition whence, GnomeVFSFileOffset offset,
GnomeVFSContext *context __attribute__((unused)))
{
GnomeVFSResult errvfsresult;
struct libntfs_file *libntfs_file;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
libntfs_file = (struct libntfs_file *)method_handle;
g_return_val_if_fail(libntfs_file != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
return errvfsresult;
switch (whence) {
case GNOME_VFS_SEEK_START:
libntfs_file->pos = offset;
break;
case GNOME_VFS_SEEK_CURRENT:
libntfs_file->pos += offset;
break;
case GNOME_VFS_SEEK_END:
/* FIXME: NOT IMPLEMENTED YET */
g_return_val_if_reached(GNOME_VFS_ERROR_BAD_PARAMETERS);
default:
g_assert_not_reached();
}
return GNOME_VFS_OK;
}
static GnomeVFSResult libntfs_gnomevfs_tell(GnomeVFSMethod *method,
GnomeVFSMethodHandle *method_handle,
GnomeVFSFileSize *offset_return)
{
GnomeVFSResult errvfsresult;
struct libntfs_file *libntfs_file;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
libntfs_file = (struct libntfs_file *)method_handle;
g_return_val_if_fail(libntfs_file != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(offset_return != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file)))
return errvfsresult;
*offset_return = libntfs_file->pos;
g_assert((s64)*offset_return == libntfs_file->pos);
return errvfsresult;
}
static gboolean libntfs_gnomevfs_is_local(GnomeVFSMethod *method,
const GnomeVFSURI *uri)
{
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(uri != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
return gnome_vfs_uri_is_local(uri->parent);
}
static GnomeVFSResult libntfs_gnomevfs_get_file_info_from_handle(
GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle,
GnomeVFSFileInfo *file_info,
GnomeVFSFileInfoOptions options __attribute__((unused)),
GnomeVFSContext *context __attribute__((unused)))
{
GnomeVFSResult errvfsresult;
struct libntfs_file *libntfs_file;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
libntfs_file = (struct libntfs_file *)method_handle;
g_return_val_if_fail(libntfs_file != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
/* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
file_info->valid_fields = 0;
/* FIXME: It is complicated to read filename of open 'ntfs_inode'. */
file_info->name = NULL;
if (GNOME_VFS_OK != (errvfsresult = libntfs_open_attr(libntfs_file))) {
/* Assume we are directory: */
file_info->type = GNOME_VFS_FILE_TYPE_DIRECTORY;
/*
* Do not: file_info->valid_fields |=
* GNOME_VFS_FILE_INFO_FIELDS_TYPE;
* as gnome-vfs-xfer.c/copy_items() does not check
* 'GNOME_VFS_FILE_INFO_FIELDS_TYPE' and we are just bluffing
* we know it.
*/
return GNOME_VFS_OK;
}
/* FIXME: Is 'data_size' the right field? */
file_info->size = libntfs_file->attr->data_size;
file_info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE;
/*
* FIXME: We do not really know the type of 'libntfs_file' but
* gnome-vfs-xfer.c/copy_items() requires 'GNOME_VFS_FILE_TYPE_REGULAR'
* to copy it.
*/
file_info->type = GNOME_VFS_FILE_TYPE_REGULAR;
/*
* Do not: file_info->valid_fields|=GNOME_VFS_FILE_INFO_FIELDS_TYPE;
* as gnome-vfs-xfer.c/copy_items() does not check
* 'GNOME_VFS_FILE_INFO_FIELDS_TYPE' and we are just bluffing we know
* it.
*/
return errvfsresult;
}
static GnomeVFSResult libntfs_gnomevfs_get_file_info(GnomeVFSMethod *method,
GnomeVFSURI *uri, GnomeVFSFileInfo *file_info,
GnomeVFSFileInfoOptions options, GnomeVFSContext *context)
{
GnomeVFSResult errvfsresult;
GnomeVFSMethodHandle *method_handle;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(file_info != NULL, GNOME_VFS_ERROR_BAD_PARAMETERS);
/* handle 'options & GNOME_VFS_FILE_INFO_GET_MIME_TYPE'? */
if (GNOME_VFS_OK != (errvfsresult =
libntfs_gnomevfs_open(method, &method_handle, uri,
GNOME_VFS_OPEN_READ, context)))
return errvfsresult;
if (GNOME_VFS_OK != (errvfsresult =
libntfs_gnomevfs_get_file_info_from_handle(method,
method_handle, file_info, options, context)))
return errvfsresult;
if (GNOME_VFS_OK != (errvfsresult =
libntfs_gnomevfs_close(method, method_handle, context)))
return errvfsresult;
return GNOME_VFS_OK;
}
static GnomeVFSResult libntfs_gnomevfs_check_same_fs(GnomeVFSMethod *method,
GnomeVFSURI *a, GnomeVFSURI *b, gboolean *same_fs_return,
GnomeVFSContext *context __attribute__((unused)))
{
ntfs_volume *volume_a;
ntfs_volume *volume_b;
GnomeVFSResult errvfsresult;
g_return_val_if_fail(method == &GnomeVFSMethod_static,
GNOME_VFS_ERROR_BAD_PARAMETERS);
g_return_val_if_fail(same_fs_return != NULL,
GNOME_VFS_ERROR_BAD_PARAMETERS);
errvfsresult = libntfs_gnomevfs_uri_parent_init(&volume_a, a);
g_return_val_if_fail(errvfsresult == GNOME_VFS_OK, errvfsresult);
errvfsresult = libntfs_gnomevfs_uri_parent_init(&volume_b, b);
g_return_val_if_fail(errvfsresult == GNOME_VFS_OK, errvfsresult);
*same_fs_return = (volume_a == volume_b);
return GNOME_VFS_OK;
}
/**
* libntfs_gnomevfs_init:
*
* Returns: Initialized structure of #GnomeVFSMethod with static methods of
* libntfs-gnomevfs.
*/
GnomeVFSMethod *libntfs_gnomevfs_method_init(const gchar *method_name,
const gchar *args)
{
struct method_name_info *method_name_info;
g_return_val_if_fail(method_name != NULL, NULL);
/* 'args' may be NULL if not supplied. */
method_name_hash_init();
G_LOCK(method_name_hash);
method_name_info = g_hash_table_lookup(method_name_hash, method_name);
if (method_name_info && strcmp(method_name_info->args, args))
method_name_info = NULL;
G_UNLOCK(method_name_hash);
if (!method_name_info) {
libntfs_new(method_name_info);
method_name_info->args = g_strdup(args);
G_LOCK(method_name_hash);
g_hash_table_replace(method_name_hash, g_strdup(method_name),
method_name_info);
G_UNLOCK(method_name_hash);
}
G_LOCK(GnomeVFSMethod_static);
LIBNTFS_MEMZERO(&GnomeVFSMethod_static);
GnomeVFSMethod_static.method_table_size = sizeof(GnomeVFSMethod_static);
GnomeVFSMethod_static.open = libntfs_gnomevfs_open; /* mandatory */
GnomeVFSMethod_static.create = libntfs_gnomevfs_create; /* mandatory */
GnomeVFSMethod_static.close = libntfs_gnomevfs_close;
GnomeVFSMethod_static.read = libntfs_gnomevfs_read;
GnomeVFSMethod_static.seek = libntfs_gnomevfs_seek;
GnomeVFSMethod_static.tell = libntfs_gnomevfs_tell;
GnomeVFSMethod_static.open_directory = libntfs_gnomevfs_open_directory;
GnomeVFSMethod_static.close_directory =
libntfs_gnomevfs_close_directory;
GnomeVFSMethod_static.read_directory = libntfs_gnomevfs_read_directory;
GnomeVFSMethod_static.get_file_info =
libntfs_gnomevfs_get_file_info; /* mandatory */
GnomeVFSMethod_static.get_file_info_from_handle =
libntfs_gnomevfs_get_file_info_from_handle;
GnomeVFSMethod_static.is_local =
libntfs_gnomevfs_is_local; /* mandatory */
GnomeVFSMethod_static.check_same_fs = libntfs_gnomevfs_check_same_fs;
/* TODO: GnomeVFSMethodFindDirectoryFunc find_directory; */
/* TODO: GnomeVFSMethodFileControlFunc file_control; */
/* R/W: GnomeVFSMethodCreateSymbolicLinkFunc create_symbolic_link; */
/* R/W: GnomeVFSMethodMonitorAddFunc monitor_add; */
/* R/W: GnomeVFSMethodMonitorCancelFunc monitor_cancel; */
/* R/W: GnomeVFSMethod_static.write; */
/* R/W: GnomeVFSMethod_static.truncate_handle; */
/* R/W: GnomeVFSMethod_static.make_directory; */
/* R/W: GnomeVFSMethod_static.remove_directory; */
/* R/W: GnomeVFSMethod_static.move; */
/* R/W: GnomeVFSMethod_static.unlink; */
/* R/W: GnomeVFSMethod_static.set_file_info; */
/* R/W: GnomeVFSMethod_static.truncate; */
G_UNLOCK(GnomeVFSMethod_static);
return &GnomeVFSMethod_static;
}
/**
* libntfs_gnomevfs_method_shutdown:
*
* Shutdowns libntfs-gnomevfs successfuly flushing all caches.
*
* Sad note about gnome-vfs-2.1.5 is that it never calls this function. :-)
*/
void libntfs_gnomevfs_method_shutdown(void)
{
uri_parent_string_hash_init();
G_LOCK(uri_parent_string_hash);
g_hash_table_destroy(uri_parent_string_hash);
uri_parent_string_hash = NULL;
G_UNLOCK(uri_parent_string_hash);
method_name_hash_init();
G_LOCK(method_name_hash);
g_hash_table_destroy(method_name_hash);
method_name_hash = NULL;
G_UNLOCK(method_name_hash);
}

View File

@ -0,0 +1,77 @@
/*
* gnome-vfs-module.c - Gnome-VFS init/shutdown implementation of interface to
* libntfs. Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
* 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "gnome-vfs-method.h"
#include <libgnomevfs/gnome-vfs-module.h>
#include <glib/gmessages.h>
#include <glib/gutils.h> /* for g_atexit() */
/* Filesystem-module-scope lock for _any_ libntfs access. */
G_LOCK_DEFINE(libntfs);
static void vfs_module_shutdown_atexit(void);
/**
* vfs_module_init:
* @method_name: FIXME
* @args: FIXME
*
* FIXME
*
* Returns: FIXME
*/
GnomeVFSMethod *vfs_module_init(const char *method_name, const char *args)
{
GnomeVFSMethod *libntfs_gnomevfs_method_ptr;
g_return_val_if_fail(method_name != NULL, NULL);
/* 'args' may be NULL if not supplied. */
libntfs_gnomevfs_method_ptr = libntfs_gnomevfs_method_init(method_name,
args);
g_atexit(vfs_module_shutdown_atexit);
return libntfs_gnomevfs_method_ptr;
}
/**
* vfs_module_shutdown:
*/
void vfs_module_shutdown(GnomeVFSMethod *method __attribute__((unused)))
{
/*
* 'method' may be NULL if we are called from
* vfs_module_shutdown_atexit().
*/
libntfs_gnomevfs_method_shutdown();
}
static void vfs_module_shutdown_atexit(void)
{
vfs_module_shutdown(NULL);
}

View File

@ -0,0 +1,110 @@
.\" -*- nroff -*-
.\" Copyright (c) 2003 Anton Altaparmakov. All Rights Reserved.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSPROGS 8 "November 2003" "Linux-NTFS version @VERSION@"
.SH NAME
libntfs-gnomevfs \- Module for GNOME VFS that allows access to NTFS filesystems.
.SH OVERVIEW
The GNOME virtual filesystem (VFS) provides universal access to different filesystems.
The
.BR libntfs-gnomevfs
module enables GNOME VFS aware clients to seamlessly utilize the NTFS library
.BR libntfs-3g .
So you can access an NTFS filesystem without needing to use the NTFS utilities themselves
(at least in theory anyway). In practice this is probably more useful for programs and
programmers to make using
.BR libntfs-3g
easier, more generic, and to allow easier debugging of
.BR libntfs-3g .
.SH Examples
.SS Prerequisites
.PP
To be able to follow these examples you will need to have installed the test utilities
from the gnome-vfs-2.4.x package. The easiest way to do this is to download and compile
the gnome-vfs-2 package, e.g. download from:
http://ftp.gnome.org/pub/GNOME/desktop/2.4/2.4.0/sources/gnome-vfs-2.4.0.tar.gz
Then run ./configure followed by make and make install (as root). This will install
it into /usr/local so it should not conflict with your existing installation from
rpm or deb packages which will be in /usr.
Note you may also need to add /usr/local/lib to /etc/ld.so.conf and then run ldconfig
(as root) to let your system see the installed gnome-vfs-2.4.x libraries.
Then run ./configure followed by make and make install (as root) in the main
.BR ntfsprogs
directory to build and install the
.BR libntfs-gnomevfs
module.
.SS Copying a file from an NTFS partition
.PP
To copy the file autoexec.bat from the main directory of an NTFS partition (/dev/hda1)
to the /tmp directory on your system you could run:
/path/to/gnome-vfs-2.4.x/test/test-xfer file:///dev/hda1#libntfs:/autoexec.bat /tmp/autoexec.bat
To copy a file from a directory inside the NTFS partition you would just specify the full path.
So for example to copy the file win.ini from the Windows directory you would run:
/path/to/gnome-vfs-2.4.x/test/test-xfer file:///dev/hda1#libntfs:/Windows/win.ini /tmp/win.ini
.SS Shell access to an NTFS partition
.PP
For debugging it is most useful to be able to do various things to the NTFS partition while it
is being operated upon by
.BR libntfs-3g .
This is achieved using the test-shell utility (from the gnome-vfs-2.4.x package) by running:
/path/to/gnome-vfs-2.4.x/test/test-shell
This drops you into the GNOME VFS shell from where you can now cd into the NTFS partition (/dev/hda1)
by typing: cd file:///dev/hda1#libntfs:/
You are now in the root directory of the NTFS partition. The first thing you will probably want to
do is to type "ls" to display the directory contents.
You could then change directories using the "cd" command, e.g. to enter the Windows directory you
would type: cd Windows
You can then open files, seek inside files, read from files (write is not enabled at present), etc
thus exercising large portions of the NTFS library.
Use the "help" command while in the shell to see the available commands.
.SH BUGS
.PP
No bugs are known but there are several limitations at the moment:
You cannot get information about files other than what the "ls" command
in the test-shell can give you, i.e. the "info" command in the test-shell
does not work.
Further access to the partition is read-only and hence you cannot write
to files. This will be changed in the future once the module has had
more wide testing.
There may be other limitations and possibly bugs. Please report any
problems to the NTFS mailing list: linux-ntfs-dev@lists.sourceforge.net
.SH AUTHORS
.PP
The
.BR libntfs-gnomevfs
module was written by Jan Kratochvil. This man page was written by Anton Altaparmakov.
.SH AVAILABILITY
The
.BR ntfsprogs
package which contains the
.BR libntfs-gnomevfs
module can be downloaded from http://www.linux-ntfs.org/content/view/19/37/
.BR
These manual pages can be viewed online at http://man.linux-ntfs.org/ntfsprogs.8.html
.SH SEE ALSO
.BR ntfsprogs (8)

0
libntfs/libntfs.conf.in Normal file
View File

215
libntfs/rich.c Normal file
View File

@ -0,0 +1,215 @@
/**
* rich.c - Temporary junk file. Part of the Linux-NTFS project.
*
* 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef NTFS_RICH
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include "rich.h"
#include "layout.h"
#include "logging.h"
/**
* 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;
}
ntfs_log_trace ("\n");
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;
}
ntfs_log_trace ("\n");
ctx = ntfs_attr_get_search_ctx(NULL, mft);
if (!ctx) {
//XXX 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;
}
/**
* ntfs_name_print - Send a Unicode name to the debug log
* @name:
* @name_len:
*
* Description...
*
* Returns:
*/
void ntfs_name_print(ntfschar *name, int name_len)
{
char *buffer = NULL;
if (name_len) {
ntfs_ucstombs(name, name_len, &buffer, 0);
ntfs_log_debug("%s", buffer);
free(buffer);
} else {
ntfs_log_debug("!");
}
}
/**
* utils_free_non_residents3 - Free all the non-resident attributes of an inode
* @bmp:
* @inode:
* @attr:
*
* Description...
*
* Returns:
*/
int utils_free_non_residents3(struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_RECORD *attr)
{
ntfs_attr *na;
runlist_element *rl;
LCN size;
LCN count;
if (!bmp)
return 1;
if (!inode)
return 1;
if (!attr)
return 1;
if (!attr->non_resident)
return 0;
ntfs_log_trace ("\n");
na = ntfs_attr_open(inode, attr->type, NULL, 0);
if (!na)
return 1;
ntfs_attr_map_whole_runlist(na);
rl = na->rl;
size = na->allocated_size >> inode->vol->cluster_size_bits;
for (count = 0; count < size; count += rl->length, rl++) {
if (ntfs_bmp_set_range(bmp, rl->lcn, rl->length, 0) < 0) {
ntfs_log_warning("set range : %lld - %lld FAILED\n", rl->lcn, rl->lcn+rl->length-1);
}
}
ntfs_attr_close(na);
return 0;
}
/**
* utils_free_non_residents2 - Find all the non-resident attributes of an inode
* @inode:
* @bmp:
*
* Description...
*
* Returns:
*/
int utils_free_non_residents2(ntfs_inode *inode, struct ntfs_bmp *bmp)
{
ntfs_attr_search_ctx *ctx;
if (!inode)
return -1;
if (!bmp)
return -1;
ntfs_log_trace ("\n");
ctx = ntfs_attr_get_search_ctx(NULL, inode->mrec);
if (!ctx) {
ntfs_log_info("can't create a search context\n");
return -1;
}
while (ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx) == 0) {
utils_free_non_residents3(bmp, inode, ctx->attr);
}
ntfs_attr_put_search_ctx(ctx);
return 0;
}
#endif /* NTFS_RICH */

2366
libntfs/tree.c Normal file

File diff suppressed because it is too large Load Diff

206
ntfsprogs.spec.in Normal file
View File

@ -0,0 +1,206 @@
%define name @PACKAGE@
%define ver @VERSION@
%define rel 1
%define prefix /usr
%define bindir /usr/bin
%define sbindir /usr/sbin
%define mandir /usr/share/man
Summary : NTFS filesystem libraries and utilities
Name : %{name}
Version : %{ver}
Release : %{rel}
Source : http://prdownloads.sf.net/linux-ntfs/ntfsprogs-%{ver}.tar.gz
Buildroot : %{_tmppath}/%{name}-root
Packager : Anton Altaparmakov <aia21@cantab.net>
License : GPL
Group : System Environment/Base
%description
The Linux-NTFS project (http://www.linux-ntfs.org/) aims to bring full support
for the NTFS filesystem to the Linux operating system. The ntfsprogs package
currently consists of a static library and utilities such as mkntfs, ntfscat,
ntfsls, ntfsresize, and ntfsundelete (for a full list of included utilities
see man 8 ntfsprogs after installation).
%package gnomevfs
Summary : NTFS GNOME virtual filesystem module
Group : System Environment/Base
Requires : ntfsprogs = %{ver}-%{rel}
BuildRequires : glib2-devel
Requires : glib2
BuildRequires : gnome-vfs2-devel
Requires : gnome-vfs2
%description gnomevfs
This package contains the NTFS GNOME virtual filesystem (VFS) module which
allows GNOME VFS clients to seamlessly utilize the NTFS library (libntfs).
%package fuse
Summary : NTFS FUSE module (ntfsmount)
Group : System Environment/Base
Requires : ntfsprogs = %{ver}-%{rel}
Requires : fuse >= 2.3.0
%description fuse
This package contains the ntfsmount utility which is an NTFS filesystem in
userspace (FUSE) module allowing users to mount an ntfs filesystem from
userspace and accessing it using the functionality provided by the NTFS
library (libntfs).
%package devel
Summary : files required to compile software that uses libntfs
Group : Development/System
Requires : ntfsprogs = %{ver}-%{rel}
%description devel
This package includes the header files and libraries needed to link software
with the NTFS library (libntfs).
%prep
%setup
%build
if [ -n "$LINGUAS" ]; then unset LINGUAS; fi
%configure --enable-gnome-vfs --enable-fuse-module
make
%install
rm -rf "$RPM_BUILD_ROOT"
make DESTDIR="$RPM_BUILD_ROOT" install-strip
%clean
rm -rf "$RPM_BUILD_ROOT"
%post
/sbin/ldconfig
%postun
/sbin/ldconfig
%files
%defattr(-,root,root)
%doc AUTHORS COPYING CREDITS ChangeLog INSTALL NEWS README TODO.include TODO.libntfs TODO.ntfsprogs doc/CodingStyle doc/attribute_definitions doc/attributes.txt doc/compression.txt doc/tunable_settings doc/template.c doc/template.h doc/system_files.txt doc/system_security_descriptors.txt
%{bindir}/ntfs[^m][^o]*
%{sbindir}/*
/sbin/mkfs.ntfs
%{mandir}/man8/mkntfs.8*
%{mandir}/man8/mkfs.ntfs.8*
%{mandir}/man8/ntfs[^m][^o]*.8*
%{_libdir}/libntfs.*so*
%files gnomevfs
%defattr(-,root,root)
%{mandir}/man8/libntfs-gnomevfs.8*
%{_libdir}/gnome-vfs-2.0/modules/libntfs-gnomevfs.*so*
%config %{_sysconfdir}/gnome-vfs-2.0/modules/libntfs.conf
%files fuse
%defattr(-,root,root)
%{bindir}/ntfsmount*
/sbin/mount.ntfs-fuse
%{mandir}/man8/ntfsmount.8*
%{mandir}/man8/mount.ntfs-fuse.8*
%files devel
%defattr(-,root,root)
%{_includedir}/*
%{_libdir}/libntfs.*a*
%{_libdir}/gnome-vfs-2.0/modules/libntfs-gnomevfs.*a*
%changelog
* Fri Oct 7 2005 Anton Altaparmakov <aia21@cantab.net>
- Fix the file distribution after new binaries have been added as they were
ending up in the wrong rpms.
* Mon Aug 15 2005 Szabolcs Szakacsits <szaka@sienet.hu>
- Add mkfs.ntfs.
* Mon Jul 18 2005 Anton Altaparmakov <aia21@cantab.net>
- Add ntfsmount fuse module in separate rpm ntfsprogs-fuse.
* Wed Mar 10 2004 Anton Altaparmakov <aia21@cantab.net>
- Cleanup descriptions ready for 1.9.0 release.
* Mon Jan 19 2004 Anton Altaparmakov <aia21@cantab.net>
- Add %config to tell rpm that libntfs.conf is a config file.
* Thu Nov 6 2003 Anton Altaparmakov <aia21@cantab.net>
- update description (it was getting too long)
- merge libntfs-gnomevfs
* Fri Oct 19 2003 Richard Russon <ntfs@flatcap.org>
- added the new utility ntfscat
* Tue Sep 30 2003 Anton Altaparmakov <aia21@cantab.net>
- added the new utilities, ntfsclone, ntfscluster, ntfsinfo, ntfsls.
* Sat Jan 18 2003 Anton Altaparmakov <aia21@cantab.net>
- renamed to ntfsprogs.spec.in
- change source tar ball name to ntfsprogs
* Tue Dec 10 2002 Anton Altaparmakov <aia21@cantab.net>
- added ntfsresize
* Wed Jul 18 2002 Richard Russon <ntfs@flatcap.org>
- added ntfsundelete
- change TODO names
* Wed Jul 3 2002 Anton Altaparmakov <aia21@cantab.net>
- update my email address
* Mon Jun 3 2002 Anton Altaparmakov <aia21@cam.ac.uk>
- update %doc with new TODO files
* Tue Apr 12 2002 Anton Altaparmakov <aia21@cam.ac.uk>
- update %description text for ntfslabel
* Tue Mar 12 2002 Anton Altaparmakov <aia21@cam.ac.uk>
- update %description text
* Sat Jan 26 2002 Anton Altaparmakov <aia21@cam.ac.uk>
- update %description text
- make dependencies pick the right version automatically
* Thu Jan 10 2002 Anton Altaparmakov <aia21@cam.ac.uk>
- add dependency on linux-ntfs to linux-ntfs-devel
- update %description text
* Fri Nov 09 2001 Anton Altaparmakov <aia21@cam.ac.uk>
- update %description text
- (re)enable installation of shared libraries
* Wed Aug 22 2001 Anton Altaparmakov <aia21@cam.ac.uk>
- update %description text
* Thu Aug 2 2001 Anton Altaparmakov <aia21@cam.ac.uk>
- update %description text
* Wed Jul 25 2001 Anton Altaparmakov <aia21@cam.ac.uk>
- include sbin install path (mkntfs now is in sbin)
* Tue Jul 24 2001 Anton Altaparmakov <aia21@cam.ac.uk>
- update %description text
* Mon Jun 11 2001 Anton Altaparmakov <aia21@cam.ac.uk>
- remove duplicate %configure options
- remove shared library installation as shared libraries are disabled by
default
* Sun Jun 10 2001 Anton Altaparmakov <aia21@cam.ac.uk>
- add man pages stuff
- update info text
- add new doc/ stuff
- modify installation to do install-strip instead of install followed by manual
stripping
- update download URL to be the fast sourceforge http download server
* Fri Feb 2 2001 Anton Altaparmakov <aia21@cam.ac.uk>
- started changelog

25
ntfsprogs/.cvsignore Normal file
View File

@ -0,0 +1,25 @@
.deps
.libs
Makefile
Makefile.in
mkntfs
ntfscat
ntfsclone
ntfscluster
ntfscmp
ntfscp
ntfsdecrypt
ntfsdump_logfile
ntfsfix
ntfsinfo
ntfslabel
ntfsls
ntfsmftalloc
ntfsmount
ntfsmove
ntfsresize
ntfsrm
ntfstruncate
ntfsundelete
ntfswipe
*.8

150
ntfsprogs/Makefile.am Normal file
View File

@ -0,0 +1,150 @@
if REALLYSTATIC
AM_LIBS =
AM_LFLAGS = -static
STATIC_LINK = $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
else
AM_LIBS = $(NTFS_3G_MODULE_LIBS)
AM_CFLAGS = $(NTFS_3G_MODULE_CFLAGS)
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)
bin_PROGRAMS = ntfsfix ntfsinfo ntfscluster ntfsls ntfscat ntfscmp
sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize ntfsclone \
ntfscp
EXTRA_PROGRAMS = ntfsdump_logfile ntfswipe ntfstruncate ntfsmove \
ntfsmftalloc
man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8 \
ntfsundelete.8 ntfsresize.8 ntfsprogs.8 ntfsls.8 \
ntfsclone.8 ntfscluster.8 ntfscat.8 ntfscp.8 \
ntfscmp.8
EXTRA_MANS =
CLEANFILES = $(EXTRA_PROGRAMS)
MAINTAINERCLEANFILES = Makefile.in
linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs
if ENABLE_CRYPTO
EXTRA_PROGRAMS += ntfsdecrypt
endif
if ENABLE_RICH
EXTRA_PROGRAMS += ntfsrm
endif
# Set the include path.
AM_CPPFLAGS = -I$(top_srcdir)/include/ntfs $(all_includes)
ntfsfix_SOURCES = ntfsfix.c utils.c utils.h
ntfsfix_LDADD = $(AM_LIBS)
ntfsfix_LDFLAGS = $(AM_LFLAGS)
mkntfs_SOURCES = attrdef.c attrdef.h upcase.c upcase.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h
mkntfs_LDADD = $(AM_LIBS)
mkntfs_LDFLAGS = $(AM_LFLAGS)
ntfslabel_SOURCES = ntfslabel.c utils.c utils.h
ntfslabel_LDADD = $(AM_LIBS)
ntfslabel_LDFLAGS = $(AM_LFLAGS)
ntfsinfo_SOURCES = ntfsinfo.c utils.c utils.h
ntfsinfo_LDADD = $(AM_LIBS)
ntfsinfo_LDFLAGS = $(AM_LFLAGS)
ntfsundelete_SOURCES = ntfsundelete.c ntfsundelete.h utils.c utils.h
ntfsundelete_LDADD = $(AM_LIBS)
ntfsundelete_LDFLAGS = $(AM_LFLAGS)
ntfsresize_SOURCES = ntfsresize.c utils.c utils.h
ntfsresize_LDADD = $(AM_LIBS)
ntfsresize_LDFLAGS = $(AM_LFLAGS)
ntfsclone_SOURCES = ntfsclone.c utils.c utils.h
ntfsclone_LDADD = $(AM_LIBS)
ntfsclone_LDFLAGS = $(AM_LFLAGS)
ntfscluster_SOURCES = ntfscluster.c ntfscluster.h cluster.c cluster.h utils.c utils.h
ntfscluster_LDADD = $(AM_LIBS)
ntfscluster_LDFLAGS = $(AM_LFLAGS)
ntfsls_SOURCES = ntfsls.c utils.c utils.h
ntfsls_LDADD = $(AM_LIBS)
ntfsls_LDFLAGS = $(AM_LFLAGS)
ntfscat_SOURCES = ntfscat.c ntfscat.h utils.c utils.h
ntfscat_LDADD = $(AM_LIBS)
ntfscat_LDFLAGS = $(AM_LFLAGS)
ntfscp_SOURCES = ntfscp.c utils.c utils.h
ntfscp_LDADD = $(AM_LIBS)
ntfscp_LDFLAGS = $(AM_LFLAGS)
ntfscmp_SOURCES = ntfscmp.c utils.c utils.h
ntfscmp_LDADD = $(AM_LIBS)
ntfscmp_LDFLAGS = $(AM_LFLAGS)
# We don't distribute these
if ENABLE_RICH
ntfsrm_SOURCES = ntfsrm.c ntfsrm.h utils.c utils.h
ntfsrm_LDADD = $(AM_LIBS)
ntfsrm_LDFLAGS = $(AM_LFLAGS)
endif
ntfstruncate_SOURCES = attrdef.c ntfstruncate.c utils.c utils.h
ntfstruncate_LDADD = $(AM_LIBS)
ntfstruncate_LDFLAGS = $(AM_LFLAGS)
ntfsmftalloc_SOURCES = ntfsmftalloc.c utils.c utils.h
ntfsmftalloc_LDADD = $(AM_LIBS)
ntfsmftalloc_LDFLAGS = $(AM_LFLAGS)
ntfsmove_SOURCES = ntfsmove.c ntfsmove.h utils.c utils.h
ntfsmove_LDADD = $(AM_LIBS)
ntfsmove_LDFLAGS = $(AM_LFLAGS)
ntfswipe_SOURCES = ntfswipe.c ntfswipe.h utils.c utils.h
ntfswipe_LDADD = $(AM_LIBS)
ntfswipe_LDFLAGS = $(AM_LFLAGS)
ntfsdump_logfile_SOURCES= ntfsdump_logfile.c
ntfsdump_logfile_LDADD = $(AM_LIBS)
ntfsdump_logfile_LDFLAGS= $(AM_LFLAGS)
if ENABLE_CRYPTO
ntfsdecrypt_SOURCES = ntfsdecrypt.c utils.c utils.h
ntfsdecrypt_LDADD = $(AM_LIBS)
ntfsdecrypt_LDFLAGS = $(AM_LFLAGS) -lgcrypt -lgnutls
endif
# Extra targets
strip: $(bin_PROGRAMS) $(sbin_PROGRAMS)
$(STRIP) $^
libs:
(cd ../libntfs && $(MAKE) libs) || exit 1;
extra: extras
extras: libs $(EXTRA_PROGRAMS)
# mkfs.ntfs[.8] hard link
install-exec-hook:
$(INSTALL) -d $(DESTDIR)/sbin
$(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)/sbin/mkfs.ntfs
install-data-hook:
$(INSTALL) -d $(DESTDIR)$(man8dir)
$(LN_S) -f mkntfs.8 $(DESTDIR)$(man8dir)/mkfs.ntfs.8
uninstall-local:
$(RM) -f $(DESTDIR)/sbin/mkfs.ntfs
$(RM) -f $(DESTDIR)$(man8dir)/mkfs.ntfs.8

322
ntfsprogs/attrdef.c Normal file
View File

@ -0,0 +1,322 @@
/**
* attrdef_ntfs12_array
*/
const unsigned char attrdef_ntfs12_array[2400] = {
36, 0, 83, 0, 84, 0, 65, 0, 78, 0, 68, 0, 65, 0, 82, 0,
68, 0, 95, 0, 73, 0, 78, 0, 70, 0, 79, 0, 82, 0, 77, 0,
65, 0, 84, 0, 73, 0, 79, 0, 78, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
48, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0,
36, 0, 65, 0, 84, 0, 84, 0, 82, 0, 73, 0, 66, 0, 85, 0,
84, 0, 69, 0, 95, 0, 76, 0, 73, 0, 83, 0, 84, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 70, 0, 73, 0, 76, 0, 69, 0, 95, 0, 78, 0, 65, 0,
77, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0,
68, 0, 0, 0, 0, 0, 0, 0, 66, 2, 0, 0, 0, 0, 0, 0,
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
86, 0, 69, 0, 82, 0, 83, 0, 73, 0, 79, 0, 78, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
36, 0, 83, 0, 69, 0, 67, 0, 85, 0, 82, 0, 73, 0, 84, 0,
89, 0, 95, 0, 68, 0, 69, 0, 83, 0, 67, 0, 82, 0, 73, 0,
80, 0, 84, 0, 79, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
78, 0, 65, 0, 77, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
73, 0, 78, 0, 70, 0, 79, 0, 82, 0, 77, 0, 65, 0, 84, 0,
73, 0, 79, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
36, 0, 68, 0, 65, 0, 84, 0, 65, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 73, 0, 78, 0, 68, 0, 69, 0, 88, 0, 95, 0, 82, 0,
79, 0, 79, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 73, 0, 78, 0, 68, 0, 69, 0, 88, 0, 95, 0, 65, 0,
76, 0, 76, 0, 79, 0, 67, 0, 65, 0, 84, 0, 73, 0, 79, 0,
78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 66, 0, 73, 0, 84, 0, 77, 0, 65, 0, 80, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 83, 0, 89, 0, 77, 0, 66, 0, 79, 0, 76, 0, 73, 0,
67, 0, 95, 0, 76, 0, 73, 0, 78, 0, 75, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
36, 0, 69, 0, 65, 0, 95, 0, 73, 0, 78, 0, 70, 0, 79, 0,
82, 0, 77, 0, 65, 0, 84, 0, 73, 0, 79, 0, 78, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
36, 0, 69, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/**
* attrdef_ntfs3x_array
*/
const unsigned char attrdef_ntfs3x_array[2560] = {
0x24, 0x00, 0x53, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x41, 0x00, 0x52, 0x00,
0x44, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x4D, 0x00,
0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x41, 0x00, 0x54, 0x00, 0x54, 0x00, 0x52, 0x00, 0x49, 0x00, 0x42, 0x00, 0x55, 0x00,
0x54, 0x00, 0x45, 0x00, 0x5F, 0x00, 0x4C, 0x00, 0x49, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4C, 0x00, 0x45, 0x00, 0x5F, 0x00, 0x4E, 0x00, 0x41, 0x00,
0x4D, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x4F, 0x00, 0x42, 0x00, 0x4A, 0x00, 0x45, 0x00, 0x43, 0x00, 0x54, 0x00, 0x5F, 0x00,
0x49, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x53, 0x00, 0x45, 0x00, 0x43, 0x00, 0x55, 0x00, 0x52, 0x00, 0x49, 0x00, 0x54, 0x00,
0x59, 0x00, 0x5F, 0x00, 0x44, 0x00, 0x45, 0x00, 0x53, 0x00, 0x43, 0x00, 0x52, 0x00, 0x49, 0x00,
0x50, 0x00, 0x54, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x56, 0x00, 0x4F, 0x00, 0x4C, 0x00, 0x55, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x5F, 0x00,
0x4E, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x56, 0x00, 0x4F, 0x00, 0x4C, 0x00, 0x55, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x5F, 0x00,
0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x54, 0x00,
0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x52, 0x00,
0x4F, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x41, 0x00,
0x4C, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x43, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00,
0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x42, 0x00, 0x49, 0x00, 0x54, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x52, 0x00, 0x45, 0x00, 0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x53, 0x00, 0x45, 0x00,
0x5F, 0x00, 0x50, 0x00, 0x4F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x45, 0x00, 0x41, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00,
0x52, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x45, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x47, 0x00, 0x47, 0x00, 0x45, 0x00, 0x44, 0x00, 0x5F, 0x00,
0x55, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4C, 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5F, 0x00,
0x53, 0x00, 0x54, 0x00, 0x52, 0x00, 0x45, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

8
ntfsprogs/attrdef.h Normal file
View File

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

222
ntfsprogs/boot.c Normal file
View File

@ -0,0 +1,222 @@
/**
* boot_array - the first 3429 bytes of $Boot
* The first 3429 bytes of $Boot. The rest is just zero. Total 8192 bytes.
*/
const unsigned char boot_array[3429] = {
235, 91, 144, 78, 84, 70, 83, 32, 32, 32, 32, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 51, 192,
142, 208, 188, 0, 124, 251, 184, 192, 7, 142, 216, 199, 6, 84, 0, 0,
0, 199, 6, 86, 0, 0, 0, 199, 6, 91, 0, 16, 0, 184, 0, 13,
142, 192, 43, 219, 232, 7, 0, 104, 0, 13, 104, 102, 2, 203, 80, 83,
81, 82, 6, 102, 161, 84, 0, 102, 3, 6, 28, 0, 102, 51, 210, 102,
15, 183, 14, 24, 0, 102, 247, 241, 254, 194, 136, 22, 90, 0, 102, 139,
208, 102, 193, 234, 16, 247, 54, 26, 0, 136, 22, 37, 0, 163, 88, 0,
161, 24, 0, 42, 6, 90, 0, 64, 59, 6, 91, 0, 118, 3, 161, 91,
0, 80, 180, 2, 139, 22, 88, 0, 177, 6, 210, 230, 10, 54, 90, 0,
139, 202, 134, 233, 138, 54, 37, 0, 178, 128, 205, 19, 88, 114, 42, 1,
6, 84, 0, 131, 22, 86, 0, 0, 41, 6, 91, 0, 118, 11, 193, 224,
5, 140, 194, 3, 208, 142, 194, 235, 138, 7, 90, 89, 91, 88, 195, 190,
89, 1, 235, 8, 190, 227, 1, 235, 3, 190, 57, 1, 232, 9, 0, 190,
173, 1, 232, 3, 0, 251, 235, 254, 172, 60, 0, 116, 9, 180, 14, 187,
7, 0, 205, 16, 235, 242, 195, 29, 0, 65, 32, 100, 105, 115, 107, 32,
114, 101, 97, 100, 32, 101, 114, 114, 111, 114, 32, 111, 99, 99, 117, 114,
114, 101, 100, 46, 13, 10, 0, 41, 0, 65, 32, 107, 101, 114, 110, 101,
108, 32, 102, 105, 108, 101, 32, 105, 115, 32, 109, 105, 115, 115, 105, 110,
103, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 100, 105, 115, 107, 46,
13, 10, 0, 37, 0, 65, 32, 107, 101, 114, 110, 101, 108, 32, 102, 105,
108, 101, 32, 105, 115, 32, 116, 111, 111, 32, 100, 105, 115, 99, 111, 110,
116, 105, 103, 117, 111, 117, 115, 46, 13, 10, 0, 51, 0, 73, 110, 115,
101, 114, 116, 32, 97, 32, 115, 121, 115, 116, 101, 109, 32, 100, 105, 115,
107, 101, 116, 116, 101, 32, 97, 110, 100, 32, 114, 101, 115, 116, 97, 114,
116, 13, 10, 116, 104, 101, 32, 115, 121, 115, 116, 101, 109, 46, 13, 10,
0, 23, 0, 92, 78, 84, 76, 68, 82, 32, 105, 115, 32, 99, 111, 109,
112, 114, 101, 115, 115, 101, 100, 46, 13, 10, 0, 0, 0, 0, 85, 170,
5, 0, 78, 0, 84, 0, 76, 0, 68, 0, 82, 0, 4, 0, 36, 0,
73, 0, 51, 0, 48, 0, 0, 224, 0, 0, 0, 48, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 140, 200, 142, 216, 193, 224, 4, 250, 139, 224,
251, 102, 15, 183, 6, 11, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227,
102, 163, 78, 2, 102, 139, 14, 64, 0, 128, 249, 0, 15, 143, 14, 0,
246, 217, 102, 184, 1, 0, 0, 0, 102, 211, 224, 235, 8, 144, 102, 161,
78, 2, 102, 247, 225, 102, 163, 82, 2, 102, 15, 183, 30, 11, 0, 102,
51, 210, 102, 247, 243, 102, 163, 86, 2, 232, 44, 4, 102, 139, 14, 74,
2, 102, 137, 14, 34, 2, 102, 3, 14, 82, 2, 102, 137, 14, 38, 2,
102, 3, 14, 82, 2, 102, 137, 14, 42, 2, 102, 3, 14, 82, 2, 102,
137, 14, 58, 2, 102, 3, 14, 82, 2, 102, 137, 14, 66, 2, 102, 184,
144, 0, 0, 0, 102, 139, 14, 34, 2, 232, 65, 9, 102, 11, 192, 15,
132, 22, 254, 102, 163, 46, 2, 102, 184, 160, 0, 0, 0, 102, 139, 14,
38, 2, 232, 40, 9, 102, 163, 50, 2, 102, 184, 176, 0, 0, 0, 102,
139, 14, 42, 2, 232, 22, 9, 102, 163, 54, 2, 102, 161, 46, 2, 102,
11, 192, 15, 132, 227, 253, 103, 128, 120, 8, 0, 15, 133, 218, 253, 103,
102, 141, 80, 16, 103, 3, 66, 4, 103, 102, 15, 182, 72, 12, 102, 137,
14, 94, 2, 103, 102, 139, 72, 8, 102, 137, 14, 90, 2, 102, 161, 90,
2, 102, 15, 183, 14, 11, 0, 102, 51, 210, 102, 247, 241, 102, 163, 98,
2, 102, 161, 66, 2, 102, 3, 6, 90, 2, 102, 163, 70, 2, 102, 131,
62, 50, 2, 0, 15, 132, 25, 0, 102, 131, 62, 54, 2, 0, 15, 132,
135, 253, 102, 139, 30, 54, 2, 30, 7, 102, 139, 62, 70, 2, 232, 177,
1, 102, 15, 183, 14, 0, 2, 102, 184, 2, 2, 0, 0, 232, 153, 6,
102, 11, 192, 15, 132, 88, 253, 103, 102, 139, 0, 30, 7, 102, 139, 62,
58, 2, 232, 209, 4, 102, 161, 58, 2, 102, 187, 128, 0, 0, 0, 102,
185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 203, 0, 102, 11,
192, 15, 132, 42, 253, 103, 102, 15, 183, 88, 12, 102, 129, 227, 255, 0,
0, 0, 15, 133, 30, 253, 102, 139, 216, 104, 0, 32, 7, 102, 43, 255,
232, 79, 1, 138, 22, 36, 0, 184, 232, 3, 142, 192, 141, 54, 11, 0,
43, 192, 104, 0, 32, 80, 203, 80, 83, 81, 82, 6, 255, 54, 91, 0,
255, 54, 84, 0, 255, 54, 86, 0, 139, 195, 193, 232, 4, 140, 193, 3,
193, 37, 255, 15, 45, 0, 16, 247, 216, 139, 14, 91, 0, 193, 225, 5,
81, 59, 193, 118, 2, 139, 193, 80, 193, 232, 5, 163, 91, 0, 232, 61,
252, 88, 89, 43, 200, 118, 11, 140, 194, 3, 208, 142, 194, 184, 0, 16,
235, 222, 143, 6, 86, 0, 143, 6, 84, 0, 143, 6, 91, 0, 7, 90,
89, 91, 88, 195, 6, 30, 102, 96, 102, 139, 218, 102, 15, 182, 14, 13,
0, 102, 247, 225, 102, 163, 84, 0, 102, 139, 195, 102, 247, 225, 163, 91,
0, 139, 223, 131, 227, 15, 140, 192, 102, 193, 239, 4, 3, 199, 80, 7,
232, 116, 255, 102, 97, 144, 31, 7, 195, 103, 3, 64, 20, 103, 102, 131,
56, 255, 15, 132, 76, 0, 103, 102, 57, 24, 15, 133, 51, 0, 102, 11,
201, 15, 133, 10, 0, 103, 128, 120, 9, 0, 15, 133, 35, 0, 195, 103,
58, 72, 9, 15, 133, 26, 0, 102, 139, 240, 103, 3, 112, 10, 232, 61,
5, 102, 81, 30, 7, 102, 139, 250, 243, 167, 102, 89, 15, 133, 1, 0,
195, 103, 102, 131, 120, 4, 0, 15, 132, 7, 0, 103, 102, 3, 64, 4,
235, 171, 102, 43, 192, 195, 102, 139, 243, 232, 18, 5, 103, 102, 3, 0,
103, 247, 64, 12, 2, 0, 15, 133, 52, 0, 103, 102, 141, 80, 16, 103,
58, 74, 64, 15, 133, 24, 0, 103, 102, 141, 114, 66, 232, 239, 4, 102,
81, 30, 7, 102, 139, 251, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103,
131, 120, 8, 0, 15, 132, 6, 0, 103, 3, 64, 8, 235, 194, 102, 51,
192, 195, 103, 128, 123, 8, 0, 15, 133, 28, 0, 6, 30, 102, 96, 103,
102, 141, 83, 16, 103, 102, 139, 10, 102, 139, 243, 103, 3, 114, 4, 243,
164, 102, 97, 144, 31, 7, 195, 103, 102, 141, 83, 16, 103, 102, 139, 74,
8, 102, 65, 102, 43, 192, 232, 1, 0, 195, 6, 30, 102, 96, 103, 128,
123, 8, 1, 15, 132, 3, 0, 233, 127, 251, 102, 131, 249, 0, 15, 133,
6, 0, 102, 97, 144, 31, 7, 195, 102, 83, 102, 80, 102, 81, 102, 87,
6, 232, 87, 3, 102, 139, 209, 7, 102, 95, 102, 89, 102, 59, 202, 15,
141, 3, 0, 102, 139, 209, 232, 171, 254, 102, 43, 202, 102, 139, 218, 102,
139, 194, 102, 15, 182, 22, 13, 0, 102, 247, 226, 102, 15, 183, 22, 11,
0, 102, 247, 226, 102, 3, 248, 102, 88, 102, 3, 195, 102, 91, 235, 170,
6, 30, 102, 96, 103, 128, 123, 8, 1, 15, 132, 3, 0, 233, 25, 251,
102, 131, 249, 0, 15, 133, 6, 0, 102, 97, 144, 31, 7, 195, 102, 83,
102, 80, 102, 81, 102, 87, 6, 102, 81, 102, 51, 210, 102, 15, 182, 14,
13, 0, 102, 247, 241, 102, 82, 232, 225, 2, 102, 15, 182, 30, 13, 0,
102, 247, 227, 102, 90, 102, 3, 194, 102, 80, 102, 15, 182, 6, 13, 0,
102, 247, 225, 102, 139, 208, 102, 88, 102, 89, 7, 102, 95, 102, 89, 102,
59, 202, 15, 141, 3, 0, 102, 139, 209, 102, 163, 84, 0, 137, 22, 91,
0, 6, 30, 102, 96, 139, 223, 131, 227, 15, 140, 192, 102, 193, 239, 4,
3, 199, 80, 7, 232, 160, 253, 102, 97, 144, 31, 7, 102, 43, 202, 102,
139, 218, 102, 139, 194, 102, 15, 183, 22, 11, 0, 102, 247, 226, 102, 3,
248, 102, 88, 102, 3, 195, 102, 91, 233, 101, 255, 6, 30, 102, 96, 38,
103, 102, 15, 183, 95, 4, 38, 103, 102, 15, 183, 79, 6, 102, 11, 201,
15, 132, 101, 250, 102, 3, 223, 102, 131, 195, 2, 102, 129, 199, 254, 1,
0, 0, 102, 73, 102, 11, 201, 15, 132, 23, 0, 38, 103, 139, 3, 38,
103, 137, 7, 102, 131, 195, 2, 102, 129, 199, 0, 2, 0, 0, 102, 73,
235, 226, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 184, 1, 0,
0, 0, 102, 163, 30, 2, 102, 161, 26, 2, 102, 3, 6, 82, 2, 102,
163, 74, 2, 102, 161, 48, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227,
102, 163, 84, 0, 102, 161, 86, 2, 163, 91, 0, 102, 139, 30, 26, 2,
30, 7, 232, 242, 252, 102, 15, 183, 251, 232, 111, 255, 102, 161, 26, 2,
102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0,
0, 0, 232, 100, 253, 102, 11, 192, 15, 132, 87, 0, 102, 139, 216, 30,
7, 102, 139, 62, 22, 2, 232, 249, 253, 102, 139, 30, 22, 2, 103, 102,
129, 59, 128, 0, 0, 0, 15, 132, 6, 0, 103, 3, 91, 4, 235, 238,
103, 102, 129, 59, 128, 0, 0, 0, 15, 133, 39, 0, 102, 83, 103, 102,
139, 67, 16, 102, 139, 62, 74, 2, 30, 7, 232, 9, 1, 102, 91, 102,
161, 82, 2, 102, 1, 6, 74, 2, 102, 255, 6, 30, 2, 103, 3, 91,
4, 235, 205, 102, 97, 144, 31, 7, 195, 102, 139, 208, 102, 139, 14, 30,
2, 102, 161, 26, 2, 102, 82, 102, 80, 102, 81, 102, 82, 102, 187, 128,
0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232,
215, 252, 102, 11, 192, 15, 132, 64, 249, 102, 139, 216, 102, 88, 232, 42,
1, 102, 11, 192, 15, 132, 7, 0, 102, 91, 102, 91, 102, 91, 195, 102,
89, 102, 88, 102, 90, 102, 3, 6, 82, 2, 226, 185, 102, 51, 192, 195,
6, 30, 102, 96, 102, 80, 102, 81, 102, 51, 210, 102, 15, 182, 30, 13,
0, 102, 247, 243, 102, 82, 232, 144, 255, 102, 11, 192, 15, 132, 249, 248,
102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 90, 102, 3, 194, 102, 163,
84, 0, 102, 89, 102, 15, 182, 30, 13, 0, 102, 59, 203, 15, 142, 19,
0, 137, 30, 91, 0, 102, 43, 203, 102, 88, 102, 3, 195, 102, 80, 102,
81, 235, 20, 144, 102, 88, 102, 3, 193, 102, 80, 137, 14, 91, 0, 102,
185, 0, 0, 0, 0, 102, 81, 6, 102, 87, 139, 223, 131, 227, 15, 140,
192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 155, 251, 102, 95, 7, 102,
3, 62, 78, 2, 102, 89, 102, 88, 102, 131, 249, 0, 15, 143, 116, 255,
102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 247, 38, 86, 2, 102,
139, 14, 86, 2, 232, 89, 255, 232, 241, 253, 102, 97, 144, 31, 7, 195,
6, 30, 102, 96, 102, 247, 38, 98, 2, 102, 139, 30, 50, 2, 102, 139,
14, 98, 2, 30, 7, 102, 139, 62, 66, 2, 232, 35, 253, 232, 203, 253,
102, 97, 144, 31, 7, 195, 102, 80, 102, 83, 102, 81, 102, 139, 30, 70,
2, 102, 139, 200, 102, 193, 232, 3, 102, 131, 225, 7, 102, 3, 216, 102,
184, 1, 0, 0, 0, 102, 211, 224, 103, 132, 3, 15, 132, 4, 0, 248,
235, 2, 144, 249, 102, 89, 102, 91, 102, 88, 195, 103, 128, 123, 8, 1,
15, 132, 4, 0, 102, 43, 192, 195, 103, 102, 141, 115, 16, 103, 102, 139,
86, 8, 102, 59, 194, 15, 135, 11, 0, 103, 102, 139, 22, 102, 59, 194,
15, 131, 4, 0, 102, 43, 192, 195, 103, 3, 94, 16, 102, 43, 246, 103,
128, 59, 0, 15, 132, 62, 0, 232, 129, 0, 102, 3, 241, 232, 57, 0,
102, 3, 202, 102, 59, 193, 15, 140, 33, 0, 102, 139, 209, 102, 80, 103,
102, 15, 182, 11, 102, 139, 193, 102, 131, 224, 15, 102, 193, 233, 4, 102,
3, 217, 102, 3, 216, 102, 67, 102, 88, 235, 196, 102, 43, 200, 102, 43,
194, 102, 3, 198, 195, 102, 43, 192, 195, 102, 43, 201, 103, 138, 11, 128,
225, 15, 102, 131, 249, 0, 15, 133, 4, 0, 102, 43, 201, 195, 102, 83,
102, 82, 102, 3, 217, 103, 102, 15, 190, 19, 102, 73, 102, 75, 102, 131,
249, 0, 15, 132, 13, 0, 102, 193, 226, 8, 103, 138, 19, 102, 75, 102,
73, 235, 235, 102, 139, 202, 102, 90, 102, 91, 195, 102, 83, 102, 82, 102,
43, 210, 103, 138, 19, 102, 131, 226, 15, 102, 43, 201, 103, 138, 11, 192,
233, 4, 102, 131, 249, 0, 15, 133, 8, 0, 102, 43, 201, 102, 90, 102,
91, 195, 102, 3, 218, 102, 3, 217, 103, 102, 15, 190, 19, 102, 73, 102,
75, 102, 131, 249, 0, 15, 132, 13, 0, 102, 193, 226, 8, 103, 138, 19,
102, 75, 102, 73, 235, 235, 102, 139, 202, 102, 90, 102, 91, 195, 102, 11,
201, 15, 133, 1, 0, 195, 102, 81, 102, 86, 103, 131, 62, 97, 15, 140,
12, 0, 103, 131, 62, 122, 15, 143, 4, 0, 103, 131, 46, 32, 102, 131,
198, 2, 226, 230, 102, 94, 102, 89, 195, 102, 80, 102, 81, 102, 139, 208,
102, 161, 46, 2, 103, 102, 141, 88, 16, 103, 3, 67, 4, 103, 102, 141,
64, 16, 102, 139, 218, 232, 158, 250, 102, 11, 192, 15, 132, 5, 0, 102,
89, 102, 89, 195, 102, 161, 50, 2, 102, 11, 192, 15, 133, 8, 0, 102,
89, 102, 89, 102, 51, 192, 195, 102, 139, 22, 50, 2, 103, 102, 141, 82,
16, 103, 102, 139, 66, 8, 102, 64, 102, 139, 30, 78, 2, 102, 247, 227,
102, 51, 210, 102, 247, 54, 90, 2, 102, 80, 102, 88, 102, 11, 192, 15,
132, 48, 0, 102, 72, 102, 80, 232, 28, 254, 114, 238, 232, 241, 253, 102,
90, 102, 89, 102, 91, 102, 83, 102, 81, 102, 82, 102, 161, 66, 2, 103,
102, 141, 64, 24, 232, 47, 250, 102, 11, 192, 116, 206, 102, 89, 102, 89,
102, 89, 195, 102, 89, 102, 89, 102, 51, 192, 195, 6, 30, 102, 96, 102,
139, 54, 66, 2, 102, 185, 32, 0, 0, 0, 102, 247, 193, 3, 0, 0,
0, 15, 133, 3, 0, 232, 13, 0, 102, 173, 232, 105, 0, 226, 235, 102,
97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 51, 192, 102, 51, 219, 176,
13, 180, 14, 187, 7, 0, 205, 16, 176, 10, 180, 14, 187, 7, 0, 205,
16, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 11, 201, 15, 133,
9, 0, 232, 208, 255, 102, 97, 144, 31, 7, 195, 102, 51, 192, 102, 51,
219, 173, 180, 14, 187, 7, 0, 205, 16, 226, 240, 232, 183, 255, 102, 97,
144, 31, 7, 195, 96, 172, 60, 0, 116, 9, 180, 14, 187, 7, 0, 205,
16, 235, 242, 97, 144, 195, 6, 30, 102, 96, 102, 185, 8, 0, 0, 0,
102, 139, 208, 102, 131, 226, 15, 102, 82, 102, 193, 232, 4, 226, 241, 102,
185, 8, 0, 0, 0, 102, 88, 102, 131, 248, 9, 15, 143, 7, 0, 102,
131, 192, 48, 235, 9, 144, 102, 131, 232, 10, 102, 131, 192, 65, 102, 51,
219, 180, 14, 187, 7, 0, 205, 16, 226, 219, 176, 32, 180, 14, 187, 7,
0, 205, 16, 102, 97, 144, 31, 7, 232, 96, 0, 195, 6, 30, 102, 96,
102, 190, 22, 13, 0, 0, 232, 79, 245, 102, 97, 144, 31, 7, 195, 6,
30, 102, 96, 102, 190, 38, 13, 0, 0, 232, 60, 245, 102, 97, 144, 31,
7, 195, 6, 30, 102, 96, 102, 190, 54, 13, 0, 0, 232, 41, 245, 102,
97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 190, 70, 13, 0, 0, 232,
22, 245, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 190, 86, 13,
0, 0, 232, 3, 245, 102, 97, 144, 31, 7, 195, 102, 80, 102, 184, 0,
0, 245, 255, 102, 64, 102, 11, 192, 117, 249, 102, 88, 195, 102, 81, 102,
80, 102, 184, 5, 0, 0, 0, 30, 7, 102, 139, 249, 232, 71, 252, 102,
139, 193, 102, 91, 102, 83, 102, 15, 183, 14, 12, 2, 102, 186, 14, 2,
0, 0, 232, 68, 248, 102, 91, 102, 89, 102, 11, 192, 15, 133, 47, 0,
102, 139, 193, 102, 139, 203, 102, 80, 102, 83, 232, 35, 0, 102, 91, 102,
95, 102, 11, 192, 15, 132, 23, 0, 30, 7, 232, 9, 252, 102, 139, 199,
102, 15, 183, 14, 12, 2, 102, 186, 14, 2, 0, 0, 232, 10, 248, 195,
102, 81, 102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186,
0, 0, 0, 0, 232, 242, 247, 102, 11, 192, 15, 132, 82, 0, 102, 139,
216, 30, 7, 102, 139, 62, 22, 2, 232, 135, 248, 30, 7, 102, 139, 30,
22, 2, 102, 89, 38, 102, 57, 15, 15, 132, 46, 0, 38, 102, 131, 63,
255, 15, 132, 45, 0, 38, 131, 127, 4, 0, 15, 132, 36, 0, 38, 102,
15, 183, 71, 4, 3, 216, 139, 195, 37, 0, 128, 116, 215, 140, 192, 5,
0, 8, 142, 192, 129, 227, 255, 127, 235, 202, 38, 102, 139, 71, 16, 195,
102, 89, 102, 51, 192, 195, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 48, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 49, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 50, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 51, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
116, 32, 52, 13, 10
};

7
ntfsprogs/boot.h Normal file
View File

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

119
ntfsprogs/cluster.c Normal file
View File

@ -0,0 +1,119 @@
/**
* cluster - Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2003 Richard Russon
*
* This function will locate the owner of any given sector or cluster range.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <ntfs-3g/logging.h>
#include "cluster.h"
#include "utils.h"
/**
* cluster_find
*/
int cluster_find(ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void *data)
{
int j;
int result = -1;
struct mft_search_ctx *m_ctx = NULL;
ntfs_attr_search_ctx *a_ctx = NULL;
ATTR_RECORD *rec;
runlist *runs;
if (!vol || !cb)
return -1;
m_ctx = mft_get_search_ctx(vol);
m_ctx->flags_search = FEMR_IN_USE | FEMR_BASE_RECORD;
while (mft_next_record(m_ctx) == 0) {
if (!(m_ctx->flags_match & FEMR_BASE_RECORD))
continue;
ntfs_log_verbose("Inode: %llu\n", (unsigned long long)
m_ctx->inode->mft_no);
a_ctx = ntfs_attr_get_search_ctx(m_ctx->inode, NULL);
while ((rec = find_attribute(AT_UNUSED, a_ctx))) {
if (!rec->non_resident) {
ntfs_log_verbose("0x%02x skipped - attr is resident\n", a_ctx->attr->type);
continue;
}
runs = ntfs_mapping_pairs_decompress(vol, a_ctx->attr, NULL);
if (!runs) {
ntfs_log_error("Couldn't read the data runs.\n");
goto done;
}
ntfs_log_verbose("\t[0x%02X]\n", a_ctx->attr->type);
ntfs_log_verbose("\t\tVCN\tLCN\tLength\n");
for (j = 0; runs[j].length > 0; j++) {
LCN a_begin = runs[j].lcn;
LCN a_end = a_begin + runs[j].length - 1;
if (a_begin < 0)
continue; // sparse, discontiguous, etc
ntfs_log_verbose("\t\t%lld\t%lld-%lld (%lld)\n",
(long long)runs[j].vcn,
(long long)runs[j].lcn,
(long long)(runs[j].lcn +
runs[j].length - 1),
(long long)runs[j].length);
//dprint list
if ((a_begin > c_end) || (a_end < c_begin))
continue; // before or after search range
if ((*cb) (m_ctx->inode, a_ctx->attr, runs+j, data))
return 1;
}
}
ntfs_attr_put_search_ctx(a_ctx);
a_ctx = NULL;
}
result = 0;
done:
ntfs_attr_put_search_ctx(a_ctx);
mft_put_search_ctx(m_ctx);
return result;
}

39
ntfsprogs/cluster.h Normal file
View File

@ -0,0 +1,39 @@
/*
* cluster - Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Richard Russon
*
* This function will locate the owner of any given sector or cluster range.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CLUSTER_H_
#define _CLUSTER_H_
#include <ntfs-3g/types.h>
#include <ntfs-3g/volume.h>
typedef struct {
int x;
} ntfs_cluster;
typedef int (cluster_cb)(ntfs_inode *ino, ATTR_RECORD *attr, runlist_element *run, void *data);
int cluster_find(ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void *data);
#endif /* _CLUSTER_H_ */

300
ntfsprogs/mkntfs.8.in Normal file
View File

@ -0,0 +1,300 @@
.\" Copyright (c) 2001\-2006 Anton Altaparmakov.
.\" Copyright (c) 2005 Richard Russon.
.\" Copyright (c) 2005\-2006 Szabolcs Szakacsits.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH MKNTFS 8 "January 2006" "ntfsprogs @VERSION@"
.SH NAME
mkntfs \- create an NTFS file system
.SH SYNOPSIS
.B mkntfs
[\fIoptions\fR] \fIdevice \fR[\fInumber\-of\-sectors\fR]
.PP
.B mkntfs
[
.B \-C
]
[
.B \-c
.I cluster\-size
]
[
.B \-F
]
[
.B \-f
]
[
.B \-H
.I heads
]
[
.B \-h
]
[
.B \-I
]
[
.B \-L
.I volume\-label
]
[
.B \-l
]
[
.B \-n
]
[
.B \-N
.I ntfs\-version
]
[
.B \-p
.I part\-start\-sect
]
[
.B \-Q
]
[
.B \-q
]
[
.B \-S
.I sectors\-per\-track
]
[
.B \-s
.I sector\-size
]
[
.B \-T
]
[
.B \-V
]
[
.B \-v
]
[
.B \-z
.I mft\-zone\-multiplier
]
[
.B \-\-debug
]
.I device
[
.I number\-of\-sectors
]
.SH DESCRIPTION
.B mkntfs
is used to create an NTFS file system on a device (usually a disk partition)
or file.
.I device
is the special file corresponding to the device (e.g
.IR /dev/hdXX ).
.I number\-of\-sectors
is the number of blocks on the device. If omitted,
.B mkntfs
automagically figures the file system size.
.SH OPTIONS
Below is a summary of all the options that
.B mkntfs
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.SS Basic options
.TP
\fB\-f\fR, \fB\-\-fast\fR, \fB\-Q\fR, \fB\-\-quick\fR
Perform quick (fast) format. This will skip both zeroing of the volume and bad
sector checking.
.TP
\fB\-L\fR, \fB\-\-label\fR STRING
Set the volume label for the filesystem.
.TP
\fB\-C\fR, \fB\-\-enable\-compression\fR
Enable compression on the volume.
.TP
\fB\-c\fR, \fB\-\-cluster\-size\fR BYTES
Specify the size of clusters in bytes. Valid cluster size values are powers of
two, with at least 256, and at most 65536 bytes per cluster. If omitted,
.B mkntfs
determines the
.I cluster\-size
from the volume size. The value is determined as follows:
.TS
box;
lB lB lB
l l r.
Volume size Default cluster size
0 \- 512MB 512 bytes
512MB \- 1GB 1024 bytes
1GB \- 2GB 2048 bytes
2GB + 4096 bytes
.TE
.sp
.sp
Note that the default cluster size is set to be at least equal to the sector
size as a cluster cannot be smaller than a sector. Also, note that values
greater than 4096 have the side effect that compression is disabled on the
volume (due to limitations in the NTFS compression algorithm currently in use
by Windows).
.TP
\fB\-N\fR, \fB\-\-ntfs\-version\fR STRING
Select the version of NTFS you wish to create. This can be "1.2"
(Windows NT 4.0) or "3.1" (Windows XP, Server 2003 and Vista).
Versions are upwards compatible and Windows 2000, which uses version "3.0",
can read/write both.
If this option is omitted then version "3.1" is used.
.TP
\fB\-n\fR, \fB\-\-no\-action\fR
Causes
.B mkntfs
to not actually create a filesystem, but display what it would do if it were
to create a filesystem. All steps of the format are carried out except the
actual writing to the device.
.SS Advanced options
.TP
\fB\-s\fR, \fB\-\-sector\-size\fR BYTES
Specify the size of sectors in bytes. Valid sector size values are 256, 512,
1024, 2048 and 4096 bytes per sector. If omitted,
.B mkntfs
attempts to determine the
.I sector\-size
automatically and if that fails a default of 512 bytes per sector is used.
.TP
\fB\-p\fR, \fB\-\-partition\-start\fR SECTOR
Specify the partition start sector. The maximum is 4294967295 (2^32\-1). If
omitted,
.B mkntfs
attempts to determine
.I part\-start\-sect
automatically and if that fails a default of 0 is used. Note that
.I part\-start\-sect
is required for Windows to be able to boot from the created volume.
.TP
\fB\-H\fR, \fB\-\-heads\fR NUM
Specify the number of heads. The maximum is 65535 (0xffff). If omitted,
.B mkntfs
attempts to determine the number of
.I heads
automatically and if that fails a default of 0 is used. Note that
.I heads
is required for Windows to be able to boot from the created volume.
.TP
\fB\-S\fR, \fB\-\-sectors\-per\-track\fR NUM
Specify the number of sectors per track. The maximum is 65535 (0xffff). If
omitted,
.B mkntfs
attempts to determine the number of
.I sectors\-per\-track
automatically and if that fails a default of 0 is used. Note that
.I sectors\-per\-track
is required for Windows to be able to boot from the created volume.
.TP
\fB\-z\fR, \fB\-\-mft\-zone\-multiplier\fR NUM
Set the MFT zone multiplier, which determines the size of the MFT zone to use
on the volume. The MFT zone is the area at the beginning of the volume reserved
for the master file table (MFT), which stores the on disk inodes (MFT records).
It is noteworthy that small files are stored entirely within the inode;
thus, if you expect to use the volume for storing large numbers of very small
files, it is useful to set the zone multiplier to a higher value. Note, that
the MFT zone is resized on the fly as required during operation of the NTFS
driver but choosing a good value will reduce fragmentation. Valid values
are 1, 2, 3 and 4. The values have the following meaning:
.TS
box;
lB lB
lB lB
c l.
MFT zone MFT zone size
multiplier (% of volume size)
1 12.5% (default)
2 25.0%
3 37.5%
4 50.0%
.TE
.sp
.TP
\fB\-T\fR, \fB\-\-zero\-time\fR
Fake the time to be 00:00:00 UTC, Jan 1, 1970 instead of the current system
time. This is only really useful for debugging purposes.
.TP
\fB\-I\fR, \fB\-\-no\-indexing\fR
Disable content indexing on the volume. (This is only meaningful on
Windows 2000 and later. Windows NT 4.0 and earlier ignore this as they do
not implement content indexing at all.)
.TP
\fB\-F\fR, \fB\-\-force\fR
Force
.B mkntfs
to run, even if the specified
.I device
is not a block special device, or appears to be mounted.
.SS Output options
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Quiet execution; only errors are written to stderr, no output to stdout
occurs at all. Useful if
.B mkntfs
is run in a script.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Verbose execution.
.TP
\fB\-\-debug\fR
Really verbose execution; includes the verbose output from the
.B \-v
option as well as additional output useful for debugging
.B mkntfs.
.SS Help options
.TP
\fB\-V\fR, \fB\-\-version\fR
Print the version number of
.B mkntfs
and exit.
.TP
\fB\-l\fR, \fB\-\-license\fR
Print the licensing information of
.B mkntfs
and exit.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.SH BUGS
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
.B mkntfs
was written by Anton Altaparmakov, Richard Russon, Erik Sornes and Szabolcs Szakacsits.
.SH AVAILABILITY
.B mkntfs
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR badblocks (8),
.BR ntfsprogs (8)

5203
ntfsprogs/mkntfs.c Normal file

File diff suppressed because it is too large Load Diff

137
ntfsprogs/ntfscat.8.in Normal file
View File

@ -0,0 +1,137 @@
.\" Copyright (c) 2003\-2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSCAT 8 "November 2005" "ntfsprogs @VERSION@"
.SH NAME
ntfscat \- print NTFS files and streams on the standard output
.SH SYNOPSIS
[\fIoptions\fR] \fIdevice \fR[\fIfile\fR]
.SH DESCRIPTION
.B ntfscat
will read a file or stream from an NTFS volume and display the contents
on the standard output.
.PP
The case of the filename passed to
.B ntfscat
is ignored.
.SH OPTIONS
Below is a summary of all the options that
.B ntfscat
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-a\fR, \fB\-\-attribute\fR TYPE
Display the contents of a particular attribute type. By default, the unnamed
$DATA attribute will be shown. The attribute can be specified by a number
in decimal or hexadecimal, or by name.
.TS
box;
lB lB lB
l l l.
Hex Decimal Name
0x10 16 "$STANDARD_INFORMATION"
0x20 32 "$ATTRIBUTE_LIST"
0x30 48 "$FILE_NAME"
0x40 64 "$OBJECT_ID"
0x50 80 "$SECURITY_DESCRIPTOR"
0x60 96 "$VOLUME_NAME"
0x70 112 "$VOLUME_INFORMATION"
0x80 128 "$DATA"
0x90 144 "$INDEX_ROOT"
0xA0 160 "$INDEX_ALLOCATION"
0xB0 176 "$BITMAP"
0xC0 192 "$REPARSE_POINT"
0xD0 208 "$EA_INFORMATION"
0xE0 224 "$EA"
0xF0 240 "$PROPERTY_SET"
0x100 256 "$LOGGED_UTILITY_STREAM"
.TE
.sp
.sp
.B Notes
The attribute names may be given without the leading $ symbol.
.br
If you use the $ symbol, you must quote the name to prevent the shell
interpreting the name.
.TP
\fB\-n\fR, \fB\-\-attribute\-name\fR NAME
Display this named attribute, stream.
.TP
\fB\-i\fR, \fB\-\-inode\fR NUM
Specify a file by its inode number instead of its name.
.TP
\fB\-f\fR, \fB\-\-force\fR
This will override some sensible defaults, such as not using a mounted volume.
Use this option with caution.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Suppress some debug/warning/error messages.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license
.BR ntfscat .
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Display more debug/warning/error messages.
.SH EXAMPLES
Display the contents of a file in the root of an NTFS volume.
.RS
.sp
.B ntfscat /dev/hda1 boot.ini
.sp
.RE
Display the contents of a file in a subdirectory of an NTFS volume.
.RS
.sp
.B ntfscat /dev/hda1 /winnt/system32/drivers/etc/hosts
.sp
.RE
Display the contents of the $INDEX_ROOT attribute of the root directory (inode
5).
.RS
.sp
.B ntfscat /dev/hda1 \-a INDEX_ROOT \-i 5 | hexdump \-C
.sp
.RE
.SH BUGS
There are no known problems with
.BR ntfscat .
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
.B ntfscat
was written by Richard Russon, Anton Altaparmakov and Szabolcs Szakacsits.
.SH AVAILABILITY
.B ntfscat
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR ntfsls (8),
.BR ntfsprogs (8)

428
ntfsprogs/ntfscat.c Normal file
View File

@ -0,0 +1,428 @@
/**
* ntfscat - Part of the Linux-NTFS project.
*
* Copyright (c) 2003-2005 Richard Russon
* Copyright (c) 2003-2005 Anton Altaparmakov
* Copyright (c) 2003-2005 Szabolcs Szakacsits
*
* This utility will concatenate files and print on the standard output.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/volume.h>
#include <ntfs-3g/debug.h>
#include <ntfs-3g/dir.h>
#include "ntfscat.h"
/* #include "version.h" */
#include "utils.h"
static const char *EXEC_NAME = "ntfscat";
static struct options opts;
/**
* version - Print version information about the program
*
* Print a copyright statement and a brief description of the program.
*
* Return: none
*/
static void version(void)
{
ntfs_log_info("\n%s v%s (libntfs-3g) - Concatenate files and print on the "
"standard output.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c) 2003-2005 Richard Russon\n");
ntfs_log_info("Copyright (c) 2003-2005 Anton Altaparmakov\n");
ntfs_log_info("Copyright (c) 2003-2005 Szabolcs Szakacsits\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
static void usage(void)
{
ntfs_log_info("\nUsage: %s [options] device [file]\n\n"
" -a, --attribute TYPE Display this attribute type\n"
" -n, --attribute-name NAME Display this attribute name\n"
" -i, --inode NUM Display this inode\n\n"
" -f, --force Use less caution\n"
" -h, --help Print this help\n"
" -q, --quiet Less output\n"
" -V, --version Version information\n"
" -v, --verbose More output\n\n",
//" -r --raw Display the compressed or encrypted file",
EXEC_NAME);
ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
* parse_attribute - Read an attribute name, or number
* @value: String to be parsed
* @attr: Resulting attribute id (on success)
*
* Read a string representing an attribute. It may be a decimal, octal or
* hexadecimal number, or the attribute name in full. The leading $ sign is
* optional.
*
* Return: 1 Success, a valid attribute name or number
* 0 Error, not an attribute name or number
*/
static int parse_attribute(const char *value, ATTR_TYPES *attr)
{
static const char *attr_name[] = {
"$STANDARD_INFORMATION",
"$ATTRIBUTE_LIST",
"$FILE_NAME",
"$OBJECT_ID",
"$SECURITY_DESCRIPTOR",
"$VOLUME_NAME",
"$VOLUME_INFORMATION",
"$DATA",
"$INDEX_ROOT",
"$INDEX_ALLOCATION",
"$BITMAP",
"$REPARSE_POINT",
"$EA_INFORMATION",
"$EA",
"$PROPERTY_SET",
"$LOGGED_UTILITY_STREAM",
NULL
};
int i;
long num;
for (i = 0; attr_name[i]; i++) {
if ((strcmp(value, attr_name[i]) == 0) ||
(strcmp(value, attr_name[i]+1) == 0)) {
*attr = (ATTR_TYPES) ((i+1)*16);
return 1;
}
}
num = strtol(value, NULL, 0);
if ((num > 0) && (num < 257)) {
*attr = (ATTR_TYPES) num;
return 1;
}
return 0;
}
/**
* parse_options - Read and validate the programs command line
*
* Read the command line, verify the syntax and parse the options.
* This function is very long, but quite simple.
*
* Return: 1 Success
* 0 Error, one or more problems
*/
static int parse_options(int argc, char **argv)
{
static const char *sopt = "-a:fh?i:n:qVv";
static const struct option lopt[] = {
{ "attribute", required_argument, NULL, 'a' },
{ "attribute-name", required_argument, NULL, 'n' },
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "inode", required_argument, NULL, 'i' },
{ "quiet", no_argument, NULL, 'q' },
{ "version", no_argument, NULL, 'V' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
int c = -1;
int err = 0;
int ver = 0;
int help = 0;
int levels = 0;
ATTR_TYPES attr = AT_UNUSED;
opterr = 0; /* We'll handle the errors, thank you. */
opts.inode = -1;
opts.attr = -1;
opts.attr_name = NULL;
opts.attr_name_len = 0;
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1: /* A non-option argument */
if (!opts.device) {
opts.device = argv[optind-1];
} else if (!opts.file) {
opts.file = argv[optind-1];
} else {
ntfs_log_error("You must specify exactly one file.\n");
err++;
}
break;
case 'a':
if (opts.attr != (ATTR_TYPES)-1) {
ntfs_log_error("You must specify exactly one attribute.\n");
} else if (parse_attribute(optarg, &attr) > 0) {
opts.attr = attr;
break;
} else {
ntfs_log_error("Couldn't parse attribute.\n");
}
err++;
break;
case 'f':
opts.force++;
break;
case 'h':
case '?':
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
if (!ntfs_log_parse_option (argv[optind-1]))
err++;
break;
}
help++;
break;
case 'i':
if (opts.inode != -1)
ntfs_log_error("You must specify exactly one inode.\n");
else if (utils_parse_size(optarg, &opts.inode, FALSE))
break;
else
ntfs_log_error("Couldn't parse inode number.\n");
err++;
break;
case 'n':
opts.attr_name_len = ntfs_mbstoucs_libntfscompat(optarg,
&opts.attr_name, 0);
if (opts.attr_name_len < 0) {
ntfs_log_perror("Invalid attribute name '%s'", optarg);
usage();
}
case 'q':
opts.quiet++;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 'V':
ver++;
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
default:
ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
err++;
break;
}
}
/* Make sure we're in sync with the log levels */
levels = ntfs_log_get_levels();
if (levels & NTFS_LOG_LEVEL_VERBOSE)
opts.verbose++;
if (!(levels & NTFS_LOG_LEVEL_QUIET))
opts.quiet++;
if (help || ver) {
opts.quiet = 0;
} else {
if (opts.device == NULL) {
ntfs_log_error("You must specify a device.\n");
err++;
} else if (opts.file == NULL && opts.inode == -1) {
ntfs_log_error("You must specify a file or inode "
"with the -i option.\n");
err++;
} else if (opts.file != NULL && opts.inode != -1) {
ntfs_log_error("You can't specify both a file and inode.\n");
err++;
}
if (opts.quiet && opts.verbose) {
ntfs_log_error("You may not use --quiet and --verbose at the "
"same time.\n");
err++;
}
}
if (ver)
version();
if (help || err)
usage();
return (!err && !help && !ver);
}
/**
* index_get_size - Find the INDX block size from the index root
* @inode: Inode of the directory to be checked
*
* Find the size of a directory's INDX block from the INDEX_ROOT attribute.
*
* Return: n Success, the INDX blocks are n bytes in size
* 0 Error, not a directory
*/
static int index_get_size(ntfs_inode *inode)
{
ATTR_RECORD *attr90;
INDEX_ROOT *iroot;
attr90 = find_first_attribute(AT_INDEX_ROOT, inode->mrec);
if (!attr90)
return 0; // not a directory
iroot = (INDEX_ROOT*)((u8*)attr90 + le16_to_cpu(attr90->value_offset));
return iroot->index_block_size;
}
/**
* cat
*/
static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type,
ntfschar *name, int namelen)
{
const int bufsize = 4096;
char *buffer;
ntfs_attr *attr;
s64 bytes_read, written;
s64 offset;
u32 block_size;
buffer = malloc(bufsize);
if (!buffer)
return 1;
attr = ntfs_attr_open(inode, type, name, namelen);
if (!attr) {
ntfs_log_error("Cannot find attribute type 0x%lx.\n", (long) type);
free(buffer);
return 1;
}
if ((inode->mft_no < 2) && (attr->type == AT_DATA))
block_size = vol->mft_record_size;
else if (attr->type == AT_INDEX_ALLOCATION)
block_size = index_get_size(inode);
else
block_size = 0;
offset = 0;
for (;;) {
if (block_size > 0) {
// These types have fixup
bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer);
bytes_read *= block_size;
} else {
bytes_read = ntfs_attr_pread(attr, offset, bufsize, buffer);
}
//ntfs_log_info("read %lld bytes\n", bytes_read);
if (bytes_read == -1) {
ntfs_log_perror("ERROR: Couldn't read file");
break;
}
if (!bytes_read)
break;
written = fwrite(buffer, 1, bytes_read, stdout);
if (written != bytes_read) {
ntfs_log_perror("ERROR: Couldn't output all data!");
break;
}
offset += bytes_read;
}
ntfs_attr_close(attr);
free(buffer);
return 0;
}
/**
* main - Begin here
*
* Start from here.
*
* Return: 0 Success, the program worked
* 1 Error, something went wrong
*/
int main(int argc, char *argv[])
{
ntfs_volume *vol;
ntfs_inode *inode;
ATTR_TYPES attr;
int result = 1;
ntfs_log_set_handler(ntfs_log_handler_stderr);
if (!parse_options(argc, argv))
return 1;
utils_set_locale();
vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force);
if (!vol) {
ntfs_log_perror("ERROR: couldn't mount volume");
return 1;
}
if (opts.inode != -1)
inode = ntfs_inode_open(vol, opts.inode);
else
inode = ntfs_pathname_to_inode(vol, NULL, opts.file);
if (!inode) {
ntfs_log_perror("ERROR: Couldn't open inode");
return 1;
}
attr = AT_DATA;
if (opts.attr != (ATTR_TYPES)-1)
attr = opts.attr;
result = cat(vol, inode, attr, opts.attr_name, opts.attr_name_len);
ntfs_inode_close(inode);
ntfs_umount(vol, FALSE);
return result;
}

45
ntfsprogs/ntfscat.h Normal file
View File

@ -0,0 +1,45 @@
/*
* ntfscat - Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Richard Russon
* Copyright (c) 2003 Anton Altaparmakov
*
* This utility will concatenate files and print on the standard output.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFSCAT_H_
#define _NTFSCAT_H_
#include <ntfs-3g/types.h>
#include <ntfs-3g/layout.h>
struct options {
char *device; /* Device/File to work with */
char *file; /* File to display */
s64 inode; /* Inode to work with */
ATTR_TYPES attr; /* Attribute type to display */
ntfschar *attr_name; /* Attribute name to display */
int attr_name_len; /* Attribute name length */
int force; /* Override common sense */
int quiet; /* Less output */
int verbose; /* Extra output */
};
#endif /* _NTFSCAT_H_ */

366
ntfsprogs/ntfsclone.8.in Normal file
View File

@ -0,0 +1,366 @@
.\" Copyright (c) 2003\-2005 Richard Russon.
.\" Copyright (c) 2003\-2006 Szabolcs Szakacsits.
.\" Copyright (c) 2004 Per Olofsson.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSCLONE 8 "February 2006" "ntfsprogs @VERSION@"
.SH NAME
ntfsclone \- Efficiently clone, image, restore or rescue an NTFS
.SH SYNOPSIS
.B ntfsclone
[\fIOPTIONS\fR]
.I SOURCE
.br
.B ntfsclone \-\-save\-image
[\fIOPTIONS\fR]
.I SOURCE
.br
.B ntfsclone \-\-restore\-image
[\fIOPTIONS\fR]
.I SOURCE
.br
.B ntfsclone \-\-metadata
[\fIOPTIONS\fR]
.I SOURCE
.SH DESCRIPTION
.B ntfsclone
will efficiently clone (copy, save, backup, restore) or rescue an NTFS
filesystem to a sparse file, image, device (partition) or standard output.
It works at disk sector level and
copies only the used data. Unused disk space becomes zero (cloning to
sparse file), encoded with control codes (saving in special image format),
left unchanged (cloning to a disk/partition) or
filled with zeros (cloning to standard output).
.B ntfsclone
can be useful to make backups, an exact snapshot of an NTFS filesystem
and restore it later on, or for developers to test NTFS read/write
functionality, troubleshoot/investigate users' issues using the clone
without the risk of destroying the original filesystem.
The clone, if not using the special image format, is an exact copy of the
original NTFS filesystem from sector to sector thus it can be also mounted
just like the original NTFS filesystem.
For example if you clone to a file and the kernel has loopback device and
NTFS support then the file can be mounted as
.RS
.sp
.B mount \-t ntfs \-o loop ntfsclone.img /mnt/ntfsclone
.sp
.RE
.SS Windows Cloning
If you want to copy, move or restore a system or boot partition to another
computer, or to a different disk or partition (e.g. hda1\->hda2, hda1\->hdb1
or to a different disk sector offset) then you will need to take extra care.
Usually, Windows will not be able to boot, unless you copy, move or restore
NTFS to the same partition which starts at the same sector on the same type
of disk having the same BIOS legacy cylinder setting as the original
partition and disk had.
The ntfsclone utility guarantees to make an exact copy of NTFS but it
won't deal with booting issues. This is by design: ntfsclone is a
filesystem, not system utility. Its aim is only NTFS cloning, not Windows
cloning. Hereby ntfsclone can be used as a very fast and reliable
build block for Windows clonning but itself it's not enough. You
can find useful tips following the related links on the below page
.br
.nh
http://wiki.linux-ntfs.org/doku.php?id=ntfsclone
.hy
.SS Sparse Files
A file is sparse if it has unallocated blocks (holes). The reported size of
such files are always higher than the disk space consumed by them. The
.BR du
command can tell the real disk space used by a sparse file.
The holes are always read as zeros. All major Linux filesystem like,
ext2, ext3, reiserfs, Reiser4, JFS and XFS, supports
sparse files but for example the ISO 9600 CD\-ROM filesystem doesn't.
.SS Handling Large Sparse Files
As of today Linux provides inadequate support for managing (tar,
cp, gzip, gunzip, bzip2, bunzip2, cat, etc) large sparse files.
The only main Linux filesystem
having support for efficient sparse file handling is XFS by the
XFS_IOC_GETBMAPX
.BR ioctl (2) .
However none of the common utilities supports it.
This means when you tar, cp, gzip, bzip2, etc a large sparse file
they will always read the entire file, even if you use the "sparse support"
options.
.BR bzip2 (1)
compresses large sparse files much better than
.BR gzip (1)
but it does so
also much slower. Moreover neither of them handles large sparse
files efficiently during uncompression from disk space usage point
of view.
At present the most efficient way, both speed and space\-wise, to
compress and uncompress large sparse files by common tools
would be using
.BR tar (1)
with the options
.B \-S
(handle sparse files "efficiently") and
.B \-j
(filter the archive through bzip2). Although
.BR tar
still reads and analyses the entire file, it doesn't pass on the
large data blocks having only zeros to filters and it also avoids
writing large amount of zeros to the disk needlessly. But since
.BR tar
can't create an archive from the standard input, you can't do this
in\-place by just reading
.BR ntfsclone
standard output. Even more sadly, using the \-S option results
serious data loss since the end of 2004 and the GNU
.BR tar
maintainers didn't release fixed versions until the present day.
.SS The Special Image Format
It's also possible, actually it's recommended, to save an NTFS filesystem
to a special image format.
Instead of representing unallocated blocks as holes, they are
encoded using control codes. Thus, the image saves space without
requiring sparse file support. The image format is ideal for streaming
filesystem images over the network and similar, and can be used as a
replacement for Ghost or Partition Image if it is combined with other
tools. The downside is that you can't mount the image directly, you
need to restore it first.
To save an image using the special image format, use the
.B \-s
or the
.B \-\-save\-image
option. To restore an image, use the
.B \-r
or the
.B \-\-restore\-image
option. Note that you can restore images from standard input by
using '\-' as the
.I SOURCE
file.
.SS Metadata\-only Cloning
One of the features of
.BR ntfsclone
is that, it can also save only the NTFS metadata using the option
.B \-m
or
.B \-\-metadata
and the clone still will be
mountable. In this case all non\-metadata file content will be lost and
reading them back will result always zeros.
The metadata\-only image can be compressed very
well, usually to not more than 1\-8 MB thus it's easy to transfer
for investigation, troubleshooting.
In this mode of ntfsclone,
.B NONE
of the user's data is saved, including the resident user's data
embedded into metadata. All is filled with zeros.
Moreover all the file timestamps, deleted and unused spaces inside
the metadata are filled with zeros. Thus this mode is inappropriate
for example for forensic analyses.
Please note, filenames are not wiped out. They might contain
sensitive information, so think twice before sending such an
image to anybody.
.SH OPTIONS
Below is a summary of all the options that
.B ntfsclone
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.B \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.B "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-o\fR, \fB\-\-output\fR FILE
Clone NTFS to the non\-existent
.IR FILE .
If
.I FILE
is '\-' then clone to the
standard output.
.TP
\fB\-O\fR, \fB\-\-overwrite\fR FILE
Clone NTFS to
.IR FILE ,
overwriting if exists.
.TP
\fB\-s\fR, \fB\-\-save\-image\fR
Save to the special image format. This is the most efficient way space and
speed\-wise if imaging is done to the standard output, e.g. for image
compression, encryption or streaming through a network.
.TP
\fB\-r\fR, \fB\-\-restore\-image\fR
Restore from the special image format specified by
.I SOURCE
argument. If the
.I SOURCE
is '\-' then the image is read from the standard input.
.TP
\fB\-\-rescue\fR
Ignore disk read errors so disks having bad sectors, e.g. dying disks, can be
rescued the most efficiently way, with minimal stress on them. Ntfsclone works
at the lowest, sector level in this mode too thus more data can be rescued.
The contents of the unreadable sectors are filled by character '?' and the
beginning of such sectors are marked by "BadSectoR\\0".
.TP
\fB\-m\fR, \fB\-\-metadata\fR
Clone
.B ONLY METADATA
(for NTFS experts). Moreover only cloning to a file is allowed.
You can't metadata\-only clone to a device, image or standard output.
.TP
\fB\-\-ignore\-fs\-check\fR
Ignore the result of the filesystem consistency check. This option is allowed
to be used only with the
.B \-\-metadata
option, for the safety of user's data. The clusters which cause the
inconsistency are saved too.
.TP
\fB\-f\fR, \fB\-\-force\fR
Forces ntfsclone to proceed if the filesystem is marked
"dirty" for consistency check.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.SH EXIT CODES
The exit code is 0 on success, non\-zero otherwise.
.SH EXAMPLES
Clone NTFS on /dev/hda1 to /dev/hdc1:
.RS
.sp
.B ntfsclone \-\-overwrite /dev/hdc1 /dev/hda1
.sp
.RE
Save an NTFS to a file in the special image format:
.RS
.sp
.B ntfsclone \-\-save\-image \-\-output backup.img /dev/hda1
.sp
.RE
Restore an NTFS from a special image file to its original partition:
.RS
.sp
.B ntfsclone \-\-restore\-image \-\-overwrite /dev/hda1 backup.img
.sp
.RE
Save an NTFS into a compressed image file:
.RS
.sp
.B ntfsclone \-\-save\-image \-o \- /dev/hda1 | gzip \-c > backup.img.gz
.sp
.RE
Restore an NTFS volume from a compressed image file:
.RS
.sp
.B gunzip \-c backup.img.gz | \\\\
.br
.B ntfsclone \-\-restore\-image \-\-overwrite /dev/hda1 \-
.sp
.RE
Backup an NTFS volume to a remote host, using ssh. Please note, that
ssh may ask for a password!
.RS
.sp
.B ntfsclone \-\-save\-image \-\-output \- /dev/hda1 | \\\\
.br
.B gzip \-c | ssh host 'cat > backup.img.gz'
.sp
.RE
Restore an NTFS volume from a remote host via ssh. Please note, that
ssh may ask for a password!
.RS
.sp
.B ssh host 'cat backup.img.gz' | gunzip \-c | \\\\
.br
.B ntfsclone \-\-restore\-image \-\-overwrite /dev/hda1 \-
.sp
.RE
Stream an image file from a web server and restore it to a partition:
.RS
.sp
.B wget \-qO \- http://server/backup.img | \\\\
.br
.B ntfsclone \-\-restore\-image \-\-overwrite /dev/hda1 \-
.sp
.RE
Clone an NTFS volume to a non\-existent file:
.RS
.sp
.B ntfsclone \-\-output ntfs\-clone.img /dev/hda1
.sp
.RE
Pack NTFS metadata for NTFS experts. Please note that bzip2 runs
very long but results usually at least 10 times smaller archives
than gzip.
.RS
.sp
.B ntfsclone \-\-metadata \-\-output ntfsmeta.img /dev/hda1
.br
.B bzip2 ntfsmeta.img
.sp
.RE
Unpacking NTFS metadata into a sparse file:
.RS
.sp
.B bunzip2 \-c ntfsmeta.img.bz2 | \\\\
.br
.B cp \-\-sparse=always /proc/self/fd/0 ntfsmeta.img
.sp
.RE
.SH KNOWN ISSUES
There are no known problems with
.BR ntfsclone .
If you think you have found a problem then please send an email describing it
to the development team:
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.sp
Sometimes it might appear ntfsclone froze if the clone is on ReiserFS
and even CTRL\-C won't stop it. This is not a bug in ntfsclone, however
it's due to ReiserFS being extremely inefficient creating large
sparse files and not handling signals during this operation. This
ReiserFS problem was improved in kernel 2.4.22.
XFS, JFS and ext3 don't have this problem.
.hy
.SH AUTHORS
.B ntfsclone
was written by Szabolcs Szakacsits with contributions from Per Olofsson
(special image format support) and Anton Altaparmakov.
.SH AVAILABILITY
.B ntfsclone
is part of the
.B ntfsprogs
package and is available at:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The latest manual pages are available at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.sp
Additional up-to-date information can be found furthermore at:
.br
.nh
http://wiki.linux-ntfs.org/doku.php?id=ntfsclone
.hy
.SH SEE ALSO
.BR ntfsresize (8)
.BR ntfsprogs (8)
.BR xfs_copy (8)
.BR debugreiserfs (8)
.BR e2image (8)

1748
ntfsprogs/ntfsclone.c Normal file

File diff suppressed because it is too large Load Diff

129
ntfsprogs/ntfscluster.8.in Normal file
View File

@ -0,0 +1,129 @@
.\" Copyright (c) 2003\-2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSCLUSTER 8 "November 2005" "ntfsprogs @VERSION@"
.SH NAME
ntfscluster \- identify files in a specified region of an NTFS volume.
.SH SYNOPSIS
.B ntfscluster
[\fIoptions\fR] \fIdevice\fR
.SH DESCRIPTION
.B ntfscluster
has three modes of operation:
.IR info ,
.I sector
and
.IR cluster .
.SS Info
.PP
The default mode,
.I info
is currently not implemented. It will display general information about the
NTFS volume when it is working.
.SS Sector
.PP
The
.I sector
mode will display a list of files that have data in the specified range of
sectors.
.SS Cluster
The
.I cluster
mode will display a list of files that have data in the specified range of
clusters. When the cluster size is one sector, this will be equivalent to the
.I sector
mode of operation.
.SH OPTIONS
Below is a summary of all the options that
.B ntfscluster
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-c\fR, \fB\-\-cluster\fR RANGE
Any files whose data is in this range of clusters will be displayed.
.TP
\fB\-F\fR, \fB\-\-filename\fR NAME
Show information about this file.
.TP
\fB\-f\fR, \fB\-\-force\fR
This will override some sensible defaults, such as not working with a mounted
volume. Use this option with caution.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.TP
\fB\-I\fR, \fB\-\-inode\fR NUM
Show information about this inode.
.TP
\fB\-i\fR, \fB\-\-info\fR
This option is not yet implemented.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Reduce the amount of output to a minimum. Naturally, it doesn't make sense to
combine this option with
.TP
\fB\-s\fR, \fB\-\-sector\fR RANGE
Any files whose data is in this range of sectors will be displayed.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Increase the amount of output that
.B ntfscluster
prints.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license for
.BR ntfscluster .
.SH EXAMPLES
Get some information about the volume /dev/hda1.
.RS
.sp
.B ntfscluster /dev/hda1
.sp
.RE
Look for files in the first 500 clusters of /dev/hda1.
.RS
.sp
.B ntfscluster \-c 0\-500 /dev/hda1
.sp
.RE
.SH BUGS
The
.I info
mode isn't implemented yet.
.B ntfscluster
is quite limited, but it has no known bugs. If you find a bug please send an
email describing the problem to the development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
.B ntfscluster
was written by Richard Russon, with contributions from Anton Altaparmakov.
.SH AVAILABILITY
.B ntfscluster
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR ntfsinfo (8),
.BR ntfsprogs (8)

563
ntfsprogs/ntfscluster.c Normal file
View File

@ -0,0 +1,563 @@
/**
* ntfscluster - Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2003 Richard Russon
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2005-2006 Szabolcs Szakacsits
*
* This utility will locate the owner of any given sector or cluster.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/volume.h>
#include <ntfs-3g/debug.h>
#include <ntfs-3g/dir.h>
#include <ntfs-3g/logging.h>
#include "ntfscluster.h"
#include "utils.h"
#include "cluster.h"
/* #include "version.h" */
static const char *EXEC_NAME = "ntfscluster";
static struct options opts;
/**
* version - Print version information about the program
*
* Print a copyright statement and a brief description of the program.
*
* Return: none
*/
static void version(void)
{
ntfs_log_info("\n%s v%s (libntfs-3g) - Find the owner of any given sector or "
"cluster.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c) 2002-2003 Richard Russon\n");
ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n");
ntfs_log_info("Copyright (c) 2005-2006 Szabolcs Szakacsits\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
static void usage(void)
{
ntfs_log_info("\nUsage: %s [options] device\n"
" -i, --info Print information about the volume (default)\n"
"\n"
" -c, --cluster RANGE Look for objects in this range of clusters\n"
" -s, --sector RANGE Look for objects in this range of sectors\n"
" -I, --inode NUM Show information about this inode\n"
" -F, --filename NAME Show information about this file\n"
/* " -l, --last Find the last file on the volume\n" */
"\n"
" -f, --force Use less caution\n"
" -q, --quiet Less output\n"
" -v, --verbose More output\n"
" -V, --version Version information\n"
" -h, --help Print this help\n\n",
EXEC_NAME);
ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
* parse_options - Read and validate the programs command line
*
* Read the command line, verify the syntax and parse the options.
* This function is very long, but quite simple.
*
* Return: 1 Success
* 0 Error, one or more problems
*/
static int parse_options(int argc, char **argv)
{
static const char *sopt = "-c:F:fh?I:ilqs:vV";
static const struct option lopt[] = {
{ "cluster", required_argument, NULL, 'c' },
{ "filename", required_argument, NULL, 'F' },
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "info", no_argument, NULL, 'i' },
{ "inode", required_argument, NULL, 'I' },
{ "last", no_argument, NULL, 'l' },
{ "quiet", no_argument, NULL, 'q' },
{ "sector", required_argument, NULL, 's' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
int c = -1;
int err = 0;
int ver = 0;
int help = 0;
int levels = 0;
char *end = NULL;
opterr = 0; /* We'll handle the errors, thank you. */
opts.action = act_none;
opts.range_begin = -1;
opts.range_end = -1;
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1: /* A non-option argument */
if (!opts.device) {
opts.device = argv[optind-1];
} else {
opts.device = NULL;
err++;
}
break;
case 'c':
if ((opts.action == act_none) &&
(utils_parse_range(optarg, &opts.range_begin, &opts.range_end, FALSE)))
opts.action = act_cluster;
else
opts.action = act_error;
break;
case 'F':
if (opts.action == act_none) {
opts.action = act_file;
opts.filename = optarg;
} else {
opts.action = act_error;
}
break;
case 'f':
opts.force++;
break;
case 'h':
case '?':
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
if (!ntfs_log_parse_option (argv[optind-1]))
err++;
break;
}
help++;
break;
case 'I':
if (opts.action == act_none) {
opts.action = act_inode;
opts.inode = strtol(optarg, &end, 0);
if (end && *end)
err++;
} else {
opts.action = act_error;
}
break;
case 'i':
if (opts.action == act_none)
opts.action = act_info;
else
opts.action = act_error;
break;
case 'l':
if (opts.action == act_none)
opts.action = act_last;
else
opts.action = act_error;
break;
case 'q':
opts.quiet++;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 's':
if ((opts.action == act_none) &&
(utils_parse_range(optarg, &opts.range_begin, &opts.range_end, FALSE)))
opts.action = act_sector;
else
opts.action = act_error;
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
case 'V':
ver++;
break;
default:
if ((optopt == 'c') || (optopt == 's'))
ntfs_log_error("Option '%s' requires an argument.\n", argv[optind-1]);
else
ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
err++;
break;
}
}
/* Make sure we're in sync with the log levels */
levels = ntfs_log_get_levels();
if (levels & NTFS_LOG_LEVEL_VERBOSE)
opts.verbose++;
if (!(levels & NTFS_LOG_LEVEL_QUIET))
opts.quiet++;
if (help || ver) {
opts.quiet = 0;
} else {
if (opts.action == act_none)
opts.action = act_info;
if (opts.action == act_info)
opts.quiet = 0;
if (opts.device == NULL) {
if (argc > 1)
ntfs_log_error("You must specify exactly one device.\n");
err++;
}
if (opts.quiet && opts.verbose) {
ntfs_log_error("You may not use --quiet and --verbose at the same time.\n");
err++;
}
if (opts.action == act_error) {
ntfs_log_error("You may only specify one action: --info, --cluster, --sector or --last.\n");
err++;
} else if (opts.range_begin > opts.range_end) {
ntfs_log_error("The range must be in ascending order.\n");
err++;
}
}
if (ver)
version();
if (help || err)
usage();
return (!err && !help && !ver);
}
/**
* info
*/
static int info(ntfs_volume *vol)
{
u64 a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u;
int cb, sb, cps;
u64 uc = 0, mc = 0, fc = 0;
struct mft_search_ctx *m_ctx;
ntfs_attr_search_ctx *a_ctx;
runlist_element *rl;
ATTR_RECORD *rec;
int z;
int inuse = 0;
m_ctx = mft_get_search_ctx(vol);
m_ctx->flags_search = FEMR_IN_USE | FEMR_METADATA | FEMR_BASE_RECORD | FEMR_NOT_BASE_RECORD;
while (mft_next_record(m_ctx) == 0) {
if (!(m_ctx->flags_match & FEMR_IN_USE))
continue;
inuse++;
a_ctx = ntfs_attr_get_search_ctx(m_ctx->inode, NULL);
while ((rec = find_attribute(AT_UNUSED, a_ctx))) {
if (!rec->non_resident)
continue;
rl = ntfs_mapping_pairs_decompress(vol, rec, NULL);
for (z = 0; rl[z].length > 0; z++)
{
if (rl[z].lcn >= 0) {
if (m_ctx->flags_match & FEMR_METADATA)
mc += rl[z].length;
else
uc += rl[z].length;
}
}
free(rl);
}
ntfs_attr_put_search_ctx(a_ctx);
}
mft_put_search_ctx(m_ctx);
cb = vol->cluster_size_bits;
sb = vol->sector_size_bits;
cps = cb - sb;
fc = vol->nr_clusters-mc-uc;
fc <<= cb;
mc <<= cb;
uc <<= cb;
a = vol->sector_size;
b = vol->cluster_size;
c = 1 << cps;
d = vol->nr_clusters << cb;
e = vol->nr_clusters;
f = vol->nr_clusters >> cps;
g = vol->mft_na->initialized_size >> vol->mft_record_size_bits;
h = inuse;
i = h * 100 / g;
j = fc;
k = fc >> sb;
l = fc >> cb;
m = fc * 100 / b / e;
n = uc;
o = uc >> sb;
p = uc >> cb;
q = uc * 100 / b / e;
r = mc;
s = mc >> sb;
t = mc >> cb;
u = mc * 100 / b / e;
ntfs_log_info("bytes per sector : %llu\n", (unsigned long long)a);
ntfs_log_info("bytes per cluster : %llu\n", (unsigned long long)b);
ntfs_log_info("sectors per cluster : %llu\n", (unsigned long long)c);
ntfs_log_info("bytes per volume : %llu\n", (unsigned long long)d);
ntfs_log_info("sectors per volume : %llu\n", (unsigned long long)e);
ntfs_log_info("clusters per volume : %llu\n", (unsigned long long)f);
ntfs_log_info("initialized mft records : %llu\n", (unsigned long long)g);
ntfs_log_info("mft records in use : %llu\n", (unsigned long long)h);
ntfs_log_info("mft records percentage : %llu\n", (unsigned long long)i);
ntfs_log_info("bytes of free space : %llu\n", (unsigned long long)j);
ntfs_log_info("sectors of free space : %llu\n", (unsigned long long)k);
ntfs_log_info("clusters of free space : %llu\n", (unsigned long long)l);
ntfs_log_info("percentage free space : %llu\n", (unsigned long long)m);
ntfs_log_info("bytes of user data : %llu\n", (unsigned long long)n);
ntfs_log_info("sectors of user data : %llu\n", (unsigned long long)o);
ntfs_log_info("clusters of user data : %llu\n", (unsigned long long)p);
ntfs_log_info("percentage user data : %llu\n", (unsigned long long)q);
ntfs_log_info("bytes of metadata : %llu\n", (unsigned long long)r);
ntfs_log_info("sectors of metadata : %llu\n", (unsigned long long)s);
ntfs_log_info("clusters of metadata : %llu\n", (unsigned long long)t);
ntfs_log_info("percentage metadata : %llu\n", (unsigned long long)u);
return 0;
}
/**
* dump_file
*/
static int dump_file(ntfs_volume *vol, ntfs_inode *ino)
{
char buffer[1024];
ntfs_attr_search_ctx *ctx;
ATTR_RECORD *rec;
int i;
runlist *runs;
utils_inode_get_name(ino, buffer, sizeof(buffer));
ntfs_log_info("Dump: %s\n", buffer);
ctx = ntfs_attr_get_search_ctx(ino, NULL);
while ((rec = find_attribute(AT_UNUSED, ctx))) {
ntfs_log_info(" 0x%02x - ", rec->type);
if (rec->non_resident) {
ntfs_log_info("non-resident\n");
runs = ntfs_mapping_pairs_decompress(vol, rec, NULL);
if (runs) {
ntfs_log_info(" VCN LCN Length\n");
for (i = 0; runs[i].length > 0; i++) {
ntfs_log_info(" %8lld %8lld %8lld\n",
(long long)runs[i].vcn,
(long long)runs[i].lcn,
(long long)
runs[i].length);
}
free(runs);
}
} else {
ntfs_log_info("resident\n");
}
}
ntfs_attr_put_search_ctx(ctx);
return 0;
}
/**
* print_match
*/
static int print_match(ntfs_inode *ino, ATTR_RECORD *attr,
runlist_element *run, void *data __attribute__((unused)))
{
char *buffer;
if (!ino || !attr || !run)
return 1;
buffer = malloc(MAX_PATH);
if (!buffer) {
ntfs_log_error("!buffer\n");
return 1;
}
utils_inode_get_name(ino, buffer, MAX_PATH);
ntfs_log_info("Inode %llu %s", (unsigned long long)ino->mft_no, buffer);
utils_attr_get_name(ino->vol, attr, buffer, MAX_PATH);
ntfs_log_info("/%s\n", buffer);
free(buffer);
return 0;
}
/**
* find_last
*/
static int find_last(ntfs_inode *ino, ATTR_RECORD *attr, runlist_element *run,
void *data)
{
struct match *m;
if (!ino || !attr || !run || !data)
return 1;
m = data;
if ((run->lcn + run->length) > m->lcn) {
m->inum = ino->mft_no;
m->lcn = run->lcn + run->length;
}
return 0;
}
/**
* main - Begin here
*
* Start from here.
*
* Return: 0 Success, the program worked
* 1 Error, something went wrong
*/
int main(int argc, char *argv[])
{
ntfs_volume *vol;
ntfs_inode *ino = NULL;
struct match m;
int result = 1;
ntfs_log_set_handler(ntfs_log_handler_outerr);
if (!parse_options(argc, argv))
return 1;
utils_set_locale();
vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force);
if (!vol)
return 1;
switch (opts.action) {
case act_sector:
if (opts.range_begin == opts.range_end)
ntfs_log_quiet("Searching for sector %llu\n",
(unsigned long long)opts.range_begin);
else
ntfs_log_quiet("Searching for sector range %llu-%llu\n", (unsigned long long)opts.range_begin, (unsigned long long)opts.range_end);
/* Convert to clusters */
opts.range_begin >>= (vol->cluster_size_bits - vol->sector_size_bits);
opts.range_end >>= (vol->cluster_size_bits - vol->sector_size_bits);
result = cluster_find(vol, opts.range_begin, opts.range_end, (cluster_cb*)&print_match, NULL);
break;
case act_cluster:
if (opts.range_begin == opts.range_end)
ntfs_log_quiet("Searching for cluster %llu\n",
(unsigned long long)opts.range_begin);
else
ntfs_log_quiet("Searching for cluster range %llu-%llu\n", (unsigned long long)opts.range_begin, (unsigned long long)opts.range_end);
result = cluster_find(vol, opts.range_begin, opts.range_end, (cluster_cb*)&print_match, NULL);
break;
case act_file:
ino = ntfs_pathname_to_inode(vol, NULL, opts.filename);
if (ino)
result = dump_file(vol, ino);
break;
case act_inode:
ino = ntfs_inode_open(vol, opts.inode);
if (ino) {
result = dump_file(vol, ino);
ntfs_inode_close(ino);
} else {
ntfs_log_error("Cannot open inode %llu\n",
(unsigned long long)opts.inode);
}
break;
case act_last:
memset(&m, 0, sizeof(m));
m.lcn = -1;
result = cluster_find(vol, 0, LONG_MAX, (cluster_cb*)&find_last, &m);
if (m.lcn >= 0) {
ino = ntfs_inode_open(vol, m.inum);
if (ino) {
result = dump_file(vol, ino);
ntfs_inode_close(ino);
} else {
ntfs_log_error("Cannot open inode %llu\n",
(unsigned long long)
opts.inode);
}
result = 0;
} else {
result = 1;
}
break;
case act_info:
default:
result = info(vol);
break;
}
ntfs_umount(vol, FALSE);
return result;
}

64
ntfsprogs/ntfscluster.h Normal file
View File

@ -0,0 +1,64 @@
/*
* ntfscluster - Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2003 Richard Russon
*
* This utility will locate the owner of any given sector or cluster.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFSCLUSTER_H_
#define _NTFSCLUSTER_H_
#include <ntfs-3g/types.h>
#include <ntfs-3g/layout.h>
enum action {
act_none,
act_info,
act_cluster,
act_sector,
act_inode,
act_file,
act_last,
act_error,
};
struct options {
char *device; /* Device/File to work with */
enum action action; /* What to do */
int quiet; /* Less output */
int verbose; /* Extra output */
int force; /* Override common sense */
char *filename; /* File to examine */
u64 inode; /* Inode to examine */
s64 range_begin; /* Look for objects in this range */
s64 range_end;
};
struct match {
u64 inum; /* Inode number */
LCN lcn; /* Last cluster in use */
ATTR_TYPES type; /* Attribute type */
ntfschar *name; /* Attribute name */
int name_len; /* Length of attribute name */
u8 padding[4]; /* Unused: padding to 64 bit. */
};
#endif /* _NTFSCLUSTER_H_ */

82
ntfsprogs/ntfscmp.8.in Normal file
View File

@ -0,0 +1,82 @@
.\" Copyright (c) 2005\-2006 Szabolcs Szakacsits.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSCMP 8 "April 2006" "ntfsprogs @VERSION@"
.SH NAME
ntfscmp \- compare two NTFS filesystems and tell the differences
.SH SYNOPSIS
.B ntfscmp
[\fIOPTIONS\fR]
.I DEVICE1
.I DEVICE2
.br
.SH DESCRIPTION
The
.B ntfscmp
program makes a comparison between two NTFS filesystems from all aspects and
reports all variances it finds.
The filesystems can be on block devices or images files. Ntfscmp can be used
for volume verification however its primary purpose was to be an efficient
development tool, used to quickly locate, identify and check the correctness
of the metadata changes made to NTFS.
If one is interested only in the NTFS metadata changes then it could be useful
to compare the metadata images created by
using the --metadata option of
.BR ntfsclone (8)
to eliminate the usually uninteresting timestamp changes.
The terse output of
.B ntfscmp
is intentional because the provided information is enough in each case
to determine the exact differences. This can be achieved, for instance,
if one compares the verbose outputs of
.BR ntfsinfo (8)
for each reported inodes by the
.BR diff (1)
utility.
.SH OPTIONS
Below is a summary of the options that
.B ntfscmp
accepts.
.TP
\fB\-P\fR, \fB\-\-no\-progress\-bar\fR
Don't show progress bars.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
More informational output.
.TP
\fB\-h\fR, \fB\-\-help\fR
Display help and exit.
.SH EXIT CODES
The exit code is 0 on success, non\-zero otherwise.
.SH KNOWN ISSUES
No problem is known. If you would find otherwise then please send
your report to the development team:
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHOR
.B ntfscmp
was written by Szabolcs Szakacsits (szaka@sienet.hu).
.SH AVAILABILITY
.B ntfscmp
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR ntfsinfo (8),
.BR ntfscat (8),
.BR diff (1),
.BR ntfsclone (8),
.BR ntfsprogs (8)

872
ntfsprogs/ntfscmp.c Normal file
View File

@ -0,0 +1,872 @@
/**
* ntfscmp - compare two NTFS volumes.
*
* Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2005 Anton Altaparmakov
*
* This utility is part of the Linux-NTFS project.
*/
#include "config.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include "utils.h"
/* #include "version.h" */
static const char *EXEC_NAME = "ntfscmp";
static const char *invalid_ntfs_msg =
"Apparently device '%s' doesn't have a valid NTFS.\n"
"Maybe you selected the wrong partition? Or the whole disk instead of a\n"
"partition (e.g. /dev/hda, not /dev/hda1)?\n";
static const char *corrupt_volume_msg =
"Apparently you have a corrupted NTFS. Please run the filesystem checker\n"
"on Windows by invoking chkdsk /f. Don't forget the /f (force) parameter,\n"
"it's important! You probably also need to reboot Windows to take effect.\n";
static const char *hibernated_volume_msg =
"Apparently the NTFS partition is hibernated. Windows must be resumed and\n"
"turned off properly\n";
struct {
int debug;
int show_progress;
int verbose;
char *vol1;
char *vol2;
} opt;
#define NTFS_PROGBAR 0x0001
#define NTFS_PROGBAR_SUPPRESS 0x0002
struct progress_bar {
u64 start;
u64 stop;
int resolution;
int flags;
float unit;
u8 padding[4]; /* Unused: padding to 64 bit. */
};
/* WARNING: don't modify the text, external tools grep for it */
#define ERR_PREFIX "ERROR"
#define PERR_PREFIX ERR_PREFIX "(%d): "
#define NERR_PREFIX ERR_PREFIX ": "
__attribute__((format(printf, 2, 3)))
static void perr_printf(int newline, const char *fmt, ...)
{
va_list ap;
int eo = errno;
fprintf(stdout, PERR_PREFIX, eo);
va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
va_end(ap);
fprintf(stdout, ": %s", strerror(eo));
if (newline)
fprintf(stdout, "\n");
fflush(stdout);
fflush(stderr);
}
#define perr_print(...) perr_printf(0, __VA_ARGS__)
#define perr_println(...) perr_printf(1, __VA_ARGS__)
__attribute__((format(printf, 1, 2)))
static void err_printf(const char *fmt, ...)
{
va_list ap;
fprintf(stdout, NERR_PREFIX);
va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
va_end(ap);
fflush(stdout);
fflush(stderr);
}
/**
* err_exit
*
* Print and error message and exit the program.
*/
__attribute__((noreturn))
__attribute__((format(printf, 1, 2)))
static int err_exit(const char *fmt, ...)
{
va_list ap;
fprintf(stdout, NERR_PREFIX);
va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
va_end(ap);
fflush(stdout);
fflush(stderr);
exit(1);
}
/**
* perr_exit
*
* Print and error message and exit the program
*/
__attribute__((noreturn))
__attribute__((format(printf, 1, 2)))
static int perr_exit(const char *fmt, ...)
{
va_list ap;
int eo = errno;
fprintf(stdout, PERR_PREFIX, eo);
va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
va_end(ap);
printf(": %s\n", strerror(eo));
fflush(stdout);
fflush(stderr);
exit(1);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
__attribute__((noreturn))
static void usage(void)
{
printf("\nUsage: %s [OPTIONS] DEVICE1 DEVICE2\n"
" Compare two NTFS volumes and tell the differences.\n"
"\n"
" -P, --no-progress-bar Don't show progress bar\n"
" -v, --verbose More output\n"
" -h, --help Display this help\n"
#ifdef DEBUG
" -d, --debug Show debug information\n"
#endif
"\n", EXEC_NAME);
printf("%s%s", ntfs_bugs, ntfs_home);
exit(1);
}
static void parse_options(int argc, char **argv)
{
static const char *sopt = "-dhPv";
static const struct option lopt[] = {
#ifdef DEBUG
{ "debug", no_argument, NULL, 'd' },
#endif
{ "help", no_argument, NULL, 'h' },
{ "no-progress-bar", no_argument, NULL, 'P' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
int c;
memset(&opt, 0, sizeof(opt));
opt.show_progress = 1;
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1: /* A non-option argument */
if (!opt.vol1) {
opt.vol1 = argv[optind - 1];
} else if (!opt.vol2) {
opt.vol2 = argv[optind - 1];
} else {
err_printf("Too many arguments!\n");
usage();
}
break;
#ifdef DEBUG
case 'd':
opt.debug++;
break;
#endif
case 'h':
case '?':
usage();
case 'P':
opt.show_progress = 0;
break;
case 'v':
opt.verbose++;
break;
default:
err_printf("Unknown option '%s'.\n", argv[optind - 1]);
usage();
break;
}
}
if (opt.vol1 == NULL || opt.vol2 == NULL) {
err_printf("You must specify exactly 2 volumes.\n");
usage();
}
/* Redirect stderr to stdout, note fflush()es are essential! */
fflush(stdout);
fflush(stderr);
if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) {
perror("Failed to redirect stderr to stdout");
exit(1);
}
fflush(stdout);
fflush(stderr);
#ifdef DEBUG
if (!opt.debug)
if (!freopen("/dev/null", "w", stderr))
perr_exit("Failed to redirect stderr to /dev/null");
#endif
}
static ntfs_attr_search_ctx *attr_get_search_ctx(ntfs_inode *ni)
{
ntfs_attr_search_ctx *ret;
if ((ret = ntfs_attr_get_search_ctx(ni, NULL)) == NULL)
perr_println("ntfs_attr_get_search_ctx");
return ret;
}
static void progress_init(struct progress_bar *p, u64 start, u64 stop, int flags)
{
p->start = start;
p->stop = stop;
p->unit = 100.0 / (stop - start);
p->resolution = 100;
p->flags = flags;
}
static void progress_update(struct progress_bar *p, u64 current)
{
float percent;
if (!(p->flags & NTFS_PROGBAR))
return;
if (p->flags & NTFS_PROGBAR_SUPPRESS)
return;
/* WARNING: don't modify the texts, external tools grep for them */
percent = p->unit * current;
if (current != p->stop) {
if ((current - p->start) % p->resolution)
return;
printf("%6.2f percent completed\r", percent);
} else
printf("100.00 percent completed\n");
fflush(stdout);
}
static u64 inumber(ntfs_inode *ni)
{
if (ni->nr_extents >= 0)
return ni->mft_no;
return ni->base_ni->mft_no;
}
static int inode_close(ntfs_inode *ni)
{
if (ni == NULL)
return 0;
if (ntfs_inode_close(ni)) {
perr_println("ntfs_inode_close: inode %llu", inumber(ni));
return -1;
}
return 0;
}
static inline s64 get_nr_mft_records(ntfs_volume *vol)
{
return vol->mft_na->initialized_size >> vol->mft_record_size_bits;
}
#define NTFSCMP_OK 0
#define NTFSCMP_INODE_OPEN_ERROR 1
#define NTFSCMP_INODE_OPEN_IO_ERROR 2
#define NTFSCMP_INODE_OPEN_ENOENT_ERROR 3
#define NTFSCMP_EXTENSION_RECORD 4
#define NTFSCMP_INODE_CLOSE_ERROR 5
const char *ntfscmp_errs[] = {
"OK",
"INODE_OPEN_ERROR",
"INODE_OPEN_IO_ERROR",
"INODE_OPEN_ENOENT_ERROR",
"EXTENSION_RECORD",
"INODE_CLOSE_ERROR",
""
};
static const char *err2string(int err)
{
return ntfscmp_errs[err];
}
static const char *pret2str(void *p)
{
if (p == NULL)
return "FAILED";
return "OK";
}
static int inode_open(ntfs_volume *vol, MFT_REF mref, ntfs_inode **ni)
{
*ni = ntfs_inode_open(vol, mref);
if (*ni == NULL) {
if (errno == EIO)
return NTFSCMP_INODE_OPEN_IO_ERROR;
if (errno == ENOENT)
return NTFSCMP_INODE_OPEN_ENOENT_ERROR;
perr_println("Reading inode %lld failed", mref);
return NTFSCMP_INODE_OPEN_ERROR;
}
if ((*ni)->mrec->base_mft_record) {
if (inode_close(*ni) != 0)
return NTFSCMP_INODE_CLOSE_ERROR;
return NTFSCMP_EXTENSION_RECORD;
}
return NTFSCMP_OK;
}
static ntfs_inode *base_inode(ntfs_attr_search_ctx *ctx)
{
if (ctx->base_ntfs_ino)
return ctx->base_ntfs_ino;
return ctx->ntfs_ino;
}
static void print_inode(u64 inum)
{
printf("Inode %llu ", inum);
}
static void print_inode_ni(ntfs_inode *ni)
{
print_inode(inumber(ni));
}
static void print_attribute_type(ATTR_TYPES atype)
{
printf("attribute 0x%x", atype);
}
static void print_attribute_name(char *name)
{
if (name)
printf(":%s", name);
}
#define GET_ATTR_NAME(a) \
((ntfschar *)(((u8 *)(a)) + ((a)->name_offset))), ((a)->name_length)
static void free_name(char **name)
{
if (*name) {
free(*name);
*name = NULL;
}
}
static char *get_attr_name(u64 mft_no,
ATTR_TYPES atype,
const ntfschar *uname,
const int uname_len)
{
char *name = NULL;
int name_len;
if (atype == AT_END)
return NULL;
name_len = ntfs_ucstombs(uname, uname_len, &name, 0);
if (name_len < 0) {
perr_print("ntfs_ucstombs");
print_inode(mft_no);
print_attribute_type(atype);
puts("");
exit(1);
} else if (name_len > 0)
return name;
free_name(&name);
return NULL;
}
static char *get_attr_name_na(ntfs_attr *na)
{
return get_attr_name(inumber(na->ni), na->type, na->name, na->name_len);
}
static char *get_attr_name_ctx(ntfs_attr_search_ctx *ctx)
{
u64 mft_no = inumber(ctx->ntfs_ino);
ATTR_TYPES atype = ctx->attr->type;
return get_attr_name(mft_no, atype, GET_ATTR_NAME(ctx->attr));
}
static void print_attribute(ATTR_TYPES atype, char *name)
{
print_attribute_type(atype);
print_attribute_name(name);
printf(" ");
}
static void print_na(ntfs_attr *na)
{
char *name = get_attr_name_na(na);
print_inode_ni(na->ni);
print_attribute(na->type, name);
free_name(&name);
}
static void print_attribute_ctx(ntfs_attr_search_ctx *ctx)
{
char *name = get_attr_name_ctx(ctx);
print_attribute(ctx->attr->type, name);
free_name(&name);
}
static void print_ctx(ntfs_attr_search_ctx *ctx)
{
char *name = get_attr_name_ctx(ctx);
print_inode_ni(base_inode(ctx));
print_attribute(ctx->attr->type, name);
free_name(&name);
}
static void cmp_attribute_data(ntfs_attr *na1, ntfs_attr *na2)
{
s64 pos;
s64 count1 = 0, count2;
u8 buf1[NTFS_BUF_SIZE];
u8 buf2[NTFS_BUF_SIZE];
for (pos = 0; pos <= na1->data_size; pos += count1) {
count1 = ntfs_attr_pread(na1, pos, NTFS_BUF_SIZE, buf1);
count2 = ntfs_attr_pread(na2, pos, NTFS_BUF_SIZE, buf2);
if (count1 != count2) {
print_na(na1);
printf("abrupt length: %lld != %lld ",
na1->data_size, na2->data_size);
printf("(count: %lld != %lld)", count1, count2);
puts("");
return;
}
if (count1 == -1) {
err_printf("%s read error: ", __FUNCTION__);
print_na(na1);
printf("len = %lld, pos = %lld\n", na1->data_size, pos);
exit(1);
}
if (count1 == 0) {
if (pos + count1 == na1->data_size)
return; /* we are ready */
err_printf("%s read error before EOF: ", __FUNCTION__);
print_na(na1);
printf("%lld != %lld\n", pos + count1, na1->data_size);
exit(1);
}
if (memcmp(buf1, buf2, count1)) {
print_na(na1);
printf("content");
if (opt.verbose)
printf(" (len = %lld)", count1);
printf(": DIFFER\n");
return;
}
}
err_printf("%s read overrun: ", __FUNCTION__);
print_na(na1);
err_printf("(len = %lld, pos = %lld, count = %lld)\n",
na1->data_size, pos, count1);
exit(1);
}
static int cmp_attribute_header(ATTR_RECORD *a1, ATTR_RECORD *a2)
{
u32 header_size = offsetof(ATTR_RECORD, resident_end);
if (a1->non_resident != a2->non_resident)
return 1;
if (a1->non_resident) {
/*
* FIXME: includes paddings which are not handled by ntfsinfo!
*/
header_size = a1->length;
}
return memcmp(a1, a2, header_size);
}
static void cmp_attribute(ntfs_attr_search_ctx *ctx1,
ntfs_attr_search_ctx *ctx2)
{
ATTR_RECORD *a1 = ctx1->attr;
ATTR_RECORD *a2 = ctx2->attr;
ntfs_attr *na1, *na2;
if (cmp_attribute_header(a1, a2)) {
print_ctx(ctx1);
printf("header: DIFFER\n");
}
na1 = ntfs_attr_open(base_inode(ctx1), a1->type, GET_ATTR_NAME(a1));
na2 = ntfs_attr_open(base_inode(ctx2), a2->type, GET_ATTR_NAME(a2));
if ((!na1 && na2) || (na1 && !na2)) {
print_ctx(ctx1);
printf("open: %s != %s\n", pret2str(na1), pret2str(na2));
goto close_attribs;
}
if (na1 == NULL)
goto close_attribs;
if (na1->data_size != na2->data_size) {
print_na(na1);
printf("length: %lld != %lld\n", na1->data_size, na2->data_size);
goto close_attribs;
}
if (ntfs_inode_badclus_bad(inumber(ctx1->ntfs_ino), ctx1->attr) == 1) {
/*
* If difference exists then it's already reported at the
* attribute header since the mapping pairs must differ.
*/
return;
}
cmp_attribute_data(na1, na2);
close_attribs:
ntfs_attr_close(na1);
ntfs_attr_close(na2);
}
static void vprint_attribute(ATTR_TYPES atype, char *name)
{
if (!opt.verbose)
return;
printf("0x%x", atype);
if (name)
printf(":%s", name);
printf(" ");
}
static void print_attributes(ntfs_inode *ni,
ATTR_TYPES atype1,
ATTR_TYPES atype2,
char *name1,
char *name2)
{
if (!opt.verbose)
return;
printf("Walking inode %llu attributes: ", inumber(ni));
vprint_attribute(atype1, name1);
vprint_attribute(atype2, name2);
printf("\n");
}
static int new_name(ntfs_attr_search_ctx *ctx, char *prev_name)
{
int ret = 0;
char *name = get_attr_name_ctx(ctx);
if (prev_name && name) {
if (strcmp(prev_name, name) != 0)
ret = 1;
} else if (prev_name || name)
ret = 1;
free_name(&name);
return ret;
}
static int new_attribute(ntfs_attr_search_ctx *ctx,
ATTR_TYPES prev_atype,
char *prev_name)
{
if (!prev_atype && !prev_name)
return 1;
if (!ctx->attr->non_resident)
return 1;
if (prev_atype != ctx->attr->type)
return 1;
if (new_name(ctx, prev_name))
return 1;
if (opt.verbose) {
print_inode(base_inode(ctx)->mft_no);
print_attribute_ctx(ctx);
printf("record %llu lowest_vcn %lld: SKIPPED\n",
ctx->ntfs_ino->mft_no, ctx->attr->lowest_vcn);
}
return 0;
}
static void set_prev(char **prev_name, ATTR_TYPES *prev_atype,
char *name, ATTR_TYPES atype)
{
free_name(prev_name);
if (name) {
*prev_name = strdup(name);
if (!*prev_name)
perr_exit("strdup error");
}
*prev_atype = atype;
}
static void set_cmp_attr(ntfs_attr_search_ctx *ctx, ATTR_TYPES *atype, char **name)
{
*atype = ctx->attr->type;
free_name(name);
*name = get_attr_name_ctx(ctx);
}
static int next_attr(ntfs_attr_search_ctx *ctx, ATTR_TYPES *atype, char **name,
int *err)
{
int ret;
ret = ntfs_attrs_walk(ctx);
*err = errno;
if (ret) {
*atype = AT_END;
free_name(name);
} else
set_cmp_attr(ctx, atype, name);
return ret;
}
static int cmp_attributes(ntfs_inode *ni1, ntfs_inode *ni2)
{
int ret = -1;
int old_ret1, ret1 = 0, ret2 = 0;
int errno1 = 0, errno2 = 0;
char *prev_name = NULL, *name1 = NULL, *name2 = NULL;
ATTR_TYPES old_atype1, prev_atype = 0, atype1, atype2;
ntfs_attr_search_ctx *ctx1, *ctx2;
if (!(ctx1 = attr_get_search_ctx(ni1)))
return -1;
if (!(ctx2 = attr_get_search_ctx(ni2)))
goto out;
set_cmp_attr(ctx1, &atype1, &name1);
set_cmp_attr(ctx2, &atype2, &name2);
while (1) {
old_atype1 = atype1;
old_ret1 = ret1;
if (!ret1 && (atype1 <= atype2 || ret2))
ret1 = next_attr(ctx1, &atype1, &name1, &errno1);
if (!ret2 && (old_atype1 >= atype2 || old_ret1))
ret2 = next_attr(ctx2, &atype2, &name2, &errno2);
print_attributes(ni1, atype1, atype2, name1, name2);
if (ret1 && ret2) {
if (errno1 != errno2) {
print_inode_ni(ni1);
printf("attribute walk (errno): %d != %d\n",
errno1, errno2);
}
break;
}
if (ret2 || atype1 < atype2) {
if (new_attribute(ctx1, prev_atype, prev_name)) {
print_ctx(ctx1);
printf("presence: EXISTS != MISSING\n");
set_prev(&prev_name, &prev_atype, name1, atype1);
}
} else if (ret1 || atype1 > atype2) {
if (new_attribute(ctx2, prev_atype, prev_name)) {
print_ctx(ctx2);
printf("presence: MISSING != EXISTS \n");
set_prev(&prev_name, &prev_atype, name2, atype2);
}
} else /* atype1 == atype2 */ {
if (new_attribute(ctx1, prev_atype, prev_name)) {
cmp_attribute(ctx1, ctx2);
set_prev(&prev_name, &prev_atype, name1, atype1);
}
}
}
free_name(&prev_name);
ret = 0;
ntfs_attr_put_search_ctx(ctx2);
out:
ntfs_attr_put_search_ctx(ctx1);
return ret;
}
static int cmp_inodes(ntfs_volume *vol1, ntfs_volume *vol2)
{
u64 inode;
int ret1, ret2;
ntfs_inode *ni1, *ni2;
struct progress_bar progress;
int pb_flags = 0; /* progress bar flags */
u64 nr_mft_records, nr_mft_records2;
if (opt.show_progress)
pb_flags |= NTFS_PROGBAR;
nr_mft_records = get_nr_mft_records(vol1);
nr_mft_records2 = get_nr_mft_records(vol2);
if (nr_mft_records != nr_mft_records2) {
printf("Number of mft records: %lld != %lld\n",
nr_mft_records, nr_mft_records2);
if (nr_mft_records > nr_mft_records2)
nr_mft_records = nr_mft_records2;
}
progress_init(&progress, 0, nr_mft_records - 1, pb_flags);
progress_update(&progress, 0);
for (inode = 0; inode < nr_mft_records; inode++) {
ret1 = inode_open(vol1, (MFT_REF)inode, &ni1);
ret2 = inode_open(vol2, (MFT_REF)inode, &ni2);
if (ret1 != ret2) {
print_inode(inode);
printf("open: %s != %s\n",
err2string(ret1), err2string(ret2));
goto close_inodes;
}
if (ret1 != NTFSCMP_OK)
goto close_inodes;
if (cmp_attributes(ni1, ni2) != 0) {
inode_close(ni1);
inode_close(ni2);
return -1;
}
close_inodes:
if (inode_close(ni1) != 0)
return -1;
if (inode_close(ni2) != 0)
return -1;
progress_update(&progress, inode);
}
return 0;
}
static ntfs_volume *mount_volume(const char *volume)
{
unsigned long mntflag;
ntfs_volume *vol = NULL;
if (ntfs_check_if_mounted(volume, &mntflag)) {
perr_println("Failed to check '%s' mount state", volume);
printf("Probably /etc/mtab is missing. It's too risky to "
"continue. You might try\nan another Linux distro.\n");
exit(1);
}
if (mntflag & NTFS_MF_MOUNTED) {
if (!(mntflag & NTFS_MF_READONLY))
err_exit("Device '%s' is mounted read-write. "
"You must 'umount' it first.\n", volume);
}
vol = ntfs_mount(volume, MS_RDONLY);
if (vol == NULL) {
int err = errno;
perr_println("Opening '%s' as NTFS failed", volume);
if (err == EINVAL)
printf(invalid_ntfs_msg, volume);
else if (err == EIO)
puts(corrupt_volume_msg);
else if (err == EPERM)
puts(hibernated_volume_msg);
exit(1);
}
return vol;
}
int main(int argc, char **argv)
{
ntfs_volume *vol1;
ntfs_volume *vol2;
printf("%s v%s (libntfs-3g)\n", EXEC_NAME, VERSION);
parse_options(argc, argv);
utils_set_locale();
vol1 = mount_volume(opt.vol1);
vol2 = mount_volume(opt.vol2);
if (cmp_inodes(vol1, vol2) != 0)
exit(1);
ntfs_umount(vol1, FALSE);
ntfs_umount(vol2, FALSE);
exit(0);
}

128
ntfsprogs/ntfscp.8.in Normal file
View File

@ -0,0 +1,128 @@
.\" Copyright (c) 2004\-2005 Yura Pakhuchiy.
.\" Copyright (c) 2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSCP 8 "November 2005" "ntfsprogs @VERSION@"
.SH NAME
ntfscp \- overwrite file on an NTFS volume.
.SH SYNOPSIS
.B ntfscp
[\fIoptions\fR] \fIdevice source_file destination\fR
.SH DESCRIPTION
.B ntfscp
will overwrite file on an NTFS volume. At present
.B ntfscp
can't create new files.
.B destination
can be either file or directory. In case if
.B destination
is directory specified by name then
.B source_file
is copied into this directory, in case if
.B destination
is directory and specified by inode number then unnamed data attribute is
created for this inode and
.B source_file
is copied into it (WARNING: it's unusual to have unnamed data streams in the
directories, think twice before specifying directory by inode number).
.SH OPTIONS
Below is a summary of all the options that
.B ntfscp
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-a\fR, \fB\-\-attribute\fR NUM
Write to this attribute.
.TP
\fB\-i\fR, \fB\-\-inode\fR
Treat
.I destination
as inode number.
.TP
\fB\-N\fR, \fB\-\-attr\-name\fR NAME
Write to attribute with this name.
.TP
\fB\-n\fR, \fB\-\-no\-action\fR
Use this option to make a test run before doing the real copy operation.
Volume will be opened read\-only and no write will be done.
.TP
\fB\-f\fR, \fB\-\-force\fR
This will override some sensible defaults, such as not working with a mounted
volume. Use this option with caution.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Suppress some debug/warning/error messages.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license
.BR ntfscp .
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Display more debug/warning/error messages.
.SH DATA STREAMS
All data on NTFS is stored in streams, which can have names. A file can have
more than one data streams, but exactly one must have no name. The size of a
file is the size of its unnamed data stream. Usually when you don't specify
stream name you are access to unnamed data stream. If you want access to named
data stream you need to add ":stream_name" to the filename. For example: by
opening "some.mp3:artist" you will open stream "artist" in "some.mp3". But
windows usually prevent you from accessing to named data streams, so you need
to use some program like FAR or utils from cygwin to access named data streams.
.SH EXAMPLES
Copy new_boot.ini from /home/user as boot.ini to the root of an /dev/hda1 NTFS
volume:
.RS
.sp
.B ntfscp /dev/hda1 /home/user/new_boot.ini boot.ini
.sp
.RE
Copy myfile to C:\\some\\path\\myfile:stream (assume that /dev/hda1 letter in
windows is C):
.RS
.sp
.B ntfscp \-N stream /dev/hda1 myfile /some/path
.sp
.RE
.SH BUGS
There are no known problems with
.BR ntfscp .
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
.B ntfscp
was written by Yura Pakhuchiy, with contributions from Anton Altaparmakov.
.SH DEDICATION
With love to Marina Sapego.
.SH AVAILABILITY
.B ntfscp
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR ntfsprogs (8)

480
ntfsprogs/ntfscp.c Normal file
View File

@ -0,0 +1,480 @@
/**
* ntfscp - Part of the Linux-NTFS project.
*
* Copyright (c) 2004-2005 Yura Pakhuchiy
* Copyright (c) 2005 Anton Altaparmakov
*
* This utility will overwrite files on NTFS volume.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <signal.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/volume.h>
#include <ntfs-3g/dir.h>
#include <ntfs-3g/debug.h>
#include <ntfs-3g/logging.h>
#include "utils.h"
/* #include "version.h" */
struct options {
char *device; /* Device/File to work with */
char *src_file; /* Source file */
char *dest_file; /* Destination file */
char *attr_name; /* Write to attribute with this name. */
int force; /* Override common sense */
int quiet; /* Less output */
int verbose; /* Extra output */
int noaction; /* Do not write to disk */
ATTR_TYPES attribute; /* Write to this attribute. */
int inode; /* Treat dest_file as inode number. */
};
static const char *EXEC_NAME = "ntfscp";
static struct options opts;
volatile sig_atomic_t caught_terminate = 0;
/**
* version - Print version information about the program
*
* Print a copyright statement and a brief description of the program.
*
* Return: none
*/
static void version(void)
{
ntfs_log_info("\n%s v%s (libntfs-3g) - Overwrite files on NTFS "
"volume.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c) 2004-2005 Yura Pakhuchiy\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
static void usage(void)
{
ntfs_log_info("\nUsage: %s [options] device src_file dest_file\n\n"
" -a, --attribute NUM Write to this attribute\n"
" -i, --inode Treat dest_file as inode number\n"
" -f, --force Use less caution\n"
" -h, --help Print this help\n"
" -N, --attr-name NAME Write to attribute with this name\n"
" -n, --no-action Do not write to disk\n"
" -q, --quiet Less output\n"
" -V, --version Version information\n"
" -v, --verbose More output\n\n",
EXEC_NAME);
ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
* parse_options - Read and validate the programs command line
*
* Read the command line, verify the syntax and parse the options.
* This function is very long, but quite simple.
*
* Return: 1 Success
* 0 Error, one or more problems
*/
static int parse_options(int argc, char **argv)
{
static const char *sopt = "-a:ifh?N:nqVv";
static const struct option lopt[] = {
{ "attribute", required_argument, NULL, 'a' },
{ "inode", no_argument, NULL, 'i' },
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "attr-name", required_argument, NULL, 'N' },
{ "no-action", no_argument, NULL, 'n' },
{ "quiet", no_argument, NULL, 'q' },
{ "version", no_argument, NULL, 'V' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
char *s;
int c = -1;
int err = 0;
int ver = 0;
int help = 0;
int levels = 0;
s64 attr;
opts.device = NULL;
opts.src_file = NULL;
opts.dest_file = NULL;
opts.attr_name = NULL;
opts.inode = 0;
opts.attribute = AT_DATA;
opterr = 0; /* We'll handle the errors, thank you. */
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1: /* A non-option argument */
if (!opts.device) {
opts.device = argv[optind - 1];
} else if (!opts.src_file) {
opts.src_file = argv[optind - 1];
} else if (!opts.dest_file) {
opts.dest_file = argv[optind - 1];
} else {
ntfs_log_error("You must specify exactly two "
"files.\n");
err++;
}
break;
case 'a':
if (opts.attribute != AT_DATA) {
ntfs_log_error("You can specify only one "
"attribute.\n");
err++;
break;
}
attr = strtol(optarg, &s, 0);
if (*s) {
ntfs_log_error("Couldn't parse attribute.\n");
err++;
} else
opts.attribute = (ATTR_TYPES)attr;
break;
case 'i':
opts.inode++;
break;
case 'f':
opts.force++;
break;
case 'h':
case '?':
if (strncmp(argv[optind - 1], "--log-", 6) == 0) {
if (!ntfs_log_parse_option(argv[optind - 1]))
err++;
break;
}
help++;
break;
case 'N':
if (opts.attr_name) {
ntfs_log_error("You can specify only one "
"attribute name.\n");
err++;
} else
opts.attr_name = argv[optind - 1];
break;
case 'n':
opts.noaction++;
break;
case 'q':
opts.quiet++;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 'V':
ver++;
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
default:
ntfs_log_error("Unknown option '%s'.\n",
argv[optind - 1]);
err++;
break;
}
}
/* Make sure we're in sync with the log levels */
levels = ntfs_log_get_levels();
if (levels & NTFS_LOG_LEVEL_VERBOSE)
opts.verbose++;
if (!(levels & NTFS_LOG_LEVEL_QUIET))
opts.quiet++;
if (help || ver) {
opts.quiet = 0;
} else {
if (!opts.device) {
ntfs_log_error("You must specify a device.\n");
err++;
} else if (!opts.src_file) {
ntfs_log_error("You must specify a source file.\n");
err++;
} else if (!opts.dest_file) {
ntfs_log_error("You must specify a destination "
"file.\n");
err++;
}
if (opts.quiet && opts.verbose) {
ntfs_log_error("You may not use --quiet and --verbose "
"at the same time.\n");
err++;
}
}
if (ver)
version();
if (help || err)
usage();
return (!err && !help && !ver);
}
/**
* signal_handler - Handle SIGINT and SIGTERM: abort write, sync and exit.
*/
static void signal_handler(int arg __attribute__((unused)))
{
caught_terminate++;
}
/**
* main - Begin here
*
* Start from here.
*
* Return: 0 Success, the program worked
* 1 Error, something went wrong
*/
int main(int argc, char *argv[])
{
FILE *in;
ntfs_volume *vol;
ntfs_inode *out;
ntfs_attr *na;
int flags = 0;
int result = 1;
s64 new_size;
u64 offset;
char *buf;
s64 br, bw;
ntfschar *attr_name;
int attr_name_len = 0;
ntfs_log_set_handler(ntfs_log_handler_stderr);
if (!parse_options(argc, argv))
return 1;
utils_set_locale();
/* Set SIGINT handler. */
if (signal(SIGINT, signal_handler) == SIG_ERR) {
ntfs_log_perror("Failed to set SIGINT handler");
return 1;
}
/* Set SIGTERM handler. */
if (signal(SIGTERM, signal_handler) == SIG_ERR) {
ntfs_log_perror("Failed to set SIGTERM handler");
return 1;
}
if (opts.noaction)
flags = MS_RDONLY;
vol = utils_mount_volume(opts.device, flags, opts.force);
if (!vol) {
ntfs_log_perror("ERROR: couldn't mount volume");
return 1;
}
if ((vol->flags & VOLUME_IS_DIRTY) && (!opts.force))
goto umount;
{
struct stat fst;
if (stat(opts.src_file, &fst) == -1) {
ntfs_log_perror("ERROR: Couldn't stat source file");
goto umount;
}
new_size = fst.st_size;
}
ntfs_log_verbose("New file size: %lld\n", new_size);
in = fopen(opts.src_file, "r");
if (!in) {
ntfs_log_perror("ERROR: Couldn't open source file");
goto umount;
}
if (opts.inode) {
s64 inode_num;
char *s;
inode_num = strtoll(opts.dest_file, &s, 0);
if (*s) {
ntfs_log_error("ERROR: Couldn't parse inode number.\n");
goto close_src;
}
out = ntfs_inode_open(vol, inode_num);
} else
out = ntfs_pathname_to_inode(vol, NULL, opts.dest_file);
if (!out) {
ntfs_log_perror("ERROR: Couldn't open destination file");
goto close_src;
}
if ((le16_to_cpu(out->mrec->flags) & MFT_RECORD_IS_DIRECTORY) &&
!opts.inode){
/*
* @out is directory and it was specified by pathname, add
* filename to path and reopen inode.
*/
char *filename, *new_dest_file;
/*
* FIXME: There should exist more beautiful way to get filename.
* Not sure that it will work in windows, but I don't think that
* someone will use ntfscp under windows.
*/
filename = strrchr(opts.src_file, '/');
if (filename)
filename++;
else
filename = opts.src_file;
/* Add 2 bytes for '/' and null-terminator. */
new_dest_file = malloc(strlen(opts.dest_file) +
strlen(filename) + 2);
if (!new_dest_file) {
ntfs_log_perror("ERROR: malloc() failed");
goto close_dst;
}
strcpy(new_dest_file, opts.dest_file);
strcat(new_dest_file, "/");
strcat(new_dest_file, filename);
ntfs_inode_close(out);
out = ntfs_pathname_to_inode(vol, NULL, new_dest_file);
free(new_dest_file);
if (!out) {
ntfs_log_perror("ERROR: Failed to open destination "
"file");
goto close_src;
}
}
attr_name = ntfs_str2ucs(opts.attr_name, &attr_name_len);
if (!attr_name) {
ntfs_log_perror("ERROR: Failed to parse attribute name '%s'",
opts.attr_name);
goto close_dst;
}
na = ntfs_attr_open(out, opts.attribute, attr_name, attr_name_len);
if (!na) {
if (errno != ENOENT) {
ntfs_log_perror("ERROR: Couldn't open attribute");
goto close_dst;
}
/* Requested attribute isn't present, add it. */
if (ntfs_attr_add(out, opts.attribute, attr_name,
attr_name_len, NULL, 0)) {
ntfs_log_perror("ERROR: Couldn't add attribute");
goto close_dst;
}
na = ntfs_attr_open(out, opts.attribute, attr_name,
attr_name_len);
if (!na) {
ntfs_log_perror("ERROR: Couldn't open just added "
"attribute");
goto close_dst;
}
}
ntfs_ucsfree(attr_name);
ntfs_log_verbose("Old file size: %lld\n", na->data_size);
if (na->data_size != new_size) {
if (ntfs_attr_truncate(na, new_size)) {
ntfs_log_perror("ERROR: Couldn't resize attribute");
goto close_attr;
}
}
buf = malloc(NTFS_BUF_SIZE);
if (!buf) {
ntfs_log_perror("ERROR: malloc failed");
goto close_attr;
}
ntfs_log_verbose("Starting write.\n");
offset = 0;
while (!feof(in)) {
if (caught_terminate) {
ntfs_log_error("SIGTERM or SIGINT received. "
"Aborting write.\n");
break;
}
br = fread(buf, 1, NTFS_BUF_SIZE, in);
if (!br) {
if (!feof(in)) ntfs_log_perror("ERROR: fread failed");
break;
}
bw = ntfs_attr_pwrite(na, offset, br, buf);
if (bw != br) {
ntfs_log_perror("ERROR: ntfs_attr_pwrite failed");
break;
}
offset += bw;
}
ntfs_log_verbose("Syncing.\n");
result = 0;
free(buf);
close_attr:
ntfs_attr_close(na);
close_dst:
while (ntfs_inode_close(out)) {
if (errno != EBUSY) {
ntfs_log_error("Sync failed. Run chkdsk.\n");
break;
}
ntfs_log_error("Device busy. Will retry sync in 3 seconds.\n");
sleep(3);
}
close_src:
fclose(in);
umount:
ntfs_umount(vol, FALSE);
ntfs_log_verbose("Done.\n");
return result;
}

1350
ntfsprogs/ntfsdecrypt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,777 @@
/**
* ntfsdump_logfile - Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2005 Anton Altaparmakov
*
* This utility will interpret the contents of the journal ($LogFile) of an
* NTFS partition and display the results on stdout. Errors will be output to
* stderr.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS source
* in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* TODO:
* - Remove the need for clipping at 64MiB.
* - Add normal command line switchs (use getopt_long()).
* - For a volume: allow dumping only uncommitted records.
* - For a file: get an optional command line parameter for the last SN.
* - Sanity checks.
*/
#include "config.h"
#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_STDARG_H
#include <stdarg.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
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/endians.h>
#include <ntfs-3g/volume.h>
#include <ntfs-3g/inode.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/layout.h>
#include <ntfs-3g/logfile.h>
#include <ntfs-3g/mst.h>
#include <ntfs-3g/logging.h>
#include "utils.h"
/* #include "version.h" */
typedef struct {
BOOL is_volume;
const char *filename;
s64 data_size;
union {
struct {
ntfs_volume *vol;
ntfs_inode *ni;
ntfs_attr *na;
};
struct {
int fd;
};
};
} logfile_file;
/**
* logfile_close
*/
static int logfile_close(logfile_file *logfile)
{
if (logfile->is_volume) {
if (logfile->na)
ntfs_attr_close(logfile->na);
if (logfile->ni && ntfs_inode_close(logfile->ni))
ntfs_log_perror("Warning: Failed to close $LogFile "
"(inode %i)", FILE_LogFile);
if (ntfs_umount(logfile->vol, 0))
ntfs_log_perror("Warning: Failed to umount %s",
logfile->filename);
} else {
if (close(logfile->fd))
ntfs_log_perror("Warning: Failed to close file %s",
logfile->filename);
}
return 0;
}
/**
* device_err_exit - put an error message, cleanup and exit.
* @vol: volume to unmount.
* @ni: Inode to free.
* @na: Attribute to close.
*
* Use when you wish to exit and collate all the cleanups together.
* if you don't have some parameter to pass, just pass NULL.
*/
__attribute__((noreturn))
__attribute__((format(printf, 4, 5)))
static void device_err_exit(ntfs_volume *vol, ntfs_inode *ni,
ntfs_attr *na, const char *fmt, ...)
{
va_list ap;
if (na)
ntfs_attr_close(na);
if (ni && ntfs_inode_close(ni))
ntfs_log_perror("Warning: Failed to close $LogFile (inode %i)",
FILE_LogFile);
if (ntfs_umount(vol, 0))
ntfs_log_perror("Warning: Failed to umount");
fprintf(stderr, "ERROR: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
ntfs_log_error("Aborting...\n");
exit(1);
}
/**
* log_err_exit -
*/
__attribute__((noreturn))
__attribute__((format(printf, 2, 3)))
static void log_err_exit(u8 *buf, const char *fmt, ...)
{
va_list ap;
free(buf);
fprintf(stderr, "ERROR: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
ntfs_log_error("Aborting...\n");
exit(1);
}
/**
* usage -
*/
__attribute__((noreturn))
static void usage(const char *exec_name)
{
ntfs_log_error("%s v%s (libntfs-3g) - Interpret and display information "
"about the journal\n($LogFile) of an NTFS volume.\n"
"Copyright (c) 2000-2005 Anton Altaparmakov.\n"
"%s is free software, released under the GNU General "
"Public License\nand you are welcome to redistribute "
"it under certain conditions.\n%s comes with "
"ABSOLUTELY NO WARRANTY; for details read the GNU\n"
"General Public License to be found in the file "
"COPYING in the main Linux-NTFS\ndistribution "
"directory.\nUsage: %s device\n e.g. %s /dev/hda6\n"
"Alternative usage: %s -f file\n e.g. %s -f "
"MyCopyOfTheLogFile\n", exec_name, VERSION,
exec_name, exec_name,
exec_name, exec_name, exec_name, exec_name);
exit(1);
}
/**
* logfile_open
*/
static int logfile_open(BOOL is_volume, const char *filename,
logfile_file *logfile)
{
if (is_volume) {
ntfs_volume *vol;
ntfs_inode *ni;
ntfs_attr *na;
vol = ntfs_mount(filename, MS_RDONLY);
if (!vol)
log_err_exit(NULL, "Failed to mount %s: %s\n",
filename, strerror(errno));
ntfs_log_info("Mounted NTFS volume %s (NTFS v%i.%i) on device %s.\n",
vol->vol_name ? vol->vol_name : "<NO_NAME>",
vol->major_ver, vol->minor_ver, filename);
if (ntfs_version_is_supported(vol))
device_err_exit(vol, NULL, NULL,
"Unsupported NTFS version.\n");
ni = ntfs_inode_open(vol, FILE_LogFile);
if (!ni)
device_err_exit(vol, NULL, NULL, "Failed to "
"open $LogFile (inode %i): %s\n",
FILE_LogFile, strerror(errno));
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
if (!na)
device_err_exit(vol, ni, NULL, "Failed to open "
"$LogFile/$DATA (attribute 0x%x):"
" %s\n", (unsigned int)
le32_to_cpu(AT_DATA), strerror(errno));
if (!na->data_size)
device_err_exit(vol, ni, na, "$LogFile has zero "
"length. Run chkdsk /f to correct "
"this.\n");
logfile->data_size = na->data_size;
logfile->vol = vol;
logfile->ni = ni;
logfile->na = na;
} else {
struct stat sbuf;
int fd;
if (stat(filename, &sbuf) == -1) {
if (errno == ENOENT)
log_err_exit(NULL, "The file %s does not "
"exist. Did you specify it "
"correctly?\n", filename);
log_err_exit(NULL, "Error getting information about "
"%s: %s\n", filename, strerror(errno));
}
fd = open(filename, O_RDONLY);
if (fd == -1)
log_err_exit(NULL, "Failed to open file %s: %s\n",
filename, strerror(errno));
logfile->data_size = sbuf.st_size;
logfile->fd = fd;
}
logfile->is_volume = is_volume;
logfile->filename = filename;
return 0;
}
/**
* logfile_read
*/
static int logfile_pread(logfile_file *logfile, int ofs, int count, u8 *buf)
{
int br;
if (logfile->is_volume) {
br = (int)ntfs_attr_pread(logfile->na, ofs, count, buf);
} else {
if (lseek(logfile->fd, ofs, SEEK_SET)==-1) {
ntfs_log_error("Could not seek to offset %u\n", ofs);
return 0;
}
br = read(logfile->fd, buf, count);
}
if (br != count) {
ntfs_log_error("Only %d out of %d bytes read starting at %d\n",
br, count, ofs);
}
return br;
}
/**
* restart_header_sanity()
*/
static void restart_header_sanity(RESTART_PAGE_HEADER *rstr, u8 *buf)
{
unsigned int usa_end_ofs, page_size;
/* Only CHKD records are allowed to have chkdsk_lsn set. */
if (!ntfs_is_chkd_record(rstr->magic) &&
sle64_to_cpu(rstr->chkdsk_lsn))
log_err_exit(buf, "$LogFile is corrupt: Restart page header "
"magic is not CHKD but a chkdsk LSN is "
"specified. Cannot handle this yet.\n");
/* Both system and log page size must be >= 512 and a power of 2. */
page_size = le32_to_cpu(rstr->log_page_size);
if (page_size < 512 || page_size & (page_size - 1))
log_err_exit(buf, "$LogFile is corrupt: Restart page header "
"specifies invalid log page size. Cannot "
"handle this yet.\n");
if (page_size != le32_to_cpu(rstr->system_page_size)) {
page_size = le32_to_cpu(rstr->system_page_size);
if (page_size < 512 || page_size & (page_size - 1))
log_err_exit(buf, "$LogFile is corrupt: Restart page "
"header specifies invalid system page "
"size. Cannot handle this yet.\n");
}
/* Abort if the version number is not 1.1. */
if (sle16_to_cpu(rstr->major_ver != 1) ||
sle16_to_cpu(rstr->minor_ver != 1))
log_err_exit(buf, "Unknown $LogFile version %i.%i. Only know "
"how to handle version 1.1.\n",
sle16_to_cpu(rstr->major_ver),
sle16_to_cpu(rstr->minor_ver));
/* Verify the location and size of the update sequence array. */
usa_end_ofs = le16_to_cpu(rstr->usa_ofs) +
le16_to_cpu(rstr->usa_count) * sizeof(u16);
if (page_size / NTFS_BLOCK_SIZE + 1 != le16_to_cpu(rstr->usa_count))
log_err_exit(buf, "Restart page header in $LogFile is "
"corrupt: Update sequence array size is "
"wrong. Cannot handle this yet.\n");
if (le16_to_cpu(rstr->usa_ofs) < sizeof(RESTART_PAGE_HEADER))
log_err_exit(buf, "Restart page header in $LogFile is "
"corrupt: Update sequence array overlaps "
"restart page header. Cannot handle this "
"yet.\n");
if (usa_end_ofs > NTFS_BLOCK_SIZE - sizeof(u16))
log_err_exit(buf, "Restart page header in $LogFile is "
"corrupt: Update sequence array overlaps or "
"is behind first protected sequence number. "
"Cannot handle this yet.\n");
if (usa_end_ofs > le16_to_cpu(rstr->restart_area_offset))
log_err_exit(buf, "Restart page header in $LogFile is "
"corrupt: Update sequence array overlaps or "
"is behind restart area. Cannot handle this "
"yet.\n");
/* Finally, verify the offset of the restart area. */
if (le16_to_cpu(rstr->restart_area_offset) & 7)
log_err_exit(buf, "Restart page header in $LogFile is "
"corrupt: Restart area offset is not aligned "
"to 8-byte boundary. Cannot handle this "
"yet.\n");
}
/**
* dump_restart_areas_header
*/
static void dump_restart_areas_header(RESTART_PAGE_HEADER *rstr)
{
ntfs_log_info("\nRestart page header:\n");
ntfs_log_info("magic = %s\n", ntfs_is_rstr_record(rstr->magic) ? "RSTR" :
"CHKD");
ntfs_log_info("usa_ofs = %u (0x%x)\n", le16_to_cpu(rstr->usa_ofs),
le16_to_cpu(rstr->usa_ofs));
ntfs_log_info("usa_count = %u (0x%x)\n", le16_to_cpu(rstr->usa_count),
le16_to_cpu(rstr->usa_count));
ntfs_log_info("chkdsk_lsn = %lli (0x%llx)\n",
(long long)sle64_to_cpu(rstr->chkdsk_lsn),
(unsigned long long)sle64_to_cpu(rstr->chkdsk_lsn));
ntfs_log_info("system_page_size = %u (0x%x)\n",
(unsigned int)le32_to_cpu(rstr->system_page_size),
(unsigned int)le32_to_cpu(rstr->system_page_size));
ntfs_log_info("log_page_size = %u (0x%x)\n",
(unsigned int)le32_to_cpu(rstr->log_page_size),
(unsigned int)le32_to_cpu(rstr->log_page_size));
ntfs_log_info("restart_offset = %u (0x%x)\n",
le16_to_cpu(rstr->restart_area_offset),
le16_to_cpu(rstr->restart_area_offset));
}
/**
* dump_restart_areas_area
*/
static void dump_restart_areas_area(RESTART_PAGE_HEADER *rstr)
{
LOG_CLIENT_RECORD *lcr;
RESTART_AREA *ra;
int client;
ra = (RESTART_AREA*)((u8*)rstr +
le16_to_cpu(rstr->restart_area_offset));
ntfs_log_info("current_lsn = %lli (0x%llx)\n",
(long long)sle64_to_cpu(ra->current_lsn),
(unsigned long long)sle64_to_cpu(ra->current_lsn));
ntfs_log_info("log_clients = %u (0x%x)\n", le16_to_cpu(ra->log_clients),
le16_to_cpu(ra->log_clients));
ntfs_log_info("client_free_list = %i (0x%x)\n",
(s16)le16_to_cpu(ra->client_free_list),
le16_to_cpu(ra->client_free_list));
ntfs_log_info("client_in_use_list = %i (0x%x)\n",
(s16)le16_to_cpu(ra->client_in_use_list),
le16_to_cpu(ra->client_in_use_list));
ntfs_log_info("flags = 0x%.4x\n", le16_to_cpu(ra->flags));
ntfs_log_info("seq_number_bits = %u (0x%x)\n",
(unsigned int)le32_to_cpu(ra->seq_number_bits),
(unsigned int)le32_to_cpu(ra->seq_number_bits));
ntfs_log_info("restart_area_length = %u (0x%x)\n",
le16_to_cpu(ra->restart_area_length),
le16_to_cpu(ra->restart_area_length));
ntfs_log_info("client_array_offset = %u (0x%x)\n",
le16_to_cpu(ra->client_array_offset),
le16_to_cpu(ra->client_array_offset));
ntfs_log_info("file_size = %lli (0x%llx)\n",
(long long)sle64_to_cpu(ra->file_size),
(unsigned long long)sle64_to_cpu(ra->file_size));
ntfs_log_info("last_lsn_data_length = %u (0x%x)\n",
(unsigned int)le32_to_cpu(ra->last_lsn_data_length),
(unsigned int)le32_to_cpu(ra->last_lsn_data_length));
ntfs_log_info("log_record_header_length = %u (0x%x)\n",
le16_to_cpu(ra->log_record_header_length),
le16_to_cpu(ra->log_record_header_length));
ntfs_log_info("log_page_data_offset = %u (0x%x)\n",
le16_to_cpu(ra->log_page_data_offset),
le16_to_cpu(ra->log_page_data_offset));
ntfs_log_info("restart_log_open_count = %u (0x%x)\n",
(unsigned)le32_to_cpu(ra->restart_log_open_count),
(unsigned)le32_to_cpu(ra->restart_log_open_count));
lcr = (LOG_CLIENT_RECORD*)((u8*)ra +
le16_to_cpu(ra->client_array_offset));
for (client = 0; client < le16_to_cpu(ra->log_clients); client++) {
char *client_name;
ntfs_log_info("\nLog client record number %i:\n", client + 1);
ntfs_log_info("oldest_lsn = %lli (0x%llx)\n",
(long long)sle64_to_cpu(lcr->oldest_lsn),
(unsigned long long)
sle64_to_cpu(lcr->oldest_lsn));
ntfs_log_info("client_restart_lsn = %lli (0x%llx)\n", (long long)
sle64_to_cpu(lcr->client_restart_lsn),
(unsigned long long)
sle64_to_cpu(lcr->client_restart_lsn));
ntfs_log_info("prev_client = %i (0x%x)\n",
(s16)le16_to_cpu(lcr->prev_client),
le16_to_cpu(lcr->prev_client));
ntfs_log_info("next_client = %i (0x%x)\n",
(s16)le16_to_cpu(lcr->next_client),
le16_to_cpu(lcr->next_client));
ntfs_log_info("seq_number = %u (0x%x)\n", le16_to_cpu(lcr->seq_number),
le16_to_cpu(lcr->seq_number));
ntfs_log_info("client_name_length = %u (0x%x)\n",
(unsigned int)le32_to_cpu(lcr->client_name_length) / 2,
(unsigned int)le32_to_cpu(lcr->client_name_length) / 2);
if (le32_to_cpu(lcr->client_name_length)) {
client_name = NULL;
if (ntfs_ucstombs(lcr->client_name,
le32_to_cpu(lcr->client_name_length) /
2, &client_name, 0) < 0) {
ntfs_log_perror("Failed to convert log client name");
client_name = strdup("<conversion error>");
}
} else
client_name = strdup("<unnamed>");
ntfs_log_info("client_name = %s\n", client_name);
free(client_name);
/*
* Log client records are fixed size so we can simply use the
* C increment operator to get to the next one.
*/
lcr++;
}
}
/**
* dump_restart_areas()
*/
static void *dump_restart_areas(RESTART_PAGE_HEADER *rstr, u8 *buf,
unsigned int page_size)
{
int pass = 1;
rstr_pass_loc:
if (ntfs_is_chkd_record(rstr->magic))
log_err_exit(buf, "The %s restart page header in $LogFile has "
"been modified by chkdsk. Do not know how to "
"handle this yet. Reboot into Windows to fix "
"this.\n", (u8*)rstr == buf ? "first" :
"second");
if (ntfs_mst_post_read_fixup((NTFS_RECORD*)rstr, page_size) ||
ntfs_is_baad_record(rstr->magic))
log_err_exit(buf, "$LogFile incomplete multi sector transfer "
"detected in restart page header. Cannot "
"handle this yet.\n");
if (pass == 1)
ntfs_log_info("$LogFile version %i.%i.\n",
sle16_to_cpu(rstr->major_ver),
sle16_to_cpu(rstr->minor_ver));
else /* if (pass == 2) */ {
RESTART_AREA *ra;
/*
* rstr is now the second restart page so we declare rstr1
* as the first restart page as this one has been verified in
* the first pass so we can use all its members safely.
*/
RESTART_PAGE_HEADER *rstr1 = (RESTART_PAGE_HEADER*)buf;
/* Exclude the usa from the comparison. */
ra = (RESTART_AREA*)((u8*)rstr1 +
le16_to_cpu(rstr1->restart_area_offset));
if (!memcmp(rstr1, rstr, le16_to_cpu(rstr1->usa_ofs)) &&
!memcmp((u8*)rstr1 + le16_to_cpu(
rstr1->restart_area_offset), (u8*)rstr +
le16_to_cpu(rstr->restart_area_offset),
le16_to_cpu(ra->restart_area_length))) {
puts("\nSkipping analysis of second restart page "
"because it fully matches the first "
"one.");
goto skip_rstr_pass;
}
/*
* The $LogFile versions specified in each of the two restart
* page headers must match.
*/
if (rstr1->major_ver != rstr->major_ver ||
rstr1->minor_ver != rstr->minor_ver)
log_err_exit(buf, "Second restart area specifies "
"different $LogFile version to first "
"restart area. Cannot handle this "
"yet.\n");
}
/* The restart page header is in rstr and it is mst deprotected. */
ntfs_log_info("\n%s restart page:\n", pass == 1 ? "1st" : "2nd");
dump_restart_areas_header(rstr);
ntfs_log_info("\nRestart area:\n");
dump_restart_areas_area(rstr);
skip_rstr_pass:
if (pass == 1) {
rstr = (RESTART_PAGE_HEADER*)((u8*)rstr + page_size);
++pass;
goto rstr_pass_loc;
}
return rstr;
}
/**
* dump_log_records()
*/
static void dump_log_record(LOG_RECORD *lr)
{
unsigned int i;
ntfs_log_info("this lsn = 0x%llx\n",
(unsigned long long)le64_to_cpu(lr->this_lsn));
ntfs_log_info("client previous lsn = 0x%llx\n", (unsigned long long)
le64_to_cpu(lr->client_previous_lsn));
ntfs_log_info("client undo next lsn = 0x%llx\n", (unsigned long long)
le64_to_cpu(lr->client_undo_next_lsn));
ntfs_log_info("client data length = 0x%x\n",
(unsigned int)le32_to_cpu(lr->client_data_length));
ntfs_log_info("client_id.seq_number = 0x%x\n",
le16_to_cpu(lr->client_id.seq_number));
ntfs_log_info("client_id.client_index = 0x%x\n",
le16_to_cpu(lr->client_id.client_index));
ntfs_log_info("record type = 0x%x\n",
(unsigned int)le32_to_cpu(lr->record_type));
ntfs_log_info("transaction_id = 0x%x\n",
(unsigned int)le32_to_cpu(lr->transaction_id));
ntfs_log_info("flags = 0x%x:", lr->flags);
if (!lr->flags)
ntfs_log_info(" NONE\n");
else {
int _b = 0;
if (lr->flags & LOG_RECORD_MULTI_PAGE) {
ntfs_log_info(" LOG_RECORD_MULTI_PAGE");
_b = 1;
}
if (lr->flags & ~LOG_RECORD_MULTI_PAGE) {
if (_b)
ntfs_log_info(" |");
ntfs_log_info(" Unknown flags");
}
ntfs_log_info("\n");
}
ntfs_log_info("redo_operation = 0x%x\n", le16_to_cpu(lr->redo_operation));
ntfs_log_info("undo_operation = 0x%x\n", le16_to_cpu(lr->undo_operation));
ntfs_log_info("redo_offset = 0x%x\n", le16_to_cpu(lr->redo_offset));
ntfs_log_info("redo_length = 0x%x\n", le16_to_cpu(lr->redo_length));
ntfs_log_info("undo_offset = 0x%x\n", le16_to_cpu(lr->undo_offset));
ntfs_log_info("undo_length = 0x%x\n", le16_to_cpu(lr->undo_length));
ntfs_log_info("target_attribute = 0x%x\n", le16_to_cpu(lr->target_attribute));
ntfs_log_info("lcns_to_follow = 0x%x\n", le16_to_cpu(lr->lcns_to_follow));
ntfs_log_info("record_offset = 0x%x\n", le16_to_cpu(lr->record_offset));
ntfs_log_info("attribute_offset = 0x%x\n", le16_to_cpu(lr->attribute_offset));
ntfs_log_info("target_vcn = 0x%llx\n",
(unsigned long long)sle64_to_cpu(lr->target_vcn));
if (le16_to_cpu(lr->lcns_to_follow) > 0)
ntfs_log_info("Array of lcns:\n");
for (i = 0; i < le16_to_cpu(lr->lcns_to_follow); i++)
ntfs_log_info("lcn_list[%u].lcn = 0x%llx\n", i, (unsigned long long)
sle64_to_cpu(lr->lcn_list[i].lcn));
}
/**
* dump_log_records()
*/
static void dump_log_records(RECORD_PAGE_HEADER *rcrd, u8 *buf,
int buf_size, unsigned int page_size)
{
LOG_RECORD *lr;
int pass = 0;
int client;
/* Reuse pass for log area. */
rcrd_pass_loc:
rcrd = (RECORD_PAGE_HEADER*)((u8*)rcrd + page_size);
if ((u8*)rcrd + page_size > buf + buf_size)
return;
ntfs_log_info("\nLog record page number %i", pass);
if (!ntfs_is_rcrd_record(rcrd->magic) &&
!ntfs_is_chkd_record(rcrd->magic)) {
unsigned int i;
for (i = 0; i < page_size; i++)
if (((u8*)rcrd)[i] != (u8)-1)
break;
if (i < page_size)
puts(" is corrupt (magic is not RCRD or CHKD).");
else
puts(" is empty.");
pass++;
goto rcrd_pass_loc;
} else
puts(":");
/* Dump log record page */
ntfs_log_info("magic = %s\n", ntfs_is_rcrd_record(rcrd->magic) ? "RCRD" :
"CHKD");
// TODO: I am here... (AIA)
ntfs_log_info("copy.last_lsn/file_offset = 0x%llx\n", (unsigned long long)
le64_to_cpu(rcrd->copy.last_lsn));
ntfs_log_info("flags = 0x%x\n", (unsigned int)le32_to_cpu(rcrd->flags));
ntfs_log_info("page count = %i\n", le16_to_cpu(rcrd->page_count));
ntfs_log_info("page position = %i\n", le16_to_cpu(rcrd->page_position));
ntfs_log_info("header.next_record_offset = 0x%llx\n", (unsigned long long)
le64_to_cpu(rcrd->header.packed.next_record_offset));
ntfs_log_info("header.last_end_lsn = 0x%llx\n", (unsigned long long)
le64_to_cpu(rcrd->header.packed.last_end_lsn));
/*
* Where does the 0x40 come from? Is it just usa_offset +
* usa_client * 2 + 7 & ~7 or is it derived from somewhere?
*/
lr = (LOG_RECORD*)((u8*)rcrd + 0x40);
client = 0;
do {
ntfs_log_info("\nLog record %i:\n", client);
dump_log_record(lr);
client++;
lr = (LOG_RECORD*)((u8*)lr + 0x70);
} while (((u8*)lr + 0x70 <= (u8*)rcrd +
le64_to_cpu(rcrd->header.packed.next_record_offset)));
pass++;
goto rcrd_pass_loc;
}
/**
* main -
*/
int main(int argc, char **argv)
{
RESTART_PAGE_HEADER *rstr;
RECORD_PAGE_HEADER *rcrd;
unsigned int page_size;
int buf_size, br, err;
logfile_file logfile;
u8 *buf;
ntfs_log_set_handler(ntfs_log_handler_outerr);
ntfs_log_info("\n");
if (argc < 2 || argc > 3)
/* print usage and exit */
usage(argv[0]);
/*
* If one argument, it is a device containing an NTFS volume which we
* need to mount and read the $LogFile from so we can dump its
* contents.
*
* If two arguments the first one must be "-f" and the second one is
* the path and name of the $LogFile (or copy thereof) which we need to
* read and dump the contents of.
*/
if (argc == 2) {
logfile_open(TRUE, argv[1], &logfile);
} else /* if (argc == 3) */ {
if (strncmp(argv[1], "-f", strlen("-f")))
usage(argv[0]);
logfile_open(FALSE, argv[2], &logfile);
}
buf_size = 64 * 1024 * 1024;
if (logfile.data_size <= buf_size)
buf_size = logfile.data_size;
else
ntfs_log_error("Warning: $LogFile is too big. "
"Only analysing the first 64MiB.\n");
/* For simplicity we read all of $LogFile/$DATA into memory. */
buf = malloc(buf_size);
if (!buf) {
ntfs_log_perror("Failed to allocate buffer for file data");
logfile_close(&logfile);
exit(1);
}
br = logfile_pread(&logfile, 0, buf_size, buf);
err = errno;
logfile_close(&logfile);
if (br != buf_size) {
log_err_exit(buf, "Failed to read $LogFile/$DATA: %s\n",
br < 0 ? strerror(err) : "Partial read.");
}
/*
* We now have the entirety of the journal ($LogFile/$DATA or argv[2])
* in the memory buffer buf and this has a size of buf_size. Note we
* apply a size capping at 64MiB, so if the journal is any bigger we
* only have the first 64MiB. This should not be a problem as I have
* never seen such a large $LogFile. Usually it is only a few MiB in
* size.
*/
rstr = (RESTART_PAGE_HEADER*)buf;
/* Check for presence of restart area signature. */
if (!ntfs_is_rstr_record(rstr->magic) &&
!ntfs_is_chkd_record(rstr->magic)) {
s8 *pos = (s8*)buf;
s8 *end = pos + buf_size;
while (pos < end && *pos == -1)
pos++;
if (pos != end)
log_err_exit(buf, "$LogFile contents are corrupt "
"(magic RSTR is missing). Cannot "
"handle this yet.\n");
/* All bytes are -1. */
free(buf);
puts("$LogFile is not initialized.");
return 0;
}
/*
* First, verify the restart page header for consistency.
*/
restart_header_sanity(rstr, buf);
page_size = le32_to_cpu(rstr->log_page_size);
/*
* Second, verify the restart area itself.
*/
// TODO: Implement this.
ntfs_log_error("Warning: Sanity checking of restart area not implemented "
"yet.\n");
/*
* Third and last, verify the array of log client records.
*/
// TODO: Implement this.
ntfs_log_error("Warning: Sanity checking of array of log client records not "
"implemented yet.\n");
/*
* Dump the restart headers & areas.
*/
rcrd = (RECORD_PAGE_HEADER*)dump_restart_areas(rstr, buf, page_size);
ntfs_log_info("\n\nFinished with restart pages. "
"Beginning with log pages.\n");
/*
* Dump the log areas.
*/
dump_log_records(rcrd, buf, buf_size, page_size);
free(buf);
return 0;
}

74
ntfsprogs/ntfsfix.8.in Normal file
View File

@ -0,0 +1,74 @@
.\" Copyright (c) 2005-2006 Szabolcs Szakacsits.
.\" Copyright (c) 2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSFIX 8 "January 2006" "ntfsprogs @VERSION@"
.SH NAME
ntfsfix \- fix common errors and force Windows to check NTFS
.SH SYNOPSIS
.B ntfsfix
[\fIoptions\fR] \fIdevice\fR
.SH DESCRIPTION
.B ntfsfix
is a utility that fixes some common NTFS problems.
.B ntfsfix
is
.B NOT
a Linux version of chkdsk. It only repairs some fundamental NTFS
inconsistencies, resets the NTFS journal file and schedules an NTFS consistency
check for the first boot into Windows.
.sp
You may run
.B ntfsfix
on an NTFS volume if you think it was damaged by Windows or some other way
and it can't be mounted.
.SH OPTIONS
Below is a summary of all the options that
.B ntfsfix
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license
.SH BUGS
There are no known problems with
.BR ntfsfix .
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
.B ntfsfix
was written by Anton Altaparmakov, with contributions from Szabolcs Szakacsits.
.SH AVAILABILITY
.B ntfsfix
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR mkntfs (8),
.BR ntfsprogs (8)

588
ntfsprogs/ntfsfix.c Normal file
View File

@ -0,0 +1,588 @@
/**
* ntfsfix - Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2006 Anton Altaparmakov.
* Copyright (c) 2002-2006 Szabolcs Szakacsits.
*
* This utility fixes some common NTFS problems, resets the NTFS journal file
* and schedules an NTFS consistency check for the first boot into Windows.
*
* Anton Altaparmakov <aia21@cantab.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS source
* in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* WARNING: This program might not work on architectures which do not allow
* unaligned access. For those, the program would need to start using
* get/put_unaligned macros (#include <asm/unaligned.h>), but not doing it yet,
* since NTFS really mostly applies to ia32 only, which does allow unaligned
* accesses. We might not actually have a problem though, since the structs are
* defined as being packed so that might be enough for gcc to insert the
* correct code.
*
* If anyone using a non-little endian and/or an aligned access only CPU tries
* this program please let me know whether it works or not!
*
* Anton Altaparmakov <aia21@cantab.net>
*/
#include "config.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/mft.h>
#include <ntfs-3g/device.h>
#include <ntfs-3g/logfile.h>
#include <ntfs-3g/logging.h>
#include "utils.h"
/* #include "version.h" */
#ifdef NO_NTFS_DEVICE_DEFAULT_IO_OPS
# error "No default device io operations! Cannot build ntfsfix. \
You need to run ./configure without the --disable-default-device-io-ops \
switch if you want to be able to build the NTFS utilities."
#endif
static const char *EXEC_NAME = "ntfsfix";
static const char *OK = "OK\n";
static const char *FAILED = "FAILED\n";
static BOOL vol_is_dirty = FALSE;
static BOOL journal_is_empty = FALSE;
struct {
char *volume;
} opt;
/**
* usage
*/
__attribute__((noreturn))
static int usage(void)
{
ntfs_log_info("%s v%s (libntfs-3g)\n"
"\n"
"Usage: %s [options] device\n"
" Attempt to fix an NTFS partition.\n"
"\n"
" -h, --help Display this help\n"
" -V, --version Display version information\n"
"\n"
"For example: %s /dev/hda6\n\n",
EXEC_NAME, VERSION, EXEC_NAME,
EXEC_NAME);
ntfs_log_info("%s%s", ntfs_bugs, ntfs_home);
exit(1);
}
/**
* version
*/
__attribute__((noreturn))
static void version(void)
{
ntfs_log_info("%s v%s\n\n"
"Attempt to fix an NTFS partition.\n\n"
"Copyright (c) 2000-2006 Anton Altaparmakov.\n"
"Copyright (c) 2002-2006 Szabolcs Szakacsits.\n\n",
EXEC_NAME, VERSION);
ntfs_log_info("%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
exit(1);
}
/**
* parse_options
*/
static void parse_options(int argc, char **argv)
{
int c;
static const char *sopt = "-hV";
static const struct option lopt[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
memset(&opt, 0, sizeof(opt));
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1: /* A non-option argument */
if (!opt.volume)
opt.volume = argv[optind - 1];
else {
ntfs_log_info("ERROR: Too many arguments.\n");
usage();
}
break;
case 'h':
case '?':
usage();
case 'V':
version();
default:
ntfs_log_info("ERROR: Unknown option '%s'.\n", argv[optind - 1]);
usage();
}
}
if (opt.volume == NULL) {
ntfs_log_info("ERROR: You must specify a device.\n");
usage();
}
}
/**
* OLD_ntfs_volume_set_flags
*/
static int OLD_ntfs_volume_set_flags(ntfs_volume *vol, const u16 flags)
{
MFT_RECORD *m = NULL;
ATTR_RECORD *a;
VOLUME_INFORMATION *c;
ntfs_attr_search_ctx *ctx;
int ret = -1; /* failure */
if (!vol) {
errno = EINVAL;
return -1;
}
if (ntfs_file_record_read(vol, FILE_Volume, &m, NULL)) {
ntfs_log_perror("Failed to read $Volume");
return -1;
}
/* Sanity check */
if (!(m->flags & MFT_RECORD_IN_USE)) {
ntfs_log_error("$Volume has been deleted. Cannot handle this "
"yet. Run chkdsk to fix this.\n");
errno = EIO;
goto err_exit;
}
/* Get a pointer to the volume information attribute. */
ctx = ntfs_attr_get_search_ctx(NULL, m);
if (!ctx) {
ntfs_log_debug("Failed to allocate attribute search "
"context.\n");
goto err_exit;
}
if (ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL,
0, ctx)) {
ntfs_log_error("Attribute $VOLUME_INFORMATION was not found in "
"$Volume!\n");
goto err_out;
}
a = ctx->attr;
/* Sanity check. */
if (a->non_resident) {
ntfs_log_error("Attribute $VOLUME_INFORMATION must be resident "
"(and it isn't)!\n");
errno = EIO;
goto err_out;
}
/* Get a pointer to the value of the attribute. */
c = (VOLUME_INFORMATION*)(le16_to_cpu(a->value_offset) + (char*)a);
/* Sanity checks. */
if ((char*)c + le32_to_cpu(a->value_length) >
(char*)m + le32_to_cpu(m->bytes_in_use) ||
le16_to_cpu(a->value_offset) +
le32_to_cpu(a->value_length) > le32_to_cpu(a->length)) {
ntfs_log_error("Attribute $VOLUME_INFORMATION in $Volume is "
"corrupt!\n");
errno = EIO;
goto err_out;
}
/* Set the volume flags. */
vol->flags = c->flags = cpu_to_le16(flags);
if (ntfs_mft_record_write(vol, FILE_Volume, m)) {
ntfs_log_perror("Error writing $Volume");
goto err_out;
}
ret = 0; /* success */
err_out:
ntfs_attr_put_search_ctx(ctx);
err_exit:
free(m);
return ret;
}
/**
* set_dirty_flag
*/
static int set_dirty_flag(ntfs_volume *vol)
{
u16 flags;
if (vol_is_dirty == TRUE)
return 0;
ntfs_log_info("Setting required flags on partition... ");
/*
* Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
* and fix it for us.
*/
flags = vol->flags | VOLUME_IS_DIRTY;
/* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */
if (vol->major_ver >= 2)
flags |= VOLUME_MOUNTED_ON_NT4;
if (OLD_ntfs_volume_set_flags(vol, flags)) {
ntfs_log_info(FAILED);
ntfs_log_error("Error setting volume flags.\n");
return -1;
}
ntfs_log_info(OK);
vol_is_dirty = TRUE;
return 0;
}
/**
* set_dirty_flag_mount
*/
static int set_dirty_flag_mount(ntfs_volume *vol)
{
u16 flags;
if (vol_is_dirty == TRUE)
return 0;
ntfs_log_info("Setting required flags on partition... ");
/*
* Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
* and fix it for us.
*/
flags = vol->flags | VOLUME_IS_DIRTY;
/* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */
if (vol->major_ver >= 2)
flags |= VOLUME_MOUNTED_ON_NT4;
if (ntfs_volume_write_flags(vol, flags)) {
ntfs_log_info(FAILED);
ntfs_log_error("Error setting volume flags.\n");
return -1;
}
ntfs_log_info(OK);
vol_is_dirty = TRUE;
return 0;
}
/**
* empty_journal
*/
static int empty_journal(ntfs_volume *vol)
{
if (journal_is_empty == TRUE)
return 0;
ntfs_log_info("Going to empty the journal ($LogFile)... ");
if (ntfs_logfile_reset(vol)) {
ntfs_log_info(FAILED);
ntfs_log_perror("Failed to reset $LogFile");
return -1;
}
ntfs_log_info(OK);
journal_is_empty = TRUE;
return 0;
}
/**
* fix_mftmirr
*/
static int fix_mftmirr(ntfs_volume *vol)
{
s64 l, br;
unsigned char *m, *m2;
int i, ret = -1; /* failure */
BOOL done;
ntfs_log_info("\nProcessing $MFT and $MFTMirr...\n");
/* Load data from $MFT and $MFTMirr and compare the contents. */
m = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
if (!m) {
ntfs_log_perror("Failed to allocate memory");
return -1;
}
m2 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
if (!m2) {
ntfs_log_perror("Failed to allocate memory");
free(m);
return -1;
}
ntfs_log_info("Reading $MFT... ");
l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
vol->mft_record_size, m);
if (l != vol->mftmirr_size) {
ntfs_log_info(FAILED);
if (l != -1)
errno = EIO;
ntfs_log_perror("Failed to read $MFT");
goto error_exit;
}
ntfs_log_info(OK);
ntfs_log_info("Reading $MFTMirr... ");
l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
vol->mft_record_size, m2);
if (l != vol->mftmirr_size) {
ntfs_log_info(FAILED);
if (l != -1)
errno = EIO;
ntfs_log_perror("Failed to read $MFTMirr");
goto error_exit;
}
ntfs_log_info(OK);
/*
* FIXME: Need to actually check the $MFTMirr for being real. Otherwise
* we might corrupt the partition if someone is experimenting with
* software RAID and the $MFTMirr is not actually in the position we
* expect it to be... )-:
* FIXME: We should emit a warning it $MFTMirr is damaged and ask
* user whether to recreate it from $MFT or whether to abort. - The
* warning needs to include the danger of software RAID arrays.
* Maybe we should go as far as to detect whether we are running on a
* MD disk and if yes then bomb out right at the start of the program?
*/
ntfs_log_info("Comparing $MFTMirr to $MFT... ");
done = FALSE;
for (i = 0; i < vol->mftmirr_size; ++i) {
MFT_RECORD *mrec, *mrec2;
const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
"$Volume", "$AttrDef", "root directory", "$Bitmap",
"$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
const char *s;
BOOL use_mirr;
if (i < 12)
s = ESTR[i];
else if (i < 16)
s = "system file";
else
s = "mft record";
use_mirr = FALSE;
mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
if (mrec->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_recordp(mrec)) {
ntfs_log_info(FAILED);
ntfs_log_error("$MFT error: Incomplete multi "
"sector transfer detected in "
"%s.\nCannot handle this yet. "
")-:\n", s);
goto error_exit;
}
if (!ntfs_is_mft_recordp(mrec)) {
ntfs_log_info(FAILED);
ntfs_log_error("$MFT error: Invalid mft "
"record for %s.\nCannot "
"handle this yet. )-:\n", s);
goto error_exit;
}
}
mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
if (mrec2->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_recordp(mrec2)) {
ntfs_log_info(FAILED);
ntfs_log_error("$MFTMirr error: Incomplete "
"multi sector transfer "
"detected in %s.\n", s);
goto error_exit;
}
if (!ntfs_is_mft_recordp(mrec2)) {
ntfs_log_info(FAILED);
ntfs_log_error("$MFTMirr error: Invalid mft "
"record for %s.\n", s);
goto error_exit;
}
/* $MFT is corrupt but $MFTMirr is ok, use $MFTMirr. */
if (!(mrec->flags & MFT_RECORD_IN_USE) &&
!ntfs_is_mft_recordp(mrec))
use_mirr = TRUE;
}
if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
if (!done) {
done = TRUE;
ntfs_log_info(FAILED);
}
ntfs_log_info("Correcting differences in $MFT%s "
"record %d...", use_mirr ? "" : "Mirr",
i);
br = ntfs_mft_record_write(vol, i,
use_mirr ? mrec2 : mrec);
if (br) {
ntfs_log_info(FAILED);
ntfs_log_perror("Error correcting $MFT%s",
use_mirr ? "" : "Mirr");
goto error_exit;
}
ntfs_log_info(OK);
}
}
if (!done)
ntfs_log_info(OK);
ntfs_log_info("Processing of $MFT and $MFTMirr completed "
"successfully.\n");
ret = 0;
error_exit:
free(m);
free(m2);
return ret;
}
/**
* fix_mount
*/
static int fix_mount(void)
{
int ret = -1; /* failure */
ntfs_volume *vol;
struct ntfs_device *dev;
ntfs_log_info("Attempting to correct errors... ");
dev = ntfs_device_alloc(opt.volume, 0, &ntfs_device_default_io_ops, NULL);
if (!dev) {
ntfs_log_info(FAILED);
ntfs_log_perror("Failed to allocate device");
return -1;
}
vol = ntfs_volume_startup(dev, 0);
if (!vol) {
ntfs_log_info(FAILED);
ntfs_log_perror("Failed to startup volume");
ntfs_log_error("Volume is corrupt. You should run chkdsk.\n");
ntfs_device_free(dev);
return -1;
}
if (fix_mftmirr(vol) < 0)
goto error_exit;
/* FIXME: Will this fail? Probably... */
if (set_dirty_flag(vol) < 0)
goto error_exit;
if (empty_journal(vol) < 0)
goto error_exit;
ret = 0;
error_exit:
/* ntfs_umount() will invoke ntfs_device_free() for us. */
if (ntfs_umount(vol, 0))
ntfs_umount(vol, 1);
return ret;
}
/**
* main
*/
int main(int argc, char **argv)
{
ntfs_volume *vol;
unsigned long mnt_flags;
int ret = 1; /* failure */
BOOL force = FALSE;
ntfs_log_set_handler(ntfs_log_handler_outerr);
parse_options(argc, argv);
if (!ntfs_check_if_mounted(opt.volume, &mnt_flags)) {
if ((mnt_flags & NTFS_MF_MOUNTED) &&
!(mnt_flags & NTFS_MF_READONLY) && !force) {
ntfs_log_error("Refusing to operate on read-write "
"mounted device %s.\n", opt.volume);
exit(1);
}
} else
ntfs_log_perror("Failed to determine whether %s is mounted",
opt.volume);
/* Attempt a full mount first. */
ntfs_log_info("Mounting volume... ");
vol = ntfs_mount(opt.volume, 0);
if (vol) {
ntfs_log_info(OK);
ntfs_log_info("Processing of $MFT and $MFTMirr completed "
"successfully.\n");
} else {
ntfs_log_info(FAILED);
if (fix_mount() < 0)
exit(1);
vol = ntfs_mount(opt.volume, 0);
if (!vol) {
ntfs_log_perror("Remount failed");
exit(1);
}
}
/* Check NTFS version is ok for us (in $Volume) */
ntfs_log_info("NTFS volume version is %i.%i.\n", vol->major_ver,
vol->minor_ver);
if (ntfs_version_is_supported(vol)) {
ntfs_log_error("Error: Unknown NTFS version.\n");
goto error_exit;
}
if (set_dirty_flag_mount(vol) < 0)
goto error_exit;
if (empty_journal(vol) < 0)
goto error_exit;
if (vol->major_ver >= 3) {
/* FIXME: If on NTFS 3.0+, check for presence of the usn journal and
disable it (if present) as Win2k might be unhappy otherwise and Bad
Things(TM) could happen depending on what applications are actually
using it for. */
}
/* FIXME: Should we be marking the quota out of date, too? */
/* That's all for now! */
ntfs_log_info("NTFS partition %s was processed successfully.\n",
vol->dev->d_name);
/* Set return code to 0. */
ret = 0;
error_exit:
if (ntfs_umount(vol, 0))
ntfs_umount(vol, 1);
return ret;
}

94
ntfsprogs/ntfsinfo.8.in Normal file
View File

@ -0,0 +1,94 @@
.\" Copyright (c) 2002\-2004 Anton Altaparmakov.
.\" Copyright (c) 2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSINFO 8 "April 2006" "ntfsprogs @VERSION@"
.SH NAME
ntfsinfo \- dump a file's attributes
.SH SYNOPSIS
.B ntfsinfo
[\fIoptions\fR] \fIdevice\fR
.SH DESCRIPTION
.B ntfsinfo
will dump the attributes of inode
.I inode\-number
or the file
.I path\-filename
and/or information about the mft (
.I \-m
option).
Run ntfsinfo without arguments for a full list of options.
.SH OPTIONS
Below is a summary of all the options that
.B ntfsinfo
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-F\fR, \fB\-\-file\fR FILE
Show information about this file
.TP
\fB\-f\fR, \fB\-\-force\fR
This will override some sensible defaults, such as not overwriting an existing
file. Use this option with caution.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.TP
\fB\-i\fR, \fB\-\-inode\fR NUM
Show information about this inode.
.TP
\fB\-m\fR, \fB\-\-mft\fR
Show information about the volume.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Produce less output.
.TP
\fB\-t\fR, \fB\-\-notime\fR
Do not display timestamps in the output.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Increase the amount of output that
.B ntfsinfo
prints.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license.
.SH BUGS
There are no known problems with
.BR ntfsinfo .
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
.B ntfsinfo
was written by Matthew J. Fanto, Anton Altaparmakov, Richard Russon, Szabolcs
Szakacsits, Yuval Fledel, Yura Pakhuchiy and Cristian Klein.
.SH AVAILABILITY
.B ntfsinfo
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR ntfsprogs (8)

2010
ntfsprogs/ntfsinfo.c Normal file

File diff suppressed because it is too large Load Diff

105
ntfsprogs/ntfslabel.8.in Normal file
View File

@ -0,0 +1,105 @@
.\" Copyright (c) 2002\-2004 Anton Altaparmakov.
.\" Copyright (c) 2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSLABEL 8 "November 2005" "ntfsprogs @VERSION@"
.SH NAME
ntfslabel \- display/change the label on an ntfs file system
.SH SYNOPSIS
.B ntfslabel
[\fIoptions\fR] \fIdevice \fR[\fInew\-label\fR]
.SH DESCRIPTION
.B ntfslabel
will display or change the file system label on the ntfs file system located on
.IR device .
.PP
If the optional argument
.I new\-label
is not present,
.B ntfslabel
will simply display the current file system label.
.PP
If the optional argument
.I new\-label
is present, then
.B ntfslabel
will set the file system label to be
.IR new\-label .
NTFS file system labels can be at most 128 Unicode characters long; if
.I new\-label
is longer than 128 Unicode characters,
.B ntfslabel
will truncate it and print a warning message.
.PP
It is also possible to set the file system label using the
.B \-L
option of
.BR mkntfs (8)
during creation of the file system.
.SH OPTIONS
Below is a summary of all the options that
.B ntfslabel
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-f\fR, \fB\-\-force\fR
This will override some sensible defaults, such as not working with a mounted
volume. Use this option with caution.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.TP
\fB\-n\fR, \fB\-\-no\-action\fR
Don't actually write to disk.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Reduce the amount of output to a minimum.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Increase the amount of output that
.B ntfslabel
prints.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license for
.BR ntfslabel .
.SH BUGS
There are no known problems with
.BR ntfslabel .
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
.B ntfslabel
was written by Matthew J. Fanto, with contributions from Anton Altaparmakov and
Richard Russon.
.SH AVAILABILITY
.B ntfslabel
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR mkntfs (8),
.BR ntfsprogs (8)

410
ntfsprogs/ntfslabel.c Normal file
View File

@ -0,0 +1,410 @@
/**
* ntfslabel - Part of the Linux-NTFS project.
*
* Copyright (c) 2002 Matthew J. Fanto
* Copyright (c) 2002-2005 Anton Altaparmakov
* Copyright (c) 2002-2003 Richard Russon
*
* This utility will display/change the label on an NTFS partition.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_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
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <ntfs-3g/debug.h>
#include <ntfs-3g/mft.h>
#include <ntfs-3g/logging.h>
#include "utils.h"
/* #include "version.h" */
static const char *EXEC_NAME = "ntfslabel";
static struct options {
char *device; /* Device/File to work with */
char *label; /* Set the label to this */
int quiet; /* Less output */
int verbose; /* Extra output */
int force; /* Override common sense */
int noaction; /* Do not write to disk */
} opts;
/**
* version - Print version information about the program
*
* Print a copyright statement and a brief description of the program.
*
* Return: none
*/
static void version(void)
{
ntfs_log_info("\n%s v%s (libntfs-3g) - Display, or set, the label for an "
"NTFS Volume.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c)\n");
ntfs_log_info(" 2002 Matthew J. Fanto\n");
ntfs_log_info(" 2002-2005 Anton Altaparmakov\n");
ntfs_log_info(" 2002-2003 Richard Russon\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
static void usage(void)
{
ntfs_log_info("\nUsage: %s [options] device [label]\n"
" -n, --no-action Do not write to disk\n"
" -f, --force Use less caution\n"
" -q, --quiet Less output\n"
" -v, --verbose More output\n"
" -V, --version Display version information\n"
" -h, --help Display this help\n\n",
EXEC_NAME);
ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
* parse_options - Read and validate the programs command line
*
* Read the command line, verify the syntax and parse the options.
* This function is very long, but quite simple.
*
* Return: 1 Success
* 0 Error, one or more problems
*/
static int parse_options(int argc, char *argv[])
{
static const char *sopt = "-fh?nqvV";
static const struct option lopt[] = {
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "no-action", no_argument, NULL, 'n' },
{ "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 },
};
int c = -1;
int err = 0;
int ver = 0;
int help = 0;
int levels = 0;
opterr = 0; /* We'll handle the errors, thank you. */
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1: /* A non-option argument */
if (!err && !opts.device)
opts.device = argv[optind-1];
else if (!err && !opts.label)
opts.label = argv[optind-1];
else
err++;
break;
case 'f':
opts.force++;
break;
case 'h':
case '?':
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
if (!ntfs_log_parse_option (argv[optind-1]))
err++;
break;
}
help++;
break;
case 'n':
opts.noaction++;
break;
case 'q':
opts.quiet++;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
case 'V':
ver++;
break;
default:
ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
err++;
break;
}
}
/* Make sure we're in sync with the log levels */
levels = ntfs_log_get_levels();
if (levels & NTFS_LOG_LEVEL_VERBOSE)
opts.verbose++;
if (!(levels & NTFS_LOG_LEVEL_QUIET))
opts.quiet++;
if (help || ver) {
opts.quiet = 0;
} else {
if (opts.device == NULL) {
if (argc > 1)
ntfs_log_error("You must specify a device.\n");
err++;
}
if (opts.quiet && opts.verbose) {
ntfs_log_error("You may not use --quiet and --verbose at "
"the same time.\n");
err++;
}
}
if (ver)
version();
if (help || err)
usage();
return (!err && !help && !ver);
}
/**
* print_label - display the current label of a mounted ntfs partition.
* @dev: device to read the label from
* @mnt_flags: mount flags of the device or 0 if not mounted
* @mnt_point: mount point of the device or NULL
*
* Print the label of the device @dev.
*/
static int print_label(ntfs_volume *vol, unsigned long mnt_flags)
{
int result = 0;
//XXX significant?
if ((mnt_flags & (NTFS_MF_MOUNTED | NTFS_MF_READONLY)) ==
NTFS_MF_MOUNTED) {
ntfs_log_error("%s is mounted read-write, results may be "
"unreliable.\n", opts.device);
result = 1;
}
ntfs_log_info("%s\n", vol->vol_name);
return result;
}
/**
* resize_resident_attribute_value - resize a resident attribute
* @m: mft record containing attribute to resize
* @a: attribute record (inside @m) which to resize
* @new_vsize: the new attribute value size to resize the attribute to
*
* Return 0 on success and -1 with errno = ENOSPC if not enough space in the
* mft record.
*/
static int resize_resident_attribute_value(MFT_RECORD *m, ATTR_RECORD *a,
const u32 new_vsize)
{
int new_alen, new_muse;
/* New attribute length and mft record bytes used. */
new_alen = (le16_to_cpu(a->value_offset) + new_vsize + 7) & ~7;
new_muse = le32_to_cpu(m->bytes_in_use) - le32_to_cpu(a->length) +
new_alen;
/* Check for sufficient space. */
if ((u32)new_muse > le32_to_cpu(m->bytes_allocated)) {
errno = ENOSPC;
return -1;
}
/* Move attributes behind @a to their new location. */
memmove((char*)a + new_alen, (char*)a + le32_to_cpu(a->length),
le32_to_cpu(m->bytes_in_use) - ((char*)a - (char*)m) -
le32_to_cpu(a->length));
/* Adjust @m to reflect change in used space. */
m->bytes_in_use = cpu_to_le32(new_muse);
/* Adjust @a to reflect new value size. */
a->length = cpu_to_le32(new_alen);
a->value_length = cpu_to_le32(new_vsize);
return 0;
}
/**
* change_label - change the current label on a device
* @dev: device to change the label on
* @mnt_flags: mount flags of the device or 0 if not mounted
* @mnt_point: mount point of the device or NULL
* @label: the new label
*
* Change the label on the device @dev to @label.
*/
static int change_label(ntfs_volume *vol, unsigned long mnt_flags, char *label, BOOL force)
{
ntfs_attr_search_ctx *ctx;
ntfschar *new_label = NULL;
ATTR_RECORD *a;
int label_len;
int result = 0;
//XXX significant?
if (mnt_flags & NTFS_MF_MOUNTED) {
/* If not the root fs or mounted read/write, refuse change. */
if (!(mnt_flags & NTFS_MF_ISROOT) ||
!(mnt_flags & NTFS_MF_READONLY)) {
if (!force) {
ntfs_log_error("Refusing to change label on "
"read-%s mounted device %s.\n",
mnt_flags & NTFS_MF_READONLY ?
"only" : "write", opts.device);
return 1;
}
}
}
ctx = ntfs_attr_get_search_ctx(vol->vol_ni, NULL);
if (!ctx) {
ntfs_log_perror("Failed to get attribute search context");
goto err_out;
}
if (ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) {
if (errno != ENOENT) {
ntfs_log_perror("Lookup of $VOLUME_NAME attribute failed");
goto err_out;
}
/* The volume name attribute does not exist. Need to add it. */
a = NULL;
} else {
a = ctx->attr;
if (a->non_resident) {
ntfs_log_error("Error: Attribute $VOLUME_NAME must be "
"resident.\n");
goto err_out;
}
}
label_len = ntfs_mbstoucs_libntfscompat(label, &new_label, 0);
if (label_len == -1) {
ntfs_log_perror("Unable to convert label string to Unicode");
goto err_out;
}
label_len *= sizeof(ntfschar);
if (label_len > 0x100) {
ntfs_log_error("New label is too long. Maximum %u characters "
"allowed. Truncating excess characters.\n",
(unsigned)(0x100 / sizeof(ntfschar)));
label_len = 0x100;
new_label[label_len / sizeof(ntfschar)] = cpu_to_le16(L'\0');
}
if (a) {
if (resize_resident_attribute_value(ctx->mrec, a, label_len)) {
ntfs_log_perror("Error resizing resident attribute");
goto err_out;
}
} else {
/* sizeof(resident attribute record header) == 24 */
int asize = (24 + label_len + 7) & ~7;
u32 biu = le32_to_cpu(ctx->mrec->bytes_in_use);
if (biu + asize > le32_to_cpu(ctx->mrec->bytes_allocated)) {
errno = ENOSPC;
ntfs_log_perror("Error adding resident attribute");
goto err_out;
}
a = ctx->attr;
memmove((u8*)a + asize, a, biu - ((u8*)a - (u8*)ctx->mrec));
ctx->mrec->bytes_in_use = cpu_to_le32(biu + asize);
a->type = AT_VOLUME_NAME;
a->length = cpu_to_le32(asize);
a->non_resident = 0;
a->name_length = 0;
a->name_offset = cpu_to_le16(24);
a->flags = cpu_to_le16(0);
a->instance = ctx->mrec->next_attr_instance;
ctx->mrec->next_attr_instance = cpu_to_le16((le16_to_cpu(
ctx->mrec->next_attr_instance) + 1) & 0xffff);
a->value_length = cpu_to_le32(label_len);
a->value_offset = a->name_offset;
a->resident_flags = 0;
a->reservedR = 0;
}
memcpy((u8*)a + le16_to_cpu(a->value_offset), new_label, label_len);
if (!opts.noaction && ntfs_inode_sync(vol->vol_ni)) {
ntfs_log_perror("Error writing MFT Record to disk");
goto err_out;
}
result = 0;
err_out:
free(new_label);
return result;
}
/**
* main - Begin here
*
* Start from here.
*
* Return: 0 Success, the program worked
* 1 Error, something went wrong
*/
int main(int argc, char **argv)
{
unsigned long mnt_flags = 0;
int result = 0;
ntfs_volume *vol;
ntfs_log_set_handler(ntfs_log_handler_outerr);
if (!parse_options(argc, argv))
return 1;
utils_set_locale();
if (!opts.label)
opts.noaction++;
vol = utils_mount_volume(opts.device, opts.noaction ? MS_RDONLY : 0,
opts.force);
if (!vol)
return 1;
if (opts.label)
result = change_label(vol, mnt_flags, opts.label, opts.force);
else
result = print_label(vol, mnt_flags);
ntfs_umount(vol, FALSE);
return result;
}

177
ntfsprogs/ntfsls.8.in Normal file
View File

@ -0,0 +1,177 @@
.\" Copyright (c) 2003 Anton Altaparmakov.
.\" Copyright (c) 2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSLS 8 "November 2005" "ntfsprogs @VERSION@"
.SH NAME
ntfsls \- list directory contents on an NTFS filesystem
.SH SYNOPSIS
.B ntfsls
[\fIoptions\fR] \fIdevice\fR
.sp
.B ntfsls
[
.B \-a
|
.B \-\-all
]
[
.B \-F
|
.B \-\-classify
]
[
.B \-f
|
.B \-\-force
]
[
.B \-h
|
.B \-\-help
]
[
.B \-i
|
.B \-\-inode
]
[
.B \-l
|
.B \-\-long
]
[
.B \-p
|
.B \-\-path
.I PATH
]
[
.B \-q
|
.B \-\-quiet
]
[
.B \-s
|
.B \-\-system
]
[
.B \-V
|
.B \-\-version
]
[
.B \-v
|
.B \-\-verbose
]
[
.B \-x
|
.B \-\-dos
]
.I device
.SH DESCRIPTION
.B ntfsls
is used to list information about the files specified by the
.I PATH
option (the root directory by default).
.I DEVICE
is the special file corresponding to the device (e.g
.IR /dev/hdXX )
or an NTFS image file.
.SH OPTIONS
Below is a summary of all the options that
.B ntfsls
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-a\fR, \fB\-\-all\fR
Display all files. If this option is not specified file names in the POSIX
namespace will not be displayed.
.TP
\fB\-F\fR, \fB\-\-classify\fR
Append indicator (one of */=@|) to entries.
.TP
\fB\-f\fR, \fB\-\-force\fR
Force execution. For example necessary to run on an NTFS partition stored in
a normal file.
.TP
\fB\-h\fR, \fB\-\-help\fR
Print the usage information of
.B ntfsls
and exit.
.TP
\fB\-i\fR, \fB\-\-inode\fR
Print inode number of each file. This is the MFT reference number in NTFS
terminology.
.TP
\fB\-l\fR, \fB\-\-long\fR
Use a long listing format.
.TP
\fB\-p\fR, \fB\-\-path\fR PATH
The directory whose contents to list or the file (including the path) about
which to display information.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Suppress some debug/warning/error messages.
.TP
\fB\-R\fR, \fB\-\-recursive\fR
Show the contents of all directories beneath the specified directory.
.TP
\fB\-s\fR, \fB\-\-system\fR
Unless this options is specified, all files beginning with a dollar sign
character will not be listed as these files are usually system files.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Display more debug/warning/error messages.
.TP
\fB\-V\fR, \fB\-\-version\fR
Print the version number of
.B ntfsls
and exit.
.TP
\fB\-x\fR, \fB\-\-dos\fR
Display short file names, i.e. files in the DOS namespace, instead of long
file names, i.e. files in the WIN32 namespace.
.SH BUGS
There are no known problems with
.BR ntfsls .
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
This version of
.B ntfsls
was written by Lode Leroy, Anton Altaparmakov, Richard Russon, Carmelo Kintana
and Giang Nguyen.
.SH AVAILABILITY
.B ntfsls
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR ntfsprogs (8)

717
ntfsprogs/ntfsls.c Normal file
View File

@ -0,0 +1,717 @@
/**
* ntfsls - Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Lode Leroy
* Copyright (c) 2003-2005 Anton Altaparmakov
* Copyright (c) 2003 Richard Russon
* Copyright (c) 2004 Carmelo Kintana
* Copyright (c) 2004 Giang Nguyen
*
* This utility will list a directory's files.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/mft.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/layout.h>
#include <ntfs-3g/inode.h>
#include <ntfs-3g/dir.h>
#include <ntfs-3g/ntfstime.h>
#include <ntfs-3g/logging.h>
#include "utils.h"
#include "list.h"
/* #include "version.h" */
static const char *EXEC_NAME = "ntfsls";
/**
* To hold sub-directory information for recursive listing.
* @depth: the level of this dir relative to opts.path
*/
struct dir {
struct list_head list;
ntfs_inode *ni;
char name[MAX_PATH];
int depth;
};
/**
* path_component - to store path component strings
*
* @name: string pointer
*
* NOTE: @name is not directly allocated memory. It simply points to the
* character array name in struct dir.
*/
struct path_component {
struct list_head list;
const char *name;
};
/* The list of sub-dirs is like a "horizontal" tree. The root of
* the tree is opts.path, but it is not part of the list because
* that's not necessary. The rules of the list are (in order of
* precedence):
* 1. directories immediately follow their parent.
* 2. siblings are next to one another.
*
* For example, if:
* 1. opts.path is /
* 2. / has 2 sub-dirs: dir1 and dir2
* 3. dir1 has 2 sub-dirs: dir11 and dir12
* 4. dir2 has 0 sub-dirs
* then the list will be:
* dummy head -> dir1 -> dir11 -> dir12 -> dir2
*
* dir_list_insert_pos keeps track of where to insert a sub-dir
* into the list.
*/
static struct list_head *dir_list_insert_pos = NULL;
/* The global depth relative to opts.path.
* ie: opts.path has depth 0, a sub-dir of opts.path has depth 1
*/
static int depth = 0;
static struct options {
char *device; /* Device/File to work with */
int quiet; /* Less output */
int verbose; /* Extra output */
int force; /* Override common sense */
int all;
int system;
int dos;
int lng;
int inode;
int classify;
int recursive;
const char *path;
} opts;
typedef struct {
ntfs_volume *vol;
} ntfsls_dirent;
static int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name,
const int name_len, const int name_type,
const s64 pos, const MFT_REF mref,
const unsigned dt_type);
/**
* version - Print version information about the program
*
* Print a copyright statement and a brief description of the program.
*
* Return: none
*/
static void version(void)
{
printf("\n%s v%s (libntfs-3g) - Display information about an NTFS "
"Volume.\n\n", EXEC_NAME, VERSION);
printf("Copyright (c) 2003 Lode Leroy\n");
printf("Copyright (c) 2003-2005 Anton Altaparmakov\n");
printf("Copyright (c) 2003 Richard Russon\n");
printf("Copyright (c) 2004 Carmelo Kintana\n");
printf("Copyright (c) 2004 Giang Nguyen\n");
printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
static void usage(void)
{
printf("\nUsage: %s [options] device\n"
"\n"
" -a, --all Display all files\n"
" -F, --classify Display classification\n"
" -f, --force Use less caution\n"
" -h, --help Display this help\n"
" -i, --inode Display inode numbers\n"
" -l, --long Display long info\n"
" -p, --path PATH Directory whose contents to list\n"
" -q, --quiet Less output\n"
" -R, --recursive Recursively list subdirectories\n"
" -s, --system Display system files\n"
" -V, --version Display version information\n"
" -v, --verbose More output\n"
" -x, --dos Use short (DOS 8.3) names\n"
"\n",
EXEC_NAME);
printf("NOTE: If neither -a nor -s is specified, the program defaults to -a.\n\n");
printf("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
* parse_options - Read and validate the programs command line
*
* Read the command line, verify the syntax and parse the options.
* This function is very long, but quite simple.
*
* Return: 1 Success
* 0 Error, one or more problems
*/
static int parse_options(int argc, char *argv[])
{
static const char *sopt = "-aFfh?ilp:qRsVvx";
static const struct option lopt[] = {
{ "all", no_argument, NULL, 'a' },
{ "classify", no_argument, NULL, 'F' },
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "inode", no_argument, NULL, 'i' },
{ "long", no_argument, NULL, 'l' },
{ "path", required_argument, NULL, 'p' },
{ "recursive", no_argument, NULL, 'R' },
{ "quiet", no_argument, NULL, 'q' },
{ "system", no_argument, NULL, 's' },
{ "version", no_argument, NULL, 'V' },
{ "verbose", no_argument, NULL, 'v' },
{ "dos", no_argument, NULL, 'x' },
{ NULL, 0, NULL, 0 },
};
int c = -1;
int err = 0;
int ver = 0;
int help = 0;
int levels = 0;
opterr = 0; /* We'll handle the errors, thank you. */
memset(&opts, 0, sizeof(opts));
opts.device = NULL;
opts.path = "/";
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1:
if (!opts.device)
opts.device = optarg;
else
err++;
break;
case 'p':
opts.path = optarg;
break;
case 'f':
opts.force++;
break;
case 'h':
case '?':
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
if (!ntfs_log_parse_option (argv[optind-1]))
err++;
break;
}
help++;
break;
case 'q':
opts.quiet++;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
case 'V':
ver++;
break;
case 'x':
opts.dos = 1;
break;
case 'l':
opts.lng++;
break;
case 'i':
opts.inode++;
break;
case 'F':
opts.classify++;
break;
case 'a':
opts.all++;
break;
case 's':
opts.system++;
break;
case 'R':
opts.recursive++;
break;
default:
ntfs_log_error("Unknown option '%s'.\n", argv[optind - 1]);
err++;
break;
}
}
/* Make sure we're in sync with the log levels */
levels = ntfs_log_get_levels();
if (levels & NTFS_LOG_LEVEL_VERBOSE)
opts.verbose++;
if (!(levels & NTFS_LOG_LEVEL_QUIET))
opts.quiet++;
/* defaults to -a if -s is not specified */
if (!opts.system)
opts.all++;
if (help || ver)
opts.quiet = 0;
else {
if (opts.device == NULL) {
if (argc > 1)
ntfs_log_error("You must specify exactly one "
"device.\n");
err++;
}
if (opts.quiet && opts.verbose) {
ntfs_log_error("You may not use --quiet and --verbose at the "
"same time.\n");
err++;
}
}
if (ver)
version();
if (help || err)
usage();
return (!err && !help && !ver);
}
/**
* free_dir - free one dir
* @tofree: the dir to free
*
* Close the inode and then free the dir
*/
static void free_dir(struct dir *tofree)
{
if (tofree) {
if (tofree->ni) {
ntfs_inode_close(tofree->ni);
tofree->ni = NULL;
}
free(tofree);
}
}
/**
* free_dirs - walk the list of dir's and free each of them
* @dir_list: the list_head of any entry in the list
*
* Iterate over @dir_list, calling free_dir on each entry
*/
static void free_dirs(struct list_head *dir_list)
{
struct dir *tofree = NULL;
struct list_head *walker = NULL;
if (dir_list) {
list_for_each(walker, dir_list) {
free_dir(tofree);
tofree = list_entry(walker, struct dir, list);
}
free_dir(tofree);
}
}
/**
* readdir_recursive - list a directory and sub-directories encountered
* @ni: ntfs inode of the directory to list
* @pos: current position in directory
* @dirent: context for filldir callback supplied by the caller
*
* For each directory, print its path relative to opts.path. List a directory,
* then list each of its sub-directories.
*
* Returns 0 on success or -1 on error.
*
* NOTE: Assumes recursive option. Currently no limit on the depths of
* recursion.
*/
static int readdir_recursive(ntfs_inode * ni, s64 * pos, ntfsls_dirent * dirent)
{
/* list of dirs to "ls" recursively */
static struct dir dirs = {
.list = LIST_HEAD_INIT(dirs.list),
.ni = NULL,
.name = {0},
.depth = 0
};
static struct path_component paths = {
.list = LIST_HEAD_INIT(paths.list),
.name = NULL
};
static struct path_component base_comp;
struct dir *subdir = NULL;
struct dir *tofree = NULL;
struct path_component comp;
struct path_component *tempcomp = NULL;
struct list_head *dir_walker = NULL;
struct list_head *comp_walker = NULL;
s64 pos2 = 0;
int ni_depth = depth;
int result = 0;
if (list_empty(&dirs.list)) {
base_comp.name = opts.path;
list_add(&base_comp.list, &paths.list);
dir_list_insert_pos = &dirs.list;
printf("%s:\n", opts.path);
}
depth++;
result = ntfs_readdir(ni, pos, dirent, (ntfs_filldir_t) list_dir_entry);
if (result == 0) {
list_add_tail(&comp.list, &paths.list);
/* for each of ni's sub-dirs: list in this iteration, then
free at the top of the next iteration or outside of loop */
list_for_each(dir_walker, &dirs.list) {
if (tofree) {
free_dir(tofree);
tofree = NULL;
}
subdir = list_entry(dir_walker, struct dir, list);
/* subdir is not a subdir of ni */
if (subdir->depth != ni_depth + 1)
break;
pos2 = 0;
dir_list_insert_pos = &dirs.list;
if (!subdir->ni) {
subdir->ni =
ntfs_pathname_to_inode(ni->vol, ni,
subdir->name);
if (!subdir->ni) {
ntfs_log_error
("ntfsls::readdir_recursive(): cannot get inode from pathname.\n");
result = -1;
break;
}
}
puts("");
comp.name = subdir->name;
/* print relative path header */
list_for_each(comp_walker, &paths.list) {
tempcomp =
list_entry(comp_walker,
struct path_component, list);
printf("%s", tempcomp->name);
if (tempcomp != &comp
&& *tempcomp->name != PATH_SEP
&& (!opts.classify
|| tempcomp == &base_comp))
putchar(PATH_SEP);
}
puts(":");
result = readdir_recursive(subdir->ni, &pos2, dirent);
if (result)
break;
tofree = subdir;
list_del(dir_walker);
}
list_del(&comp.list);
}
if (tofree)
free_dir(tofree);
/* if at the outer-most readdir_recursive, then clean up */
if (ni_depth == 0) {
free_dirs(&dirs.list);
}
depth--;
return result;
}
/**
* list_dir_entry
*
* FIXME: Should we print errors as we go along? (AIA)
*/
static int list_dir_entry(ntfsls_dirent * dirent, const ntfschar * name,
const int name_len, const int name_type,
const s64 pos __attribute__((unused)),
const MFT_REF mref, const unsigned dt_type)
{
char *filename = NULL;
int result = 0;
struct dir *dir = NULL;
filename = calloc(1, MAX_PATH);
if (!filename)
return -1;
if (ntfs_ucstombs(name, name_len, &filename, MAX_PATH) < 0) {
ntfs_log_error("Cannot represent filename in current locale.\n");
goto free;
}
result = 0; // These are successful
if ((MREF(mref) < FILE_first_user) && (!opts.system))
goto free;
if (name_type == FILE_NAME_POSIX && !opts.all)
goto free;
if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_WIN32) &&
opts.dos)
goto free;
if (((name_type & FILE_NAME_WIN32_AND_DOS) == FILE_NAME_DOS) &&
!opts.dos)
goto free;
if (dt_type == NTFS_DT_DIR && opts.classify)
sprintf(filename + strlen(filename), "/");
if (dt_type == NTFS_DT_DIR && opts.recursive
&& strcmp(filename, ".") && strcmp(filename, "./")
&& strcmp(filename, "..") && strcmp(filename, "../"))
{
dir = (struct dir *)calloc(1, sizeof(struct dir));
if (!dir) {
ntfs_log_error("Failed to allocate for subdir.\n");
result = -1;
goto free;
}
strcpy(dir->name, filename);
dir->ni = NULL;
dir->depth = depth;
}
if (!opts.lng) {
if (!opts.inode)
printf("%s\n", filename);
else
printf("%7llu %s\n", (unsigned long long)MREF(mref),
filename);
result = 0;
} else {
s64 filesize = 0;
ntfs_inode *ni;
ntfs_attr_search_ctx *ctx = NULL;
FILE_NAME_ATTR *file_name_attr;
ATTR_RECORD *attr;
struct timespec ntfs_time;
char t_buf[26];
result = -1; // Everything else is bad
ni = ntfs_inode_open(dirent->vol, mref);
if (!ni)
goto release;
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx)
goto release;
if (ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL,
0, ctx))
goto release;
attr = ctx->attr;
file_name_attr = (FILE_NAME_ATTR *)((char *)attr +
le16_to_cpu(attr->value_offset));
if (!file_name_attr)
goto release;
ntfs_time = ntfs2timespec(file_name_attr->last_data_change_time);
strcpy(t_buf, ctime(&ntfs_time.tv_sec));
memmove(t_buf+16, t_buf+19, 5);
t_buf[21] = '\0';
if (dt_type != NTFS_DT_DIR) {
if (!ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0,
NULL, 0, ctx))
filesize = ntfs_get_attribute_value_length(
ctx->attr);
}
if (opts.inode)
printf("%7llu %8lld %s %s\n",
(unsigned long long)MREF(mref),
(long long)filesize, t_buf + 4,
filename);
else
printf("%8lld %s %s\n", (long long)filesize, t_buf + 4,
filename);
if (dir) {
dir->ni = ni;
ni = NULL; /* so release does not close inode */
}
result = 0;
release:
/* Release attribute search context and close the inode. */
if (ctx)
ntfs_attr_put_search_ctx(ctx);
if (ni)
ntfs_inode_close(ni);
}
if (dir) {
if (result == 0) {
list_add(&dir->list, dir_list_insert_pos);
dir_list_insert_pos = &dir->list;
} else {
free(dir);
dir = NULL;
}
}
free:
free(filename);
return result;
}
/**
* main - Begin here
*
* Start from here.
*
* Return: 0 Success, the program worked
* 1 Error, parsing mount options failed
* 2 Error, mount attempt failed
* 3 Error, failed to open root directory
* 4 Error, failed to open directory in search path
*/
int main(int argc, char **argv)
{
s64 pos;
ntfs_volume *vol;
ntfs_inode *ni;
ntfsls_dirent dirent;
ntfs_log_set_handler(ntfs_log_handler_outerr);
if (!parse_options(argc, argv)) {
// FIXME: Print error... (AIA)
return 1;
}
utils_set_locale();
vol = utils_mount_volume(opts.device, MS_RDONLY, opts.force);
if (!vol) {
// FIXME: Print error... (AIA)
return 2;
}
ni = ntfs_pathname_to_inode(vol, NULL, opts.path);
if (!ni) {
// FIXME: Print error... (AIA)
ntfs_umount(vol, FALSE);
return 3;
}
/*
* We now are at the final path component. If it is a file just
* list it. If it is a directory, list its contents.
*/
pos = 0;
memset(&dirent, 0, sizeof(dirent));
dirent.vol = vol;
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
if (opts.recursive)
readdir_recursive(ni, &pos, &dirent);
else
ntfs_readdir(ni, &pos, &dirent,
(ntfs_filldir_t) list_dir_entry);
// FIXME: error checking... (AIA)
} else {
ATTR_RECORD *rec;
FILE_NAME_ATTR *attr;
ntfs_attr_search_ctx *ctx;
int space = 4;
ntfschar *name = NULL;
int name_len = 0;;
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx)
return -1;
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 < space) {
name = attr->file_name;
name_len = attr->file_name_length;
space = attr->file_name_type;
}
}
list_dir_entry(&dirent, name, name_len, space, pos, ni->mft_no,
NTFS_DT_REG);
// FIXME: error checking... (AIA)
ntfs_attr_put_search_ctx(ctx);
}
/* Finished with the inode; release it. */
ntfs_inode_close(ni);
ntfs_umount(vol, FALSE);
return 0;
}

369
ntfsprogs/ntfsmftalloc.c Normal file
View File

@ -0,0 +1,369 @@
/**
* ntfsmftalloc - Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2005 Anton Altaparmakov
*
* This utility will allocate and initialize an mft record.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS source
* in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif
#ifdef HAVE_STDARG_H
# include <stdarg.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_ERRNO_H
# include <errno.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#else
extern int optind;
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifndef LLONG_MAX
# define LLONG_MAX 9223372036854775807LL
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/inode.h>
#include <ntfs-3g/layout.h>
#include <ntfs-3g/volume.h>
#include <ntfs-3g/mft.h>
#include <ntfs-3g/logging.h>
#include "utils.h"
/* #include "version.h" */
static const char *EXEC_NAME = "ntfsmftalloc";
/* Need these global so ntfsmftalloc_exit can access them. */
static BOOL success = FALSE;
static char *dev_name;
static ntfs_volume *vol;
static ntfs_inode *ni = NULL;
static ntfs_inode *base_ni = NULL;
static s64 base_mft_no = -1;
static struct {
/* -h, print usage and exit. */
int no_action; /* -n, do not write to device, only display
what would be done. */
int quiet; /* -q, quiet execution. */
int verbose; /* -v, verbose execution, given twice, really
verbose execution (debug mode). */
int force; /* -f, force allocation. */
/* -V, print version and exit. */
} opts;
/**
* err_exit - error output and terminate; ignores quiet (-q)
*/
__attribute__((noreturn))
__attribute__((format(printf, 1, 2)))
static void err_exit(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "ERROR: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "Aborting...\n");
exit(1);
}
/**
* copyright - print copyright statements
*/
static void copyright(void)
{
ntfs_log_info("Copyright (c) 2004-2005 Anton Altaparmakov\n"
"Allocate and initialize a base or an extent mft "
"record. If a base mft record\nis not specified, a "
"base mft record is allocated and initialized. "
"Otherwise,\nan extent mft record is allocated and "
"initialized to point to the specified\nbase mft "
"record.\n");
}
/**
* license - print license statement
*/
static void license(void)
{
ntfs_log_info("%s", ntfs_gpl);
}
/**
* usage - print a list of the parameters to the program
*/
__attribute__((noreturn))
static void usage(void)
{
copyright();
ntfs_log_info("Usage: %s [options] device [base-mft-record]\n"
" -n Do not write to disk\n"
" -f Force execution despite errors\n"
" -q Quiet execution\n"
" -v Verbose execution\n"
" -vv Very verbose execution\n"
" -V Display version information\n"
" -l Display licensing information\n"
" -h Display this help\n", EXEC_NAME);
ntfs_log_info("%s%s", ntfs_bugs, ntfs_home);
exit(1);
}
/**
* parse_options
*/
static void parse_options(int argc, char *argv[])
{
long long ll;
char *s;
int c;
if (argc && *argv)
EXEC_NAME = *argv;
ntfs_log_info("%s v%s (libntfs-3g)\n", EXEC_NAME, VERSION);
while ((c = getopt(argc, argv, "fh?nqvVl")) != EOF) {
switch (c) {
case 'f':
opts.force = 1;
break;
case 'n':
opts.no_action = 1;
break;
case 'q':
opts.quiet = 1;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
case 'V':
/* Version number already printed, so just exit. */
exit(0);
case 'l':
copyright();
license();
exit(0);
case 'h':
case '?':
default:
usage();
}
}
if (opts.verbose > 1)
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE |
NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_QUIET);
if (optind == argc)
usage();
/* Get the device. */
dev_name = argv[optind++];
ntfs_log_verbose("device name = %s\n", dev_name);
if (optind != argc) {
/* Get the base mft record number. */
ll = strtoll(argv[optind++], &s, 0);
if (*s || !ll || (ll >= LLONG_MAX && errno == ERANGE))
err_exit("Invalid base mft record number: %s\n",
argv[optind - 1]);
base_mft_no = ll;
ntfs_log_verbose("base mft record number = 0x%llx\n", (long long)ll);
}
if (optind != argc)
usage();
}
/**
* dump_mft_record
*/
static void dump_mft_record(MFT_RECORD *m)
{
ATTR_RECORD *a;
unsigned int u;
MFT_REF r;
ntfs_log_info("-- Beginning dump of mft record. --\n");
u = le32_to_cpu(m->magic);
ntfs_log_info("Mft record signature (magic) = %c%c%c%c\n", u & 0xff,
u >> 8 & 0xff, u >> 16 & 0xff, u >> 24 & 0xff);
u = le16_to_cpu(m->usa_ofs);
ntfs_log_info("Update sequence array offset = %u (0x%x)\n", u, u);
ntfs_log_info("Update sequence array size = %u\n", le16_to_cpu(m->usa_count));
ntfs_log_info("$LogFile sequence number (lsn) = %llu\n",
(unsigned long long)le64_to_cpu(m->lsn));
ntfs_log_info("Sequence number = %u\n", le16_to_cpu(m->sequence_number));
ntfs_log_info("Reference (hard link) count = %u\n",
le16_to_cpu(m->link_count));
u = le16_to_cpu(m->attrs_offset);
ntfs_log_info("First attribute offset = %u (0x%x)\n", u, u);
ntfs_log_info("Flags = %u: ", le16_to_cpu(m->flags));
if (m->flags & MFT_RECORD_IN_USE)
ntfs_log_info("MFT_RECORD_IN_USE");
else
ntfs_log_info("MFT_RECORD_NOT_IN_USE");
if (m->flags & MFT_RECORD_IS_DIRECTORY)
ntfs_log_info(" | MFT_RECORD_IS_DIRECTORY");
ntfs_log_info("\n");
u = le32_to_cpu(m->bytes_in_use);
ntfs_log_info("Bytes in use = %u (0x%x)\n", u, u);
u = le32_to_cpu(m->bytes_allocated);
ntfs_log_info("Bytes allocated = %u (0x%x)\n", u, u);
r = le64_to_cpu(m->base_mft_record);
ntfs_log_info("Base mft record reference:\n\tMft record number = %llu\n\t"
"Sequence number = %u\n",
(unsigned long long)MREF(r), MSEQNO(r));
ntfs_log_info("Next attribute instance = %u\n",
le16_to_cpu(m->next_attr_instance));
a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
ntfs_log_info("-- Beginning dump of attributes within mft record. --\n");
while ((char*)a < (char*)m + le32_to_cpu(m->bytes_in_use)) {
if (a->type == AT_END)
break;
a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
};
ntfs_log_info("-- End of attributes. --\n");
}
/**
* ntfsmftalloc_exit
*/
static void ntfsmftalloc_exit(void)
{
if (success)
return;
/* If there is a base inode, close that instead of the extent inode. */
if (base_ni)
ni = base_ni;
/* Close the inode. */
if (ni && ntfs_inode_close(ni)) {
ntfs_log_perror("Warning: Failed to close inode 0x%llx",
(long long)ni->mft_no);
}
/* Unmount the volume. */
if (ntfs_umount(vol, 0) == -1)
ntfs_log_perror("Warning: Could not umount %s", dev_name);
}
/**
* main
*/
int main(int argc, char **argv)
{
unsigned long mnt_flags, ul;
int err;
ntfs_log_set_handler(ntfs_log_handler_outerr);
/* Initialize opts to zero / required values. */
memset(&opts, 0, sizeof(opts));
/* Parse command line options. */
parse_options(argc, argv);
utils_set_locale();
/* Make sure the file system is not mounted. */
if (ntfs_check_if_mounted(dev_name, &mnt_flags))
ntfs_log_error("Failed to determine whether %s is mounted: %s\n",
dev_name, strerror(errno));
else if (mnt_flags & NTFS_MF_MOUNTED) {
ntfs_log_error("%s is mounted.\n", dev_name);
if (!opts.force)
err_exit("Refusing to run!\n");
ntfs_log_error("ntfsmftalloc forced anyway. Hope /etc/mtab "
"is incorrect.\n");
}
/* Mount the device. */
if (opts.no_action) {
ntfs_log_quiet("Running in READ-ONLY mode!\n");
ul = MS_RDONLY;
} else
ul = 0;
vol = ntfs_mount(dev_name, ul);
if (!vol)
err_exit("Failed to mount %s: %s\n", dev_name, strerror(errno));
/* Register our exit function which will unlock and close the device. */
err = atexit(&ntfsmftalloc_exit);
if (err == -1) {
ntfs_log_error("Could not set up exit() function because atexit() "
"failed: %s Aborting...\n", strerror(errno));
ntfsmftalloc_exit();
exit(1);
}
if (base_mft_no != -1) {
base_ni = ntfs_inode_open(vol, base_mft_no);
if (!base_ni)
err_exit("Failed to open base inode 0x%llx: %s\n",
(long long)base_mft_no,
strerror(errno));
}
/* Open the specified inode. */
ni = ntfs_mft_record_alloc(vol, base_ni);
if (!ni)
err_exit("Failed to allocate mft record: %s\n",
strerror(errno));
ntfs_log_info("Allocated %s mft record 0x%llx", base_ni ? "extent" : "base",
(long long)ni->mft_no);
if (base_ni)
ntfs_log_info(" with base mft record 0x%llx",
(long long)base_mft_no);
ntfs_log_info(".\n");
if (!opts.quiet && opts.verbose > 1) {
ntfs_log_verbose("Dumping allocated mft record 0x%llx:\n",
(long long)ni->mft_no);
dump_mft_record(ni->mrec);
}
/* Close the (base) inode. */
if (base_ni)
ni = base_ni;
err = ntfs_inode_close(ni);
if (err)
err_exit("Failed to close inode 0x%llx: %s\n",
(long long)ni->mft_no, strerror(errno));
/* Unmount the volume. */
err = ntfs_umount(vol, 0);
/* Disable our ntfsmftalloc_exit() handler. */
success = TRUE;
if (err == -1)
ntfs_log_perror("Warning: Failed to umount %s", dev_name);
else
ntfs_log_quiet("ntfsmftalloc completed successfully.\n");
return 0;
}

909
ntfsprogs/ntfsmove.c Normal file
View File

@ -0,0 +1,909 @@
/**
* ntfsmove - Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Richard Russon
* Copyright (c) 2003-2005 Anton Altaparmakov
*
* This utility will move files on an NTFS volume.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/volume.h>
#include <ntfs-3g/debug.h>
#include <ntfs-3g/dir.h>
#include <ntfs-3g/bitmap.h>
#include <ntfs-3g/logging.h>
#include "utils.h"
#include "ntfsmove.h"
/* #include "version.h" */
static const char *EXEC_NAME = "ntfsmove";
static struct options opts;
/**
* version - Print version information about the program
*
* Print a copyright statement and a brief description of the program.
*
* Return: none
*/
static void version(void)
{
ntfs_log_info("\n%s v%s (libntfs-3g) - Move files and directories on an "
"NTFS volume.\n\n", EXEC_NAME, VERSION);
ntfs_log_info("Copyright (c) 2003 Richard Russon\n");
ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
}
/**
* usage - Print a list of the parameters to the program
*
* Print a list of the parameters and options for the program.
*
* Return: none
*/
static void usage(void)
{
ntfs_log_info("\nUsage: %s [options] device file\n"
"\n"
" -S --start Move to the start of the volume\n"
" -B --best Move to the best place on the volume\n"
" -E --end Move to the end of the volume\n"
" -C num --cluster num Move to this cluster offset\n"
"\n"
" -D --no-dirty Do not mark volume dirty (require chkdsk)\n"
" -n --no-action Do not write to disk\n"
" -f --force Use less caution\n"
" -h --help Print this help\n"
" -q --quiet Less output\n"
" -V --version Version information\n"
" -v --verbose More output\n\n",
EXEC_NAME);
ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
}
/**
* parse_options - Read and validate the programs command line
*
* Read the command line, verify the syntax and parse the options.
* This function is very long, but quite simple.
*
* Return: 1 Success
* 0 Error, one or more problems
*/
static int parse_options(int argc, char **argv)
{
static const char *sopt = "-BC:DEfh?nqSVv";
static const struct option lopt[] = {
{ "best", no_argument, NULL, 'B' },
{ "cluster", required_argument, NULL, 'C' },
{ "end", no_argument, NULL, 'E' },
{ "force", no_argument, NULL, 'f' },
{ "help", no_argument, NULL, 'h' },
{ "no-action", no_argument, NULL, 'n' },
{ "no-dirty", no_argument, NULL, 'D' },
{ "quiet", no_argument, NULL, 'q' },
{ "start", no_argument, NULL, 'S' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
int c = -1;
int err = 0;
int ver = 0;
int help = 0;
int levels = 0;
char *end = NULL;
opterr = 0; /* We'll handle the errors, thank you. */
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
switch (c) {
case 1: /* A non-option argument */
if (!opts.device) {
opts.device = argv[optind-1];
} else if (!opts.file) {
opts.file = argv[optind-1];
} else {
opts.device = NULL;
opts.file = NULL;
err++;
}
break;
case 'B':
if (opts.location == 0)
opts.location = NTFS_MOVE_LOC_BEST;
else
opts.location = -1;
break;
case 'C':
if (opts.location == 0) {
opts.location = strtoll(optarg, &end, 0);
if (end && *end)
err++;
} else {
opts.location = -1;
}
break;
case 'D':
opts.nodirty++;
break;
case 'E':
if (opts.location == 0)
opts.location = NTFS_MOVE_LOC_END;
else
opts.location = -1;
break;
case 'f':
opts.force++;
break;
case 'h':
case '?':
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
if (!ntfs_log_parse_option (argv[optind-1]))
err++;
break;
}
help++;
break;
case 'n':
opts.noaction++;
break;
case 'q':
opts.quiet++;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 'S':
if (opts.location == 0)
opts.location = NTFS_MOVE_LOC_START;
else
opts.location = -1;
break;
case 'V':
ver++;
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
default:
ntfs_log_error("Unknown option '%s'.\n", argv[optind-1]);
err++;
break;
}
}
/* Make sure we're in sync with the log levels */
levels = ntfs_log_get_levels();
if (levels & NTFS_LOG_LEVEL_VERBOSE)
opts.verbose++;
if (!(levels & NTFS_LOG_LEVEL_QUIET))
opts.quiet++;
if (help || ver) {
opts.quiet = 0;
} else {
if ((opts.device == NULL) ||
(opts.file == NULL)) {
if (argc > 1)
ntfs_log_error("You must specify one device and one file.\n");
err++;
}
if (opts.quiet && opts.verbose) {
ntfs_log_error("You may not use --quiet and --verbose at the "
"same time.\n");
err++;
}
if (opts.location == -1) {
ntfs_log_error("You may only specify one location option: "
"--start, --best, --end or --cluster\n");
err++;
} else if (opts.location == 0) {
opts.location = NTFS_MOVE_LOC_BEST;
}
}
if (ver)
version();
if (help || err)
usage();
return (!err && !help && !ver);
}
#if 0
/**
* ntfs_debug_runlist_dump2 - Dump a runlist.
*/
static int ntfs_debug_runlist_dump2(const runlist *rl, int abbr, char *prefix)
{
//int abbr = 3; /* abbreviate long lists */
int len = 0;
int i;
int res = 0;
u64 total = 0;
const char *lcn_str[5] = { "HOLE", "NOTMAP", "ENOENT", "EINVAL", "XXXX" };
if (!rl) {
ntfs_log_info(" Run list not present.\n");
return 0;
}
if (!prefix)
prefix = "";
if (abbr)
for (len = 0; rl[len].length; len++) ;
ntfs_log_info("%s VCN LCN len\n", prefix);
for (i = 0; rl->length; i++, rl++) {
LCN lcn = rl->lcn;
total += rl->length;
if (abbr)
if (len > 20) {
if ((i == abbr) && (len > (abbr*2)))
ntfs_log_info("%s ... ... ...\n", prefix);
if ((i > (abbr-1)) && (i < (len - (abbr-1))))
continue;
}
if (rl->vcn < -1)
res = -1;
if (lcn < (LCN)0) {
int j = -lcn - 1;
if ((j < 0) || (j > 4)) {
j = 4;
res = -1;
}
ntfs_log_info("%s%8lld %8s %8lld\n", prefix,
rl->vcn, lcn_str[j], rl->length);
} else
ntfs_log_info("%s%8lld %8lld %8lld\n", prefix,
rl->vcn, rl->lcn, rl->length);
}
ntfs_log_info("%s --------\n", prefix);
ntfs_log_info("%s %8lld\n", prefix, total);
ntfs_log_info("\n");
return res;
}
#endif /* if 0 */
/**
* resize_nonres_attr
*/
static int resize_nonres_attr(MFT_RECORD *m, ATTR_RECORD *a, const u32 new_size)
{
int this_attr;
int next_attr;
int tail_size;
int file_size;
int old_size;
u8 *ptr;
old_size = a->length;
file_size = m->bytes_in_use;
this_attr = p2n(a)-p2n(m);
next_attr = this_attr + a->length;
tail_size = file_size - next_attr;
ptr = (u8*) m;
/*
ntfs_log_info("old_size = %d\n", old_size);
ntfs_log_info("new_size = %d\n", new_size);
ntfs_log_info("file_size = %d\n", file_size);
ntfs_log_info("this_attr = %d\n", this_attr);
ntfs_log_info("next_attr = %d\n", next_attr);
ntfs_log_info("tail_size = %d\n", tail_size);
*/
memmove(ptr + this_attr + new_size, ptr + next_attr, tail_size);
a->length = new_size;
m->bytes_in_use += new_size - old_size;
return 0;
}
/**
* calc_attr_length
*/
static int calc_attr_length(ATTR_RECORD *rec, int runlength)
{
int size;
if (!rec)
return -1;
if (!rec->non_resident)
return -1;
size = rec->mapping_pairs_offset + runlength + 7;
size &= 0xFFF8;
return size;
}
#if 0
/**
* dump_runs
*/
static void dump_runs(u8 *buffer, int len)
{
int i;
ntfs_log_info("RUN: \e[01;31m");
for (i = 0; i < len; i++) {
ntfs_log_info(" %02x", buffer[i]);
}
ntfs_log_info("\e[0m\n");
}
#endif /* if 0 */
/**
* find_unused
*/
static runlist * find_unused(ntfs_volume *vol, s64 size, u64 loc
__attribute__((unused)), int flags __attribute__((unused)))
{
const int bufsize = 8192;
u8 *buffer;
int clus;
int i;
int curr = 0;
int count = 0;
s64 start = 0;
int bit = 0;
runlist *res = NULL;
//ntfs_log_info("find_unused\n");
buffer = malloc(bufsize);
if (!buffer) {
ntfs_log_info("!buffer\n");
return NULL;
}
//ntfs_log_info("looking for space for %lld clusters\n", size);
clus = vol->lcnbmp_na->allocated_size / bufsize;
//ntfs_log_info("clus = %d\n", clus);
for (i = 0; i < clus; i++) {
int bytes_read, j;
bytes_read = ntfs_attr_pread(vol->lcnbmp_na, i*bufsize,
bufsize, buffer);
if (bytes_read != bufsize) {
ntfs_log_info("!read\n");
return NULL;
}
for (j = 0; j < bufsize*8; j++) {
bit = !!test_bit(j & 7, buffer[j>>3]);
if (curr == bit) {
count++;
if ((!bit) && (count >= size)) {
//res = calloc(2, sizeof(*res));
res = calloc(1, 4096);
if (res) {
res[0].vcn = 0;
res[0].lcn = start;
res[0].length = size;
res[1].lcn = LCN_ENOENT;
}
goto done;
}
} else {
//ntfs_log_info("%d * %d\n", curr, count);
curr = bit;
count = 1;
start = i*bufsize*8 + j;
}
}
}
done:
//ntfs_log_info("%d * %d\n", curr, count);
free(buffer);
if (res) {
for (i = 0; i < size; i++) {
if (utils_cluster_in_use(vol, res->lcn + i)) {
ntfs_log_info("ERROR cluster %lld in use\n", res->lcn + i);
}
}
} else {
ntfs_log_info("failed\n");
}
return res;
}
/**
* dont_move
*
* Don't let the user move:
* ANY metadata
* Any fragmented MFT records
* The boot file 'ntldr'
*/
static int dont_move(ntfs_inode *ino)
{
static const ntfschar ntldr[6] = {
const_cpu_to_le16('n'), const_cpu_to_le16('t'), const_cpu_to_le16('l'),
const_cpu_to_le16('d'), const_cpu_to_le16('r'), const_cpu_to_le16('\0')
};
ATTR_RECORD *rec;
FILE_NAME_ATTR *name;
if (utils_is_metadata(ino)) {
ntfs_log_error("metadata\n");
return 1;
}
rec = find_first_attribute(AT_ATTRIBUTE_LIST, ino->mrec);
if (rec) {
ntfs_log_error("attribute list\n");
return 1;
}
rec = find_first_attribute(AT_FILE_NAME, ino->mrec);
if (!rec) {
ntfs_log_error("extend inode\n");
return 1;
}
name = (FILE_NAME_ATTR*) ((u8*)rec + rec->value_offset);
if (ntfs_names_are_equal(ntldr, 5, name->file_name, name->file_name_length,
IGNORE_CASE, ino->vol->upcase, ino->vol->upcase_len)) {
ntfs_log_error("ntldr\n");
return 1;
}
return 0;
}
/**
* bitmap_alloc
*/
static int bitmap_alloc(ntfs_volume *vol, runlist_element *rl)
{
int res;
if (!rl)
return -1;
res = ntfs_bitmap_set_run(vol->lcnbmp_na, rl->lcn, rl->length);
if (res < 0) {
ntfs_log_error("bitmap alloc returns %d\n", res);
}
return res;
}
/**
* bitmap_free
*/
static int bitmap_free(ntfs_volume *vol, runlist_element *rl)
{
int res;
if (!rl)
return -1;
res = ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, rl->length);
if (res < 0) {
ntfs_log_error("bitmap free returns %d\n", res);
}
return res;
}
/**
* data_copy
*/
static int data_copy(ntfs_volume *vol, runlist_element *from, runlist_element *to)
{
int i;
u8 *buffer;
s64 res = 0;
if (!vol || !from || !to)
return -1;
if ((from->length != to->length) || (from->lcn < 0) || (to->lcn < 0))
return -1;
//ntfs_log_info("data_copy: from 0x%llx to 0x%llx\n", from->lcn, to->lcn);
buffer = malloc(vol->cluster_size);
if (!buffer) {
ntfs_log_info("!buffer\n");
return -1;
}
for (i = 0; i < from->length; i++) {
//ntfs_log_info("read cluster at %8lld\n", from->lcn+i);
res = ntfs_pread(vol->dev, (from->lcn+i) * vol->cluster_size,
vol->cluster_size, buffer);
if (res != vol->cluster_size) {
ntfs_log_error("!read\n");
res = -1;
break;
}
//ntfs_log_info("write cluster to %8lld\n", to->lcn+i);
res = ntfs_pwrite(vol->dev, (to->lcn+i) * vol->cluster_size,
vol->cluster_size, buffer);
if (res != vol->cluster_size) {
ntfs_log_error("!write %lld\n", res);
res = -1;
break;
}
}
free(buffer);
return res;
}
/**
* move_runlist
*
* validate:
* runlists are the same size
* from in use
* to not in use
* allocate new space
* copy data
* deallocate old space
*/
static s64 move_runlist(ntfs_volume *vol, runlist_element *from,
runlist_element *to)
{
int i;
if (!vol || !from || !to)
return -1;
if (from->length != to->length) {
ntfs_log_error("diffsizes\n");
return -1;
}
if ((from->lcn < 0) || (to->lcn < 0)) {
ntfs_log_error("invalid runs\n");
return -1;
}
for (i = 0; i < from->length; i++) {
if (!utils_cluster_in_use(vol, from->lcn+i)) {
ntfs_log_error("from not in use\n");
return -1;
}
}
for (i = 0; i < to->length; i++) {
if (utils_cluster_in_use(vol, to->lcn+i)) {
ntfs_log_error("to is in use\n");
return -1;
}
}
if (bitmap_alloc(vol, to) < 0) {
ntfs_log_error("cannot bitmap_alloc\n");
return -1;
}
if (data_copy(vol, from, to) < 0) {
ntfs_log_error("cannot data_copy\n");
return -1;
}
if (bitmap_free(vol, from) < 0) {
ntfs_log_error("cannot bitmap_free\n");
return -1;
}
return 0;
}
/**original
* move_datarun
* > 0 Bytes moved / size to be moved
* = 0 Nothing to do
* < 0 Error
*/
// get size of runlist
// find somewhere to put data
// backup original runlist
// move the data
// got to get the runlist out of this function
// requires a mrec arg, not an ino (ino->mrec will do for now)
// check size of new runlist before allocating / moving
// replace one datarun with another (by hand)
static s64 move_datarun(ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec,
runlist_element *run, u64 loc, int flags)
{
runlist *from;
runlist *to;
int need_from;
int need_to;
int i;
s64 res = -1;
// find empty space
to = find_unused(vol, run->length, loc, flags);
if (!to) {
ntfs_log_error("!to\n");
return -1;
}
to->vcn = run->vcn;
// copy original runlist
from = ntfs_mapping_pairs_decompress(vol, rec, NULL);
if (!from) {
ntfs_log_info("!from\n");
return -1;
}
ntfs_log_info("move %lld,%lld,%lld to %lld,%lld,%lld\n", run->vcn,
run->lcn, run->length, to->vcn, to->lcn, to->length);
need_from = ntfs_get_size_for_mapping_pairs(vol, from, 0, INT_MAX);
ntfs_log_info("orig data run = %d bytes\n", need_from);
//ntfs_debug_runlist_dump2(from, 5, "\t");
for (i = 0; to[i].length > 0; i++) {
if (from[i].vcn == run->vcn) {
from[i].lcn = to->lcn;
break;
}
}
//ntfs_debug_runlist_dump2(from, 5, "\t");
need_to = ntfs_get_size_for_mapping_pairs(vol, from, 0, INT_MAX);
ntfs_log_info("new data run = %d bytes\n", need_to);
need_from = calc_attr_length(rec, need_from);
need_to = calc_attr_length(rec, need_to);
ntfs_log_info("Before %d, after %d\n", need_from, need_to);
if (need_from != need_to) {
if (resize_nonres_attr(ino->mrec, rec, need_to) < 0) {
ntfs_log_info("!resize\n");
return -1;
}
}
res = move_runlist(vol, run, to);
if (res < 0) {
ntfs_log_error("!move_runlist\n");
return -1;
}
// wipe orig runs
memset(((u8*)rec) +rec->mapping_pairs_offset, 0, need_to - rec->mapping_pairs_offset);
// update data runs
ntfs_mapping_pairs_build(vol, ((u8*)rec) + rec->mapping_pairs_offset,
need_to, from, 0, NULL);
// commit
ntfs_inode_mark_dirty(ino);
if (ntfs_inode_sync(ino) < 0) {
ntfs_log_info("!sync\n");
return -1;
}
free(from);
free(to);
return res;
}
/**
* move_attribute
* > 0 Bytes moved / size to be moved
* = 0 Nothing to do
* < 0 Error
*/
static s64 move_attribute(ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec,
u64 loc, int flags)
{
int i;
s64 res;
s64 count = 0;
runlist *runs;
// NTFS_MOVE_LOC_BEST : assess how much space this attribute will need,
// find that space and pass the location to our children.
// Anything else we pass directly to move_datarun.
runs = ntfs_mapping_pairs_decompress(vol, rec, NULL);
if (!runs) {
ntfs_log_error("!runs\n");
return -1;
}
//ntfs_debug_runlist_dump2(runs, 5, "\t");
//ntfs_log_info(" VCN LCN Length\n");
for (i = 0; runs[i].length > 0; i++) {
if (runs[i].lcn == LCN_RL_NOT_MAPPED) {
continue;
}
res = move_datarun(vol, ino, rec, runs+i, loc, flags);
//ntfs_log_info(" %8lld %8lld %8lld\n", runs[i].vcn, runs[i].lcn, runs[i].length);
if (res < 0) {
ntfs_log_error("!move_datarun\n");
count = res;
break;
}
count += res;
}
return count;
}
/**
* move_file
* > 0 Bytes moved / size to be moved
* = 0 Nothing to do
* < 0 Error
*/
static s64 move_file(ntfs_volume *vol, ntfs_inode *ino, u64 loc, int flags)
{
char *buffer;
ntfs_attr_search_ctx *ctx;
ATTR_RECORD *rec;
s64 res;
s64 count = 0;
buffer = malloc(MAX_PATH);
if (!buffer) {
ntfs_log_error("Out of memory\n");
return -1;
}
utils_inode_get_name(ino, buffer, MAX_PATH);
if (dont_move(ino)) {
ntfs_log_error("can't move\n");
return -1;
}
ntfs_log_info("Moving %s\n", buffer);
// NTFS_MOVE_LOC_BEST : assess how much space all the attributes will need,
// find that space and pass the location to our children.
// Anything else we pass directly to move_attribute.
ctx = ntfs_attr_get_search_ctx(ino, NULL);
while ((rec = find_attribute(AT_UNUSED, ctx))) {
utils_attr_get_name(vol, rec, buffer, MAX_PATH);
ntfs_log_info("\tAttribute 0x%02x %s is ", rec->type, buffer);
if (rec->non_resident) {
ntfs_log_info("non-resident. Moving it.\n");
res = move_attribute(vol, ino, rec, loc, flags);
if (res < 0) {
count = res;
break;
}
count += res;
} else {
ntfs_log_info("resident.\n\t\tSkipping it.\n");
}
}
ntfs_attr_put_search_ctx(ctx);
free(buffer);
return count;
}
/**
* main - Begin here
*
* Start from here.
*
* Return: 0 Success, the program worked
* 1 Error, something went wrong
*/
int main(int argc, char *argv[])
{
ntfs_volume *vol;
ntfs_inode *inode;
int flags = 0;
int result = 1;
s64 count;
ntfs_log_set_handler(ntfs_log_handler_outerr);
if (!parse_options(argc, argv))
return 1;
utils_set_locale();
if (opts.noaction)
flags |= MS_RDONLY;
vol = utils_mount_volume(opts.device, flags, opts.force);
if (!vol) {
ntfs_log_info("!vol\n");
return 1;
}
inode = ntfs_pathname_to_inode(vol, NULL, opts.file);
if (!inode) {
ntfs_log_info("!inode\n");
return 1;
}
count = move_file(vol, inode, opts.location, 0);
if ((count > 0) && (!opts.nodirty)) {
if (ntfs_volume_write_flags(vol, vol->flags | VOLUME_IS_DIRTY) <
0) {
ntfs_log_error("Couldn't mark volume dirty\n");
}
ntfs_log_info("Relocated %lld bytes\n", count);
}
if (count >= 0)
result = 0;
if (result)
ntfs_log_info("failed\n");
else
ntfs_log_info("success\n");
ntfs_inode_close(inode);
ntfs_umount(vol, FALSE);
return result;
}

47
ntfsprogs/ntfsmove.h Normal file
View File

@ -0,0 +1,47 @@
/*
* ntfsmove - Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Richard Russon
*
* This utility will move files on an NTFS volume.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFSMOVE_H_
#define _NTFSMOVE_H_
#include <ntfs-3g/types.h>
/* Move files to */
#define NTFS_MOVE_LOC_START -1000 /* the first available space */
#define NTFS_MOVE_LOC_BEST -1001 /* place big enough for entire file */
#define NTFS_MOVE_LOC_END -1002 /* the last available space */
struct options {
char *device; /* Device/File to work with */
char *file; /* File to display */
s64 location; /* Where to place the file */
int force; /* Override common sense */
int quiet; /* Less output */
int verbose; /* Extra output */
int noaction; /* Do not write to disk */
int nodirty; /* Do not mark volume dirty */
u8 padding[4]; /* Unused: alignment to 64 bit. */
};
#endif /* _NTFSMOVE_H_ */

72
ntfsprogs/ntfsprogs.8.in Normal file
View File

@ -0,0 +1,72 @@
.\" Copyright (c) 2002\-2005 Richard Russon.
.\" Copyright (c) 2002\-2003 Anton Altaparmakov.
.\" Copyright (c) 2005\-2006 Szabolcs Szakacsits.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSPROGS 8 "April 2006" "ntfsprogs @VERSION@"
.SH NAME
ntfsprogs \- tools for doing neat things with NTFS
.SH OVERVIEW
.B ntfsprogs
is a suite of NTFS utilities based around a shared library. The tools are
available for free and come with full source code.
.SH TOOLS
.PP
.BR mkntfs (8)
\- Create an NTFS filesystem.
.PP
.BR ntfscat (8)
\- Dump a file's content to the standard output.
.PP
.BR ntfsclone (8)
\- Efficiently clone, backup, restore or rescue NTFS.
.PP
.BR ntfscluster (8)
\- Locate the files which use the given sectors or clusters.
.PP
.BR ntfscmp (8)
\- Compare two NTFS filesystems and tell the differences.
.PP
.BR ntfscp (8)
\- Overwrite a file on an NTFS.
.PP
.BR ntfsfix (8)
\- Check and fix some common errors, clear the LogFile and make Windows
perform a thorough check next time it boots.
.PP
.BR ntfsinfo (8)
\- Show information about NTFS or one of the files or directories within it.
.PP
.BR ntfslabel (8)
\- Show, or set, an NTFS filesystem's volume label.
.PP
.BR ntfsls (8)
\- List information about files in a directory residing on an NTFS.
.PP
.BR ntfsresize (8)
\- Resize NTFS without losing data.
.PP
.BR ntfsundelete (8)
\- Recover deleted files from NTFS.
.SH AUTHORS
.PP
The tools were written by Anton Altaparmakov, Carmelo Kintana, Cristian Klein,
Erik Sornes, Giang Nguyen, Holger Ohmacht, Lode Leroy, Matthew J. Fanto, Per
Olofsson, Richard Russon, Szabolcs Szakacsits, Yura Pakhuchiy and Yuval Fledel.
.SH AVAILABILITY
The
.B ntfsprogs
can be downloaded from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
These manual pages can be viewed online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR libntfs\-gnomevfs (8)

286
ntfsprogs/ntfsresize.8.in Normal file
View File

@ -0,0 +1,286 @@
.\" Copyright (c) 2002\-2006 Szabolcs Szakacsits.
.\" Copyright (c) 2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSRESIZE 8 "February 2006" "ntfsprogs @VERSION@"
.SH NAME
ntfsresize \- resize an NTFS filesystem without data loss
.SH SYNOPSIS
.B ntfsresize
[\fIOPTIONS\fR]
.B \-\-info
.I DEVICE
.br
.B ntfsresize
[\fIOPTIONS\fR]
[\fB\-\-size \fISIZE\fR[\fBk\fR|\fBM\fR|\fBG\fR]]
.I DEVICE
.SH DESCRIPTION
The
.B ntfsresize
program safely resizes Windows XP, Windows Server 2003, Windows 2000, Windows
NT4 and Longhorn NTFS filesystems without data loss. All NTFS versions are
supported, used by 32\-bit and 64\-bit Windows.
.B Defragmentation is NOT required prior to resizing
because the program can relocate any data if needed, without risking data
integrity.
.PP
Ntfsresize can be used to shrink or enlarge any NTFS filesystem located
on an unmounted
.I DEVICE
(usually a disk partition). The new filesystem will have
.I SIZE
bytes.
The
.I SIZE
parameter may have one of the optional modifiers
.BR k ,
.BR M ,
.BR G ,
which means the
.I SIZE
parameter is given in kilo\-, mega\- or gigabytes respectively.
.B Ntfsresize
conforms to the SI, ATA, IEEE standards and the disk manufacturers
by using k=10^3, M=10^6 and G=10^9.
If both
.B \-\-info
and
.B \-\-size
are omitted then the
NTFS filesystem will be enlarged to the underlying
.I DEVICE
size.
.PP
To resize a filesystem on a partition, you must resize BOTH the filesystem
and the partition by editing the partition table on the disk. Similarly to
other command line filesystem resizers,
.B ntfsresize
doesn't manipulate the size of the partitions, hence
to do that you must use a disk partitioning tool as well, for example
.BR fdisk (8).
Alternatively you could use one of the many user friendly partitioners that
uses
.B ntfsresize
internally, like Mandriva's DiskDrake, QTParted, SUSE/Novell's YaST Partitioner,
IBM's EVMS, GParted or Debian/Ubuntu's Partman.
.PP
.B IMPORTANT!
It's a good practice making REGULAR BACKUPS of your valuable data, especially
before using ANY partitioning tools. To do so for NTFS, you could use
.BR ntfsclone (8).
Don't forget to save the partition table as well!
.SS Shrinkage
If you wish to shrink an NTFS partition, first use
.B ntfsresize
to shrink the size of the filesystem. Then you could use
.BR fdisk (8)
to shrink the size of the partition by deleting the
partition and recreating it with the smaller size.
Do not make the partition smaller than the new size of
NTFS otherwise you won't be able to boot. If you did so notwithstanding
then just recreate the partition to be as large as NTFS.
.SS Enlargement
To enlarge an NTFS filesystem, first you must enlarge the size of the
underlying partition. This can be done using
.BR fdisk (8)
by deleting the partition and recreating it with a larger size.
Make sure it will not overlap with an other existing partition.
Then you may use
.B ntfsresize
to enlarge the size of the filesystem.
.SS Partitioning
When recreating the partition by a disk partitioning tool,
make sure you create it at the same
starting sector and with the same partition type as before.
Otherwise you won't be able to access your filesystem. Use the 'u'
fdisk command to switch to the reliable sector unit from the
default cylinder one.
Also make sure you set the bootable flag for the partition if it
existed before. Failing to do so you might not be able to boot your
computer from the disk.
.SH OPTIONS
Below is a summary of all the options that
.B ntfsresize
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-i\fR, \fB\-\-info\fR
By using this option ntfsresize will determine the theoretically smallest
shrunken filesystem size supported. Most of the time the result is the space
already used on the filesystem. Ntfsresize will refuse shrinking to a
smaller size than what you got by this option and depending on several
factors it might be unable to shrink very close to this theoretical
size. Although the integrity of your data should be never in risk,
it's still strongly recommended to make a test run by using the
\fB\-\-no\-action\fR option before real resizing.
Practically the smallest shrunken size generally is
at around "used space" + (20\-200 MB). Please also take into account
that Windows might need about 50\-100 MB free space left to boot safely.
This option never causes any changes to the filesystem, the partition is
opened read\-only.
.TP
\fB\-s\fR, \fB\-\-size\fR SIZE\fR[\fBk\fR|\fBM\fR|\fBG\fR]
Resize filesystem to \fISIZE\fR[\fBk\fR|\fBM\fR|\fBG\fR] bytes.
The optional modifiers
.BR k ,
.BR M ,
.B G
mean the
.I SIZE
parameter is given in kilo\-, mega\- or gigabytes respectively.
Conforming to standards, k=10^3, M=10^6 and G=10^9. Use this option
with
.B \-\-no\-action
first.
.TP
\fB\-f\fR, \fB\-\-force\fR
Forces ntfsresize to proceed with the resize operation even if the filesystem
is marked for consistency check.
Please note, ntfsresize always marks the filesystem
for consistency check before a real resize operation
and it leaves that way for extra
safety. Thus if NTFS was marked by ntfsresize then it's safe to
use this option. If you need
to resize several times without booting into Windows between each
resizing steps then you must use this option.
.TP
.B \-n, \-\-no\-action
Use this option to make a test run before doing the real resize operation.
Volume will be opened read\-only and
.B ntfsresize
displays what it would do if it were to resize the filesystem.
Continue with the real resizing only if the test run passed.
.TP
\fB\-b\fR, \fB\-\-bad\-sectors\fR
Support disks having hardware errors, bad sectors with those
.B ntfsresize
would refuse to work by default.
Prior using this option, it's strongly recommended to make a backup by
.BR ntfsclone (8)
using the \-\-rescue option, then running 'chkdsk /f /r volume:' on Windows
from the command line. If the disk guarantee is still valid then replace it.
It's defected. Please also note, that no software can repair these type of
hardware errors. The most what they can do is to work around the permanent
defects.
This option doesn't have any effect if the disk is flawless.
.TP
\fB\-P\fR, \fB\-\-no\-progress\-bar\fR
Don't show progress bars.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
More output.
.TP
\fB\-V\fR, \fB\-\-version\fR
Print the version number of
.B ntfsresize
and exit.
.TP
\fB\-h\fR, \fB\-\-help\fR
Display help and exit.
.SH EXIT CODES
The exit code is 0 on success, non\-zero otherwise.
.SH KNOWN ISSUES
No reliability problem is known. If you need
help please try the Ntfsresize FAQ first (see below) and if you
don't find your answer then send your question, comment or bug report to
the development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.PP
There are a few very rarely met restrictions at present: filesystems having
unknown bad sectors, relocation
of the first MFT extent and resizing into the middle of a $MFTMirr extent
aren't supported yet. These cases are detected and
resizing is restricted to a safe size or the closest safe
size is displayed.
.PP
.B Ntfsresize
schedules an NTFS consistency check and
after the first boot into Windows you must see
.B chkdsk
running on a blue background. This is intentional and no need to worry about it.
Windows may force a quick reboot after the consistency check.
Moreover after repartitioning your disk and depending on the
hardware configuration, the Windows message
.B System Settings Change
may also appear. Just acknowledge it and reboot again.
.PP
The disk geometry handling semantic (HDIO_GETGEO ioctl) has changed
in an incompatible way in Linux 2.6 kernels and this triggered multitudinous
partition table corruptions resulting in unbootable Windows systems, even if
NTFS was consistent, if
.BR parted (8)
was involved in some way. This problem was often attributed to ntfsresize
but in fact it's completely independent of NTFS thus ntfsresize. Moreover
ntfsresize never touches the partition table at all. By changing
the 'Disk Access Mode' to LBA in the BIOS makes booting work
again, most of the time. You can find more information about this issue
in the Troubleshooting section of the below referred Ntfsresize FAQ.
.SH AUTHORS
.B ntfsresize
was written by Szabolcs Szakacsits, with contributions from Anton Altaparmakov
and Richard Russon.
.SH ACKNOWLEDGEMENT
Many thanks to Anton Altaparmakov and Richard Russon
for libntfs, the excellent documentation and comments,
to Gergely Madarasz, Dewey M. Sasser and Miguel Lastra and his colleagues
at the University of Granada for their continuous and highly valuable help,
furthermore to Erik Meade, Martin Fick, Sandro Hawke, Dave Croal,
Lorrin Nelson, Geert Hendrickx, Robert Bjorkman and Richard Burdick
for beta testing the relocation support, to Florian Eyben, Fritz Oppliger,
Richard Ebling, Sid\-Ahmed Touati, Jan Kiszka, Benjamin Redelings, Christopher
Haney, Ryan Durk, Ralf Beyer, Scott Hansen, Alan Evans for the valued
contributions and to Theodore Ts'o whose
.BR resize2fs (8)
man page originally formed the basis of this page.
.SH AVAILABILITY
.B ntfsresize
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.sp
.B Ntfsresize
related news, example of usage, troubleshooting, statically linked binary and
FAQ (frequently asked questions) are maintained at:
.br
.nh
http://mlf.linux.rulez.org/mlf/ezaz/ntfsresize.html
.hy
.SH SEE ALSO
.BR fdisk (8),
.BR cfdisk (8),
.BR sfdisk (8),
.BR parted (8),
.BR evms (8),
.BR ntfsclone (8),
.BR mkntfs (8),
.BR ntfsprogs (8)

2502
ntfsprogs/ntfsresize.c Normal file

File diff suppressed because it is too large Load Diff

1070
ntfsprogs/ntfsrm.c Normal file

File diff suppressed because it is too large Load Diff

63
ntfsprogs/ntfsrm.h Normal file
View File

@ -0,0 +1,63 @@
/*
* ntfsrm - Part of the Linux-NTFS project.
*
* Copyright (c) 2004-2005 Richard Russon
*
* This utility will delete files from an NTFS volume.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFSRM_H_
#define _NTFSRM_H_
#include "types.h"
#include "layout.h"
#include "volume.h"
#include "inode.h"
struct ntfs_dir;
struct ntfs_dt;
/**
* struct options
*/
struct options {
char *device; /* Device/File to work with */
char *file; /* File to delete */
int force; /* Override common sense */
int interactive; /* Ask before deleting files */
int recursive; /* Delete files in subdirectories */
int quiet; /* Less output */
int verbose; /* Extra output */
int noaction; /* Do not write to disk */
int nodirty; /* Do not mark volume dirty */
};
/**
* struct ntfs_find
*/
struct ntfs_find {
ntfs_inode *inode;
struct ntfs_dir *dir;
struct ntfs_dt *dt;
int dt_index;
MFT_REF mref;
};
#endif /* _NTFSRM_H_ */

811
ntfsprogs/ntfstruncate.c Normal file
View File

@ -0,0 +1,811 @@
/**
* ntfstruncate - Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2005 Anton Altaparmakov
*
* This utility will truncate a specified attribute belonging to a
* specified inode, i.e. file or directory, to a specified length.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS source
* in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif
#ifdef HAVE_STDARG_H
# include <stdarg.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_ERRNO_H
# include <errno.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#else
extern char *optarg;
extern int optind;
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifndef LLONG_MAX
# define LLONG_MAX 9223372036854775807LL
#endif
#include <ntfs-3g/types.h>
#include <ntfs-3g/attrib.h>
#include <ntfs-3g/inode.h>
#include <ntfs-3g/layout.h>
#include <ntfs-3g/volume.h>
#include <ntfs-3g/logging.h>
#include "utils.h"
#include "attrdef.h"
/* #include "version.h" */
const char *EXEC_NAME = "ntfstruncate";
/* Need these global so ntfstruncate_exit can access them. */
BOOL success = FALSE;
char *dev_name;
s64 inode;
u32 attr_type;
ntfschar *attr_name = NULL;
u32 attr_name_len;
s64 new_len;
ntfs_volume *vol;
ntfs_inode *ni;
ntfs_attr *na = NULL;
ATTR_DEF *attr_defs;
struct {
/* -h, print usage and exit. */
int no_action; /* -n, do not write to device, only display
what would be done. */
int quiet; /* -q, quiet execution. */
int verbose; /* -v, verbose execution, given twice, really
verbose execution (debug mode). */
int force; /* -f, force truncation. */
/* -V, print version and exit. */
} opts;
/**
* err_exit - error output and terminate; ignores quiet (-q)
*/
__attribute__((noreturn))
__attribute__((format(printf, 1, 2)))
static void err_exit(const char *fmt, ...)
{
va_list ap;
fprintf(stderr, "ERROR: ");
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "Aborting...\n");
exit(1);
}
/**
* copyright - print copyright statements
*/
static void copyright(void)
{
fprintf(stderr, "Copyright (c) 2002-2005 Anton Altaparmakov\n"
"Copyright (c) 2003 Richard Russon\n"
"Truncate a specified attribute of a specified "
"inode.\n");
}
/**
* license - print license statement
*/
static void license(void)
{
fprintf(stderr, "%s", ntfs_gpl);
}
/**
* usage - print a list of the parameters to the program
*/
__attribute__((noreturn))
static void usage(void)
{
copyright();
fprintf(stderr, "Usage: %s [options] device inode [attr-type "
"[attr-name]] new-length\n"
" If attr-type is not specified, 0x80 (i.e. $DATA) "
"is assumed.\n"
" If attr-name is not specified, an unnamed "
"attribute is assumed.\n"
" -n Do not write to disk\n"
" -f Force execution despite errors\n"
" -q Quiet execution\n"
" -v Verbose execution\n"
" -vv Very verbose execution\n"
" -V Display version information\n"
" -l Display licensing information\n"
" -h Display this help\n", EXEC_NAME);
fprintf(stderr, "%s%s", ntfs_bugs, ntfs_home);
exit(1);
}
/**
* parse_options
*/
static void parse_options(int argc, char *argv[])
{
long long ll;
char *s, *s2;
int c;
if (argc && *argv)
EXEC_NAME = *argv;
fprintf(stderr, "%s v%s (libntfs-3g)\n", EXEC_NAME, VERSION);
while ((c = getopt(argc, argv, "fh?nqvVl")) != EOF)
switch (c) {
case 'f':
opts.force = 1;
break;
case 'n':
opts.no_action = 1;
break;
case 'q':
opts.quiet = 1;
ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
break;
case 'v':
opts.verbose++;
ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
break;
case 'V':
/* Version number already printed, so just exit. */
exit(0);
case 'l':
copyright();
license();
exit(0);
case 'h':
case '?':
default:
usage();
}
if (optind == argc)
usage();
if (opts.verbose > 1)
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE |
NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_QUIET);
/* Get the device. */
dev_name = argv[optind++];
ntfs_log_verbose("device name = %s\n", dev_name);
if (optind == argc)
usage();
/* Get the inode. */
ll = strtoll(argv[optind++], &s, 0);
if (*s || !ll || (ll >= LLONG_MAX && errno == ERANGE))
err_exit("Invalid inode number: %s\n", argv[optind - 1]);
inode = ll;
ntfs_log_verbose("inode = %lli\n", (long long)inode);
if (optind == argc)
usage();
/* Get the attribute type, if specified. */
s = argv[optind++];
if (optind == argc) {
attr_type = AT_DATA;
attr_name = AT_UNNAMED;
attr_name_len = 0;
} else {
unsigned long ul;
ul = strtoul(s, &s2, 0);
if (*s2 || !ul || (ul >= ULONG_MAX && errno == ERANGE))
err_exit("Invalid attribute type %s: %s\n", s,
strerror(errno));
attr_type = ul;
/* Get the attribute name, if specified. */
s = argv[optind++];
if (optind != argc) {
/* Convert the string to little endian Unicode. */
attr_name_len = ntfs_mbstoucs_libntfscompat(s, &attr_name, 0);
if ((int)attr_name_len < 0)
err_exit("Invalid attribute name \"%s\": %s\n",
s, strerror(errno));
/* Keep hold of the original string. */
s2 = s;
s = argv[optind++];
if (optind != argc)
usage();
} else {
attr_name = AT_UNNAMED;
attr_name_len = 0;
}
}
ntfs_log_verbose("attribute type = 0x%x\n", (unsigned int)attr_type);
if (attr_name == AT_UNNAMED)
ntfs_log_verbose("attribute name = \"\" (UNNAMED)\n");
else
ntfs_log_verbose("attribute name = \"%s\" (length %u Unicode "
"characters)\n", s2,
(unsigned int)attr_name_len);
/* Get the new length. */
ll = strtoll(s, &s2, 0);
if (*s2 || ll < 0 || (ll >= LLONG_MAX && errno == ERANGE))
err_exit("Invalid new length: %s\n", s);
new_len = ll;
ntfs_log_verbose("new length = %lli\n", new_len);
}
/**
* ucstos - convert unicode-character string to ASCII
* @dest: points to buffer to receive the converted string
* @src: points to string to convert
* @maxlen: size of @dest buffer in bytes
*
* Return the number of characters written to @dest, not including the
* terminating null byte. If a unicode character was encountered which could
* not be converted -1 is returned.
*/
static int ucstos(char *dest, const ntfschar *src, int maxlen)
{
ntfschar u;
int i;
/* Need one byte for null terminator. */
maxlen--;
for (i = 0; i < maxlen; i++) {
u = le16_to_cpu(src[i]);
if (!u)
break;
if (u & 0xff00)
return -1;
dest[i] = u & 0xff;
}
dest[i] = 0;
return i;
}
/**
* dump_resident_attr_val
*/
static void dump_resident_attr_val(ATTR_TYPES type, char *val, u32 val_len)
{
const char *don_t_know = "Don't know what to do with this attribute "
"type yet.";
const char *skip = "Skipping display of $%s attribute value.\n";
const char *todo = "This is still work in progress.";
char *buf;
int i, j;
u32 u;
switch (type) {
case AT_STANDARD_INFORMATION:
// TODO
printf("%s\n", todo);
return;
case AT_ATTRIBUTE_LIST:
// TODO
printf("%s\n", todo);
return;
case AT_FILE_NAME:
// TODO
printf("%s\n", todo);
return;
case AT_OBJECT_ID:
// TODO
printf("%s\n", todo);
return;
case AT_SECURITY_DESCRIPTOR:
// TODO
printf("%s\n", todo);
return;
case AT_VOLUME_NAME:
printf("Volume name length = %u\n", (unsigned int)val_len);
if (val_len) {
buf = calloc(1, val_len);
if (!buf)
err_exit("Failed to allocate internal buffer: "
"%s\n", strerror(errno));
i = ucstos(buf, (ntfschar*)val, val_len);
if (i == -1)
printf("Volume name contains non-displayable "
"Unicode characters.\n");
printf("Volume name = %s\n", buf);
free(buf);
}
return;
case AT_VOLUME_INFORMATION:
#define VOL_INF(x) ((VOLUME_INFORMATION *)(x))
printf("NTFS version %i.%i\n", VOL_INF(val)->major_ver,
VOL_INF(val)->minor_ver);
i = VOL_INF(val)->flags;
#undef VOL_INF
printf("Volume flags = 0x%x: ", i);
if (!i) {
printf("NONE\n");
return;
}
j = 0;
if (i & VOLUME_MODIFIED_BY_CHKDSK) {
j = 1;
printf("VOLUME_MODIFIED_BY_CHKDSK");
}
if (i & VOLUME_REPAIR_OBJECT_ID) {
if (j)
printf(" | ");
else
j = 0;
printf("VOLUME_REPAIR_OBJECT_ID");
}
if (i & VOLUME_DELETE_USN_UNDERWAY) {
if (j)
printf(" | ");
else
j = 0;
printf("VOLUME_DELETE_USN_UNDERWAY");
}
if (i & VOLUME_MOUNTED_ON_NT4) {
if (j)
printf(" | ");
else
j = 0;
printf("VOLUME_MOUNTED_ON_NT4");
}
if (i & VOLUME_UPGRADE_ON_MOUNT) {
if (j)
printf(" | ");
else
j = 0;
printf("VOLUME_UPGRADE_ON_MOUNT");
}
if (i & VOLUME_RESIZE_LOG_FILE) {
if (j)
printf(" | ");
else
j = 0;
printf("VOLUME_RESIZE_LOG_FILE");
}
if (i & VOLUME_IS_DIRTY) {
if (j)
printf(" | ");
else
j = 0;
printf("VOLUME_IS_DIRTY");
}
printf("\n");
return;
case AT_DATA:
printf(skip, "DATA");
return;
case AT_INDEX_ROOT:
// TODO
printf("%s\n", todo);
return;
case AT_INDEX_ALLOCATION:
// TODO
printf("%s\n", todo);
return;
case AT_BITMAP:
printf(skip, "BITMAP");
return;
case AT_REPARSE_POINT:
// TODO
printf("%s\n", todo);
return;
case AT_EA_INFORMATION:
// TODO
printf("%s\n", don_t_know);
return;
case AT_EA:
// TODO
printf("%s\n", don_t_know);
return;
case AT_LOGGED_UTILITY_STREAM:
// TODO
printf("%s\n", don_t_know);
return;
default:
u = le32_to_cpu(type);
printf("Cannot display unknown %s defined attribute type 0x%x"
".\n", u >=
le32_to_cpu(AT_FIRST_USER_DEFINED_ATTRIBUTE) ?
"user" : "system", (unsigned int)u);
}
}
/**
* dump_resident_attr
*/
static void dump_resident_attr(ATTR_RECORD *a)
{
int i;
i = le32_to_cpu(a->value_length);
printf("Attribute value length = %u (0x%x)\n", i, i);
i = le16_to_cpu(a->value_offset);
printf("Attribute value offset = %u (0x%x)\n", i, i);
i = a->resident_flags;
printf("Resident flags = 0x%x: ", i);
if (!i)
printf("NONE\n");
else if (i & ~RESIDENT_ATTR_IS_INDEXED)
printf("UNKNOWN FLAG(S)\n");
else
printf("RESIDENT_ATTR_IS_INDEXED\n");
dump_resident_attr_val(a->type, (char*)a + le16_to_cpu(a->value_offset),
le32_to_cpu(a->value_length));
}
/**
* dump_mapping_pairs_array
*/
static void dump_mapping_pairs_array(char *b __attribute__((unused)),
unsigned int max_len __attribute__((unused)))
{
// TODO
return;
}
/**
* dump_non_resident_attr
*/
static void dump_non_resident_attr(ATTR_RECORD *a)
{
s64 l;
int i;
l = sle64_to_cpu(a->lowest_vcn);
printf("Lowest VCN = %lli (0x%llx)\n", (long long)l,
(unsigned long long)l);
l = sle64_to_cpu(a->highest_vcn);
printf("Highest VCN = %lli (0x%llx)\n", (long long)l,
(unsigned long long)l);
printf("Mapping pairs array offset = 0x%x\n",
le16_to_cpu(a->mapping_pairs_offset));
printf("Compression unit = 0x%x: %sCOMPRESSED\n", a->compression_unit,
a->compression_unit ? "" : "NOT ");
if (sle64_to_cpu(a->lowest_vcn))
printf("Attribute is not the first extent. The following "
"sizes are meaningless:\n");
l = sle64_to_cpu(a->allocated_size);
printf("Allocated size = %lli (0x%llx)\n", (long long)l,
(unsigned long long)l);
l = sle64_to_cpu(a->data_size);
printf("Data size = %lli (0x%llx)\n", (long long)l,
(unsigned long long)l);
l = sle64_to_cpu(a->initialized_size);
printf("Initialized size = %lli (0x%llx)\n", (long long)l,
(unsigned long long)l);
if (a->flags & ATTR_COMPRESSION_MASK) {
l = sle64_to_cpu(a->compressed_size);
printf("Compressed size = %lli (0x%llx)\n", (long long)l,
(unsigned long long)l);
}
i = le16_to_cpu(a->mapping_pairs_offset);
dump_mapping_pairs_array((char*)a + i, le32_to_cpu(a->length) - i);
}
/**
* dump_attr_record
*/
static void dump_attr_record(MFT_RECORD *m, ATTR_RECORD *a)
{
unsigned int u;
char s[0x200];
int i;
printf("-- Beginning dump of attribute record at offset 0x%x. --\n",
(unsigned)((u8*)a - (u8*)m));
if (a->type == AT_END) {
printf("Attribute type = 0x%x ($END)\n",
(unsigned int)le32_to_cpu(AT_END));
u = le32_to_cpu(a->length);
printf("Length of resident part = %u (0x%x)\n", u, u);
return;
}
u = le32_to_cpu(a->type);
for (i = 0; attr_defs[i].type; i++)
if (le32_to_cpu(attr_defs[i].type) >= u)
break;
if (attr_defs[i].type) {
// printf("type = 0x%x\n", le32_to_cpu(attr_defs[i].type));
// { char *p = (char*)attr_defs[i].name;
// printf("name = %c%c%c%c%c\n", *p, p[1], p[2], p[3], p[4]);
// }
if (ucstos(s, attr_defs[i].name, sizeof(s)) == -1) {
ntfs_log_error("Could not convert Unicode string to single "
"byte string in current locale.\n");
strncpy(s, "Error converting Unicode string",
sizeof(s));
}
} else
strncpy(s, "UNKNOWN_TYPE", sizeof(s));
printf("Attribute type = 0x%x (%s)\n", u, s);
u = le32_to_cpu(a->length);
printf("Length of resident part = %u (0x%x)\n", u, u);
printf("Attribute is %sresident\n", a->non_resident ? "non-" : "");
printf("Name length = %u unicode characters\n", a->name_length);
printf("Name offset = %u (0x%x)\n", cpu_to_le16(a->name_offset),
cpu_to_le16(a->name_offset));
u = a->flags;
if (a->name_length) {
if (ucstos(s, (ntfschar*)((char*)a +
cpu_to_le16(a->name_offset)),
min((int)sizeof(s),
a->name_length + 1)) == -1) {
ntfs_log_error("Could not convert Unicode string to single "
"byte string in current locale.\n");
strncpy(s, "Error converting Unicode string",
sizeof(s));
}
printf("Name = %s\n", s);
}
printf("Attribute flags = 0x%x: ", le16_to_cpu(u));
if (!u)
printf("NONE");
else {
int first = TRUE;
if (u & ATTR_COMPRESSION_MASK) {
if (u & ATTR_IS_COMPRESSED) {
printf("ATTR_IS_COMPRESSED");
first = FALSE;
}
if ((u & ATTR_COMPRESSION_MASK) & ~ATTR_IS_COMPRESSED) {
if (!first)
printf(" | ");
else
first = FALSE;
printf("ATTR_UNKNOWN_COMPRESSION");
}
}
if (u & ATTR_IS_ENCRYPTED) {
if (!first)
printf(" | ");
else
first = FALSE;
printf("ATTR_IS_ENCRYPTED");
}
if (u & ATTR_IS_SPARSE) {
if (!first)
printf(" | ");
else
first = FALSE;
printf("ATTR_IS_SPARSE");
}
}
printf("\n");
printf("Attribute instance = %u\n", le16_to_cpu(a->instance));
if (a->non_resident) {
dump_non_resident_attr(a);
} else {
dump_resident_attr(a);
}
}
/**
* dump_mft_record
*/
static void dump_mft_record(MFT_RECORD *m)
{
ATTR_RECORD *a;
unsigned int u;
MFT_REF r;
printf("-- Beginning dump of mft record. --\n");
u = le32_to_cpu(m->magic);
printf("Mft record signature (magic) = %c%c%c%c\n", u & 0xff,
u >> 8 & 0xff, u >> 16 & 0xff, u >> 24 & 0xff);
u = le16_to_cpu(m->usa_ofs);
printf("Update sequence array offset = %u (0x%x)\n", u, u);
printf("Update sequence array size = %u\n", le16_to_cpu(m->usa_count));
printf("$LogFile sequence number (lsn) = %llu\n",
(unsigned long long)le64_to_cpu(m->lsn));
printf("Sequence number = %u\n", le16_to_cpu(m->sequence_number));
printf("Reference (hard link) count = %u\n",
le16_to_cpu(m->link_count));
u = le16_to_cpu(m->attrs_offset);
printf("First attribute offset = %u (0x%x)\n", u, u);
printf("Flags = %u: ", le16_to_cpu(m->flags));
if (m->flags & MFT_RECORD_IN_USE)
printf("MFT_RECORD_IN_USE");
else
printf("MFT_RECORD_NOT_IN_USE");
if (m->flags & MFT_RECORD_IS_DIRECTORY)
printf(" | MFT_RECORD_IS_DIRECTORY");
printf("\n");
u = le32_to_cpu(m->bytes_in_use);
printf("Bytes in use = %u (0x%x)\n", u, u);
u = le32_to_cpu(m->bytes_allocated);
printf("Bytes allocated = %u (0x%x)\n", u, u);
r = le64_to_cpu(m->base_mft_record);
printf("Base mft record reference:\n\tMft record number = %llu\n\t"
"Sequence number = %u\n",
(unsigned long long)MREF(r), MSEQNO(r));
printf("Next attribute instance = %u\n",
le16_to_cpu(m->next_attr_instance));
a = (ATTR_RECORD*)((char*)m + le16_to_cpu(m->attrs_offset));
printf("-- Beginning dump of attributes within mft record. --\n");
while ((char*)a < (char*)m + le32_to_cpu(m->bytes_in_use)) {
if (a->type == cpu_to_le32(attr_type))
dump_attr_record(m, a);
if (a->type == AT_END)
break;
a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
};
printf("-- End of attributes. --\n");
}
/**
* ntfstruncate_exit
*/
static void ntfstruncate_exit(void)
{
int err;
if (success)
return;
/* Close the attribute. */
if (na)
ntfs_attr_close(na);
/* Close the inode. */
if (ni && ntfs_inode_close(ni)) {
ntfs_log_perror("Warning: Failed to close inode %lli",
(long long)inode);
}
/* Unmount the volume. */
err = ntfs_umount(vol, 0);
if (err == -1)
ntfs_log_perror("Warning: Could not umount %s", dev_name);
/* Free the attribute name if it exists. */
ntfs_ucsfree(attr_name);
}
/**
* main
*/
int main(int argc, char **argv)
{
unsigned long mnt_flags, ul;
int err;
ntfs_log_set_handler(ntfs_log_handler_outerr);
/* Initialize opts to zero / required values. */
memset(&opts, 0, sizeof(opts));
/*
* Setup a default $AttrDef. FIXME: Should be reading this from the
* volume itself, at ntfs_mount() time.
*/
attr_defs = (ATTR_DEF*)&attrdef_ntfs12_array;
/* Parse command line options. */
parse_options(argc, argv);
utils_set_locale();
/* Make sure the file system is not mounted. */
if (ntfs_check_if_mounted(dev_name, &mnt_flags))
ntfs_log_perror("Failed to determine whether %s is mounted",
dev_name);
else if (mnt_flags & NTFS_MF_MOUNTED) {
ntfs_log_error("%s is mounted.\n", dev_name);
if (!opts.force)
err_exit("Refusing to run!\n");
fprintf(stderr, "ntfstruncate forced anyway. Hope /etc/mtab "
"is incorrect.\n");
}
/* Mount the device. */
if (opts.no_action) {
ntfs_log_quiet("Running in READ-ONLY mode!\n");
ul = MS_RDONLY;
} else
ul = 0;
vol = ntfs_mount(dev_name, ul);
if (!vol)
err_exit("Failed to mount %s: %s\n", dev_name, strerror(errno));
/* Register our exit function which will unlock and close the device. */
err = atexit(&ntfstruncate_exit);
if (err == -1) {
ntfs_log_error("Could not set up exit() function because atexit() "
"failed: %s Aborting...\n", strerror(errno));
ntfstruncate_exit();
exit(1);
}
/* Open the specified inode. */
ni = ntfs_inode_open(vol, inode);
if (!ni)
err_exit("Failed to open inode %lli: %s\n", (long long)inode,
strerror(errno));
/* Open the specified attribute. */
na = ntfs_attr_open(ni, attr_type, attr_name, attr_name_len);
if (!na)
err_exit("Failed to open attribute 0x%x: %s\n",
(unsigned int)attr_type, strerror(errno));
if (!opts.quiet && opts.verbose > 1) {
ntfs_log_verbose("Dumping mft record before calling "
"ntfs_attr_truncate():\n");
dump_mft_record(ni->mrec);
}
/* Truncate the attribute. */
err = ntfs_attr_truncate(na, new_len);
if (err)
err_exit("Failed to truncate attribute 0x%x: %s\n",
(unsigned int)attr_type, strerror(errno));
if (!opts.quiet && opts.verbose > 1) {
ntfs_log_verbose("Dumping mft record after calling "
"ntfs_attr_truncate():\n");
dump_mft_record(ni->mrec);
}
/* Close the attribute. */
ntfs_attr_close(na);
na = NULL;
/* Close the inode. */
err = ntfs_inode_close(ni);
if (err)
err_exit("Failed to close inode %lli: %s\n", (long long)inode,
strerror(errno));
/* Unmount the volume. */
err = ntfs_umount(vol, 0);
if (err == -1)
ntfs_log_perror("Warning: Failed to umount %s", dev_name);
/* Free the attribute name if it exists. */
ntfs_ucsfree(attr_name);
/* Finally, disable our ntfstruncate_exit() handler. */
success = TRUE;
ntfs_log_quiet("ntfstruncate completed successfully. Have a nice day.\n");
return 0;
}

329
ntfsprogs/ntfsundelete.8.in Normal file
View File

@ -0,0 +1,329 @@
.\" Copyright (c) 2002\-2005 Richard Russon.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH NTFSUNDELETE 8 "November 2005" "ntfsprogs @VERSION@"
.SH NAME
ntfsundelete \- recover a deleted file from an NTFS volume.
.SH SYNOPSIS
.B ntfsundelete
[\fIoptions\fR] \fIdevice\fR
.SH DESCRIPTION
.B ntfsundelete
has three modes of operation:
.IR scan ,
.I undelete
and
.IR copy .
.SS Scan
.PP
The default mode,
.I scan
simply reads an NTFS Volume and looks for files that have been deleted. Then it
will print a list giving the inode number, name and size.
.SS Undelete
.PP
The
.I undelete
mode takes the files either matching the regular expression (option \-m)
or specified by the inode\-expressions and recovers as much of the data
as possible. It saves the result to another location. Partly for
safety, but mostly because NTFS write support isn't finished.
.SS Copy
.PP
This is a wizard's option. It will save a portion of the MFT to a file. This
probably only be useful when debugging
.I ntfsundelete
.SS Notes
.B ntfsundelete
only ever
.B reads
from the NTFS Volume.
.B ntfsundelete
will never change the volume.
.SH CAVEATS
.SS Miracles
.B ntfsundelete
cannot perform the impossible.
.PP
When a file is deleted the MFT Record is marked as not in use and the bitmap
representing the disk usage is updated. If the power isn't turned off
immediately, the free space, where the file used to live, may become
overwritten. Worse, the MFT Record may be reused for another file. If this
happens it is impossible to tell where the file was on disk.
.PP
Even if all the clusters of a file are not in use, there is no guarantee that
they haven't been overwritten by some short\-lived file.
.SS Locale
In NTFS all the filenames are stored as Unicode. They will be converted into
the current locale for display by
.BR ntfsundelete .
The utility has successfully displayed some Chinese pictogram filenames and then
correctly recovered them.
.SS Extended MFT Records
In rare circumstances, a single MFT Record will not be large enough to hold the
metadata describing a file (a file would have to be in hundreds of fragments
for this to happen). In these cases one MFT record may hold the filename, but
another will hold the information about the data.
.B ntfsundelete
will not try and piece together such records. It will simply show unnamed files
with data.
.SS Compressed and Encrypted Files
.B ntfsundelete
cannot recover compressed or encrypted files. When scanning for them, it will
display as being 0% recoverable.
.SS The Recovered File's Size and Date
To recover a file
.B ntfsundelete
has to read the file's metadata. Unfortunately, this isn't always intact.
When a file is deleted, the metadata can be left in an inconsistent state. e.g.
the file size may be zero; the dates of the file may be set to the time it was
deleted, or random.
.br
To be safe
.B ntfsundelete
will pick the largest file size it finds and write that to disk. It will also
try and set the file's date to the last modified date. This date may be the
correct last modified date, or something unexpected.
.SH OPTIONS
Below is a summary of all the options that
.B ntfsundelete
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.TP
\fB\-b\fR, \fB\-\-byte\fR NUM
If any clusters of the file cannot be recovered, the missing parts will be
filled with this byte. The default is zeros.
.TP
\fB\-C\fR, \fB\-\-case\fR
When scanning an NTFS volume, any filename matching (using the
.B \-\-match
option) is case\-insensitive. This option makes the matching case\-sensitive.
.TP
\fB\-c\fR, \fB\-\-copy\fR RANGE
This wizard's option will write a block of MFT FILE records to a file. The
default file is
.I mft
which will be created in the current directory. This option can be combined
with the
.B \-\-output
and
.B \-\-destination
options.
.TP
\fB\-d\fR, \fB\-\-destination\fR DIR
This option controls where to put the output file of the
.B \-\-undelete
and
.B \-\-copy
options.
.TP
\fB\-f\fR, \fB\-\-force\fR
This will override some sensible defaults, such as not overwriting an existing
file. Use this option with caution.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.TP
\fB\-i\fR, \fB\-\-inodes\fR RANGE
Recover the files with these inode numbers.
.I RANGE
can be a single inode number, several numbers separated by commas "," or a
range separated by a dash "\-".
.TP
\fB\-m\fR, \fB\-\-match\fR PATTERN
Filter the output by only looking for matching filenames. The pattern can
include the wildcards '?', match exactly one character or '*', match zero or
more characters. By default the matching is case\-insensitive. To make the
search case sensitive, use the
.B \-\-case
option.
.TP
\fB\-O\fR, \fB\-\-optimistic\fR
Recover parts of the file even if they are currently marked as in use.
.TP
\fB\-o\fR, \fB\-\-output\fR FILE
Use this option to set name of output file that
.B \-\-undelete
or
.B \-\-copy
will create.
.TP
\fB\-P\fR, \fB\-\-parent\fR
Display the parent directory of a deleted file.
.TP
\fB\-p\fR, \fB\-\-percentage\fR NUM
Filter the output of the
.B \-\-scan
option, by only matching files with a certain amount of recoverable content.
.B Please read the caveats section for more details.
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Reduce the amount of output to a minimum. Naturally, it doesn't make sense to
combine this option with
.BR \-\-scan .
.TP
\fB\-s\fR, \fB\-\-scan\fR
Search through an NTFS volume and print a list of files that could be recovered.
This is the default action of
.BR ntfsundelete .
This list can be filtered by filename, size, percentage recoverable or last
modification time, using the
.BR \-\-match ,
.BR \-\-size ,
.B \-\-percent
and
.B \-\-time
options, respectively.
.sp
The output of scan will be:
.sp
.nf
Inode Flags %age Date Size Filename
6038 FN.. 93% 2002\-07\-17 26629 thesis.doc
.fi
.TS
box;
lB lB
l l.
Flag Description
F/D File/Directory
N/R (Non\-)Resident data stream
C/E Compressed/Encrypted data stream
! Missing attributes
.TE
.sp
.sp
The percentage field shows how much of the file can potentially be recovered.
.TP
\fB\-S\fR, \fB\-\-size\fR RANGE
Filter the output of the
.B \-\-scan
option, by looking for a particular range of file sizes. The range may be
specified as two numbers separated by a '\-'. The sizes may be abbreviated
using the suffixes k, m, g, t, for kilobytes, megabytes, gigabytes and terabytes
respectively.
.TP
\fB\-t\fR, \fB\-\-time\fR SINCE
Filter the output of the
.B \-\-scan
option. Only match files that have been altered since this time. The time must
be given as number using a suffix of d, w, m, y for days, weeks, months or years
ago.
.TP
\fB\-T\fR, \fB\-\-truncate\fR
If
.B ntfsundelete
is confident about the size of a deleted file, then it will restore the file to
exactly that size. The default behaviour is to round up the size to the nearest
cluster (which will be a multiple of 512 bytes).
.TP
\fB\-u\fR, \fB\-\-undelete\fR
Select
.B undelete
mode. You can specify the files to be recovered using by using
.B \-\-match
or
.B \-\-inodes
options. This option can be combined with
.BR \-\-output ,
.BR \-\-destination ,
and
.BR \-\-byte .
.sp
When the file is recovered it will be given its original name, unless the
.B \-\-output
option is used.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Increase the amount of output that
.B ntfsundelete
prints.
.TP
\fB\-V\fR, \fB\-\-version\fR
Show the version number, copyright and license for
.BR ntfsundelete .
.SH EXAMPLES
Look for deleted files on /dev/hda1.
.RS
.sp
.B ntfsundelete /dev/hda1
.sp
.RE
Look for deleted documents on /dev/hda1.
.RS
.sp
.B ntfsundelete /dev/hda1 \-s \-m '*.doc'
.sp
.RE
Look for deleted files between 5000 and 6000000 bytes, with at least 90% of the
data recoverable, on /dev/hda1.
.RS
.sp
.B ntfsundelete /dev/hda1 \-S 5k\-6m \-p 90
.sp
.RE
Look for deleted files altered in the last two days
.RS
.sp
.B ntfsundelete /dev/hda1 \-t 2d
.sp
.RE
Undelete inodes 2, 5 and 100 to 131 of device /dev/sda1
.RS
.sp
.B ntfsundelete /dev/sda1 \-u \-i 2,5,100\-131
.sp
.RE
Undelete inode number 3689, call the file 'work.doc' and put it in the user's
home directory.
.RS
.sp
.B ntfsundelete /dev/hda1 \-u \-i 3689 \-o work.doc \-d ~
.sp
.RE
Save MFT Records 3689 to 3690 to a file 'debug'
.RS
.sp
.B ntfsundelete /dev/hda1 \-c 3689\-3690 \-o debug
.sp
.RE
.SH BUGS
There are some small limitations to
.BR ntfsundelete ,
but currently no known bugs. If you find a bug please send an email describing
the problem to the development team:
.br
.nh
linux\-ntfs\-dev@lists.sourceforge.net
.hy
.SH AUTHORS
.B ntfsundelete
was written by Richard Russon and Holger Ohmacht, with contributions from Anton
Altaparmakov.
.SH AVAILABILITY
.B ntfsundelete
is part of the
.B ntfsprogs
package and is available from:
.br
.nh
http://www.linux\-ntfs.org/content/view/19/37
.hy
.sp
The manual pages are available online at:
.br
.nh
http://man.linux-ntfs.org/
.hy
.SH SEE ALSO
.BR ntfsinfo (8),
.BR ntfsprogs (8)

2165
ntfsprogs/ntfsundelete.c Normal file

File diff suppressed because it is too large Load Diff

115
ntfsprogs/ntfsundelete.h Normal file
View File

@ -0,0 +1,115 @@
/*
* ntfsundelete - Part of the Linux-NTFS project.
*
* Copyright (c) 2002 Richard Russon
*
* This utility will recover deleted files from an NTFS volume.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFSUNDELETE_H_
#define _NTFSUNDELETE_H_
#include <ntfs-3g/types.h>
#include <ntfs-3g/runlist.h>
#include "list.h"
enum optmode {
MODE_NONE = 0,
MODE_SCAN,
MODE_UNDELETE,
MODE_COPY,
MODE_ERROR
};
struct options {
char *device; /* Device/File to work with */
enum optmode mode; /* Scan / Undelete / Copy */
int percent; /* Minimum recoverability */
int uinode; /* Undelete this inode */
char *dest; /* Save file to this directory */
char *output; /* With this filename */
char *match; /* Pattern for filename matching */
int match_case; /* Case sensitive matching */
int truncate; /* Truncate files to exact size. */
int quiet; /* Less output */
int verbose; /* Extra output */
int force; /* Override common sense */
int optimistic; /* Undelete in-use clusters as well */
int parent; /* Show parent directory */
time_t since; /* Since this time */
s64 size_begin; /* Range for file size */
s64 size_end;
s64 mft_begin; /* Range for mft copy */
s64 mft_end;
char fillbyte; /* Use for unrecoverable sections */
char padding[7]; /* Unused: padding to 64 bit. */
};
struct filename {
struct list_head list; /* Previous/Next links */
ntfschar *uname; /* Filename in unicode */
int uname_len; /* and its length */
long long size_alloc; /* Allocated size (multiple of cluster size) */
long long size_data; /* Actual size of data */
FILE_ATTR_FLAGS flags;
time_t date_c; /* Time created */
time_t date_a; /* altered */
time_t date_m; /* mft record changed */
time_t date_r; /* read */
char *name; /* Filename in current locale */
FILE_NAME_TYPE_FLAGS name_space;
long long parent_mref;
char *parent_name;
char padding[7]; /* Unused: padding to 64 bit. */
};
struct data {
struct list_head list; /* Previous/Next links */
char *name; /* Stream name in current locale */
ntfschar *uname; /* Unicode stream name */
int uname_len; /* and its length */
int resident; /* Stream is resident */
int compressed; /* Stream is compressed */
int encrypted; /* Stream is encrypted */
long long size_alloc; /* Allocated size (multiple of cluster size) */
long long size_data; /* Actual size of data */
long long size_init; /* Initialised size, may be less than data size */
long long size_vcn; /* Highest VCN in the data runs */
runlist_element *runlist; /* Decoded data runs */
int percent; /* Amount potentially recoverable */
void *data; /* If resident, a pointer to the data */
char padding[4]; /* Unused: padding to 64 bit. */
};
struct ufile {
long long inode; /* MFT record number */
time_t date; /* Last modification date/time */
struct list_head name; /* A list of filenames */
struct list_head data; /* A list of data streams */
char *pref_name; /* Preferred filename */
char *pref_pname; /* parent filename */
long long max_size; /* Largest size we find */
int attr_list; /* MFT record may be one of many */
int directory; /* MFT record represents a directory */
MFT_RECORD *mft; /* Raw MFT record */
char padding[4]; /* Unused: padding to 64 bit. */
};
#endif /* _NTFSUNDELETE_H_ */

1436
ntfsprogs/ntfswipe.c Normal file

File diff suppressed because it is too large Load Diff

53
ntfsprogs/ntfswipe.h Normal file
View File

@ -0,0 +1,53 @@
/*
* ntfswipe - Part of the Linux-NTFS project.
*
* Copyright (c) 2002 Richard Russon
*
* This utility will overwrite unused space on an NTFS volume.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFSWIPE_H_
#define _NTFSWIPE_H_
#include <ntfs-3g/types.h>
enum action {
act_info,
act_test,
act_wipe,
};
struct options {
char *device; /* Device/File to work with */
int info; /* Show volume info */
int force; /* Override common sense */
int quiet; /* Less output */
int verbose; /* Extra output */
int noaction; /* Do not write to disk */
int count; /* Number of iterations */
int *bytes; /* List of overwrite characters */
int directory; /* Wipe directory indexes */
int logfile; /* Wipe the logfile (journal) */
int mft; /* Wipe mft slack space */
int pagefile; /* Wipe pagefile (swap space) */
int tails; /* Wipe file tails */
int unused; /* Wipe unused clusters */
};
#endif /* _NTFSWIPE_H_ */

1027
ntfsprogs/sd.c Normal file

File diff suppressed because it is too large Load Diff

12
ntfsprogs/sd.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _NTFS_SD_H_
#define _NTFS_SD_H_
#include <ntfs-3g/types.h>
void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len);
void init_root_sd_31(u8 **sd_val, int *sd_val_len);
void init_secure_30(char *sd_val);
void init_secure_31(char *sd_val);
#endif /* _NTFS_SD_H_ */

90
ntfsprogs/upcase.c Normal file
View File

@ -0,0 +1,90 @@
/**
* upcase - Part of the Linux-NTFS project.
*
* Copyright (c) 2001 Richard Russon
* Copyright (c) 2001-2006 Anton Altaparmakov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS source
* in the file COPYING); if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <ntfs-3g/endians.h>
#include <ntfs-3g/types.h>
#include "upcase.h"
/**
* init_upcase_table
*/
void init_upcase_table(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(uc, 0, uc_len);
uc_len >>= 1;
/* Generate the little endian Unicode upcase table used by ntfs. */
for (i = 0; (u32)i < uc_len; i++)
uc[i] = cpu_to_le16(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] = cpu_to_le16(le16_to_cpu(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] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1);
for (r = 0; uc_byte_table[r][0]; r++)
uc[uc_byte_table[r][0]] = cpu_to_le16(uc_byte_table[r][1]);
}

7
ntfsprogs/upcase.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _NTFS_UPCASE_H_
#define _NTFS_UPCASE_H_
void init_upcase_table(ntfschar *uc, u32 uc_len);
#endif /* _NTFS_UPCASE_H_ */

1016
ntfsprogs/utils.c Normal file

File diff suppressed because it is too large Load Diff

157
ntfsprogs/utils.h Normal file
View File

@ -0,0 +1,157 @@
/*
* utils.h - Part of 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_UTILS_H_
#define _NTFS_UTILS_H_
#include "config.h"
#include <ntfs-3g/types.h>
#include <ntfs-3g/layout.h>
#include <ntfs-3g/volume.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
extern const char *ntfs_bugs;
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);
#ifndef _NTFS_RICH_H_
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);
#endif
#if !(defined(_NTFS_VOLUME_H) && defined(NTFS_RICH))
int utils_valid_device(const char *name, int force);
ntfs_volume * utils_mount_volume(const char *device, unsigned long flags, BOOL force);
#endif
/**
* 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)
/* MAX_PATH definition was missing in ntfs-3g's headers. */
#ifndef MAX_PATH
#define MAX_PATH 1024
#endif
/**
* linux-ntfs's ntfs_mbstoucs has different semantics, so we emulate it with
* ntfs-3g's.
*/
static __inline__ int ntfs_mbstoucs_libntfscompat(const char *ins,
ntfschar **outs, int outs_len)
{
if(!outs) {
errno = EINVAL;
return -1;
}
else if(*outs != NULL) {
/* Note: libntfs's mbstoucs implementation allows the caller to
* specify a preallocated buffer while libntfs-3g's always
* allocates the output buffer.
*/
ntfschar *tmpstr = NULL;
int tmpstr_len;
tmpstr_len = ntfs_mbstoucs(ins, &tmpstr);
if(tmpstr_len >= 0) {
if((tmpstr_len + 1) > outs_len) {
/* Doing a realloc instead of reusing tmpstr
* because it emulates libntfs's mbstoucs more
* closely. */
ntfschar *re_outs = realloc(*outs,
sizeof(ntfschar)*(tmpstr_len + 1));
if(!re_outs)
tmpstr_len = -1;
else
*outs = re_outs;
}
if(tmpstr_len >= 0) {
/* The extra character is the \0 terminator. */
memcpy(*outs, tmpstr,
sizeof(ntfschar)*(tmpstr_len + 1));
}
free(tmpstr);
}
return tmpstr_len;
}
else
return ntfs_mbstoucs(ins, outs);
}
#endif /* _NTFS_UTILS_H_ */

5
test/.cvsignore Normal file
View File

@ -0,0 +1,5 @@
.deps
.libs
Makefile
Makefile.in
runlist

59
test/Makefile.am Normal file
View File

@ -0,0 +1,59 @@
if REALLYSTATIC
AM_LIBS = $(top_builddir)/libntfs/.libs/libntfs.a
AM_LFLAGS = -static
STATIC_LINK = $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
else
AM_LIBS = $(top_builddir)/libntfs/libntfs.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)
#TEST_VALGRIND = valgrind
bin_PROGRAMS = runlist
EXTRA_DIST = runlist-data
CLEANFILES = attr[123].bin frag[123][123][123] pure-[cn][ms] zero
MAINTAINERCLEANFILES = Makefile.in
linux_ntfsincludedir = -I$(top_srcdir)/include/ntfs
# Set the include path.
AM_CPPFLAGS = -I$(top_srcdir)/include/ntfs $(all_includes)
runlist_SOURCES = runlist.c
runlist_LDADD = $(AM_LIBS)
runlist_LDFLAGS = $(AM_LFLAGS)
# Extra targets
libs:
(cd ../libntfs && $(MAKE) libs) || exit 1;
test: runlist testz testp testf
testz: runlist
@$(TEST_VALGRIND) ./runlist zero > zero
@diff -qs {runlist-data/,}zero
testp: runlist
@for i in contig noncontig; do \
for j in single multi; do \
L1=`echo $$i | cut -b1`; \
L2=`echo $$j | cut -b1`; \
FILE=pure-$$L1$$L2; \
$(TEST_VALGRIND) ./runlist pure $$i $$j > $$FILE; \
diff -qs {runlist-data/,}$$FILE; \
done; \
done
testf: runlist
@for i in 123 132 213 231 312 321; do \
$(TEST_VALGRIND) ./runlist frag $$i > frag$$i; \
diff -qs {runlist-data/,}frag$$i; \
done

BIN
test/runlist-data/attr1.bin Normal file

Binary file not shown.

BIN
test/runlist-data/attr2.bin Normal file

Binary file not shown.

BIN
test/runlist-data/attr3.bin Normal file

Binary file not shown.

2213
test/runlist-data/frag123 Normal file

File diff suppressed because it is too large Load Diff

2061
test/runlist-data/frag132 Normal file

File diff suppressed because it is too large Load Diff

2213
test/runlist-data/frag213 Normal file

File diff suppressed because it is too large Load Diff

2133
test/runlist-data/frag231 Normal file

File diff suppressed because it is too large Load Diff

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