mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 10:04:00 +08:00
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:
commit
02bab2956c
24
.cvsignore
Normal file
24
.cvsignore
Normal 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
20
CREDITS
@ -38,4 +38,24 @@ Ismail Donmez
|
|||||||
Laszlo Dvornik
|
Laszlo Dvornik
|
||||||
Pallaghy Ajtony
|
Pallaghy Ajtony
|
||||||
Szabolcs Szakacsits
|
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
|
||||||
|
|
||||||
|
13
Makefile.am
13
Makefile.am
@ -24,9 +24,20 @@ MAINTAINERCLEANFILES=\
|
|||||||
$(srcdir)/m4/lt~obsolete.m4 \
|
$(srcdir)/m4/lt~obsolete.m4 \
|
||||||
$(srcdir)/m4/ltoptions.m4
|
$(srcdir)/m4/ltoptions.m4
|
||||||
|
|
||||||
SUBDIRS = include libfuse-lite libntfs-3g src
|
SUBDIRS = doc include libfuse-lite libntfs-3g ntfsprogs src
|
||||||
|
|
||||||
doc_DATA = README
|
doc_DATA = README
|
||||||
|
|
||||||
dist-hook:
|
dist-hook:
|
||||||
$(MKDIR_P) "$(distdir)/m4"
|
$(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
37
README
@ -66,3 +66,40 @@ line at the END(!) of the /etc/fstab file:
|
|||||||
|
|
||||||
/dev/sda1 /mnt/windows ntfs-3g defaults 0 0
|
/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
11
TODO.include
Normal 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
65
TODO.libntfs
Normal 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
128
TODO.ntfsprogs
Normal 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
|
64
configure.ac
64
configure.ac
@ -3,6 +3,7 @@
|
|||||||
# compilation.
|
# compilation.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2000-2006 Anton Altaparmakov
|
# Copyright (c) 2000-2006 Anton Altaparmakov
|
||||||
|
# Copyright (c) 2003 Jan Kratochvil
|
||||||
# Copyright (c) 2005-2009 Szabolcs Szakacsits
|
# Copyright (c) 2005-2009 Szabolcs Szakacsits
|
||||||
# Copyright (C) 2007-2008 Alon Bar-Lev
|
# Copyright (C) 2007-2008 Alon Bar-Lev
|
||||||
#
|
#
|
||||||
@ -127,6 +128,12 @@ AC_ARG_ENABLE(
|
|||||||
[enable_device_default_io_ops="yes"]
|
[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(
|
AC_ARG_ENABLE(
|
||||||
[nfconv],
|
[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@:>@])],
|
[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_LIBTOOL]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
AC_PATH_PROG([MV], [mv])
|
AC_PATH_PROG([MV], [mv])
|
||||||
AC_PATH_PROG([RM], [rm])
|
AC_PATH_PROG([RM], [rm])
|
||||||
AC_PATH_PROG([SED], [sed])
|
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,[ ]*$,,'`
|
FUSE_LIB_PATH=`$PKG_CONFIG --libs-only-L fuse | sed -e 's,/[/]*,/,g' -e 's,[ ]*$,,'`
|
||||||
fi
|
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.
|
# Checks for header files.
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
|
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 \
|
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/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 \
|
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.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_HEADER_STDBOOL
|
AC_HEADER_STDBOOL
|
||||||
@ -280,6 +325,7 @@ AC_C_BIGENDIAN(
|
|||||||
]
|
]
|
||||||
,
|
,
|
||||||
)
|
)
|
||||||
|
AC_C_CONST
|
||||||
AC_C_INLINE
|
AC_C_INLINE
|
||||||
AC_TYPE_OFF_T
|
AC_TYPE_OFF_T
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
@ -413,13 +459,29 @@ fi
|
|||||||
# generate files
|
# generate files
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
Makefile
|
Makefile
|
||||||
|
doc/Makefile
|
||||||
include/Makefile
|
include/Makefile
|
||||||
include/fuse-lite/Makefile
|
include/fuse-lite/Makefile
|
||||||
|
include/ntfs/Makefile
|
||||||
include/ntfs-3g/Makefile
|
include/ntfs-3g/Makefile
|
||||||
libfuse-lite/Makefile
|
libfuse-lite/Makefile
|
||||||
libntfs-3g/Makefile
|
libntfs-3g/Makefile
|
||||||
libntfs-3g/libntfs-3g.pc
|
libntfs-3g/libntfs-3g.pc
|
||||||
libntfs-3g/libntfs-3g.script.so
|
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/Makefile
|
||||||
src/ntfs-3g.8
|
src/ntfs-3g.8
|
||||||
src/ntfs-3g.probe.8
|
src/ntfs-3g.probe.8
|
||||||
|
2
doc/.cvsignore
Normal file
2
doc/.cvsignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Makefile
|
||||||
|
Makefile.in
|
24
doc/CodingStyle
Normal file
24
doc/CodingStyle
Normal 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
12
doc/Makefile.am
Normal 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
129
doc/attribute_definitions
Normal 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
111
doc/attributes.txt
Normal 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
153
doc/compression.txt
Normal 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
0
doc/encryption.txt
Normal file
41
doc/system_files.txt
Normal file
41
doc/system_files.txt
Normal 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. */
|
||||||
|
|
33
doc/system_security_descriptors.txt
Normal file
33
doc/system_security_descriptors.txt
Normal 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
47
doc/template.c
Normal 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
26
doc/template.h
Normal 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
31
doc/tunable_settings
Normal 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
27
getgccver
Executable 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
2
include/.cvsignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Makefile
|
||||||
|
Makefile.in
|
@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||||
|
|
||||||
SUBDIRS = ntfs-3g fuse-lite
|
SUBDIRS = ntfs ntfs-3g fuse-lite
|
||||||
|
2
include/ntfs/.cvsignore
Normal file
2
include/ntfs/.cvsignore
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Makefile
|
||||||
|
Makefile.in
|
11
include/ntfs/Makefile.am
Normal file
11
include/ntfs/Makefile.am
Normal 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
|
43
include/ntfs/gnome-vfs-method.h
Normal file
43
include/ntfs/gnome-vfs-method.h
Normal 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 */
|
||||||
|
|
42
include/ntfs/gnome-vfs-module.h
Normal file
42
include/ntfs/gnome-vfs-module.h
Normal 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
192
include/ntfs/list.h
Normal 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
40
include/ntfs/rich.h
Normal 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
82
include/ntfs/tree.h
Normal 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
9
libntfs/.cvsignore
Normal 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
59
libntfs/Makefile.am
Normal 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
888
libntfs/gnome-vfs-method.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
77
libntfs/gnome-vfs-module.c
Normal file
77
libntfs/gnome-vfs-module.c
Normal 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);
|
||||||
|
}
|
||||||
|
|
110
libntfs/libntfs-gnomevfs.8.in
Normal file
110
libntfs/libntfs-gnomevfs.8.in
Normal 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
0
libntfs/libntfs.conf.in
Normal file
215
libntfs/rich.c
Normal file
215
libntfs/rich.c
Normal 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
2366
libntfs/tree.c
Normal file
File diff suppressed because it is too large
Load Diff
206
ntfsprogs.spec.in
Normal file
206
ntfsprogs.spec.in
Normal 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
25
ntfsprogs/.cvsignore
Normal 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
150
ntfsprogs/Makefile.am
Normal 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
322
ntfsprogs/attrdef.c
Normal 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
8
ntfsprogs/attrdef.h
Normal 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
222
ntfsprogs/boot.c
Normal 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
7
ntfsprogs/boot.h
Normal 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
119
ntfsprogs/cluster.c
Normal 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
39
ntfsprogs/cluster.h
Normal 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
300
ntfsprogs/mkntfs.8.in
Normal 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
5203
ntfsprogs/mkntfs.c
Normal file
File diff suppressed because it is too large
Load Diff
137
ntfsprogs/ntfscat.8.in
Normal file
137
ntfsprogs/ntfscat.8.in
Normal 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
428
ntfsprogs/ntfscat.c
Normal 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
45
ntfsprogs/ntfscat.h
Normal 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
366
ntfsprogs/ntfsclone.8.in
Normal 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
1748
ntfsprogs/ntfsclone.c
Normal file
File diff suppressed because it is too large
Load Diff
129
ntfsprogs/ntfscluster.8.in
Normal file
129
ntfsprogs/ntfscluster.8.in
Normal 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
563
ntfsprogs/ntfscluster.c
Normal 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
64
ntfsprogs/ntfscluster.h
Normal 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
82
ntfsprogs/ntfscmp.8.in
Normal 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
872
ntfsprogs/ntfscmp.c
Normal 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
128
ntfsprogs/ntfscp.8.in
Normal 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
480
ntfsprogs/ntfscp.c
Normal 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
1350
ntfsprogs/ntfsdecrypt.c
Normal file
File diff suppressed because it is too large
Load Diff
777
ntfsprogs/ntfsdump_logfile.c
Normal file
777
ntfsprogs/ntfsdump_logfile.c
Normal 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
74
ntfsprogs/ntfsfix.8.in
Normal 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
588
ntfsprogs/ntfsfix.c
Normal 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
94
ntfsprogs/ntfsinfo.8.in
Normal 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
2010
ntfsprogs/ntfsinfo.c
Normal file
File diff suppressed because it is too large
Load Diff
105
ntfsprogs/ntfslabel.8.in
Normal file
105
ntfsprogs/ntfslabel.8.in
Normal 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
410
ntfsprogs/ntfslabel.c
Normal 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
177
ntfsprogs/ntfsls.8.in
Normal 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
717
ntfsprogs/ntfsls.c
Normal 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
369
ntfsprogs/ntfsmftalloc.c
Normal 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
909
ntfsprogs/ntfsmove.c
Normal 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
47
ntfsprogs/ntfsmove.h
Normal 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
72
ntfsprogs/ntfsprogs.8.in
Normal 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
286
ntfsprogs/ntfsresize.8.in
Normal 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
2502
ntfsprogs/ntfsresize.c
Normal file
File diff suppressed because it is too large
Load Diff
1070
ntfsprogs/ntfsrm.c
Normal file
1070
ntfsprogs/ntfsrm.c
Normal file
File diff suppressed because it is too large
Load Diff
63
ntfsprogs/ntfsrm.h
Normal file
63
ntfsprogs/ntfsrm.h
Normal 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
811
ntfsprogs/ntfstruncate.c
Normal 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
329
ntfsprogs/ntfsundelete.8.in
Normal 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
2165
ntfsprogs/ntfsundelete.c
Normal file
File diff suppressed because it is too large
Load Diff
115
ntfsprogs/ntfsundelete.h
Normal file
115
ntfsprogs/ntfsundelete.h
Normal 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
1436
ntfsprogs/ntfswipe.c
Normal file
File diff suppressed because it is too large
Load Diff
53
ntfsprogs/ntfswipe.h
Normal file
53
ntfsprogs/ntfswipe.h
Normal 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
1027
ntfsprogs/sd.c
Normal file
File diff suppressed because it is too large
Load Diff
12
ntfsprogs/sd.h
Normal file
12
ntfsprogs/sd.h
Normal 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
90
ntfsprogs/upcase.c
Normal 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
7
ntfsprogs/upcase.h
Normal 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
1016
ntfsprogs/utils.c
Normal file
File diff suppressed because it is too large
Load Diff
157
ntfsprogs/utils.h
Normal file
157
ntfsprogs/utils.h
Normal 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
5
test/.cvsignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.deps
|
||||||
|
.libs
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
|
runlist
|
59
test/Makefile.am
Normal file
59
test/Makefile.am
Normal 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
BIN
test/runlist-data/attr1.bin
Normal file
Binary file not shown.
BIN
test/runlist-data/attr2.bin
Normal file
BIN
test/runlist-data/attr2.bin
Normal file
Binary file not shown.
BIN
test/runlist-data/attr3.bin
Normal file
BIN
test/runlist-data/attr3.bin
Normal file
Binary file not shown.
2213
test/runlist-data/frag123
Normal file
2213
test/runlist-data/frag123
Normal file
File diff suppressed because it is too large
Load Diff
2061
test/runlist-data/frag132
Normal file
2061
test/runlist-data/frag132
Normal file
File diff suppressed because it is too large
Load Diff
2213
test/runlist-data/frag213
Normal file
2213
test/runlist-data/frag213
Normal file
File diff suppressed because it is too large
Load Diff
2133
test/runlist-data/frag231
Normal file
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
Loading…
Reference in New Issue
Block a user