isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.
This commit is contained in:
1 parent
3dacbd32c8
commit
73abd6f90d
441 files changed
+187073
-6549
No files matched your search
@@ -0,0 +1,195 @@
|
||||
if REALLYSTATIC
|
||||
AM_LIBS = $(top_builddir)/libntfs-3g/.libs/libntfs-3g.a $(NTFSPROGS_STATIC_LIBS)
|
||||
# older builds may need -static instead of newer -all-static
|
||||
AM_LFLAGS = -static
|
||||
STATIC_LINK = $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
else
|
||||
AM_LIBS = $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
AM_LFLAGS = $(all_libraries)
|
||||
LIBTOOL_LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
endif
|
||||
|
||||
# Workaround to make REALLYSTATIC work with automake 1.5.
|
||||
LINK=$(STATIC_LINK) $(LIBTOOL_LINK)
|
||||
|
||||
if ENABLE_NTFSPROGS
|
||||
|
||||
bin_PROGRAMS = ntfsfix ntfsinfo ntfscluster ntfsls ntfscat ntfscmp
|
||||
sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize ntfsclone \
|
||||
ntfscp
|
||||
EXTRA_PROGRAM_NAMES = ntfswipe ntfstruncate ntfsrecover \
|
||||
ntfsusermap ntfssecaudit
|
||||
|
||||
QUARANTINED_PROGRAM_NAMES = ntfsdump_logfile ntfsmftalloc ntfsmove ntfsck \
|
||||
ntfsfallocate
|
||||
|
||||
man_MANS = mkntfs.8 \
|
||||
ntfscat.8 \
|
||||
ntfsclone.8 \
|
||||
ntfscluster.8 \
|
||||
ntfscmp.8 \
|
||||
ntfscp.8 \
|
||||
ntfsdecrypt.8 \
|
||||
ntfsfallocate.8 \
|
||||
ntfsfix.8 \
|
||||
ntfsinfo.8 \
|
||||
ntfslabel.8 \
|
||||
ntfsls.8 \
|
||||
ntfsprogs.8 \
|
||||
ntfsresize.8 \
|
||||
ntfsundelete.8
|
||||
|
||||
EXTRA_MANS = ntfsrecover.8 \
|
||||
ntfssecaudit.8 \
|
||||
ntfstruncate.8 \
|
||||
ntfsusermap.8 \
|
||||
ntfswipe.8
|
||||
|
||||
CLEANFILES = $(EXTRA_PROGRAMS)
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
||||
if ENABLE_CRYPTO
|
||||
EXTRA_PROGRAM_NAMES += ntfsdecrypt
|
||||
endif
|
||||
|
||||
if ENABLE_EXTRAS
|
||||
bin_PROGRAMS += $(EXTRA_PROGRAM_NAMES)
|
||||
if ENABLE_QUARANTINED
|
||||
bin_PROGRAMS += $(QUARANTINED_PROGRAM_NAMES)
|
||||
endif
|
||||
man_MANS += $(EXTRA_MANS)
|
||||
else
|
||||
EXTRA_PROGRAMS = $(EXTRA_PROGRAM_NAMES)
|
||||
endif
|
||||
|
||||
# Set the include path.
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include/ntfs-3g $(all_includes)
|
||||
|
||||
ntfsfix_SOURCES = ntfsfix.c utils.c utils.h
|
||||
ntfsfix_LDADD = $(AM_LIBS)
|
||||
ntfsfix_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
mkntfs_CPPFLAGS = $(AM_CPPFLAGS) $(MKNTFS_CPPFLAGS)
|
||||
mkntfs_SOURCES = attrdef.c attrdef.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h
|
||||
mkntfs_LDADD = $(AM_LIBS) $(MKNTFS_LIBS)
|
||||
mkntfs_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfslabel_SOURCES = ntfslabel.c utils.c utils.h
|
||||
ntfslabel_LDADD = $(AM_LIBS)
|
||||
ntfslabel_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsinfo_SOURCES = ntfsinfo.c utils.c utils.h
|
||||
ntfsinfo_LDADD = $(AM_LIBS)
|
||||
ntfsinfo_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsundelete_SOURCES = ntfsundelete.c ntfsundelete.h utils.c utils.h list.h
|
||||
ntfsundelete_LDADD = $(AM_LIBS)
|
||||
ntfsundelete_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsresize_SOURCES = ntfsresize.c utils.c utils.h
|
||||
ntfsresize_LDADD = $(AM_LIBS)
|
||||
ntfsresize_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsclone_SOURCES = ntfsclone.c utils.c utils.h
|
||||
ntfsclone_LDADD = $(AM_LIBS)
|
||||
ntfsclone_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfscluster_SOURCES = ntfscluster.c ntfscluster.h cluster.c cluster.h utils.c utils.h
|
||||
ntfscluster_LDADD = $(AM_LIBS)
|
||||
ntfscluster_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsls_SOURCES = ntfsls.c utils.c utils.h list.h
|
||||
ntfsls_LDADD = $(AM_LIBS)
|
||||
ntfsls_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfscat_SOURCES = ntfscat.c ntfscat.h utils.c utils.h
|
||||
ntfscat_LDADD = $(AM_LIBS)
|
||||
ntfscat_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfscp_SOURCES = ntfscp.c utils.c utils.h
|
||||
ntfscp_LDADD = $(AM_LIBS)
|
||||
ntfscp_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsck_SOURCES = ntfsck.c utils.c utils.h
|
||||
ntfsck_LDADD = $(AM_LIBS)
|
||||
ntfsck_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfscmp_SOURCES = ntfscmp.c utils.c utils.h
|
||||
ntfscmp_LDADD = $(AM_LIBS)
|
||||
ntfscmp_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsrecover_SOURCES = playlog.c ntfsrecover.c utils.c utils.h ntfsrecover.h
|
||||
ntfsrecover_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS)
|
||||
ntfsrecover_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsusermap_SOURCES = ntfsusermap.c utils.c utils.h
|
||||
ntfsusermap_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS)
|
||||
ntfsusermap_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfssecaudit_SOURCES = ntfssecaudit.c utils.c utils.h
|
||||
ntfssecaudit_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS)
|
||||
ntfssecaudit_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
# We don't distribute these
|
||||
|
||||
ntfstruncate_SOURCES = attrdef.c ntfstruncate.c utils.c utils.h
|
||||
ntfstruncate_LDADD = $(AM_LIBS)
|
||||
ntfstruncate_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsmftalloc_SOURCES = ntfsmftalloc.c utils.c utils.h
|
||||
ntfsmftalloc_LDADD = $(AM_LIBS)
|
||||
ntfsmftalloc_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsmove_SOURCES = ntfsmove.c ntfsmove.h utils.c utils.h
|
||||
ntfsmove_LDADD = $(AM_LIBS)
|
||||
ntfsmove_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfswipe_SOURCES = ntfswipe.c ntfswipe.h utils.c utils.h
|
||||
ntfswipe_LDADD = $(AM_LIBS)
|
||||
ntfswipe_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsdump_logfile_SOURCES= ntfsdump_logfile.c
|
||||
ntfsdump_logfile_LDADD = $(AM_LIBS)
|
||||
ntfsdump_logfile_LDFLAGS= $(AM_LFLAGS)
|
||||
|
||||
ntfsfallocate_SOURCES = ntfsfallocate.c utils.c utils.h
|
||||
ntfsfallocate_LDADD = $(AM_LIBS)
|
||||
ntfsfallocate_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
if ENABLE_CRYPTO
|
||||
ntfsdecrypt_SOURCES = ntfsdecrypt.c utils.c utils.h
|
||||
ntfsdecrypt_LDADD = $(AM_LIBS) $(GNUTLS_LIBS) $(LIBGCRYPT_LIBS)
|
||||
ntfsdecrypt_LDFLAGS = $(AM_LFLAGS)
|
||||
ntfsdecrypt_CFLAGS = $(GNUTLS_CFLAGS) $(LIBGCRYPT_CFLAGS)
|
||||
endif
|
||||
|
||||
# Extra targets
|
||||
|
||||
strip: $(bin_PROGRAMS) $(sbin_PROGRAMS)
|
||||
$(STRIP) $^
|
||||
|
||||
libs:
|
||||
(cd ../libntfs-3g && $(MAKE) libs) || exit 1;
|
||||
|
||||
extra: extras
|
||||
|
||||
extras: libs $(EXTRA_PROGRAMS)
|
||||
|
||||
# mkfs.ntfs[.8] hard link
|
||||
|
||||
if ENABLE_MOUNT_HELPER
|
||||
install-exec-hook:
|
||||
$(INSTALL) -d $(DESTDIR)/$(sbindir)
|
||||
$(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)$(sbindir)/mkfs.ntfs
|
||||
|
||||
install-data-hook:
|
||||
$(INSTALL) -d $(DESTDIR)$(man8dir)
|
||||
$(LN_S) -f mkntfs.8 $(DESTDIR)$(man8dir)/mkfs.ntfs.8
|
||||
|
||||
uninstall-local:
|
||||
$(RM) -f $(DESTDIR)/sbin/mkfs.ntfs
|
||||
$(RM) -f $(DESTDIR)$(man8dir)/mkfs.ntfs.8
|
||||
endif
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,168 @@
|
||||
#include "attrdef.h"
|
||||
|
||||
/**
|
||||
* attrdef_ntfs3x_array
|
||||
*/
|
||||
const unsigned char attrdef_ntfs3x_array[2560] = {
|
||||
0x24, 0x00, 0x53, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x41, 0x00, 0x52, 0x00,
|
||||
0x44, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x4D, 0x00,
|
||||
0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x41, 0x00, 0x54, 0x00, 0x54, 0x00, 0x52, 0x00, 0x49, 0x00, 0x42, 0x00, 0x55, 0x00,
|
||||
0x54, 0x00, 0x45, 0x00, 0x5F, 0x00, 0x4C, 0x00, 0x49, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x24, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4C, 0x00, 0x45, 0x00, 0x5F, 0x00, 0x4E, 0x00, 0x41, 0x00,
|
||||
0x4D, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
|
||||
0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x4F, 0x00, 0x42, 0x00, 0x4A, 0x00, 0x45, 0x00, 0x43, 0x00, 0x54, 0x00, 0x5F, 0x00,
|
||||
0x49, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x53, 0x00, 0x45, 0x00, 0x43, 0x00, 0x55, 0x00, 0x52, 0x00, 0x49, 0x00, 0x54, 0x00,
|
||||
0x59, 0x00, 0x5F, 0x00, 0x44, 0x00, 0x45, 0x00, 0x53, 0x00, 0x43, 0x00, 0x52, 0x00, 0x49, 0x00,
|
||||
0x50, 0x00, 0x54, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x24, 0x00, 0x56, 0x00, 0x4F, 0x00, 0x4C, 0x00, 0x55, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x5F, 0x00,
|
||||
0x4E, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x56, 0x00, 0x4F, 0x00, 0x4C, 0x00, 0x55, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x5F, 0x00,
|
||||
0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x54, 0x00,
|
||||
0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x24, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x52, 0x00,
|
||||
0x4F, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x24, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x41, 0x00,
|
||||
0x4C, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x43, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00,
|
||||
0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x24, 0x00, 0x42, 0x00, 0x49, 0x00, 0x54, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x50, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x24, 0x00, 0x52, 0x00, 0x45, 0x00, 0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x53, 0x00, 0x45, 0x00,
|
||||
0x5F, 0x00, 0x50, 0x00, 0x4F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x45, 0x00, 0x41, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00,
|
||||
0x52, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x45, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x47, 0x00, 0x47, 0x00, 0x45, 0x00, 0x44, 0x00, 0x5F, 0x00,
|
||||
0x55, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4C, 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5F, 0x00,
|
||||
0x53, 0x00, 0x54, 0x00, 0x52, 0x00, 0x45, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef _NTFS_ATTRDEF_H_
|
||||
#define _NTFS_ATTRDEF_H_
|
||||
|
||||
extern const unsigned char attrdef_ntfs3x_array[2560];
|
||||
|
||||
#endif /* _NTFS_ATTRDEF_H_ */
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* NTFS bootsector, adapted from the vfat one.
|
||||
*/
|
||||
|
||||
/* mkfs.fat.c - utility to create FAT/MS-DOS filesystems
|
||||
* Copyright (C) 1991 Linus Torvalds <torvalds@klaava.helsinki.fi>
|
||||
* Copyright (C) 1992-1993 Remy Card <card@masi.ibp.fr>
|
||||
* Copyright (C) 1993-1994 David Hudson <dave@humbug.demon.co.uk>
|
||||
* Copyright (C) 1998 H. Peter Anvin <hpa@zytor.com>
|
||||
* Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
|
||||
* Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
|
||||
* Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* The complete text of the GNU General Public License
|
||||
* can be found in /usr/share/common-licenses/GPL-3 file.
|
||||
*/
|
||||
|
||||
#include "boot.h"
|
||||
|
||||
#define BOOTCODE_SIZE 4136
|
||||
|
||||
/* The "boot code" we put into the filesystem... it writes a message and
|
||||
* tells the user to try again */
|
||||
|
||||
#define MSG_OFFSET_OFFSET 3
|
||||
|
||||
const unsigned char boot_array[BOOTCODE_SIZE] =
|
||||
|
||||
"\xeb\x52\x90" /* jump to code at 0x54 (0x7c54) */
|
||||
"NTFS \0" /* NTFS signature */
|
||||
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0" /* 72 bytes for device parameters */
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
/* Boot code run at location 0x7c54 */
|
||||
"\x0e" /* push cs */
|
||||
"\x1f" /* pop ds */
|
||||
"\xbe\x71\x7c" /* mov si, offset message_txt (at location 0x7c71) */
|
||||
/* write_msg: */
|
||||
"\xac" /* lodsb */
|
||||
"\x22\xc0" /* and al, al */
|
||||
"\x74\x0b" /* jz key_press */
|
||||
"\x56" /* push si */
|
||||
"\xb4\x0e" /* mov ah, 0eh */
|
||||
"\xbb\x07\x00" /* mov bx, 0007h */
|
||||
"\xcd\x10" /* int 10h */
|
||||
"\x5e" /* pop si */
|
||||
"\xeb\xf0" /* jmp write_msg */
|
||||
/* key_press: */
|
||||
"\x32\xe4" /* xor ah, ah */
|
||||
"\xcd\x16" /* int 16h */
|
||||
"\xcd\x19" /* int 19h */
|
||||
"\xeb\xfe" /* foo: jmp foo */
|
||||
/* message_txt: */
|
||||
"This is not a bootable disk. Please insert a bootable floppy and\r\n"
|
||||
"press any key to try again ... \r\n"
|
||||
/* At location 0xd4, 298 bytes to reach 0x1fe */
|
||||
/* 298 = 4 blocks of 72 then 10 */
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
|
||||
"\0\0\0\0\0\0\0\0\0\0"
|
||||
/* Boot signature at 0x1fe */
|
||||
"\x55\xaa";
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef _NTFS_BOOT_H_
|
||||
#define _NTFS_BOOT_H_
|
||||
|
||||
extern const unsigned char boot_array[4136];
|
||||
|
||||
#endif /* _NTFS_BOOT_H_ */
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* cluster - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2003 Richard Russon
|
||||
* Copyright (c) 2014 Jean-Pierre Andre
|
||||
*
|
||||
* This function will locate the owner of any given sector or cluster range.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "cluster.h"
|
||||
#include "utils.h"
|
||||
#include "logging.h"
|
||||
|
||||
/**
|
||||
* cluster_find
|
||||
*/
|
||||
int cluster_find(ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void *data)
|
||||
{
|
||||
int j;
|
||||
int result = -1;
|
||||
struct mft_search_ctx *m_ctx = NULL;
|
||||
ntfs_attr_search_ctx *a_ctx = NULL;
|
||||
s64 count;
|
||||
BOOL found;
|
||||
ATTR_RECORD *rec;
|
||||
runlist *runs;
|
||||
|
||||
if (!vol || !cb)
|
||||
return -1;
|
||||
|
||||
m_ctx = mft_get_search_ctx(vol);
|
||||
m_ctx->flags_search = FEMR_IN_USE | FEMR_BASE_RECORD;
|
||||
count = 0;
|
||||
|
||||
while (mft_next_record(m_ctx) == 0) {
|
||||
|
||||
if (!(m_ctx->flags_match & FEMR_BASE_RECORD))
|
||||
continue;
|
||||
|
||||
ntfs_log_verbose("Inode: %llu\n", (unsigned long long)
|
||||
m_ctx->inode->mft_no);
|
||||
|
||||
a_ctx = ntfs_attr_get_search_ctx(m_ctx->inode, NULL);
|
||||
|
||||
found = FALSE;
|
||||
while ((rec = find_attribute(AT_UNUSED, a_ctx))) {
|
||||
|
||||
if (!rec->non_resident) {
|
||||
ntfs_log_verbose("0x%02x skipped - attr is resident\n",
|
||||
(int)le32_to_cpu(a_ctx->attr->type));
|
||||
continue;
|
||||
}
|
||||
|
||||
runs = ntfs_mapping_pairs_decompress(vol, a_ctx->attr, NULL);
|
||||
if (!runs) {
|
||||
ntfs_log_error("Couldn't read the data runs.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ntfs_log_verbose("\t[0x%02X]\n",
|
||||
(int)le32_to_cpu(a_ctx->attr->type));
|
||||
|
||||
ntfs_log_verbose("\t\tVCN\tLCN\tLength\n");
|
||||
for (j = 0; runs[j].length > 0; j++) {
|
||||
LCN a_begin = runs[j].lcn;
|
||||
LCN a_end = a_begin + runs[j].length - 1;
|
||||
|
||||
if (a_begin < 0)
|
||||
continue; // sparse, discontiguous, etc
|
||||
|
||||
ntfs_log_verbose("\t\t%lld\t%lld-%lld (%lld)\n",
|
||||
(long long)runs[j].vcn,
|
||||
(long long)runs[j].lcn,
|
||||
(long long)(runs[j].lcn +
|
||||
runs[j].length - 1),
|
||||
(long long)runs[j].length);
|
||||
//dprint list
|
||||
|
||||
if ((a_begin > c_end) || (a_end < c_begin))
|
||||
continue; // before or after search range
|
||||
|
||||
if ((*cb) (m_ctx->inode, a_ctx->attr, runs+j, data))
|
||||
return 1;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
ntfs_attr_put_search_ctx(a_ctx);
|
||||
a_ctx = NULL;
|
||||
if (found)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count > 1)
|
||||
ntfs_log_info("* %lld inodes found\n",(long long)count);
|
||||
else
|
||||
ntfs_log_info("* %s inode found\n", (count ? "one" : "no"));
|
||||
result = 0;
|
||||
done:
|
||||
ntfs_attr_put_search_ctx(a_ctx);
|
||||
mft_put_search_ctx(m_ctx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -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 "types.h"
|
||||
#include "volume.h"
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
} ntfs_cluster;
|
||||
|
||||
typedef int (cluster_cb)(ntfs_inode *ino, ATTR_RECORD *attr, runlist_element *run, void *data);
|
||||
|
||||
int cluster_find(ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void *data);
|
||||
|
||||
#endif /* _CLUSTER_H_ */
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* list.h - Linked list implementation. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2002 Anton Altaparmakov and others
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_LIST_H
|
||||
#define _NTFS_LIST_H
|
||||
|
||||
/**
|
||||
* struct ntfs_list_head - Simple doubly linked list implementation.
|
||||
*
|
||||
* Copied from Linux kernel 2.4.2-ac18 into Linux-NTFS (with minor
|
||||
* modifications). - AIA
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
struct ntfs_list_head {
|
||||
struct ntfs_list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define NTFS_LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define NTFS_LIST_HEAD(name) \
|
||||
struct ntfs_list_head name = NTFS_LIST_HEAD_INIT(name)
|
||||
|
||||
#define NTFS_INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* __ntfs_list_add - Insert a new entry between two known consecutive entries.
|
||||
* @new:
|
||||
* @prev:
|
||||
* @next:
|
||||
*
|
||||
* This is only for internal list manipulation where we know the prev/next
|
||||
* entries already!
|
||||
*/
|
||||
static __inline__ void __ntfs_list_add(struct ntfs_list_head * new,
|
||||
struct ntfs_list_head * prev, struct ntfs_list_head * next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void ntfs_list_add(struct ntfs_list_head *new,
|
||||
struct ntfs_list_head *head)
|
||||
{
|
||||
__ntfs_list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void ntfs_list_add_tail(struct ntfs_list_head *new,
|
||||
struct ntfs_list_head *head)
|
||||
{
|
||||
__ntfs_list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* __ntfs_list_del -
|
||||
* @prev:
|
||||
* @next:
|
||||
*
|
||||
* Delete a list entry by making the prev/next entries point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know the prev/next
|
||||
* entries already!
|
||||
*/
|
||||
static __inline__ void __ntfs_list_del(struct ntfs_list_head * prev,
|
||||
struct ntfs_list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
*
|
||||
* Note: ntfs_list_empty on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static __inline__ void ntfs_list_del(struct ntfs_list_head *entry)
|
||||
{
|
||||
__ntfs_list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static __inline__ void ntfs_list_del_init(struct ntfs_list_head *entry)
|
||||
{
|
||||
__ntfs_list_del(entry->prev, entry->next);
|
||||
NTFS_INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int ntfs_list_empty(struct ntfs_list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static __inline__ void ntfs_list_splice(struct ntfs_list_head *list,
|
||||
struct ntfs_list_head *head)
|
||||
{
|
||||
struct ntfs_list_head *first = list->next;
|
||||
|
||||
if (first != list) {
|
||||
struct ntfs_list_head *last = list->prev;
|
||||
struct ntfs_list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_list_entry - get the struct for this entry
|
||||
* @ptr: the &struct ntfs_list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define ntfs_list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* ntfs_list_for_each - iterate over a list
|
||||
* @pos: the &struct ntfs_list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define ntfs_list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* ntfs_list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct ntfs_list_head to use as a loop counter.
|
||||
* @n: another &struct ntfs_list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define ntfs_list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
#endif /* defined _NTFS_LIST_H */
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
.\" Copyright (c) 2001\-2006 Anton Altaparmakov.
|
||||
.\" Copyright (c) 2005 Richard Russon.
|
||||
.\" Copyright (c) 2005\-2006 Szabolcs Szakacsits.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH MKNTFS 8 "January 2006" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
mkntfs \- create an NTFS file system
|
||||
.SH SYNOPSIS
|
||||
.B mkntfs
|
||||
[\fIoptions\fR] \fIdevice \fR[\fInumber\-of\-sectors\fR]
|
||||
.PP
|
||||
.B mkntfs
|
||||
[
|
||||
.B \-C
|
||||
]
|
||||
[
|
||||
.B \-c
|
||||
.I cluster\-size
|
||||
]
|
||||
[
|
||||
.B \-F
|
||||
]
|
||||
[
|
||||
.B \-f
|
||||
]
|
||||
[
|
||||
.B \-H
|
||||
.I heads
|
||||
]
|
||||
[
|
||||
.B \-h
|
||||
]
|
||||
[
|
||||
.B \-I
|
||||
]
|
||||
[
|
||||
.B \-L
|
||||
.I volume\-label
|
||||
]
|
||||
[
|
||||
.B \-l
|
||||
]
|
||||
[
|
||||
.B \-n
|
||||
]
|
||||
[
|
||||
.B \-p
|
||||
.I part\-start\-sect
|
||||
]
|
||||
[
|
||||
.B \-Q
|
||||
]
|
||||
[
|
||||
.B \-q
|
||||
]
|
||||
[
|
||||
.B \-S
|
||||
.I sectors\-per\-track
|
||||
]
|
||||
[
|
||||
.B \-s
|
||||
.I sector\-size
|
||||
]
|
||||
[
|
||||
.B \-T
|
||||
]
|
||||
[
|
||||
.B \-U
|
||||
]
|
||||
[
|
||||
.B \-V
|
||||
]
|
||||
[
|
||||
.B \-v
|
||||
]
|
||||
[
|
||||
.B \-z
|
||||
.I mft\-zone\-multiplier
|
||||
]
|
||||
[
|
||||
.B \-\-debug
|
||||
]
|
||||
.I device
|
||||
[
|
||||
.I number\-of\-sectors
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B mkntfs
|
||||
is used to create an NTFS file system on a device (usually a disk partition)
|
||||
or file.
|
||||
.I device
|
||||
is the special file corresponding to the device (e.g
|
||||
.IR /dev/hdXX ).
|
||||
.I number\-of\-sectors
|
||||
is the number of sectors on the device. If omitted,
|
||||
.B mkntfs
|
||||
automagically figures the file system size.
|
||||
.SH OPTIONS
|
||||
Below is a summary of all the options that
|
||||
.B mkntfs
|
||||
accepts. Nearly all options have two equivalent names. The short name is
|
||||
preceded by
|
||||
.B \-
|
||||
and the long name is preceded by
|
||||
.BR \-\- .
|
||||
Any single letter options, that don't take an argument, can be combined into a
|
||||
single command, e.g.
|
||||
.B \-fv
|
||||
is equivalent to
|
||||
.BR "\-f \-v" .
|
||||
Long named options can be abbreviated to any unique prefix of their name.
|
||||
.SS Basic options
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-fast\fR, \fB\-Q\fR, \fB\-\-quick\fR
|
||||
Perform quick (fast) format. This will skip both zeroing of the volume and bad
|
||||
sector checking.
|
||||
.TP
|
||||
\fB\-L\fR, \fB\-\-label\fR STRING
|
||||
Set the volume label for the filesystem.
|
||||
.TP
|
||||
\fB\-C\fR, \fB\-\-enable\-compression\fR
|
||||
Enable compression on the volume.
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-no\-action\fR
|
||||
Causes
|
||||
.B mkntfs
|
||||
to not actually create a filesystem, but display what it would do if it were
|
||||
to create a filesystem. All steps of the format are carried out except the
|
||||
actual writing to the device.
|
||||
.SS Advanced options
|
||||
.TP
|
||||
\fB\-c\fR, \fB\-\-cluster\-size\fR BYTES
|
||||
Specify the size of clusters in bytes. Valid cluster size values are powers of
|
||||
two, with at least 256, and at most 2097152 bytes (2MB) per cluster. If omitted,
|
||||
.B mkntfs
|
||||
uses 4096 bytes as the default cluster size.
|
||||
.sp
|
||||
Note that the default cluster size is set to be at least equal to the sector
|
||||
size as a cluster cannot be smaller than a sector. Also, note that values
|
||||
greater than 4096 have the side effect that compression is disabled on the
|
||||
volume (due to limitations in the NTFS compression algorithm currently in use
|
||||
by Windows).
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-sector\-size\fR BYTES
|
||||
Specify the size of sectors in bytes. Valid sector size values are 256, 512,
|
||||
1024, 2048 and 4096 bytes per sector. If omitted,
|
||||
.B mkntfs
|
||||
attempts to determine the
|
||||
.I sector\-size
|
||||
automatically and if that fails a default of 512 bytes per sector is used.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-partition\-start\fR SECTOR
|
||||
Specify the partition start sector. The maximum is 4294967295 (2^32\-1). If
|
||||
omitted,
|
||||
.B mkntfs
|
||||
attempts to determine
|
||||
.I part\-start\-sect
|
||||
automatically and if that fails or the value is oversized, a
|
||||
default of 0 is used. The partition is usable despite a wrong value,
|
||||
however note that a correct
|
||||
.I part\-start\-sect
|
||||
is required for Windows to be able to boot from the created volume.
|
||||
.TP
|
||||
\fB\-H\fR, \fB\-\-heads\fR NUM
|
||||
Specify the number of heads. The maximum is 65535 (0xffff). If omitted,
|
||||
.B mkntfs
|
||||
attempts to determine the number of
|
||||
.I heads
|
||||
automatically and if that fails a default of 0 is used. Note that
|
||||
.I heads
|
||||
is required for Windows to be able to boot from the created volume.
|
||||
.TP
|
||||
\fB\-S\fR, \fB\-\-sectors\-per\-track\fR NUM
|
||||
Specify the number of sectors per track. The maximum is 65535 (0xffff). If
|
||||
omitted,
|
||||
.B mkntfs
|
||||
attempts to determine the number of
|
||||
.I sectors\-per\-track
|
||||
automatically and if that fails a default of 0 is used. Note that
|
||||
.I sectors\-per\-track
|
||||
is required for Windows to be able to boot from the created volume.
|
||||
.TP
|
||||
\fB\-z\fR, \fB\-\-mft\-zone\-multiplier\fR NUM
|
||||
Set the MFT zone multiplier, which determines the size of the MFT zone to use
|
||||
on the volume. The MFT zone is the area at the beginning of the volume reserved
|
||||
for the master file table (MFT), which stores the on disk inodes (MFT records).
|
||||
It is noteworthy that small files are stored entirely within the inode;
|
||||
thus, if you expect to use the volume for storing large numbers of very small
|
||||
files, it is useful to set the zone multiplier to a higher value. Note, that
|
||||
the MFT zone is resized on the fly as required during operation of the NTFS
|
||||
driver but choosing a good value will reduce fragmentation. Valid values
|
||||
are 1, 2, 3 and 4. The values have the following meaning:
|
||||
.TS
|
||||
box;
|
||||
lB lB
|
||||
lB lB
|
||||
c l.
|
||||
MFT zone MFT zone size
|
||||
multiplier (% of volume size)
|
||||
1 12.5% (default)
|
||||
2 25.0%
|
||||
3 37.5%
|
||||
4 50.0%
|
||||
.TE
|
||||
.sp
|
||||
.TP
|
||||
\fB\-T\fR, \fB\-\-zero\-time\fR
|
||||
Fake the time to be 00:00:00 UTC, Jan 1, 1970 instead of the current system
|
||||
time. This is only really useful for debugging purposes.
|
||||
.TP
|
||||
\fB\-U\fR, \fB\-\-with\-uuid\fR
|
||||
Generate a random volume UUID.
|
||||
.TP
|
||||
\fB\-I\fR, \fB\-\-no\-indexing\fR
|
||||
Disable content indexing on the volume. (This is only meaningful on
|
||||
Windows 2000 and later. Windows NT 4.0 and earlier ignore this as they do
|
||||
not implement content indexing at all.)
|
||||
.TP
|
||||
\fB\-F\fR, \fB\-\-force\fR
|
||||
Force
|
||||
.B mkntfs
|
||||
to run, even if the specified
|
||||
.I device
|
||||
is not a block special device, or appears to be mounted.
|
||||
.SS Output options
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
Quiet execution; only errors are written to stderr, no output to stdout
|
||||
occurs at all. Useful if
|
||||
.B mkntfs
|
||||
is run in a script.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Verbose execution.
|
||||
.TP
|
||||
\fB\-\-debug\fR
|
||||
Really verbose execution; includes the verbose output from the
|
||||
.B \-v
|
||||
option as well as additional output useful for debugging
|
||||
.B mkntfs.
|
||||
.SS Help options
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
Print the version number of
|
||||
.B mkntfs
|
||||
and exit.
|
||||
.TP
|
||||
\fB\-l\fR, \fB\-\-license\fR
|
||||
Print the licensing information of
|
||||
.B mkntfs
|
||||
and exit.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Show a list of options with a brief description of each one.
|
||||
.SH KNOWN ISSUES
|
||||
When applying chkdsk to a file system, it sometimes throws a warning
|
||||
"Correcting errors in the uppercase file." The uppercase file is created
|
||||
while formatting and it defines the mapping of lower case characters to
|
||||
upper case ones, as needed to sort file names in directories. The warning
|
||||
means that the uppercase file defined on the file system is not the same as
|
||||
the one used by the Windows OS on which chkdsk is running, and this may
|
||||
happen because newer versions of Windows take into account new characters
|
||||
defined by the Unicode consortium.
|
||||
.P
|
||||
Currently, mkntfs creates the uppercase table so that no warning is thrown
|
||||
by Windows Vista, Windows 7 or Windows 8. A warning may be thrown by
|
||||
other Windows versions, or if chkdsk is applied in succession on different
|
||||
Windows versions.
|
||||
.SH BUGS
|
||||
If you find a bug please send an email describing the problem to the
|
||||
development team:
|
||||
.br
|
||||
.nh
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B mkntfs
|
||||
was written by Anton Altaparmakov, Richard Russon, Erik Sornes and Szabolcs Szakacsits.
|
||||
It was ported to ntfs-3g by Erik Larsson and Jean-Pierre Andre.
|
||||
.SH AVAILABILITY
|
||||
.B mkntfs
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR badblocks (8),
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,136 @@
|
||||
.\" Copyright (c) 2003\-2005 Richard Russon.
|
||||
.\" Copyright (c) 2007 Yura Pakhuchiy.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSCAT 8 "September 2007" "ntfs-3g @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
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfscat
|
||||
was written by Richard Russon, Anton Altaparmakov and Szabolcs Szakacsits.
|
||||
It was ported to ntfs-3g by Erik Larsson.
|
||||
.SH AVAILABILITY
|
||||
.B ntfscat
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
Read \fBlibntfs\fR(8) for details how to access encrypted files.
|
||||
.sp
|
||||
.BR libntfs (8),
|
||||
.BR ntfsls (8),
|
||||
.BR ntfsprogs (8)
|
||||
@@ -0,0 +1,462 @@
|
||||
/**
|
||||
* 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
|
||||
* Copyright (c) 2007 Yura Pakhuchiy
|
||||
*
|
||||
* 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 "types.h"
|
||||
#include "attrib.h"
|
||||
#include "utils.h"
|
||||
#include "volume.h"
|
||||
#include "debug.h"
|
||||
#include "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("Copyright (c) 2007 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 [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",
|
||||
// Does not work for compressed files at present so leave undocumented...
|
||||
// " -r --raw Display the raw data (e.g. for 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)cpu_to_le32((i + 1) * 16);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
num = strtol(value, NULL, 0);
|
||||
if ((num > 0) && (num < 257)) {
|
||||
*attr = (ATTR_TYPES)cpu_to_le32(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:qVvr";
|
||||
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' },
|
||||
{ "raw", no_argument, NULL, 'r' },
|
||||
{ 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 = const_cpu_to_le32(-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 != const_cpu_to_le32(-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':
|
||||
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(optarg,
|
||||
&opts.attr_name);
|
||||
if (opts.attr_name_len < 0) {
|
||||
ntfs_log_perror("Invalid attribute name '%s'",
|
||||
optarg);
|
||||
usage();
|
||||
}
|
||||
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;
|
||||
case 'r':
|
||||
opts.raw = TRUE;
|
||||
break;
|
||||
case '?':
|
||||
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
|
||||
if (!ntfs_log_parse_option (argv[optind-1]))
|
||||
err++;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
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();
|
||||
|
||||
/* tri-state 0 : done, 1 : error, -1 : proceed */
|
||||
return (err ? 1 : (help || ver ? 0 : -1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 le32_to_cpu(iroot->index_block_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* cat
|
||||
*/
|
||||
static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type,
|
||||
ntfschar *name, int namelen)
|
||||
{
|
||||
char *buffer;
|
||||
ntfs_attr *attr;
|
||||
s64 bytes_read, written;
|
||||
s64 offset;
|
||||
u32 block_size;
|
||||
u32 bufsize = 4096;
|
||||
|
||||
attr = ntfs_attr_open(inode, type, name, namelen);
|
||||
if (!attr) {
|
||||
ntfs_log_error("Cannot find attribute type 0x%x.\n",
|
||||
le32_to_cpu(type));
|
||||
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;
|
||||
|
||||
if (bufsize < block_size) {
|
||||
bufsize = block_size;
|
||||
}
|
||||
|
||||
buffer = malloc(bufsize);
|
||||
if (!buffer) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
for (;;) {
|
||||
if (!opts.raw && block_size > 0) {
|
||||
// These types have fixup
|
||||
bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer);
|
||||
if (bytes_read > 0)
|
||||
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 res;
|
||||
int result = 1;
|
||||
|
||||
ntfs_log_set_handler(ntfs_log_handler_stderr);
|
||||
|
||||
res = parse_options(argc, argv);
|
||||
if (res >= 0)
|
||||
return (res);
|
||||
|
||||
utils_set_locale();
|
||||
|
||||
vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY |
|
||||
(opts.force ? NTFS_MNT_RECOVER : 0));
|
||||
if (!vol) {
|
||||
ntfs_log_perror("ERROR: couldn't mount volume");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opts.inode != -1)
|
||||
inode = ntfs_inode_open(vol, opts.inode);
|
||||
else {
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
char *unix_name;
|
||||
|
||||
unix_name = ntfs_utils_unix_path(opts.file);
|
||||
if (unix_name) {
|
||||
inode = ntfs_pathname_to_inode(vol, NULL,
|
||||
unix_name);
|
||||
free(unix_name);
|
||||
} else
|
||||
inode = (ntfs_inode*)NULL;
|
||||
#else
|
||||
inode = ntfs_pathname_to_inode(vol, NULL, opts.file);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!inode) {
|
||||
ntfs_log_perror("ERROR: Couldn't open inode");
|
||||
return 1;
|
||||
}
|
||||
|
||||
attr = AT_DATA;
|
||||
if (opts.attr != const_cpu_to_le32(-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;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 "types.h"
|
||||
#include "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 */
|
||||
BOOL raw; /* Raw data output */
|
||||
};
|
||||
|
||||
#endif /* _NTFSCAT_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +1,884 @@
|
||||
/**
|
||||
* ntfsck - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2006 Yuval Fledel
|
||||
*
|
||||
* This utility will check and fix errors 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_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <layout.h>
|
||||
#include <bitmap.h>
|
||||
#include <endians.h>
|
||||
#include <bootsect.h>
|
||||
#include <misc.h>
|
||||
|
||||
#include "cluster.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define RETURN_FS_ERRORS_CORRECTED (1)
|
||||
#define RETURN_SYSTEM_NEEDS_REBOOT (2)
|
||||
#define RETURN_FS_ERRORS_LEFT_UNCORRECTED (4)
|
||||
#define RETURN_OPERATIONAL_ERROR (8)
|
||||
#define RETURN_USAGE_OR_SYNTAX_ERROR (16)
|
||||
#define RETURN_CANCELLED_BY_USER (32)
|
||||
/* Where did 64 go? */
|
||||
#define RETURN_SHARED_LIBRARY_ERROR (128)
|
||||
|
||||
/* todo: command line: (everything is optional)
|
||||
* fsck-frontend options:
|
||||
* -C [fd] : display progress bar (send it to the file descriptor if specified)
|
||||
* -T : don't show the title on startup
|
||||
* fsck-checker options:
|
||||
* -a : auto-repair. no questions. (optional: if marked clean and -f not specified, just check if mounable)
|
||||
* -p : auto-repair safe. no questions (optional: same)
|
||||
* -n : only check. no repair.
|
||||
* -r : interactively repair.
|
||||
* -y : always yes.
|
||||
* -v : verbose.
|
||||
* -V : version.
|
||||
* taken from fsck.ext2
|
||||
* -b sb : use the superblock from sb. For corrupted volumes. (do we want separete boot/mft options?)
|
||||
* -c : use badblocks(8) to find bad blocks (R/O mode) and add the findings to $Bad.
|
||||
* -C fd : write competion info to fd. If 0, print a completion bar.
|
||||
* -d : debugging output.
|
||||
* -D : rebalance indices.
|
||||
* -f : force checking even if marked clean.
|
||||
* -F : flush buffers before beginning. (for time-benchmarking)
|
||||
* -k : When used with -c, don't erase previous $Bad items.
|
||||
* -n : Open fs as readonly. assume always no. (why is it needed if -r is not specified?)
|
||||
* -t : Print time statistics.
|
||||
* taken from fsck.reiserfs
|
||||
* --rebuild-sb : try to find $MFT start and rebuild the boot sector.
|
||||
* --rebuild-tree : scan for items and rebuild the indices that point to them (0x30, $SDS, etc.)
|
||||
* --clean-reserved: zero rezerved fields. (use with care!)
|
||||
* --adjust-size -z: insert a sparse hole if the data_size is larger than the size marked in the runlist.
|
||||
* --logfile file : report corruptions (unlike other errors) to a file instead of stderr.
|
||||
* --nolog : don't report corruptions at all.
|
||||
* --quiet -q : no progress bar.
|
||||
* taken from fsck.msdos
|
||||
* -w : flush after every write.
|
||||
* - do n passes. (only 2 in fsck.msdos. second should not report errors. Bonus: stop when error list does not change)
|
||||
* taken from fsck.jfs
|
||||
* --omit-journal-reply: self-descriptive (why would someone do that?)
|
||||
* --replay-journal-only: self-descriptive. don't check otherwise.
|
||||
* taken from fsck.xfs
|
||||
* -s : only serious errors should be reported.
|
||||
* -i ino : verbose behaviour only for inode ino.
|
||||
* -b bno : verbose behaviour only for cluster bno.
|
||||
* -L : zero log.
|
||||
* inspired by others
|
||||
* - don't do cluster accounting.
|
||||
* - don't do mft record accounting.
|
||||
* - don't do file names accounting.
|
||||
* - don't do security_id accounting.
|
||||
* - don't check acl inheritance problems.
|
||||
* - undelete unused mft records. (bonus: different options for 100% salvagable and less)
|
||||
* - error-level-report n: only report errors above this error level
|
||||
* - error-level-repair n: only repair errors below this error level
|
||||
* - don't fail on ntfsclone metadata pruning.
|
||||
* signals:
|
||||
* SIGUSR1 : start displaying progress bar
|
||||
* SIGUSR2 : stop displaying progress bar.
|
||||
*/
|
||||
|
||||
/* Assuming NO_NTFS_DEVICE_DEFAULT_IO_OPS is not set */
|
||||
|
||||
static int errors = 0;
|
||||
static int unsupported = 0;
|
||||
|
||||
static short bytes_per_sector, sectors_per_cluster;
|
||||
//static s64 mft_offset, mftmirr_offset;
|
||||
static s64 current_mft_record;
|
||||
|
||||
/**
|
||||
* This is just a preliminary volume.
|
||||
* Filled while checking the boot sector and used in the preliminary MFT check.
|
||||
*/
|
||||
//static ntfs_volume vol;
|
||||
|
||||
static runlist_element *mft_rl, *mft_bitmap_rl;
|
||||
|
||||
#define check_failed(FORMAT, ARGS...) \
|
||||
do { \
|
||||
errors++; \
|
||||
ntfs_log_redirect(__FUNCTION__,__FILE__,__LINE__, \
|
||||
NTFS_LOG_LEVEL_ERROR,NULL,FORMAT,##ARGS); \
|
||||
} while (0);
|
||||
|
||||
/**
|
||||
* 0 success.
|
||||
* 1 fail.
|
||||
*/
|
||||
static int assert_u32_equal(u32 val, u32 ok, const char *name)
|
||||
{
|
||||
if (val!=ok) {
|
||||
check_failed("Assertion failed for '%lld:%s'. should be 0x%x, "
|
||||
"was 0x%x.\n", (long long)current_mft_record, name,
|
||||
(int)ok, (int)val);
|
||||
//errors++;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int assert_u32_noteq(u32 val, u32 wrong, const char *name)
|
||||
{
|
||||
if (val==wrong) {
|
||||
check_failed("Assertion failed for '%lld:%s'. should not be "
|
||||
"0x%x.\n", (long long)current_mft_record, name,
|
||||
(int)wrong);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int assert_u32_lesseq(u32 val1, u32 val2, const char *name)
|
||||
{
|
||||
if (val1 > val2) {
|
||||
check_failed("Assertion failed for '%s'. 0x%x > 0x%x\n",
|
||||
name, (int)val1, (int)val2);
|
||||
//errors++;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int assert_u32_less(u32 val1, u32 val2, const char *name)
|
||||
{
|
||||
if (val1 >= val2) {
|
||||
check_failed("Assertion failed for '%s'. 0x%x >= 0x%x\n",
|
||||
name, (int)val1, (int)val2);
|
||||
//errors++;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return: 0 ok, 1 error.
|
||||
*
|
||||
* todo: may we use ntfs_boot_sector_is_ntfs() instead?
|
||||
* It already does the checks but will not be able to fix anything.
|
||||
*/
|
||||
static BOOL verify_boot_sector(struct ntfs_device *dev, ntfs_volume *rawvol)
|
||||
{
|
||||
u8 buf[512];
|
||||
NTFS_BOOT_SECTOR *ntfs_boot = (NTFS_BOOT_SECTOR *)&buf;
|
||||
//u32 bytes_per_cluster;
|
||||
|
||||
current_mft_record = 9;
|
||||
|
||||
if (ntfs_pread(dev, 0, sizeof(buf), buf) != sizeof(buf)) {
|
||||
check_failed("Failed to read boot sector.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((buf[0]!=0xeb) ||
|
||||
((buf[1]!=0x52) && (buf[1]!=0x5b)) ||
|
||||
(buf[2]!=0x90)) {
|
||||
check_failed("Boot sector: Bad jump.\n");
|
||||
}
|
||||
if (ntfs_boot->oem_id != magicNTFS) {
|
||||
check_failed("Boot sector: Bad NTFS magic.\n");
|
||||
}
|
||||
bytes_per_sector = le16_to_cpu(ntfs_boot->bpb.bytes_per_sector);
|
||||
if (!bytes_per_sector) {
|
||||
check_failed("Boot sector: Bytes per sector is 0.\n");
|
||||
}
|
||||
if (bytes_per_sector%512) {
|
||||
check_failed("Boot sector: Bytes per sector is not a multiple"
|
||||
" of 512.\n");
|
||||
}
|
||||
sectors_per_cluster = ntfs_boot->bpb.sectors_per_cluster;
|
||||
|
||||
// todo: if partition, query bios and match heads/tracks? */
|
||||
|
||||
// Initialize some values into rawvol. We will need those later.
|
||||
rawvol->dev = dev;
|
||||
ntfs_boot_sector_parse(rawvol, (NTFS_BOOT_SECTOR *)buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the runlist of the <attr_type> attribute.
|
||||
*
|
||||
* Return NULL if an error.
|
||||
* The caller is responsible on freeing the allocated memory if the result is not NULL.
|
||||
*
|
||||
* Set size_of_file_record to some reasonable size when in doubt (the Windows default is 1024.)
|
||||
*
|
||||
* attr_type must be little endian.
|
||||
*
|
||||
* This function has code duplication with check_file_record() and
|
||||
* check_attr_record() but its goal is to be less strict. Thus the
|
||||
* duplicated checks are the minimal required for not crashing.
|
||||
*
|
||||
* Assumes dev is open.
|
||||
*/
|
||||
static runlist *load_runlist(ntfs_volume *rawvol, s64 offset_to_file_record, ATTR_TYPES attr_type, u32 size_of_file_record)
|
||||
{
|
||||
u8 *buf;
|
||||
u16 attrs_offset;
|
||||
u32 length;
|
||||
ATTR_RECORD *attr_rec;
|
||||
|
||||
if (size_of_file_record<22) // offset to attrs_offset
|
||||
return NULL;
|
||||
|
||||
buf = (u8*)ntfs_malloc(size_of_file_record);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
if (ntfs_pread(rawvol->dev, offset_to_file_record, size_of_file_record, buf) !=
|
||||
size_of_file_record) {
|
||||
check_failed("Failed to read file record at offset %lld (0x%llx).\n",
|
||||
(long long)offset_to_file_record,
|
||||
(long long)offset_to_file_record);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
attrs_offset = le16_to_cpu(((MFT_RECORD*)buf)->attrs_offset);
|
||||
// first attribute must be after the header.
|
||||
if (attrs_offset<42) {
|
||||
check_failed("First attribute must be after the header (%u).\n", (int)attrs_offset);
|
||||
}
|
||||
attr_rec = (ATTR_RECORD *)(buf + attrs_offset);
|
||||
//printf("uv1.\n");
|
||||
|
||||
while ((u8*)attr_rec<=buf+size_of_file_record-4) {
|
||||
|
||||
//printf("Attr type: 0x%x.\n", attr_rec->type);
|
||||
// Check attribute record. (Only what is in the buffer)
|
||||
if (attr_rec->type==AT_END) {
|
||||
check_failed("Attribute 0x%x not found in file record at offset %lld (0x%llx).\n", (int)le32_to_cpu(attr_rec->type),
|
||||
(long long)offset_to_file_record,
|
||||
(long long)offset_to_file_record);
|
||||
return NULL;
|
||||
}
|
||||
if ((u8*)attr_rec>buf+size_of_file_record-8) {
|
||||
// not AT_END yet no room for the length field.
|
||||
check_failed("Attribute 0x%x is not AT_END, yet no "
|
||||
"room for the length field.\n",
|
||||
(int)le32_to_cpu(attr_rec->type));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
length = le32_to_cpu(attr_rec->length);
|
||||
|
||||
// Check that this attribute does not overflow the mft_record
|
||||
if ((u8*)attr_rec+length >= buf+size_of_file_record) {
|
||||
check_failed("Attribute (0x%x) is larger than FILE record at offset %lld (0x%llx).\n",
|
||||
(int)le32_to_cpu(attr_rec->type),
|
||||
(long long)offset_to_file_record,
|
||||
(long long)offset_to_file_record);
|
||||
return NULL;
|
||||
}
|
||||
// todo: what ATTRIBUTE_LIST (0x20)?
|
||||
|
||||
if (attr_rec->type==attr_type) {
|
||||
// Eurika!
|
||||
|
||||
// ntfs_mapping_pairs_decompress only use two values from vol. Just fake it.
|
||||
// todo: it will also use vol->major_ver if defined(DEBUG). But only for printing purposes.
|
||||
|
||||
// Assume ntfs_boot_sector_parse() was called.
|
||||
return ntfs_mapping_pairs_decompress(rawvol, attr_rec, NULL);
|
||||
}
|
||||
|
||||
attr_rec = (ATTR_RECORD*)((u8*)attr_rec+length);
|
||||
}
|
||||
// If we got here, there was an overflow.
|
||||
check_failed("file record corrupted at offset %lld (0x%llx).\n",
|
||||
(long long)offset_to_file_record,
|
||||
(long long)offset_to_file_record);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return: >=0 last VCN
|
||||
* LCN_EINVAL error.
|
||||
*/
|
||||
static VCN get_last_vcn(runlist *rl)
|
||||
{
|
||||
VCN res;
|
||||
|
||||
if (!rl)
|
||||
return LCN_EINVAL;
|
||||
|
||||
res = LCN_EINVAL;
|
||||
while (rl->length) {
|
||||
ntfs_log_verbose("vcn: %lld, length: %lld.\n",
|
||||
(long long)rl->vcn, (long long)rl->length);
|
||||
if (rl->vcn<0)
|
||||
res = rl->vcn;
|
||||
else
|
||||
res = rl->vcn + rl->length;
|
||||
rl++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static u32 mft_bitmap_records;
|
||||
static u8 *mft_bitmap_buf;
|
||||
|
||||
/**
|
||||
* Assumes mft_bitmap_rl is initialized.
|
||||
* return: 0 ok.
|
||||
* RETURN_OPERATIONAL_ERROR on error.
|
||||
*/
|
||||
static int mft_bitmap_load(ntfs_volume *rawvol)
|
||||
{
|
||||
VCN vcn;
|
||||
u32 mft_bitmap_length;
|
||||
|
||||
vcn = get_last_vcn(mft_bitmap_rl);
|
||||
if (vcn<=LCN_EINVAL) {
|
||||
mft_bitmap_buf = NULL;
|
||||
/* This case should not happen, not even with on-disk errors */
|
||||
goto error;
|
||||
}
|
||||
|
||||
mft_bitmap_length = vcn * rawvol->cluster_size;
|
||||
mft_bitmap_records = 8 * mft_bitmap_length * rawvol->cluster_size /
|
||||
rawvol->mft_record_size;
|
||||
|
||||
//printf("sizes: %d, %d.\n", mft_bitmap_length, mft_bitmap_records);
|
||||
|
||||
mft_bitmap_buf = (u8*)ntfs_malloc(mft_bitmap_length);
|
||||
if (!mft_bitmap_buf)
|
||||
goto error;
|
||||
if (ntfs_rl_pread(rawvol, mft_bitmap_rl, 0, mft_bitmap_length,
|
||||
mft_bitmap_buf)!=mft_bitmap_length)
|
||||
goto error;
|
||||
return 0;
|
||||
error:
|
||||
mft_bitmap_records = 0;
|
||||
ntfs_log_error("Could not load $MFT/Bitmap.\n");
|
||||
return RETURN_OPERATIONAL_ERROR;
|
||||
}
|
||||
|
||||
/**
|
||||
* -1 Error.
|
||||
* 0 Unused record
|
||||
* 1 Used record
|
||||
*
|
||||
* Assumes mft_bitmap_rl was initialized.
|
||||
*/
|
||||
static int mft_bitmap_get_bit(s64 mft_no)
|
||||
{
|
||||
if (mft_no>=mft_bitmap_records)
|
||||
return -1;
|
||||
return ntfs_bit_get(mft_bitmap_buf, mft_no);
|
||||
}
|
||||
|
||||
/**
|
||||
* @attr_rec: The attribute record to check
|
||||
* @mft_rec: The parent FILE record.
|
||||
* @buflen: The size of the FILE record.
|
||||
*
|
||||
* Return:
|
||||
* NULL: Fatal error occured. Not sure where is the next record.
|
||||
* otherwise: pointer to the next attribute record.
|
||||
*
|
||||
* The function only check fields that are inside this attr record.
|
||||
*
|
||||
* Assumes mft_rec is current_mft_record.
|
||||
*/
|
||||
static ATTR_REC *check_attr_record(ATTR_REC *attr_rec, MFT_RECORD *mft_rec,
|
||||
u16 buflen)
|
||||
{
|
||||
u16 name_offset;
|
||||
u16 attrs_offset = le16_to_cpu(mft_rec->attrs_offset);
|
||||
u32 attr_type = le32_to_cpu(attr_rec->type);
|
||||
u32 length = le32_to_cpu(attr_rec->length);
|
||||
|
||||
// Check that this attribute does not overflow the mft_record
|
||||
if ((u8*)attr_rec+length >= ((u8*)mft_rec)+buflen) {
|
||||
check_failed("Attribute (0x%x) is larger than FILE record (%lld).\n",
|
||||
(int)attr_type, (long long)current_mft_record);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Attr type must be a multiple of 0x10 and 0x10<=x<=0x100.
|
||||
if ((attr_type & ~0x0F0) && (attr_type != 0x100)) {
|
||||
check_failed("Unknown attribute type 0x%x.\n",
|
||||
(int)attr_type);
|
||||
goto check_attr_record_next_attr;
|
||||
}
|
||||
|
||||
if (length<24) {
|
||||
check_failed("Attribute %lld:0x%x Length too short (%u).\n",
|
||||
(long long)current_mft_record, (int)attr_type,
|
||||
(int)length);
|
||||
goto check_attr_record_next_attr;
|
||||
}
|
||||
|
||||
// If this is the first attribute:
|
||||
// todo: instance number must be smaller than next_instance.
|
||||
if ((u8*)attr_rec == ((u8*)mft_rec) + attrs_offset) {
|
||||
if (!mft_rec->base_mft_record)
|
||||
assert_u32_equal(attr_type, 0x10,
|
||||
"First attribute type");
|
||||
// The following not always holds.
|
||||
// attr 0x10 becomes instance 1 and attr 0x40 becomes 0.
|
||||
//assert_u32_equal(attr_rec->instance, 0,
|
||||
// "First attribute instance number");
|
||||
} else {
|
||||
assert_u32_noteq(attr_type, 0x10,
|
||||
"Not-first attribute type");
|
||||
// The following not always holds.
|
||||
//assert_u32_noteq(attr_rec->instance, 0,
|
||||
// "Not-first attribute instance number");
|
||||
}
|
||||
//if (current_mft_record==938 || current_mft_record==1683 || current_mft_record==3152 || current_mft_record==22410)
|
||||
//printf("Attribute %lld:0x%x instance: %u isbase:%d.\n",
|
||||
// current_mft_record, (int)attr_type, (int)le16_to_cpu(attr_rec->instance), (int)mft_rec->base_mft_record);
|
||||
// todo: instance is unique.
|
||||
|
||||
// Check flags.
|
||||
if (attr_rec->flags & ~(const_cpu_to_le16(0xc0ff))) {
|
||||
check_failed("Attribute %lld:0x%x Unknown flags (0x%x).\n",
|
||||
(long long)current_mft_record, (int)attr_type,
|
||||
(int)le16_to_cpu(attr_rec->flags));
|
||||
}
|
||||
|
||||
if (attr_rec->non_resident>1) {
|
||||
check_failed("Attribute %lld:0x%x Unknown non-resident "
|
||||
"flag (0x%x).\n", (long long)current_mft_record,
|
||||
(int)attr_type, (int)attr_rec->non_resident);
|
||||
goto check_attr_record_next_attr;
|
||||
}
|
||||
|
||||
name_offset = le16_to_cpu(attr_rec->name_offset);
|
||||
/*
|
||||
* todo: name must be legal unicode.
|
||||
* Not really, information below in urls is about filenames, but I
|
||||
* believe it also applies to attribute names. (Yura)
|
||||
* http://blogs.msdn.com/michkap/archive/2006/09/24/769540.aspx
|
||||
* http://blogs.msdn.com/michkap/archive/2006/09/10/748699.aspx
|
||||
*/
|
||||
|
||||
if (attr_rec->non_resident) {
|
||||
// Non-Resident
|
||||
|
||||
// Make sure all the fields exist.
|
||||
if (length<64) {
|
||||
check_failed("Non-resident attribute %lld:0x%x too short (%u).\n",
|
||||
(long long)current_mft_record, (int)attr_type,
|
||||
(int)length);
|
||||
goto check_attr_record_next_attr;
|
||||
}
|
||||
if (attr_rec->compression_unit && (length<72)) {
|
||||
check_failed("Compressed attribute %lld:0x%x too short (%u).\n",
|
||||
(long long)current_mft_record, (int)attr_type,
|
||||
(int)length);
|
||||
goto check_attr_record_next_attr;
|
||||
}
|
||||
|
||||
// todo: name comes before mapping pairs, and after the header.
|
||||
// todo: length==mapping_pairs_offset+length of compressed mapping pairs.
|
||||
// todo: mapping_pairs_offset is 8-byte aligned.
|
||||
|
||||
// todo: lowest vcn <= highest_vcn
|
||||
// todo: if base record -> lowest vcn==0
|
||||
// todo: lowest_vcn!=0 -> attribute list is used.
|
||||
// todo: lowest_vcn & highest_vcn are in the drive (0<=x<total clusters)
|
||||
// todo: mapping pairs agree with highest_vcn.
|
||||
// todo: compression unit == 0 or 4.
|
||||
// todo: reserved1 == 0.
|
||||
// todo: if not compressed nor sparse, initialized_size <= allocated_size and data_size <= allocated_size.
|
||||
// todo: if compressed or sparse, allocated_size <= initialized_size and allocated_size <= data_size
|
||||
// todo: if mft_no!=0 and not compressed/sparse, data_size==initialized_size.
|
||||
// todo: if mft_no!=0 and compressed/sparse, allocated_size==initialized_size.
|
||||
// todo: what about compressed_size if compressed?
|
||||
// todo: attribute must not be 0x10, 0x30, 0x40, 0x60, 0x70, 0x90, 0xd0 (not sure about 0xb0, 0xe0, 0xf0)
|
||||
} else {
|
||||
u16 value_offset = le16_to_cpu(attr_rec->value_offset);
|
||||
u32 value_length = le32_to_cpu(attr_rec->value_length);
|
||||
// Resident
|
||||
if (attr_rec->name_length) {
|
||||
if (name_offset < 24)
|
||||
check_failed("Resident attribute with "
|
||||
"name intersecting header.\n");
|
||||
if (value_offset < name_offset +
|
||||
attr_rec->name_length)
|
||||
check_failed("Named resident attribute "
|
||||
"with value before name.\n");
|
||||
}
|
||||
// if resident, length==value_length+value_offset
|
||||
//assert_u32_equal(le32_to_cpu(attr_rec->value_length)+
|
||||
// value_offset, length,
|
||||
// "length==value_length+value_offset");
|
||||
// if resident, length==value_length+value_offset
|
||||
if (value_length+value_offset > length) {
|
||||
check_failed("value_length(%d)+value_offset(%d)>length(%d) for attribute 0x%x.\n", (int)value_length, (int)value_offset, (int)length, (int)attr_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check resident_flags.
|
||||
if (attr_rec->resident_flags>0x01) {
|
||||
check_failed("Unknown resident flags (0x%x) for attribute 0x%x.\n", (int)attr_rec->resident_flags, (int)attr_type);
|
||||
} else if (attr_rec->resident_flags && (attr_type!=0x30)) {
|
||||
check_failed("Resident flags mark attribute 0x%x as indexed.\n", (int)attr_type);
|
||||
}
|
||||
|
||||
// reservedR is 0.
|
||||
assert_u32_equal(attr_rec->reservedR, 0, "Resident Reserved");
|
||||
|
||||
// todo: attribute must not be 0xa0 (not sure about 0xb0, 0xe0, 0xf0)
|
||||
// todo: check content well-formness per attr_type.
|
||||
}
|
||||
return 0;
|
||||
check_attr_record_next_attr:
|
||||
return (ATTR_REC *)(((u8 *)attr_rec) + length);
|
||||
}
|
||||
|
||||
/**
|
||||
* All checks that can be satisfied only by data from the buffer.
|
||||
* No other [MFT records/metadata files] are required.
|
||||
*
|
||||
* The buffer is changed by removing the Update Sequence.
|
||||
*
|
||||
* Return:
|
||||
* 0 Everything's cool.
|
||||
* else Consider this record as damaged.
|
||||
*/
|
||||
static BOOL check_file_record(u8 *buffer, u16 buflen)
|
||||
{
|
||||
u16 usa_count, usa_ofs, attrs_offset, usa;
|
||||
u32 bytes_in_use, bytes_allocated, i;
|
||||
MFT_RECORD *mft_rec = (MFT_RECORD *)buffer;
|
||||
ATTR_REC *attr_rec;
|
||||
|
||||
// check record magic
|
||||
assert_u32_equal(le32_to_cpu(mft_rec->magic), le32_to_cpu(magic_FILE), "FILE record magic");
|
||||
// todo: records 16-23 must be filled in order.
|
||||
// todo: what to do with magic_BAAD?
|
||||
|
||||
// check usa_count+offset to update seq <= attrs_offset <
|
||||
// bytes_in_use <= bytes_allocated <= buflen.
|
||||
usa_ofs = le16_to_cpu(mft_rec->usa_ofs);
|
||||
usa_count = le16_to_cpu(mft_rec->usa_count);
|
||||
attrs_offset = le16_to_cpu(mft_rec->attrs_offset);
|
||||
bytes_in_use = le32_to_cpu(mft_rec->bytes_in_use);
|
||||
bytes_allocated = le32_to_cpu(mft_rec->bytes_allocated);
|
||||
if (assert_u32_lesseq(usa_ofs+usa_count, attrs_offset,
|
||||
"usa_ofs+usa_count <= attrs_offset") ||
|
||||
assert_u32_less(attrs_offset, bytes_in_use,
|
||||
"attrs_offset < bytes_in_use") ||
|
||||
assert_u32_lesseq(bytes_in_use, bytes_allocated,
|
||||
"bytes_in_use <= bytes_allocated") ||
|
||||
assert_u32_lesseq(bytes_allocated, buflen,
|
||||
"bytes_allocated <= max_record_size")) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// We should know all the flags.
|
||||
if (le16_to_cpu(mft_rec->flags) > 0xf) {
|
||||
check_failed("Unknown MFT record flags (0x%x).\n",
|
||||
(unsigned int)le16_to_cpu(mft_rec->flags));
|
||||
}
|
||||
// todo: flag in_use must be on.
|
||||
|
||||
// Remove update seq & check it.
|
||||
usa = *(u16*)(buffer+usa_ofs); // The value that should be at the end of every sector.
|
||||
if (assert_u32_equal(usa_count-1, buflen/NTFS_BLOCK_SIZE, "USA length"))
|
||||
return (1);
|
||||
for (i=1;i<usa_count;i++) {
|
||||
u16 *fixup = (u16*)(buffer+NTFS_BLOCK_SIZE*i-2); // the value at the end of the sector.
|
||||
u16 saved_val = *(u16*)(buffer+usa_ofs+2*i); // the actual data value that was saved in the us array.
|
||||
|
||||
assert_u32_equal(*fixup, usa, "fixup");
|
||||
*fixup = saved_val; // remove it.
|
||||
}
|
||||
|
||||
attr_rec = (ATTR_REC *)(buffer + attrs_offset);
|
||||
while ((u8*)attr_rec<=buffer+buflen-4) {
|
||||
|
||||
// Check attribute record. (Only what is in the buffer)
|
||||
if (attr_rec->type==AT_END) {
|
||||
// Done.
|
||||
return 0;
|
||||
}
|
||||
if ((u8*)attr_rec>buffer+buflen-8) {
|
||||
// not AT_END yet no room for the length field.
|
||||
check_failed("Attribute 0x%x is not AT_END, yet no "
|
||||
"room for the length field.\n",
|
||||
(int)le32_to_cpu(attr_rec->type));
|
||||
return 1;
|
||||
}
|
||||
|
||||
attr_rec = check_attr_record(attr_rec, mft_rec, buflen);
|
||||
if (!attr_rec)
|
||||
return 1;
|
||||
}
|
||||
// If we got here, there was an overflow.
|
||||
return 1;
|
||||
|
||||
// todo: an attribute should be at the offset to first attribute, and the offset should be inside the buffer. It should have the value of "next attribute id".
|
||||
// todo: if base record, it should start with attribute 0x10.
|
||||
|
||||
// Highlevel check of attributes.
|
||||
// todo: Attributes are well-formed.
|
||||
// todo: Room for next attribute in the end of the previous record.
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void replay_log(ntfs_volume *vol __attribute__((unused)))
|
||||
{
|
||||
// At this time, only check that the log is fully replayed.
|
||||
ntfs_log_warning("Unsupported: replay_log()\n");
|
||||
// todo: if logfile is clean, return success.
|
||||
unsupported++;
|
||||
}
|
||||
|
||||
static void verify_mft_record(ntfs_volume *vol, s64 mft_num)
|
||||
{
|
||||
u8 *buffer;
|
||||
int is_used;
|
||||
|
||||
current_mft_record = mft_num;
|
||||
|
||||
is_used = mft_bitmap_get_bit(mft_num);
|
||||
if (is_used<0) {
|
||||
ntfs_log_error("Error getting bit value for record %lld.\n",
|
||||
(long long)mft_num);
|
||||
} else if (!is_used) {
|
||||
ntfs_log_verbose("Record %lld unused. Skipping.\n",
|
||||
(long long)mft_num);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = ntfs_malloc(vol->mft_record_size);
|
||||
if (!buffer)
|
||||
goto verify_mft_record_error;
|
||||
|
||||
ntfs_log_verbose("MFT record %lld\n", (long long)mft_num);
|
||||
if (ntfs_attr_pread(vol->mft_na, mft_num*vol->mft_record_size, vol->mft_record_size, buffer) < 0) {
|
||||
ntfs_log_perror("Couldn't read $MFT record %lld", (long long)mft_num);
|
||||
goto verify_mft_record_error;
|
||||
}
|
||||
|
||||
check_file_record(buffer, vol->mft_record_size);
|
||||
// todo: if offset to first attribute >= 0x30, number of mft record should match.
|
||||
// todo: Match the "record is used" with the mft bitmap.
|
||||
// todo: if this is not base, check that the parent is a base, and is in use, and pointing to this record.
|
||||
|
||||
// todo: if base record: for each extent record:
|
||||
// todo: verify_file_record
|
||||
// todo: hard link count should be the number of 0x30 attributes.
|
||||
// todo: Order of attributes.
|
||||
// todo: make sure compression_unit is the same.
|
||||
|
||||
return;
|
||||
verify_mft_record_error:
|
||||
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
errors++;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function serves as bootstraping for the more comprehensive checks.
|
||||
* It will load the MFT runlist and MFT/Bitmap runlist.
|
||||
* It should not depend on other checks or we may have a circular dependancy.
|
||||
* Also, this loadng must be forgiving, unlike the comprehensive checks.
|
||||
*/
|
||||
static int verify_mft_preliminary(ntfs_volume *rawvol)
|
||||
{
|
||||
current_mft_record = 0;
|
||||
s64 mft_offset, mftmirr_offset;
|
||||
int res;
|
||||
|
||||
ntfs_log_trace("Entering verify_mft_preliminary().\n");
|
||||
// todo: get size_of_file_record from boot sector
|
||||
// Load the first segment of the $MFT/DATA runlist.
|
||||
mft_offset = rawvol->mft_lcn * rawvol->cluster_size;
|
||||
mftmirr_offset = rawvol->mftmirr_lcn * rawvol->cluster_size;
|
||||
mft_rl = load_runlist(rawvol, mft_offset, AT_DATA, 1024);
|
||||
if (!mft_rl) {
|
||||
check_failed("Loading $MFT runlist failed. Trying $MFTMirr.\n");
|
||||
mft_rl = load_runlist(rawvol, mftmirr_offset, AT_DATA, 1024);
|
||||
}
|
||||
if (!mft_rl) {
|
||||
check_failed("Loading $MFTMirr runlist failed too. Aborting.\n");
|
||||
return RETURN_FS_ERRORS_LEFT_UNCORRECTED | RETURN_OPERATIONAL_ERROR;
|
||||
}
|
||||
// TODO: else { recover $MFT } // Use $MFTMirr to recover $MFT.
|
||||
// todo: support loading the next runlist extents when ATTRIBUTE_LIST is used on $MFT.
|
||||
// If attribute list: Gradually load mft runlist. (parse runlist from first file record, check all referenced file records, continue with the next file record). If no attribute list, just load it.
|
||||
|
||||
// Load the runlist of $MFT/Bitmap.
|
||||
// todo: what about ATTRIBUTE_LIST? Can we reuse code?
|
||||
mft_bitmap_rl = load_runlist(rawvol, mft_offset, AT_BITMAP, 1024);
|
||||
if (!mft_bitmap_rl) {
|
||||
check_failed("Loading $MFT/Bitmap runlist failed. Trying $MFTMirr.\n");
|
||||
mft_bitmap_rl = load_runlist(rawvol, mftmirr_offset, AT_BITMAP, 1024);
|
||||
}
|
||||
if (!mft_bitmap_rl) {
|
||||
check_failed("Loading $MFTMirr/Bitmap runlist failed too. Aborting.\n");
|
||||
return RETURN_FS_ERRORS_LEFT_UNCORRECTED;
|
||||
// todo: rebuild the bitmap by using the "in_use" file record flag or by filling it with 1's.
|
||||
}
|
||||
|
||||
/* Load $MFT/Bitmap */
|
||||
if ((res = mft_bitmap_load(rawvol)))
|
||||
return res;
|
||||
return -1; /* FIXME: Just added to fix compiler warning without
|
||||
thinking about what should be here. (Yura) */
|
||||
}
|
||||
|
||||
static void check_volume(ntfs_volume *vol)
|
||||
{
|
||||
s64 mft_num, nr_mft_records;
|
||||
|
||||
ntfs_log_warning("Unsupported: check_volume()\n");
|
||||
unsupported++;
|
||||
|
||||
// For each mft record, verify that it contains a valid file record.
|
||||
nr_mft_records = vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits;
|
||||
ntfs_log_info("Checking %lld MFT records.\n", (long long)nr_mft_records);
|
||||
|
||||
for (mft_num=0; mft_num < nr_mft_records; mft_num++) {
|
||||
verify_mft_record(vol, mft_num);
|
||||
}
|
||||
|
||||
// todo: Check metadata files.
|
||||
|
||||
// todo: Second pass on mft records. Now check the contents as well.
|
||||
// todo: When going through runlists, build a bitmap.
|
||||
|
||||
// todo: cluster accounting.
|
||||
return;
|
||||
}
|
||||
|
||||
static int reset_dirty(ntfs_volume *vol)
|
||||
{
|
||||
le16 flags;
|
||||
|
||||
if (!(vol->flags | VOLUME_IS_DIRTY))
|
||||
return 0;
|
||||
|
||||
ntfs_log_verbose("Resetting dirty flag.\n");
|
||||
|
||||
flags = vol->flags & ~VOLUME_IS_DIRTY;
|
||||
|
||||
if (ntfs_volume_write_flags(vol, flags)) {
|
||||
ntfs_log_error("Error setting volume flags.\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* main - Does just what C99 claim it does.
|
||||
*
|
||||
* For more details on arguments and results, check the man page.
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ntfs_device *dev;
|
||||
ntfs_volume rawvol;
|
||||
ntfs_volume *vol;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
if (argc != 2)
|
||||
return RETURN_USAGE_OR_SYNTAX_ERROR;
|
||||
name = argv[1];
|
||||
|
||||
ntfs_log_set_handler(ntfs_log_handler_outerr);
|
||||
//ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG | NTFS_LOG_LEVEL_TRACE | NTFS_LOG_LEVEL_QUIET | NTFS_LOG_LEVEL_INFO | NTFS_LOG_LEVEL_VERBOSE | NTFS_LOG_LEVEL_PROGRESS);
|
||||
|
||||
/* Allocate an ntfs_device structure. */
|
||||
dev = ntfs_device_alloc(name, 0, &ntfs_device_default_io_ops, NULL);
|
||||
if (!dev)
|
||||
return RETURN_OPERATIONAL_ERROR;
|
||||
if (dev->d_ops->open(dev, O_RDONLY)) { //O_RDWR/O_RDONLY?
|
||||
ntfs_log_perror("Error opening partition device");
|
||||
ntfs_device_free(dev);
|
||||
return RETURN_OPERATIONAL_ERROR;
|
||||
}
|
||||
|
||||
if ((ret = verify_boot_sector(dev,&rawvol))) {
|
||||
dev->d_ops->close(dev);
|
||||
return ret;
|
||||
}
|
||||
ntfs_log_verbose("Boot sector verification complete. Proceeding to $MFT");
|
||||
|
||||
verify_mft_preliminary(&rawvol);
|
||||
|
||||
/* ntfs_device_mount() expects the device to be closed. */
|
||||
if (dev->d_ops->close(dev))
|
||||
ntfs_log_perror("Failed to close the device.");
|
||||
|
||||
// at this point we know that the volume is valid enough for mounting.
|
||||
|
||||
/* Call ntfs_device_mount() to do the actual mount. */
|
||||
vol = ntfs_device_mount(dev, NTFS_MNT_RDONLY);
|
||||
if (!vol) {
|
||||
ntfs_device_free(dev);
|
||||
return 2;
|
||||
}
|
||||
|
||||
replay_log(vol);
|
||||
|
||||
if (vol->flags & VOLUME_IS_DIRTY)
|
||||
ntfs_log_warning("Volume is dirty.\n");
|
||||
|
||||
check_volume(vol);
|
||||
|
||||
if (errors)
|
||||
ntfs_log_info("Errors found.\n");
|
||||
if (unsupported)
|
||||
ntfs_log_info("Unsupported cases found.\n");
|
||||
|
||||
if (!errors && !unsupported) {
|
||||
reset_dirty(vol);
|
||||
}
|
||||
|
||||
ntfs_umount(vol, FALSE);
|
||||
|
||||
if (errors)
|
||||
return 2;
|
||||
if (unsupported)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
.\" Copyright (c) 2003\-2005 Richard Russon.
|
||||
.\" Copyright (c) 2003\-2006 Szabolcs Szakacsits.
|
||||
.\" Copyright (c) 2004 Per Olofsson.
|
||||
.\" Copyright (c) 2010\-2013 Jean-Pierre Andre.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSCLONE 8 "February 2013" "ntfs-3g @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 cloning but itself it's not enough.
|
||||
.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.
|
||||
This mode may be combined with \fB\-\-save\-image\fP to create a
|
||||
special image format file instead of a sparse file.
|
||||
|
||||
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. This option cannot be used for creating a partition,
|
||||
use \fB\-\-overwrite\fR for an existing partition.
|
||||
.TP
|
||||
\fB\-O\fR, \fB\-\-overwrite\fR FILE
|
||||
Clone NTFS to
|
||||
.IR FILE ,
|
||||
which can be an existing partition or a regular file which will be
|
||||
overwritten if it 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\-n\fR, \fB\-\-no\-action\fR
|
||||
Test the consistency of a saved image by simulating its restoring without
|
||||
writing anything. The NTFS data contained in the image is not tested.
|
||||
The option \fB\-\-restore\-image\fR must also be present, and the options
|
||||
\fB\-\-output\fR and \fB\-\-overwrite\fR must be omitted.
|
||||
.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). Only cloning to a (sparse) file is allowed, unless used
|
||||
the option \fB\-\-save\-image\fP is also used.
|
||||
You can't metadata\-only clone to a device.
|
||||
.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\-t\fR, \fB\-\-preserve\-timestamps\fR
|
||||
Do not wipe the timestamps, to be used only with the
|
||||
.B \-\-metadata
|
||||
option.
|
||||
.TP
|
||||
\fB\-\-full\-logfile\fR
|
||||
Include the Windows log file in the copy. This is only useful for
|
||||
extracting metadata, saving or cloning a file system which was not
|
||||
properly unmounted from Windows.
|
||||
.TP
|
||||
\fB\-\-new\-serial\fR, or
|
||||
.TP
|
||||
\fB\-\-new\-half\-serial\fR
|
||||
Set a new random serial number to the clone. The serial number is a 64
|
||||
bit number used to identify the device during the mounting process, so
|
||||
it has to be changed to enable the original file system
|
||||
and the clone to be mounted at the same time on the same computer.
|
||||
|
||||
The option \fB\-\-new\-half\-serial\fP only changes the upper part of the
|
||||
serial number, keeping the lower part which is used by Windows unchanged.
|
||||
|
||||
The options \fB\-\-new\-serial\fP and \fB\-\-new\-half\-serial\fP can
|
||||
only be used when cloning a file system of restoring from an image.
|
||||
|
||||
The serial number is not the volume UUID used by Windows
|
||||
to locate files which have been moved to another volume.
|
||||
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-force\fR
|
||||
Forces ntfsclone to proceed if the filesystem is marked
|
||||
"dirty" for consistency check.
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
Do not display any progress-bars during operation.
|
||||
.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 on a sparse file.
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsclone \-\-metadata \-\-output ntfsmeta.img /dev/hda1
|
||||
.br
|
||||
.B bzip2 ntfsmeta.img
|
||||
.sp
|
||||
Or, outputting to a compressed image :
|
||||
.br
|
||||
.B ntfsclone \-mst \-\-output - /dev/hda1 | bzip2 > ntfsmeta.bz2
|
||||
.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
|
||||
ntfs\-3g\-devel@lists.sf.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.
|
||||
It was ported to ntfs-3g by Erik Larsson and Jean-Pierre Andre.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsclone
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available at:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfsresize (8)
|
||||
.BR ntfsprogs (8)
|
||||
.BR xfs_copy (8)
|
||||
.BR debugreiserfs (8)
|
||||
.BR e2image (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,124 @@
|
||||
.\" Copyright (c) 2003\-2005 Richard Russon.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSCLUSTER 8 "November 2005" "ntfs-3g @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 \fB\-\-verbose\fR
|
||||
.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
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfscluster
|
||||
was written by Richard Russon, with contributions from Anton Altaparmakov.
|
||||
It was ported to ntfs-3g by Erik Larsson.
|
||||
.SH AVAILABILITY
|
||||
.B ntfscluster
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfsinfo (8),
|
||||
.BR ntfsprogs (8)
|
||||
@@ -0,0 +1,580 @@
|
||||
/**
|
||||
* 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 "ntfscluster.h"
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
#include "utils.h"
|
||||
#include "volume.h"
|
||||
#include "debug.h"
|
||||
#include "dir.h"
|
||||
#include "cluster.h"
|
||||
/* #include "version.h" */
|
||||
#include "logging.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':
|
||||
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;
|
||||
case '?':
|
||||
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
|
||||
if (!ntfs_log_parse_option (argv[optind-1]))
|
||||
err++;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
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();
|
||||
|
||||
/* tri-state 0 : done, 1 : error, -1 : proceed */
|
||||
return (err ? 1 : (help || ver ? 0 : -1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 - ", (int)le32_to_cpu(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 res;
|
||||
int result = 1;
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
char *unix_name;
|
||||
#endif
|
||||
|
||||
ntfs_log_set_handler(ntfs_log_handler_outerr);
|
||||
|
||||
res = parse_options(argc, argv);
|
||||
if (res >= 0)
|
||||
return (res);
|
||||
|
||||
utils_set_locale();
|
||||
|
||||
vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY |
|
||||
(opts.force ? NTFS_MNT_RECOVER : 0));
|
||||
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:
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
unix_name = ntfs_utils_unix_path(opts.filename);
|
||||
ino = 0;
|
||||
if (unix_name) {
|
||||
ino = ntfs_pathname_to_inode(vol, NULL,
|
||||
unix_name);
|
||||
free(unix_name);
|
||||
}
|
||||
#else
|
||||
ino = ntfs_pathname_to_inode(vol, NULL, opts.filename);
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 "types.h"
|
||||
#include "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 */
|
||||
};
|
||||
|
||||
#endif /* _NTFSCLUSTER_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
.\" Copyright (c) 2005\-2006 Szabolcs Szakacsits.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSCMP 8 "April 2006" "ntfs-3g @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
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHOR
|
||||
.B ntfscmp
|
||||
was written by Szabolcs Szakacsits.
|
||||
It was ported to ntfs-3g by Erik Larsson.
|
||||
.SH AVAILABILITY
|
||||
.B ntfscmp
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfsinfo (8),
|
||||
.BR ntfscat (8),
|
||||
.BR diff (1),
|
||||
.BR ntfsclone (8),
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,119 @@
|
||||
.\" Copyright (c) 2004\-2007 Yura Pakhuchiy.
|
||||
.\" Copyright (c) 2005 Richard Russon.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSCP 8 "September 2007" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
ntfscp \- copy file to an NTFS volume.
|
||||
.SH SYNOPSIS
|
||||
\fBntfscp\fR [\fIoptions\fR] \fIdevice source_file destination\fR
|
||||
.SH DESCRIPTION
|
||||
\fBntfscp\fR will copy file to an NTFS volume. \fIdestination\fR can be either
|
||||
file or directory. In case if \fIdestination\fR is directory specified by name
|
||||
then \fIsource_file\fR is copied into this directory, in case if
|
||||
\fIdestination\fR is directory and specified by inode number then unnamed data
|
||||
attribute is created for this inode and \fIsource_file\fR 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\-m\fR, \fB\-\-min-fragments\fR
|
||||
Minimize fragmentation when allocating space to the attribute. This is
|
||||
mostly useful when creating big files.
|
||||
.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\-t\fR, \fB\-\-timestamp\fR
|
||||
Copy the modification time of source_file to destination. This is
|
||||
not compatible with \fB\-\-attr\-name\fR and \fB\-\-attribute\fR.
|
||||
.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 \fBntfscp\fR. If you find a bug please send an
|
||||
email describing the problem to the development team:
|
||||
.br
|
||||
.nh
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
\fBntfscp\fR was written by Yura Pakhuchiy, with contributions from Anton
|
||||
Altaparmakov and Hil Liao.
|
||||
It was ported to ntfs-3g by Erik Larsson.
|
||||
.SH DEDICATION
|
||||
With love to Marina Sapego.
|
||||
.SH AVAILABILITY
|
||||
.B ntfscp
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,129 @@
|
||||
.\" Copyright (c) 2014 Jean-Pierre Andre
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSDECRYPT 8 "June 2014" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
ntfsdecrypt \- decrypt or update NTFS files encrypted according to EFS
|
||||
.SH SYNOPSIS
|
||||
\fBntfsdecrypt\fR [\fIoptions\fR] -k \fIkey.pfx \fIdevice file\fR
|
||||
.SH DESCRIPTION
|
||||
.B ntfsdecrypt
|
||||
decrypts a file from an unmounted device and print the decrypted data
|
||||
on the standard output.
|
||||
It can also update an encrypted file with the encryption key unchanged.
|
||||
.PP
|
||||
The NTFS file encryption (known as EFS) uses a two-level encryption :
|
||||
first, the file contents is encrypted with a random symmetric key, then
|
||||
this symmetric key is encrypted with the public keys of each of the users
|
||||
allowed to decrypt the file (RSA public key encryptions).
|
||||
.P
|
||||
Three symmetric encryption modes are currently implemented in ntfsdecrypt :
|
||||
DESX (a DES variant), 3DES (triple DES) and AES_256 (an AES variant).
|
||||
.P
|
||||
All the encrypted symmetric keys are stored along with the file in a
|
||||
special extended attribute named "$LOGGED_UTILITY_STREAM".
|
||||
Usually, at least two users are allowed to read the file : its owner and
|
||||
the recovery manager who is able to decrypt all the files in a company.
|
||||
When backing up an encrypted file, it is important to also backup the
|
||||
corresponding $LOGGED_UTILITY_STREAM, otherwise the file cannot be
|
||||
decrypted, even by the recovery manager. Also note that encrypted files
|
||||
are slightly bigger than apparent, and the option "efs_raw" has
|
||||
to be used when backing up encrypted files with ntfs-3g.
|
||||
.P
|
||||
When ntfsdecrypt is used to update a file, the keys and the
|
||||
$LOGGED_UTILITY_STREAM are kept unchanged, so a single key file has to
|
||||
be designated.
|
||||
.P
|
||||
Note : the EFS encryption is only available in professional versions
|
||||
of Windows;
|
||||
.SH OPTIONS
|
||||
Below is a summary of all the options that
|
||||
.B ntfsdecrypt
|
||||
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\-\-inode\fR NUM
|
||||
Display or update the contents of a file designated through its inode number
|
||||
instead of its name.
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-encrypt\fR
|
||||
Update an existing encrypted file and get the new contents from the
|
||||
standard input. The full public and private key file has to be designated,
|
||||
as the symmetric key is kept unchanged, so the private key is needed to
|
||||
extract it.
|
||||
.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\-k\fR, \fB\-\-keyfile\-name\fR key.pfx
|
||||
Define the file which contains the public and private keys in PKCS#12 format.
|
||||
This file obviously contains the keys of one of the users allowed to decrypt
|
||||
or update the file. It has to be extracted from Windows in PKCS#12 format
|
||||
(its usual suffix is .p12 or .pfx), and it is protected by a passphrase
|
||||
which has to be typed in for the keys to be extracted. This can be the
|
||||
key file of any user allowed to read the file, including the one of the
|
||||
recovery manager.
|
||||
.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 of
|
||||
.BR ntfsdecrypt .
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Display more debug/warning/error messages.
|
||||
.SH EXAMPLES
|
||||
Display the contents of the file hamlet.doc in the directory Documents of
|
||||
the root of the NTFS file system on the device /dev/sda1
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsdecrypt -k foo.key /dev/sda1 Documents/hamlet.doc
|
||||
.sp
|
||||
.RE
|
||||
Update the file hamlet.doc
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsdecrypt -k foo.key /dev/sda1 Documents/hamlet.doc < new.doc
|
||||
.sp
|
||||
.RE
|
||||
.SH BUGS
|
||||
There are no known problems with
|
||||
.BR ntfsdecrypt .
|
||||
If you find a bug please send an email describing the problem to the
|
||||
development team:
|
||||
.br
|
||||
.nh
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfsdecrypt
|
||||
was written by Yuval Fledel, Anton Altaparmakov and Yura Pakhuchiy.
|
||||
It was ported to ntfs-3g by Erik Larsson and upgraded by Jean-Pierre Andre.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsdecrypt
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
Read \fBntfs-3g\fR(8) for details on option efs_raw,
|
||||
.RE
|
||||
.BR ntfscat (8),
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
+781
@@ -0,0 +1,781 @@
|
||||
/**
|
||||
* 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 "types.h"
|
||||
#include "endians.h"
|
||||
#include "volume.h"
|
||||
#include "inode.h"
|
||||
#include "attrib.h"
|
||||
#include "layout.h"
|
||||
#include "logfile.h"
|
||||
#include "mst.h"
|
||||
#include "utils.h"
|
||||
/* #include "version.h" */
|
||||
#include "logging.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;
|
||||
|
||||
/* Porting note: NTFS_MNT_FORENSIC is not needed when we mount
|
||||
* the volume in read-only mode. No changes will be made to the
|
||||
* logfile or anything else when we are in read only-mode. */
|
||||
vol = ntfs_mount(filename, NTFS_MNT_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;
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd == -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, "Failed to open file %s: %s\n",
|
||||
filename, strerror(errno));
|
||||
}
|
||||
|
||||
if (fstat(fd, &sbuf) == -1) {
|
||||
log_err_exit(NULL, "Error getting information about "
|
||||
"%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) < offsetof(RESTART_PAGE_HEADER, usn))
|
||||
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)sle64_to_cpu(lr->this_lsn));
|
||||
ntfs_log_info("client previous lsn = 0x%llx\n", (unsigned long long)
|
||||
sle64_to_cpu(lr->client_previous_lsn));
|
||||
ntfs_log_info("client undo next lsn = 0x%llx\n", (unsigned long long)
|
||||
sle64_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:", le16_to_cpu(lr->log_record_flags));
|
||||
if (!lr->log_record_flags)
|
||||
ntfs_log_info(" NONE\n");
|
||||
else {
|
||||
int _b = 0;
|
||||
|
||||
if (lr->log_record_flags & LOG_RECORD_MULTI_PAGE) {
|
||||
ntfs_log_info(" LOG_RECORD_MULTI_PAGE");
|
||||
_b = 1;
|
||||
}
|
||||
if (lr->log_record_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]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
sle64_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)
|
||||
le16_to_cpu(rcrd->next_record_offset));
|
||||
ntfs_log_info("header.last_end_lsn = 0x%llx\n", (unsigned long long)
|
||||
sle64_to_cpu(rcrd->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 +
|
||||
le16_to_cpu(rcrd->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;
|
||||
}
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
.\" Copyright (c) 2014 Jean-Pierre Andre
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSFALLOCATE 8 "June 2014" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
ntfsfallocate \- preallocate space to a file on an NTFS volume
|
||||
.SH SYNOPSIS
|
||||
\fBntfsfallocate\fR [\fIoptions\fR] -l \fIlength\fR \fIdevice\fR \fIfile\fR \fI[attr-type\fR [\fIattr-name\fR]]
|
||||
.SH DESCRIPTION
|
||||
.B ntfsfallocate
|
||||
preallocates space for any attribute of a file or directory, thus reserving
|
||||
space before actual contents is written. This is similar to fallocate(1).
|
||||
.SH OPTIONS
|
||||
Below is a summary of all the options that
|
||||
.B ntfsfallocate
|
||||
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 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\-l\fR, \fB\-\-length\fR LENGTH
|
||||
This is a mandatory option to specify the number of bytes to preallocate.
|
||||
It will be rounded up to a multiple of the cluster size.
|
||||
A suffix of K, M, G, T, P or E may be appended to
|
||||
mean a multiplicative factor of a power of 1000. Similarly a suffix of
|
||||
Ki, Mi, Gi, Ti, Pi or Ei may be appended to mean a multiplicative factor
|
||||
of a power of 1024.
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-no-size-change\fR
|
||||
Do not change the apparent size of the file. The space allocated beyond
|
||||
the apparent size is not zeroed, but subsequent writing beyond the apparent
|
||||
end of file will force zeroing the inner allocated space as it cannot be
|
||||
considered as a hole any more, and this may take significant time.
|
||||
.TP
|
||||
\fB\-N\fR, \fB\-\-no-action\fR
|
||||
Simulate the allocation without actually write to device.
|
||||
.TP
|
||||
\fB\-o\fR, \fB\-\-offset\fR OFFSET
|
||||
Specify the offset in the file where preallocation starts. By default,
|
||||
the preallocation is counted from the beginning of the file. Space already
|
||||
allocated in the area defined by offset and length is preserved.
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
Suppress some debug/warning/error messages.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Display more debug/warning/error messages.
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
Show the version number, copyright and license of
|
||||
.BR ntfsfallocate .
|
||||
.TP
|
||||
\fBattr-type\fR
|
||||
Define a particular attribute type to be preallocated (advanced use only).
|
||||
By default, the unnamed $DATA attribute (the contents of a plain file) will
|
||||
be preallocated. The attribute has to be specified by a number in decimal
|
||||
or hexadecimal :
|
||||
.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
|
||||
.TP
|
||||
\fBattr-name\fR
|
||||
Define the name of the particular attribute type to be preallocated
|
||||
(advanced use only).
|
||||
.SH EXAMPLES
|
||||
Preallocate 100MB to the file database.db located in the Data directory
|
||||
which is at the root of an NTFS file system.
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsfallocate -l 100M /dev/sda1 Data/database.db
|
||||
.sp
|
||||
.RE
|
||||
.SH BUGS
|
||||
There are no known problems with
|
||||
.BR ntfsfallocate ,
|
||||
however it can lead to configurations not supported by Windows
|
||||
and Windows may crash (BSOD) when writing to preallocated clusters
|
||||
which were not written to earlier. Files with preallocated space should
|
||||
be fully be written to before they are updated by Windows.
|
||||
.P
|
||||
If you find a bug in \fBntfsfallocate\fR proper, please send an email
|
||||
describing the problem to the development team:
|
||||
.br
|
||||
.nh
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfsfallocate
|
||||
was written by Jean-Pierre Andre.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsfallocate
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfs-3g (8),
|
||||
.BR ntfstruncate (8),
|
||||
.BR ntfsprogs (8),
|
||||
.BR fallocate (1)
|
||||
@@ -0,0 +1,905 @@
|
||||
/**
|
||||
* ntfsfallocate
|
||||
*
|
||||
* Copyright (c) 2013-2020 Jean-Pierre Andre
|
||||
*
|
||||
* This utility will allocate clusters to a specified attribute belonging
|
||||
* to a specified file or directory, to a specified length.
|
||||
*
|
||||
* WARNING : this can lead to configurations not supported by Windows
|
||||
* and Windows may crash (BSOD) when writing to preallocated clusters
|
||||
* which were not written to.
|
||||
*
|
||||
* 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_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.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 "types.h"
|
||||
#include "attrib.h"
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
#include "logging.h"
|
||||
#include "runlist.h"
|
||||
#include "dir.h"
|
||||
#include "bitmap.h"
|
||||
#include "lcnalloc.h"
|
||||
#include "utils.h"
|
||||
#include "misc.h"
|
||||
|
||||
const char *EXEC_NAME = "ntfsfallocate";
|
||||
|
||||
char *dev_name;
|
||||
const char *file_name;
|
||||
le32 attr_type;
|
||||
ntfschar *attr_name = NULL;
|
||||
u32 attr_name_len;
|
||||
s64 opt_alloc_offs;
|
||||
s64 opt_alloc_len;
|
||||
|
||||
ATTR_DEF *attr_defs;
|
||||
|
||||
static struct {
|
||||
/* -h, print usage and exit. */
|
||||
int no_action; /* do not write to device, only display
|
||||
what would be done. */
|
||||
int no_size_change; /* -n, do not change the apparent size */
|
||||
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;
|
||||
|
||||
static const struct option lopt[] = {
|
||||
{ "offset", required_argument, NULL, 'o' },
|
||||
{ "length", required_argument, NULL, 'l' },
|
||||
{ "force", no_argument, NULL, 'f' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "no-action", no_argument, NULL, 'N' },
|
||||
{ "no-size-change", no_argument, NULL, 'n' },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
/**
|
||||
* err_exit - error output and terminate; ignores quiet (-q)
|
||||
*
|
||||
* DO NOT USE when allocations are not in initial state
|
||||
*/
|
||||
__attribute__((noreturn))
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
static void err_exit(ntfs_volume *vol, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "ERROR: ");
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "Aborting...\n");
|
||||
if (vol && ntfs_umount(vol, 0))
|
||||
fprintf(stderr, "Warning: Could not umount %s\n", dev_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* copyright - print copyright statements
|
||||
*/
|
||||
static void copyright(void)
|
||||
{
|
||||
fprintf(stderr, "Copyright (c) 2013-2014 Jean-Pierre Andre\n"
|
||||
"Allocate clusters to a specified attribute of "
|
||||
"a specified file.\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(int ret)
|
||||
{
|
||||
copyright();
|
||||
fprintf(stderr, "Usage: %s [options] -l length device file [attr-type "
|
||||
"[attr-name]]\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"
|
||||
" -f Force execution despite errors\n"
|
||||
" -n Do not change the apparent size of file\n"
|
||||
" -l length Allocate length bytes\n"
|
||||
" -o offset Start allocating at offset\n"
|
||||
" -v Verbose execution\n"
|
||||
" -vv Very verbose execution\n"
|
||||
" -V Display version information\n"
|
||||
" -h Display this help\n", EXEC_NAME);
|
||||
fprintf(stderr, "%s%s", ntfs_bugs, ntfs_home);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* err_exit - error output, display usage and exit
|
||||
*/
|
||||
__attribute__((noreturn))
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
static void err_usage(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "ERROR: ");
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
usage(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a value option with a possible multiple suffix
|
||||
*/
|
||||
|
||||
static s64 option_value(const char *arg)
|
||||
{
|
||||
s64 ll;
|
||||
char *s;
|
||||
s64 fact;
|
||||
int count;
|
||||
BOOL err;
|
||||
|
||||
err = FALSE;
|
||||
ll = strtoll(arg, &s, 0);
|
||||
if ((ll >= LLONG_MAX) && (errno == ERANGE))
|
||||
err_exit((ntfs_volume*)NULL, "Too big value : %s\n",arg);
|
||||
if (*s) {
|
||||
count = 0;
|
||||
switch (*s++) {
|
||||
case 'E' : count++;
|
||||
/* FALLTHRU */
|
||||
case 'P' : count++;
|
||||
/* FALLTHRU */
|
||||
case 'T' : count++;
|
||||
/* FALLTHRU */
|
||||
case 'G' : count++;
|
||||
/* FALLTHRU */
|
||||
case 'M' : count++;
|
||||
/* FALLTHRU */
|
||||
case 'K' : count++;
|
||||
switch (*s++) {
|
||||
case 'i' :
|
||||
fact = 1024;
|
||||
if (*s++ != 'B')
|
||||
err = TRUE;
|
||||
break;
|
||||
case 'B' :
|
||||
fact = 1000;
|
||||
break;
|
||||
case '\0' :
|
||||
fact = 1024;
|
||||
s--;
|
||||
break;
|
||||
default :
|
||||
err = TRUE;
|
||||
fact = 1;
|
||||
break;
|
||||
}
|
||||
if (*s)
|
||||
err = TRUE;
|
||||
break;
|
||||
default :
|
||||
err = TRUE;
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
err_exit((ntfs_volume*)NULL,
|
||||
"Invalid suffix in : %s\n",arg);
|
||||
else
|
||||
while (count-- > 0) {
|
||||
if (ll > LLONG_MAX/1024)
|
||||
err_exit((ntfs_volume*)NULL,
|
||||
"Too big value : %s\n",arg);
|
||||
ll *= fact;
|
||||
}
|
||||
}
|
||||
return (ll);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* parse_options
|
||||
*/
|
||||
static void parse_options(int argc, char *argv[])
|
||||
{
|
||||
long long ll;
|
||||
char *s, *s2;
|
||||
int c;
|
||||
|
||||
opt_alloc_len = 0;
|
||||
opt_alloc_offs = 0;
|
||||
if (argc && *argv)
|
||||
EXEC_NAME = *argv;
|
||||
fprintf(stderr, "%s v%s (libntfs-3g)\n", EXEC_NAME, VERSION);
|
||||
while ((c = getopt_long(argc, argv, "fh?no:qvVl:", lopt, NULL)) != EOF) {
|
||||
switch (c) {
|
||||
case 'f':
|
||||
opts.force = 1;
|
||||
break;
|
||||
case 'n':
|
||||
opts.no_size_change = 1;
|
||||
break;
|
||||
case 'N': /* Not proposed as a short option */
|
||||
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 */
|
||||
license();
|
||||
exit(0);
|
||||
case 'l':
|
||||
ll = option_value(argv[optind - 1]);
|
||||
if ((ll <= 0)
|
||||
|| (ll >= LLONG_MAX && errno == ERANGE))
|
||||
err_usage("Invalid length : %s\n",
|
||||
argv[optind - 1]);
|
||||
opt_alloc_len = ll;
|
||||
break;
|
||||
case 'o':
|
||||
ll = option_value(argv[optind - 1]);
|
||||
if ((ll < 0)
|
||||
|| (ll >= LLONG_MAX && errno == ERANGE))
|
||||
err_usage("Invalid offset : %s\n",
|
||||
argv[optind - 1]);
|
||||
opt_alloc_offs = ll;
|
||||
break;
|
||||
case 'h':
|
||||
usage(0);
|
||||
case '?':
|
||||
default:
|
||||
usage(1);
|
||||
}
|
||||
}
|
||||
if (!opt_alloc_len) {
|
||||
err_usage("Missing allocation length\n");
|
||||
}
|
||||
|
||||
ntfs_log_verbose("length = %lli = 0x%llx\n",
|
||||
(long long)opt_alloc_len, (long long)opt_alloc_len);
|
||||
ntfs_log_verbose("offset = %lli = 0x%llx\n",
|
||||
(long long)opt_alloc_offs, (long long)opt_alloc_offs);
|
||||
|
||||
if (optind == argc)
|
||||
usage(1);
|
||||
|
||||
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(1);
|
||||
|
||||
/* Get the file name. */
|
||||
file_name = argv[optind++];
|
||||
ntfs_log_verbose("file name = \"%s\"\n", file_name);
|
||||
|
||||
/* Get the attribute type, if specified. */
|
||||
if (optind == argc) {
|
||||
attr_type = AT_DATA;
|
||||
attr_name = AT_UNNAMED;
|
||||
attr_name_len = 0;
|
||||
} else {
|
||||
unsigned long ul;
|
||||
|
||||
s = argv[optind++];
|
||||
ul = strtoul(s, &s2, 0);
|
||||
if (*s2 || !ul || (ul >= ULONG_MAX && errno == ERANGE))
|
||||
err_usage("Invalid attribute type %s: %s\n", s,
|
||||
strerror(errno));
|
||||
attr_type = cpu_to_le32(ul);
|
||||
|
||||
/* Get the attribute name, if specified. */
|
||||
if (optind != argc) {
|
||||
s = argv[optind++];
|
||||
/* Convert the string to little endian Unicode. */
|
||||
attr_name_len = ntfs_mbstoucs(s, &attr_name);
|
||||
if ((int)attr_name_len < 0)
|
||||
err_usage("Invalid attribute name "
|
||||
"\"%s\": %s\n",
|
||||
s, strerror(errno));
|
||||
|
||||
/* Keep hold of the original string. */
|
||||
s2 = s;
|
||||
|
||||
s = argv[optind++];
|
||||
if (optind != argc)
|
||||
usage(1);
|
||||
} else {
|
||||
attr_name = AT_UNNAMED;
|
||||
attr_name_len = 0;
|
||||
}
|
||||
}
|
||||
ntfs_log_verbose("attribute type = 0x%lx\n",
|
||||
(unsigned long)le32_to_cpu(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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the initial runlist, to be restored on error
|
||||
*/
|
||||
|
||||
static runlist_element *ntfs_save_rl(runlist_element *rl)
|
||||
{
|
||||
runlist_element *save;
|
||||
int n;
|
||||
|
||||
n = 0;
|
||||
save = (runlist_element*)NULL;
|
||||
if (rl) {
|
||||
while (rl[n].length)
|
||||
n++;
|
||||
save = (runlist_element*)malloc((n + 1)*sizeof(runlist_element));
|
||||
if (save) {
|
||||
memcpy(save, rl, (n + 1)*sizeof(runlist_element));
|
||||
}
|
||||
}
|
||||
return (save);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the common part of two runs
|
||||
*/
|
||||
|
||||
static void free_common(ntfs_volume *vol, runlist_element *brl, s64 blth,
|
||||
runlist_element *grl, s64 glth)
|
||||
{
|
||||
VCN begin_common;
|
||||
VCN end_common;
|
||||
|
||||
begin_common = max(grl->vcn, brl->vcn);
|
||||
end_common = min(grl->vcn + glth, brl->vcn + blth);
|
||||
if (end_common > begin_common) {
|
||||
if (ntfs_bitmap_clear_run(vol->lcnbmp_na,
|
||||
brl->lcn + begin_common - brl->vcn,
|
||||
end_common - begin_common))
|
||||
ntfs_log_error("Failed to free %lld clusters "
|
||||
"from 0x%llx\n",
|
||||
(long long)end_common - begin_common,
|
||||
(long long)(brl->lcn + begin_common
|
||||
- brl->vcn));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the cluster allocations to initial state
|
||||
*
|
||||
* If a new error occurs, only output a message
|
||||
*/
|
||||
|
||||
static void ntfs_restore_rl(ntfs_attr *na, runlist_element *oldrl)
|
||||
{
|
||||
runlist_element *brl; /* Pointer to bad runlist */
|
||||
runlist_element *grl; /* Pointer to good runlist */
|
||||
ntfs_volume *vol;
|
||||
|
||||
vol = na->ni->vol;
|
||||
/* Examine allocated entries from the bad runlist */
|
||||
for (brl=na->rl; brl->length; brl++) {
|
||||
if (brl->lcn != LCN_HOLE) {
|
||||
// TODO improve by examining both list in parallel
|
||||
/* Find the holes in the good runlist which overlap */
|
||||
for (grl=oldrl; grl->length
|
||||
&& (grl->vcn<=(brl->vcn+brl->length)); grl++) {
|
||||
if (grl->lcn == LCN_HOLE) {
|
||||
free_common(vol, brl, brl->length, grl,
|
||||
grl->length);
|
||||
}
|
||||
}
|
||||
/* Free allocations beyond the end of good runlist */
|
||||
if (grl && !grl->length
|
||||
&& ((brl->vcn + brl->length) > grl->vcn)) {
|
||||
free_common(vol, brl, brl->length, grl,
|
||||
brl->vcn + brl->length - grl->vcn);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(na->rl);
|
||||
na->rl = oldrl;
|
||||
if (ntfs_attr_update_mapping_pairs(na, 0)) {
|
||||
ntfs_log_error("Failed to restore the original runlist\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero newly allocated runs up to initialized_size
|
||||
*/
|
||||
|
||||
static int ntfs_inner_zero(ntfs_attr *na, runlist_element *rl)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
char *buf;
|
||||
runlist_element *zrl;
|
||||
s64 cofs;
|
||||
s64 pos;
|
||||
s64 zeroed;
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
vol = na->ni->vol;
|
||||
buf = (char*)malloc(vol->cluster_size);
|
||||
if (buf) {
|
||||
memset(buf, 0, vol->cluster_size);
|
||||
zrl = rl;
|
||||
pos = zrl->vcn << vol->cluster_size_bits;
|
||||
while (zrl->length
|
||||
&& !err
|
||||
&& (pos < na->initialized_size)) {
|
||||
for (cofs=0; cofs<zrl->length && !err; cofs++) {
|
||||
zeroed = ntfs_pwrite(vol->dev,
|
||||
(rl->lcn + cofs)
|
||||
<< vol->cluster_size_bits,
|
||||
vol->cluster_size, buf);
|
||||
if (zeroed != vol->cluster_size) {
|
||||
ntfs_log_error("Failed to zero at "
|
||||
"offset %lld\n",
|
||||
(long long)pos);
|
||||
errno = EIO;
|
||||
err = -1;
|
||||
}
|
||||
pos += vol->cluster_size;
|
||||
}
|
||||
zrl++;
|
||||
pos = zrl->vcn << vol->cluster_size_bits;
|
||||
}
|
||||
free(buf);
|
||||
} else {
|
||||
ntfs_log_error("Failed to allocate memory\n");
|
||||
errno = ENOSPC;
|
||||
err = -1;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge newly allocated runs into runlist
|
||||
*/
|
||||
|
||||
static int ntfs_merge_allocation(ntfs_attr *na, runlist_element *rl,
|
||||
s64 size)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
vol = na->ni->vol;
|
||||
/* Newly allocated clusters before initialized size need be zeroed */
|
||||
if ((rl->vcn << vol->cluster_size_bits) < na->initialized_size) {
|
||||
err = ntfs_inner_zero(na, rl);
|
||||
}
|
||||
if (!err) {
|
||||
if (na->data_flags & ATTR_IS_SPARSE) {
|
||||
na->compressed_size += size;
|
||||
if (na->compressed_size >= na->allocated_size) {
|
||||
na->data_flags &= ~ATTR_IS_SPARSE;
|
||||
if (na->compressed_size > na->allocated_size) {
|
||||
ntfs_log_error("File size error : "
|
||||
"apparent %lld, "
|
||||
"compressed %lld > "
|
||||
"allocated %lld",
|
||||
(long long)na->data_size,
|
||||
(long long)na->compressed_size,
|
||||
(long long)na->allocated_size);
|
||||
errno = EIO;
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
rl = ntfs_runlists_merge(na->rl, rl);
|
||||
if (!rl) {
|
||||
ntfs_log_error("Failed to merge the new allocation\n");
|
||||
err = -1;
|
||||
} else {
|
||||
na->rl = rl;
|
||||
/* Update the runlist */
|
||||
if (ntfs_attr_update_mapping_pairs(na, 0)) {
|
||||
ntfs_log_error(
|
||||
"Failed to update the runlist\n");
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int ntfs_inner_allocation(ntfs_attr *na, s64 alloc_offs, s64 alloc_len)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
runlist_element *rl;
|
||||
runlist_element *prl;
|
||||
runlist_element *rlc;
|
||||
VCN from_vcn;
|
||||
VCN end_vcn;
|
||||
LCN lcn_seek_from;
|
||||
VCN from_hole;
|
||||
VCN end_hole;
|
||||
s64 need;
|
||||
int err;
|
||||
BOOL done;
|
||||
|
||||
err = 0;
|
||||
vol = na->ni->vol;
|
||||
/* Find holes which overlap the requested allocation */
|
||||
from_vcn = alloc_offs >> vol->cluster_size_bits;
|
||||
end_vcn = (alloc_offs + alloc_len + vol->cluster_size - 1)
|
||||
>> vol->cluster_size_bits;
|
||||
do {
|
||||
done = FALSE;
|
||||
rl = na->rl;
|
||||
while (rl->length
|
||||
&& ((rl->lcn >= 0)
|
||||
|| ((rl->vcn + rl->length) <= from_vcn)
|
||||
|| (rl->vcn >= end_vcn)))
|
||||
rl++;
|
||||
if (!rl->length)
|
||||
done = TRUE;
|
||||
else {
|
||||
from_hole = max(from_vcn, rl->vcn);
|
||||
end_hole = min(end_vcn, rl->vcn + rl->length);
|
||||
need = end_hole - from_hole;
|
||||
lcn_seek_from = -1;
|
||||
if (rl->vcn) {
|
||||
/* Avoid fragmentation when possible */
|
||||
prl = rl;
|
||||
if ((--prl)->lcn >= 0) {
|
||||
lcn_seek_from = prl->lcn
|
||||
+ from_hole - prl->vcn;
|
||||
}
|
||||
}
|
||||
if (need <= 0) {
|
||||
ntfs_log_error("Wrong hole size %lld\n",
|
||||
(long long)need);
|
||||
errno = EIO;
|
||||
err = -1;
|
||||
} else {
|
||||
rlc = ntfs_cluster_alloc(vol, from_hole, need,
|
||||
lcn_seek_from, DATA_ZONE);
|
||||
if (!rlc)
|
||||
err = -1;
|
||||
else
|
||||
err = ntfs_merge_allocation(na, rlc,
|
||||
need << vol->cluster_size_bits);
|
||||
}
|
||||
}
|
||||
} while (!err && !done);
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int ntfs_full_allocation(ntfs_attr *na, ntfs_attr_search_ctx *ctx,
|
||||
s64 alloc_offs, s64 alloc_len)
|
||||
{
|
||||
ATTR_RECORD *attr;
|
||||
ntfs_inode *ni;
|
||||
s64 initialized_size;
|
||||
s64 data_size;
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
initialized_size = na->initialized_size;
|
||||
data_size = na->data_size;
|
||||
|
||||
if (na->allocated_size <= alloc_offs) {
|
||||
/*
|
||||
* Request is fully beyond what was already allocated :
|
||||
* only need to expand the attribute
|
||||
*/
|
||||
err = ntfs_attr_truncate(na, alloc_offs);
|
||||
if (!err)
|
||||
err = ntfs_attr_truncate_solid(na,
|
||||
alloc_offs + alloc_len);
|
||||
} else {
|
||||
/*
|
||||
* Request overlaps what was already allocated :
|
||||
* We may have to fill existing holes, and force zeroes
|
||||
* into clusters which are visible.
|
||||
*/
|
||||
if ((alloc_offs + alloc_len) > na->allocated_size)
|
||||
err = ntfs_attr_truncate(na, alloc_offs + alloc_len);
|
||||
if (!err)
|
||||
err = ntfs_inner_allocation(na, alloc_offs, alloc_len);
|
||||
}
|
||||
/* Set the sizes, even after an error, to keep consistency */
|
||||
na->initialized_size = initialized_size;
|
||||
/* Restore the original apparent size if requested or error */
|
||||
if (err || opts.no_size_change
|
||||
|| ((alloc_offs + alloc_len) < data_size))
|
||||
na->data_size = data_size;
|
||||
else {
|
||||
/*
|
||||
* "man 1 fallocate" does not define the new apparent size
|
||||
* when size change is allowed (no --keep-size).
|
||||
* Assuming the same as no FALLOC_FL_KEEP_SIZE in fallocate(2) :
|
||||
* "the file size will be changed if offset + len is greater
|
||||
* than the file size"
|
||||
// TODO check the behavior of another file system
|
||||
*/
|
||||
na->data_size = alloc_offs + alloc_len;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
/* Find the attribute, which may have been relocated for allocations */
|
||||
if (ntfs_attr_lookup(attr_type, attr_name, attr_name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
err = -1;
|
||||
ntfs_log_error("Failed to locate the attribute\n");
|
||||
} else {
|
||||
/* Feed the sizes into the attribute */
|
||||
attr = ctx->attr;
|
||||
attr->data_size = cpu_to_sle64(na->data_size);
|
||||
attr->initialized_size
|
||||
= cpu_to_sle64(na->initialized_size);
|
||||
attr->allocated_size
|
||||
= cpu_to_sle64(na->allocated_size);
|
||||
if (na->data_flags & ATTR_IS_SPARSE)
|
||||
attr->compressed_size
|
||||
= cpu_to_sle64(na->compressed_size);
|
||||
/* Copy the unnamed data attribute sizes to inode */
|
||||
if ((attr_type == AT_DATA) && !attr_name_len) {
|
||||
ni = na->ni;
|
||||
ni->data_size = na->data_size;
|
||||
if (na->data_flags & ATTR_IS_SPARSE) {
|
||||
ni->allocated_size
|
||||
= na->compressed_size;
|
||||
ni->flags |= FILE_ATTR_SPARSE_FILE;
|
||||
} else
|
||||
ni->allocated_size
|
||||
= na->allocated_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Do the actual allocations
|
||||
*/
|
||||
|
||||
static int ntfs_fallocate(ntfs_inode *ni, s64 alloc_offs, s64 alloc_len)
|
||||
{
|
||||
s64 allocated_size;
|
||||
s64 data_size;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ntfs_attr *na;
|
||||
runlist_element *oldrl;
|
||||
const char *errmess;
|
||||
int save_errno;
|
||||
int err;
|
||||
|
||||
err = 0;
|
||||
/* Open the specified attribute. */
|
||||
na = ntfs_attr_open(ni, attr_type, attr_name, attr_name_len);
|
||||
if (!na) {
|
||||
ntfs_log_perror("Failed to open attribute 0x%lx: ",
|
||||
(unsigned long)le32_to_cpu(attr_type));
|
||||
err = -1;
|
||||
} else {
|
||||
errmess = (const char*)NULL;
|
||||
if (na->data_flags & ATTR_IS_COMPRESSED) {
|
||||
errmess= "Cannot fallocate a compressed file";
|
||||
}
|
||||
|
||||
/* Locate the attribute record, needed for updating sizes */
|
||||
ctx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||
if (!ctx) {
|
||||
errmess = "Failed to allocate a search context";
|
||||
}
|
||||
if (errmess) {
|
||||
ntfs_log_error("%s\n",errmess);
|
||||
err = -1;
|
||||
} else {
|
||||
/* Get and save the initial allocations */
|
||||
allocated_size = na->allocated_size;
|
||||
data_size = ni->data_size;
|
||||
if (na->rl)
|
||||
err = ntfs_attr_map_whole_runlist(na);
|
||||
if (!err) {
|
||||
if (na->rl)
|
||||
oldrl = ntfs_save_rl(na->rl);
|
||||
else
|
||||
oldrl = (runlist_element*)NULL;
|
||||
if (!na->rl || oldrl) {
|
||||
err = ntfs_full_allocation(na, ctx,
|
||||
alloc_offs, alloc_len);
|
||||
if (err) {
|
||||
save_errno = errno;
|
||||
ni->allocated_size
|
||||
= allocated_size;
|
||||
ni->data_size = data_size;
|
||||
ntfs_restore_rl(na, oldrl);
|
||||
errno = save_errno;
|
||||
} else {
|
||||
free(oldrl);
|
||||
/* Mark file name dirty, to update the sizes in directories */
|
||||
NInoFileNameSetDirty(ni);
|
||||
NInoSetDirty(ni);
|
||||
}
|
||||
} else
|
||||
err = -1;
|
||||
}
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
}
|
||||
/* Close the attribute. */
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
/**
|
||||
* main
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned long mnt_flags, ul;
|
||||
int err;
|
||||
ntfs_inode *ni;
|
||||
ntfs_volume *vol;
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
char *unix_name;
|
||||
#endif
|
||||
|
||||
vol = (ntfs_volume*)NULL;
|
||||
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_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((ntfs_volume*)NULL, "Refusing to run!\n");
|
||||
fprintf(stderr, "ntfsfallocate 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 = NTFS_MNT_RDONLY;
|
||||
} else
|
||||
if (opts.force)
|
||||
ul = NTFS_MNT_RECOVER;
|
||||
else
|
||||
ul = 0;
|
||||
vol = ntfs_mount(dev_name, ul);
|
||||
if (!vol)
|
||||
err_exit(vol, "Failed to mount %s: %s\n", dev_name,
|
||||
strerror(errno));
|
||||
|
||||
if ((vol->flags & VOLUME_IS_DIRTY) && !opts.force)
|
||||
err_exit(vol, "Volume is dirty, please run chkdsk.\n");
|
||||
|
||||
if (ntfs_volume_get_free_space(vol))
|
||||
err_exit(vol, "Failed to get free clusters %s: %s\n",
|
||||
dev_name, strerror(errno));
|
||||
|
||||
/* Open the specified inode. */
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
unix_name = ntfs_utils_unix_path(file_name);
|
||||
if (unix_name) {
|
||||
ni = ntfs_pathname_to_inode(vol, NULL, unix_name);
|
||||
free(unix_name);
|
||||
} else
|
||||
ni = (ntfs_inode*)NULL;
|
||||
#else
|
||||
ni = ntfs_pathname_to_inode(vol, NULL, file_name);
|
||||
#endif
|
||||
if (!ni)
|
||||
err_exit(vol, "Failed to open file \"%s\": %s\n", file_name,
|
||||
strerror(errno));
|
||||
if (!opts.no_action)
|
||||
err = ntfs_fallocate(ni, opt_alloc_offs, opt_alloc_len);
|
||||
|
||||
/* Close the inode. */
|
||||
if (ntfs_inode_close(ni)) {
|
||||
err = -1;
|
||||
err_exit(vol, "Failed to close inode \"%s\" : %s\n", file_name,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
/* Unmount the volume. */
|
||||
err = ntfs_umount(vol, 0);
|
||||
vol = (ntfs_volume*)NULL;
|
||||
if (err)
|
||||
ntfs_log_perror("Warning: Failed to umount %s", dev_name);
|
||||
|
||||
/* Free the attribute name if it exists. */
|
||||
if (attr_name_len)
|
||||
ntfs_ucsfree(attr_name);
|
||||
|
||||
ntfs_log_quiet("ntfsfallocate completed successfully. Have a nice day.\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
.\" Copyright (c) 2005-2006 Szabolcs Szakacsits.
|
||||
.\" Copyright (c) 2005 Richard Russon.
|
||||
.\" Copyright (c) 2011-2013 Jean-Pierre Andre
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSFIX 8 "January 2013" "ntfs-3g @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 cannot 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\-b\fR, \fB\-\-clear\-bad\-sectors\fR
|
||||
Clear the list of bad sectors. This is useful after cloning an old disk
|
||||
with bad sectors to a new disk.
|
||||
.TP
|
||||
\fB\-d\fR, \fB\-\-clear\-dirty\fR
|
||||
Clear the volume dirty flag if the volume can be fixed and mounted.
|
||||
If the option is not present or the volume cannot be fixed, the dirty
|
||||
volume flag is set to request a volume checking at next mount.
|
||||
.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
|
||||
Do not write anything, just show what would have been done.
|
||||
.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
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfsfix
|
||||
was written by Anton Altaparmakov, with contributions from Szabolcs Szakacsits.
|
||||
It was ported to ntfs-3g by Erik Larsson and Jean-Pierre Andre.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsfix
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR mkntfs (8),
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,89 @@
|
||||
.\" 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" "ntfs-3g @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
|
||||
ntfs\-3g\-devel@lists.sf.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.
|
||||
It was ported to ntfs-3g by Erik Larsson and Jean-Pierre Andre.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsinfo
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,119 @@
|
||||
.\" Copyright (c) 2002\-2004 Anton Altaparmakov.
|
||||
.\" Copyright (c) 2005 Richard Russon.
|
||||
.\" Copyright (c) 2012 Jean-Pierre Andre.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSLABEL 8 "January 2012" "ntfs-3g @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 .
|
||||
It can also change the serial number of the
|
||||
.IR device .
|
||||
.PP
|
||||
If the optional argument
|
||||
.I new\-label
|
||||
is not present, and no option is 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\-\-new\-serial\fR[\fI=ssssssssssssssss\fR], or
|
||||
.TP
|
||||
\fB\-\-new\-half\-serial\fR[\fI=ssssssss\fR]
|
||||
Set a new serial number to the device, either the argument value, or a random
|
||||
one if no argument is given. The serial number is a 64 bit number,
|
||||
represented as a sixteen-digit hexadecimal number, used to identify the
|
||||
device during the mounting process. As a consequence, two devices with the
|
||||
same serial number cannot be mounted at the same time on the same computer.
|
||||
This is not the volume UUID used by Windows to locate files which have been
|
||||
moved to another volume.
|
||||
|
||||
The option \-\-new\-half\-serial only changes the upper part of the serial
|
||||
number, keeping the lower part which is used by Windows unchanged.
|
||||
In this case the optional argument is an eight-digit hexadecimal number.
|
||||
|
||||
.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. The label and the serial number are displayed.
|
||||
.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
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfslabel
|
||||
was written by Matthew J. Fanto, with contributions from Anton Altaparmakov and
|
||||
Richard Russon.
|
||||
It was ported to ntfs-3g by Erik Larsson.
|
||||
.SH AVAILABILITY
|
||||
.B ntfslabel
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR mkntfs (8),
|
||||
.BR ntfsprogs (8)
|
||||
@@ -0,0 +1,464 @@
|
||||
/**
|
||||
* 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
|
||||
* Copyright (c) 2012-2014 Jean-Pierre Andre
|
||||
*
|
||||
* 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
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "mft.h"
|
||||
#include "utils.h"
|
||||
/* #include "version.h" */
|
||||
#include "logging.h"
|
||||
#include "misc.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 new_serial; /* Change the serial number */
|
||||
unsigned long long serial; /* Forced serial number value */
|
||||
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(" 2012-2014 Jean-Pierre Andre\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"
|
||||
" --new-serial Set a new serial number\n"
|
||||
" --new-half-serial Set a partial new serial number\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?IinqvV";
|
||||
static const struct option lopt[] = {
|
||||
{ "force", no_argument, NULL, 'f' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "new-serial", optional_argument, NULL, 'I' },
|
||||
{ "new-half-serial", optional_argument, NULL, 'i' },
|
||||
{ "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;
|
||||
char *endserial;
|
||||
|
||||
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':
|
||||
help++;
|
||||
break;
|
||||
case 'I' : /* not proposed as a short option letter */
|
||||
if (optarg) {
|
||||
opts.serial = strtoull(optarg, &endserial, 16);
|
||||
if (*endserial)
|
||||
ntfs_log_error("Bad hexadecimal serial number.\n");
|
||||
}
|
||||
opts.new_serial |= 2;
|
||||
break;
|
||||
case 'i' : /* not proposed as a short option letter */
|
||||
if (optarg) {
|
||||
opts.serial = strtoull(optarg, &endserial, 16)
|
||||
<< 32;
|
||||
if (*endserial)
|
||||
ntfs_log_error("Bad hexadecimal serial number.\n");
|
||||
}
|
||||
opts.new_serial |= 1;
|
||||
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;
|
||||
case '?':
|
||||
if (strncmp (argv[optind-1], "--log-", 6) == 0) {
|
||||
if (!ntfs_log_parse_option (argv[optind-1]))
|
||||
err++;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
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();
|
||||
|
||||
/* tri-state 0 : done, 1 : error, -1 : proceed */
|
||||
return (err ? 1 : (help || ver ? 0 : -1));
|
||||
}
|
||||
|
||||
static int change_serial(ntfs_volume *vol, u64 sector, le64 serial_number,
|
||||
NTFS_BOOT_SECTOR *bs, NTFS_BOOT_SECTOR *oldbs)
|
||||
{
|
||||
int res;
|
||||
le64 mask;
|
||||
BOOL same;
|
||||
|
||||
res = -1;
|
||||
if ((ntfs_pread(vol->dev, sector << vol->sector_size_bits,
|
||||
vol->sector_size, bs) == vol->sector_size)) {
|
||||
same = TRUE;
|
||||
if (!sector)
|
||||
/* save the real bootsector */
|
||||
memcpy(oldbs, bs, vol->sector_size);
|
||||
else
|
||||
/* backup bootsector must be similar */
|
||||
same = !memcmp(oldbs, bs, vol->sector_size);
|
||||
if (same) {
|
||||
if (opts.new_serial & 2)
|
||||
bs->volume_serial_number = serial_number;
|
||||
else {
|
||||
mask = const_cpu_to_le64(~0x0ffffffffULL);
|
||||
bs->volume_serial_number
|
||||
= (serial_number & mask)
|
||||
| (bs->volume_serial_number & ~mask);
|
||||
}
|
||||
if (opts.noaction
|
||||
|| (ntfs_pwrite(vol->dev,
|
||||
sector << vol->sector_size_bits,
|
||||
vol->sector_size, bs) == vol->sector_size)) {
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
ntfs_log_info("* Warning : the backup boot sector"
|
||||
" does not match (leaving unchanged)\n");
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
static int set_new_serial(ntfs_volume *vol)
|
||||
{
|
||||
NTFS_BOOT_SECTOR *bs; /* full boot sectors */
|
||||
NTFS_BOOT_SECTOR *oldbs; /* full original boot sector */
|
||||
le64 serial_number;
|
||||
u64 number_of_sectors;
|
||||
u64 sn;
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
bs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
|
||||
oldbs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
|
||||
if (bs && oldbs) {
|
||||
if (opts.serial)
|
||||
serial_number = cpu_to_le64(opts.serial);
|
||||
else {
|
||||
/* different values for parallel processes */
|
||||
srandom(time((time_t*)NULL) ^ (getpid() << 16));
|
||||
sn = ((u64)random() << 32)
|
||||
| ((u64)random() & 0xffffffff);
|
||||
serial_number = cpu_to_le64(sn);
|
||||
}
|
||||
if (!change_serial(vol, 0, serial_number, bs, oldbs)) {
|
||||
number_of_sectors = ntfs_device_size_get(vol->dev,
|
||||
vol->sector_size);
|
||||
if (!change_serial(vol, number_of_sectors - 1,
|
||||
serial_number, bs, oldbs)) {
|
||||
ntfs_log_info("New serial number : %016llx\n",
|
||||
(long long)le64_to_cpu(
|
||||
bs->volume_serial_number));
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
free(bs);
|
||||
free(oldbs);
|
||||
}
|
||||
if (res)
|
||||
ntfs_log_info("Error setting a new serial number\n");
|
||||
return (res);
|
||||
}
|
||||
|
||||
static int print_serial(ntfs_volume *vol)
|
||||
{
|
||||
NTFS_BOOT_SECTOR *bs; /* full boot sectors */
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
bs = (NTFS_BOOT_SECTOR*)ntfs_malloc(vol->sector_size);
|
||||
if (bs
|
||||
&& (ntfs_pread(vol->dev, 0,
|
||||
vol->sector_size, bs) == vol->sector_size)) {
|
||||
ntfs_log_info("Serial number : %016llx\n",
|
||||
(long long)le64_to_cpu(bs->volume_serial_number));
|
||||
res = 0;
|
||||
free(bs);
|
||||
}
|
||||
if (res)
|
||||
ntfs_log_info("Error getting the serial number\n");
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
if (opts.verbose)
|
||||
ntfs_log_info("Volume label : %s\n", vol->vol_name);
|
||||
else
|
||||
ntfs_log_info("%s\n", vol->vol_name);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, char *label)
|
||||
{
|
||||
ntfschar *new_label = NULL;
|
||||
int label_len;
|
||||
int result = 0;
|
||||
|
||||
label_len = ntfs_mbstoucs(label, &new_label);
|
||||
if (label_len == -1) {
|
||||
ntfs_log_perror("Unable to convert label string to Unicode");
|
||||
return 1;
|
||||
}
|
||||
else if (label_len*sizeof(ntfschar) > 0x100) {
|
||||
ntfs_log_warning("New label is too long. Maximum %u characters "
|
||||
"allowed. Truncating %u excess characters.\n",
|
||||
(unsigned)(0x100 / sizeof(ntfschar)),
|
||||
(unsigned)(label_len -
|
||||
(0x100 / sizeof(ntfschar))));
|
||||
label_len = 0x100 / sizeof(ntfschar);
|
||||
new_label[label_len] = const_cpu_to_le16(0);
|
||||
}
|
||||
|
||||
if(!opts.noaction)
|
||||
result = ntfs_volume_rename(vol, new_label, label_len) ? 1 : 0;
|
||||
|
||||
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);
|
||||
|
||||
result = parse_options(argc, argv);
|
||||
if (result >= 0)
|
||||
return (result);
|
||||
|
||||
result = 0;
|
||||
utils_set_locale();
|
||||
|
||||
if ((opts.label || opts.new_serial)
|
||||
&& !opts.noaction
|
||||
&& !opts.force
|
||||
&& !ntfs_check_if_mounted(opts.device, &mnt_flags)
|
||||
&& (mnt_flags & NTFS_MF_MOUNTED)) {
|
||||
ntfs_log_error("Cannot make changes to a mounted device\n");
|
||||
result = 1;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!opts.label && !opts.new_serial)
|
||||
opts.noaction++;
|
||||
|
||||
vol = utils_mount_volume(opts.device,
|
||||
(opts.noaction ? NTFS_MNT_RDONLY : 0) |
|
||||
(opts.force ? NTFS_MNT_RECOVER : 0));
|
||||
if (!vol)
|
||||
return 1;
|
||||
|
||||
if (opts.new_serial) {
|
||||
result = set_new_serial(vol);
|
||||
if (result)
|
||||
goto unmount;
|
||||
} else {
|
||||
if (opts.verbose)
|
||||
result = print_serial(vol);
|
||||
}
|
||||
if (opts.label)
|
||||
result = change_label(vol, opts.label);
|
||||
else
|
||||
result = print_label(vol, mnt_flags);
|
||||
|
||||
unmount :
|
||||
ntfs_umount(vol, FALSE);
|
||||
abort :
|
||||
/* "result" may be a negative reply of a library function */
|
||||
return (result ? 1 : 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
.\" 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" "ntfs-3g @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
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
This version of
|
||||
.B ntfsls
|
||||
was written by Lode Leroy, Anton Altaparmakov, Richard Russon, Carmelo Kintana
|
||||
and Giang Nguyen.
|
||||
It was ported to ntfs-3g by Erik Larsson.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsls
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfsprogs (8)
|
||||
@@ -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 "types.h"
|
||||
#include "mft.h"
|
||||
#include "attrib.h"
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
#include "utils.h"
|
||||
#include "dir.h"
|
||||
#include "list.h"
|
||||
#include "ntfstime.h"
|
||||
/* #include "version.h" */
|
||||
#include "logging.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 ntfs_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 ntfs_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 ntfs_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 ntfs_list_head of any entry in the list
|
||||
*
|
||||
* Iterate over @dir_list, calling free_dir on each entry
|
||||
*/
|
||||
static void free_dirs(struct ntfs_list_head *dir_list)
|
||||
{
|
||||
struct dir *tofree = NULL;
|
||||
struct ntfs_list_head *walker = NULL;
|
||||
|
||||
if (dir_list) {
|
||||
ntfs_list_for_each(walker, dir_list) {
|
||||
free_dir(tofree);
|
||||
tofree = ntfs_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 = NTFS_LIST_HEAD_INIT(dirs.list),
|
||||
.ni = NULL,
|
||||
.name = {0},
|
||||
.depth = 0
|
||||
};
|
||||
|
||||
static struct path_component paths = {
|
||||
.list = NTFS_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 ntfs_list_head *dir_walker = NULL;
|
||||
struct ntfs_list_head *comp_walker = NULL;
|
||||
s64 pos2 = 0;
|
||||
int ni_depth = depth;
|
||||
int result = 0;
|
||||
|
||||
if (ntfs_list_empty(&dirs.list)) {
|
||||
base_comp.name = opts.path;
|
||||
ntfs_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) {
|
||||
ntfs_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 */
|
||||
ntfs_list_for_each(dir_walker, &dirs.list) {
|
||||
if (tofree) {
|
||||
free_dir(tofree);
|
||||
tofree = NULL;
|
||||
}
|
||||
subdir = ntfs_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 */
|
||||
ntfs_list_for_each(comp_walker, &paths.list) {
|
||||
tempcomp =
|
||||
ntfs_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;
|
||||
ntfs_list_del(dir_walker);
|
||||
}
|
||||
|
||||
ntfs_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 change_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;
|
||||
|
||||
change_time = ntfs2timespec(file_name_attr->last_data_change_time);
|
||||
strcpy(t_buf, ctime(&change_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) {
|
||||
ntfs_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, NTFS_MNT_RDONLY |
|
||||
(opts.force ? NTFS_MNT_RECOVER : 0));
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
/**
|
||||
* 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 "types.h"
|
||||
#include "attrib.h"
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
#include "mft.h"
|
||||
#include "utils.h"
|
||||
/* #include "version.h" */
|
||||
#include "logging.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)sle64_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 = NTFS_MNT_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;
|
||||
}
|
||||
@@ -0,0 +1,926 @@
|
||||
/**
|
||||
* 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
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
#include "utils.h"
|
||||
#include "volume.h"
|
||||
#include "debug.h"
|
||||
#include "dir.h"
|
||||
#include "bitmap.h"
|
||||
#include "ntfsmove.h"
|
||||
/* #include "version.h" */
|
||||
#include "logging.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 = le32_to_cpu(a->length);
|
||||
file_size = le32_to_cpu(m->bytes_in_use);
|
||||
this_attr = p2n(a)-p2n(m);
|
||||
next_attr = this_attr + le32_to_cpu(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 = cpu_to_le32(new_size);
|
||||
m->bytes_in_use = cpu_to_le32(le32_to_cpu(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 = le16_to_cpu(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",
|
||||
(long long)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 + le16_to_cpu(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", (long long)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",
|
||||
(long long)run->vcn, (long long)run->lcn, (long long)run->length,
|
||||
(long long)to->vcn, (long long)to->lcn, (long long)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) + le16_to_cpu(rec->mapping_pairs_offset), 0, need_to - le16_to_cpu(rec->mapping_pairs_offset));
|
||||
|
||||
// update data runs
|
||||
ntfs_mapping_pairs_build(vol, ((u8*)rec) + le16_to_cpu(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 ", le32_to_cpu(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 |= NTFS_MNT_RDONLY;
|
||||
if (opts.force)
|
||||
flags |= NTFS_MNT_RECOVER;
|
||||
|
||||
vol = utils_mount_volume(opts.device, flags);
|
||||
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)) {
|
||||
|
||||
/* Porting note: libntfs-3g does not automatically set or clear
|
||||
* dirty flags on mount/unmount. It always preserves them until
|
||||
* they are explicitly changed with ntfs_volume_write_flags.
|
||||
* This means that the dirty flag is possibly not set, but
|
||||
* should be set. So we explicitly set it with a call to
|
||||
* ntfs_volume_write_flags. */
|
||||
if(!(vol->flags & VOLUME_IS_DIRTY) && ntfs_volume_write_flags(
|
||||
vol, vol->flags | VOLUME_IS_DIRTY)) {
|
||||
ntfs_log_error("Error: Failed to set volume dirty "
|
||||
"flag (%d (%s))!\n", errno, strerror(errno));
|
||||
}
|
||||
|
||||
ntfs_log_info("Relocated %lld bytes\n", (long long)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;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 "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 */
|
||||
};
|
||||
|
||||
#endif /* _NTFSMOVE_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
.\" Copyright (c) 2002\-2005 Richard Russon.
|
||||
.\" Copyright (c) 2002\-2003 Anton Altaparmakov.
|
||||
.\" Copyright (c) 2005\-2006 Szabolcs Szakacsits.
|
||||
.\" Copyright (c) 2005\-2007 Yura Pakhuchiy.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSPROGS 8 "September 2007" "ntfs-3g @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)
|
||||
\- Copy a file to an NTFS volume.
|
||||
.PP
|
||||
.BR ntfsfallocate (8)
|
||||
\- Preallocate space to a file on an NTFS volume
|
||||
.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 ntfsrecover (8)
|
||||
\- Recover updates committed by Windows on an NTFS volume.
|
||||
.PP
|
||||
.BR ntfstruncate (8)
|
||||
\- Truncate a file on an NTFS volume.
|
||||
.PP
|
||||
.BR ntfsundelete (8)
|
||||
\- Recover deleted files from NTFS.
|
||||
.PP
|
||||
.BR ntfswipe (8)
|
||||
\- Overwrite unused space on an NTFS volume.
|
||||
.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
|
||||
are part of the
|
||||
.B ntfs-3g
|
||||
package which can be downloaded from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfs\-3g (8)
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
.\" Copyright (c) 2015 Jean-Pierre Andre
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSRECOVER 8 "September 2015" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
ntfsrecover \- Recover updates committed by Windows on an NTFS volume
|
||||
.SH SYNOPSIS
|
||||
\fBntfsrecover\fR [\fIoptions\fR] \fIdevice\fR
|
||||
.SH DESCRIPTION
|
||||
.B ntfsrecover
|
||||
applies to the metadata the updates which were requested on Windows but could
|
||||
not be completed because they were interrupted by some event such as a power
|
||||
failure, a hardware crash, a software crash or the device being unplugged.
|
||||
Doing so, the file system is restored to a consistent state, however updates
|
||||
to user data may still be lost.
|
||||
|
||||
Updating the file system generally requires updating several records which
|
||||
should all be made for the file system to be kept consistent. For instance,
|
||||
creating a new file requires reserving an inode number (set a bit in a bit
|
||||
map), creating a file record (store the file name and file attributes), and
|
||||
registering the file in a directory (locate the file from some path). When an
|
||||
unfortunate event occurs, and one of these updates could be done but not all
|
||||
of them, the file system is left inconsistent.
|
||||
|
||||
A group of updates which have all to be done to preserve consistency is
|
||||
called a transaction, and the end of updates within a transaction is called
|
||||
the commitment of the transaction.
|
||||
|
||||
To protect from unfortunate events, Windows first logs in a special file all
|
||||
the metadata update requests without applying any, until the commitment is
|
||||
known. If the event occurs before the commitment, no update has been made and
|
||||
the file system is consistent. If the event occurs after the update, the log
|
||||
file can be analyzed later and the transactions which were committed can be
|
||||
executed again, thus restoring the integrity of the file system.
|
||||
|
||||
.B ntfsrecover
|
||||
similarly examines the log file and applies the updates within committed
|
||||
transactions which could not be done by Windows.
|
||||
|
||||
Currently, ntfs-3g does not log updates, so
|
||||
.B ntfsrecover
|
||||
cannot be used to restore consistency after an unfortunate event occurred
|
||||
while the file system was updated by Linux.
|
||||
|
||||
.SH OPTIONS
|
||||
Below is a summary of all the options that
|
||||
.B ntfsrecover
|
||||
accepts. The normal usage is to use no option at all, as most of these
|
||||
options are oriented towards developers needs.
|
||||
|
||||
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 \-bv
|
||||
is equivalent to
|
||||
.BR "\-b \-v" .
|
||||
Long named options can be abbreviated to any unique prefix of their name.
|
||||
.TP
|
||||
\fB\-b\fR, \fB\-\-backward\fR
|
||||
Examine the actions described in the logfile backward from the latest one to
|
||||
the earliest one without applying any update. This may encompass records
|
||||
generated during several sessions, and when Windows is restarted, it often
|
||||
does not restart writing where it ended the previous session, so this leads
|
||||
to errors and bad sequencing when examining the full log file.
|
||||
.TP
|
||||
\fB\-c\fR, \fB\-\-clusters\fR \fBCLUSTER-RANGE\fR
|
||||
Restrict the output generated when using options -b -f -u -p
|
||||
to the actions operating on a cluster within the given cluster range.
|
||||
CLUSTER-RANGE is defined by the first and last cluster numbers separated
|
||||
by a hyphen, for instance 100-109 or 0x3e8-0x3ff. A single number means
|
||||
restricting to a single cluster. The first four log blocks have a special
|
||||
role and they are always shown.
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-forward\fR \fBNUM\fR
|
||||
Examine the actions described in the logfile forward from the first one to
|
||||
the last one without applying any update. As the log file is reused
|
||||
circularly, the first one is generally not the earliest. Moreover when
|
||||
Windows is restarted, it often does not restart writing where it ended the
|
||||
previous sessions, and this leads to errors when examining a log file
|
||||
generated during several sessions.
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Show some help information.
|
||||
.TP
|
||||
\fB\-k\fR, \fB\-\-kill\-fast\-restart\fR
|
||||
When Windows has been interrupted with fast restart mode activated,
|
||||
part of pending changes are kept in the Windows cache and only the same
|
||||
Windows version can recover them. This option can be used to apply the
|
||||
changes recorded in the log file and drop the ones in the Windows cache.
|
||||
This is dangerous and may cause loss of data.
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-no-action\fR
|
||||
Do not apply any modification, useful when using the options -p, -s or -u.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-play\fR \fBCOUNT\fR
|
||||
Undo COUNT transaction sets and redo a single one, a transaction set being
|
||||
all transactions between two consecutive checkpoints. This is useful for
|
||||
replaying some transaction in the past. As a few actions are not undoable,
|
||||
this is not always possible.
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-range\fR \fBBLOCK-RANGE\fR
|
||||
Examine the actions described in the logfile forward restricted to the
|
||||
requested log file block range without applying any update. The first four
|
||||
log blocks have a special role and they are always examined.
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-sync\fR
|
||||
Sync the file system by applying the committed actions which have not
|
||||
been synced previously. This is the default option, used when none of
|
||||
the options -n, -f, -r, -p and -u are present.
|
||||
|
||||
The option -s can be repeated to request applying the committed actions
|
||||
mentioned in the obsolete restart page. This is useful for testing the
|
||||
situations where the latest restart page cannot be read though it can
|
||||
actually be read.
|
||||
.TP
|
||||
\fB\-t\fR, \fB\-\-transactions\fR \fBCOUNT\fR
|
||||
Display the transaction parameters when examining the log file with one
|
||||
of the options --forward, --backward or --range.
|
||||
.TP
|
||||
\fB\-u\fR, \fB\-\-undo\fR \fBCOUNT\fR
|
||||
Undo COUNT transaction sets, thus resetting the file system to some
|
||||
checkpoint in the past, a transaction set being all transactions between
|
||||
two consecutive checkpoints. As a few actions are not undoable, this is
|
||||
not always possible.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Display more debug/warning/error messages. This option may be used twice
|
||||
to display even more information.
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
Show the version number, copyright and license of
|
||||
.BR ntfsrecover .
|
||||
.SH EXAMPLES
|
||||
Sync an NTFS volume on /dev/sda1.
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsrecover -s /dev/sda1
|
||||
.sp
|
||||
.RE
|
||||
Display all actions which updated a cluster in range 100 to 119 :
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsrecover --verbose --backward --clusters=100-119 /dev/sda1
|
||||
.sp
|
||||
.RE
|
||||
.SH BUGS
|
||||
If you find a bug please send an email describing the problem to the
|
||||
development team:
|
||||
.br
|
||||
.nh
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfsrecover
|
||||
was written by Jean-Pierre Andre
|
||||
.SH AVAILABILITY
|
||||
.B ntfsrecover
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfs-3g (8),
|
||||
.BR ntfsfix (8),
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Declarations for processing log data
|
||||
*
|
||||
* Copyright (c) 2000-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2014-2016 Jean-Pierre Andre
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the NTFS-3G
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define getle16(p,x) le16_to_cpu(*(const le16*)((const char*)(p) + (x)))
|
||||
#define getle32(p,x) le32_to_cpu(*(const le32*)((const char*)(p) + (x)))
|
||||
#define getle64(p,x) le64_to_cpu(*(const le64*)((const char*)(p) + (x)))
|
||||
|
||||
#define feedle16(p,x) (*(const le16*)((const char*)(p) + (x)))
|
||||
#define feedle32(p,x) (*(const le32*)((const char*)(p) + (x)))
|
||||
#define feedle64(p,x) (*(const le64*)((const char*)(p) + (x)))
|
||||
|
||||
enum ACTIONS {
|
||||
Noop, /* 0 */
|
||||
CompensationlogRecord, /* 1 */
|
||||
InitializeFileRecordSegment, /* 2 */
|
||||
DeallocateFileRecordSegment, /* 3 */
|
||||
WriteEndofFileRecordSegment, /* 4 */
|
||||
CreateAttribute, /* 5 */
|
||||
DeleteAttribute, /* 6 */
|
||||
UpdateResidentValue, /* 7 */
|
||||
UpdateNonResidentValue, /* 8 */
|
||||
UpdateMappingPairs, /* 9 */
|
||||
DeleteDirtyClusters, /* 10 */
|
||||
SetNewAttributeSizes, /* 11 */
|
||||
AddIndexEntryRoot, /* 12 */
|
||||
DeleteIndexEntryRoot, /* 13 */
|
||||
AddIndexEntryAllocation, /* 14 */
|
||||
DeleteIndexEntryAllocation, /* 15 */
|
||||
WriteEndOfIndexBuffer, /* 16 */
|
||||
SetIndexEntryVcnRoot, /* 17 */
|
||||
SetIndexEntryVcnAllocation, /* 18 */
|
||||
UpdateFileNameRoot, /* 19 */
|
||||
UpdateFileNameAllocation, /* 20 */
|
||||
SetBitsInNonResidentBitMap, /* 21 */
|
||||
ClearBitsInNonResidentBitMap, /* 22 */
|
||||
HotFix, /* 23 */
|
||||
EndTopLevelAction, /* 24 */
|
||||
PrepareTransaction, /* 25 */
|
||||
CommitTransaction, /* 26 */
|
||||
ForgetTransaction, /* 27 */
|
||||
OpenNonResidentAttribute, /* 28 */
|
||||
OpenAttributeTableDump, /* 29 */
|
||||
AttributeNamesDump, /* 30 */
|
||||
DirtyPageTableDump, /* 31 */
|
||||
TransactionTableDump, /* 32 */
|
||||
UpdateRecordDataRoot, /* 33 */
|
||||
UpdateRecordDataAllocation, /* 34 */
|
||||
Win10Action35, /* 35 */
|
||||
Win10Action36, /* 36 */
|
||||
Win10Action37, /* 37 */
|
||||
LastAction /* 38 */
|
||||
} ;
|
||||
|
||||
struct BUFFER {
|
||||
unsigned int num;
|
||||
unsigned int rnum;
|
||||
unsigned int size;
|
||||
unsigned int headsz;
|
||||
BOOL safe;
|
||||
union {
|
||||
u64 alignment;
|
||||
RESTART_PAGE_HEADER restart;
|
||||
RECORD_PAGE_HEADER record;
|
||||
char data[1];
|
||||
} block; /* variable length, keep at the end */
|
||||
} ;
|
||||
|
||||
struct ACTION_RECORD {
|
||||
struct ACTION_RECORD *next;
|
||||
struct ACTION_RECORD *prev;
|
||||
int num;
|
||||
unsigned int flags;
|
||||
LOG_RECORD record; /* variable length, keep at the end */
|
||||
} ;
|
||||
|
||||
enum { /* Flag values for ACTION_RECORD */
|
||||
ACTION_TO_REDO = 1 /* Committed, possibly not synced */
|
||||
} ;
|
||||
|
||||
struct ATTR {
|
||||
u64 inode;
|
||||
u64 lsn;
|
||||
le32 type;
|
||||
u16 key;
|
||||
u16 namelen;
|
||||
le16 name[1];
|
||||
} ;
|
||||
|
||||
extern u32 clustersz;
|
||||
extern int clusterbits;
|
||||
extern u32 blocksz;
|
||||
extern int blockbits;
|
||||
extern u16 bytespersect;
|
||||
extern u64 mftlcn;
|
||||
extern u32 mftrecsz;
|
||||
extern int mftrecbits;
|
||||
extern u32 mftcnt; /* number of entries */
|
||||
extern BOOL optc;
|
||||
extern BOOL optn;
|
||||
extern int opts;
|
||||
extern int optv;
|
||||
extern unsigned int redocount;
|
||||
extern unsigned int undocount;
|
||||
extern ntfs_inode *log_ni;
|
||||
extern ntfs_attr *log_na;
|
||||
extern u64 logfilelcn;
|
||||
extern u32 logfilesz; /* bytes */
|
||||
extern u64 redos_met;
|
||||
extern u64 committed_lsn;
|
||||
extern u64 synced_lsn;
|
||||
extern u64 latest_lsn;
|
||||
extern u64 restart_lsn;
|
||||
|
||||
extern RESTART_AREA restart;
|
||||
extern LOG_CLIENT_RECORD client;
|
||||
|
||||
const char *actionname(int op);
|
||||
const char *mftattrname(ATTR_TYPES attr);
|
||||
void showname(const char *prefix, const char *name, int cnt);
|
||||
int fixnamelen(const char *name, int len);
|
||||
BOOL within_lcn_range(const LOG_RECORD *logr);
|
||||
struct ATTR *getattrentry(unsigned int key, unsigned int lth);
|
||||
void copy_attribute(struct ATTR *pa, const char *buf, int length);
|
||||
u32 get_undo_offset(const LOG_RECORD *logr);
|
||||
u32 get_redo_offset(const LOG_RECORD *logr);
|
||||
u32 get_extra_offset(const LOG_RECORD *logr);
|
||||
BOOL exception(int num);
|
||||
|
||||
struct STORE;
|
||||
extern int play_undos(ntfs_volume *vol, const struct ACTION_RECORD *firstundo);
|
||||
extern int play_redos(ntfs_volume *vol, const struct ACTION_RECORD *firstredo);
|
||||
extern void show_redos(void);
|
||||
extern void freeclusterentry(struct STORE*);
|
||||
void hexdump(const char *buf, unsigned int lth);
|
||||
@@ -0,0 +1,318 @@
|
||||
.\" Copyright (c) 2002\-2006 Szabolcs Szakacsits.
|
||||
.\" Copyright (c) 2005 Richard Russon.
|
||||
.\" Copyright (c) 2011\-2013 Jean-Pierre Andre.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSRESIZE 8 "July 2013" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
ntfsresize \- resize an NTFS filesystem without data loss
|
||||
.SH SYNOPSIS
|
||||
.B ntfsresize
|
||||
[\fIOPTIONS\fR]
|
||||
.B \-\-info(\-mb\-only)
|
||||
.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 fit in a DEVICE
|
||||
whose desired size is
|
||||
.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(\-mb\-only)
|
||||
and
|
||||
.B \-\-size
|
||||
are omitted then the
|
||||
NTFS filesystem will be enlarged to match 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 another existing partition.
|
||||
You may enlarge upwards (first sector unchanged) or downwards (last
|
||||
sector unchanged), but you may not enlarge at both ends in a single step.
|
||||
If you merge two NTFS partitions, only one of them can be expanded to the
|
||||
merged partition.
|
||||
After you have enlarged the partition, 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\-c\fR, \fB\-\-check\fR
|
||||
By using this option ntfsresize will only check the device to ensure that it
|
||||
is ready to be resized. If not, it will print any errors detected.
|
||||
If the device is fine, nothing will be printed.
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-info\fR
|
||||
By using this option without \fB\-\-expand\fP, 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.
|
||||
|
||||
If used in association with option \fB\-\-expand\fP, ntfsresize will determine
|
||||
the smallest downwards expansion size and the possible increments to the
|
||||
size. These are exact byte counts which must not be rounded.
|
||||
This option may be used after the partition has been expanded
|
||||
provided the upper bound has not been changed.
|
||||
|
||||
This option never causes any changes to the filesystem, the partition is
|
||||
opened read\-only.
|
||||
.TP
|
||||
\fB\-m\fR, \fB\-\-info\-mb\-only\fR
|
||||
Like the info option, only print out the shrinkable size in MB. Print nothing
|
||||
if the shrink size is the same as the original size (in MB).
|
||||
This option cannot be used in association with option \fB\-\-expand\fP.
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-size\fR SIZE\fR[\fBk\fR|\fBM\fR|\fBG\fR]
|
||||
Resize filesystem to fit in a partition whose size is
|
||||
\fISIZE\fR[\fBk\fR|\fBM\fR|\fBG\fR] bytes by shifting its end and keeping
|
||||
its beginning unchanged. The filesystem size is set to be at least one
|
||||
sector smaller than the partition.
|
||||
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. ki=2^10, Mi=2^20
|
||||
and Gi=2^30 are also allowed. Use this option
|
||||
with
|
||||
.B \-\-no\-action
|
||||
first.
|
||||
.TP
|
||||
\fB\-x\fR, \fB\-\-expand\fR
|
||||
Expand the filesystem to the current partition size, shifting down its
|
||||
beginning and keeping its end unchanged. The metadata is recreated in the
|
||||
expanded space and no user data is relocated. This is incompatible with
|
||||
option \-s (or \-\-size) and can only be made if the expanded space is an
|
||||
exact multiple of the cluster size. It must also be large enough to hold the
|
||||
new metadata.
|
||||
|
||||
If the expansion is interrupted for some reason (power outage, etc), you may
|
||||
restart the resizing, as the original data and metadata have been kept
|
||||
unchanged.
|
||||
|
||||
Note : expanding a Windows system partition and filesystem downwards may lead
|
||||
to the registry or some files not matching the new system layout, or to
|
||||
some important files being located too far from the beginning of the
|
||||
partition, thus making Windows not bootable.
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-force\fR
|
||||
Forces ntfsresize to proceed with the resize operation either without
|
||||
prompting for an explicit acceptance, or if the filesystem is marked for
|
||||
consistency check. Double the option (-ff, --force --force) to avoid
|
||||
prompting even if the file system is marked for 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 find a bug please send an email describing the problem to the
|
||||
development team at:
|
||||
.br
|
||||
.nh
|
||||
ntfs\-3g\-devel@lists.sf.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.
|
||||
It was ported to ntfs-3g by Erik Larsson and Jean-Pierre Andre.
|
||||
.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 ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.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)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,184 @@
|
||||
.\" Copyright (c) 2007-2016 Jean-Pierre André.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSSECAUDIT 8 "February 2010" "ntfssecaudit 1.5.0"
|
||||
.SH NAME
|
||||
ntfssecaudit \- NTFS Security Data Auditing
|
||||
.SH SYNOPSIS
|
||||
.B ntfssecaudit
|
||||
\fB[\fIoptions\fP\fB]\fR
|
||||
.I args
|
||||
.PP
|
||||
Where \fIoptions\fP is a combination of :
|
||||
.RS
|
||||
-a full auditing of security data (Linux only)
|
||||
.RE
|
||||
.RS
|
||||
-b backup ACLs
|
||||
.RE
|
||||
.RS
|
||||
-e setting extra backed-up parameters (in conjunction with -s)
|
||||
.RE
|
||||
.RS
|
||||
-h displaying hexadecimal security descriptors saved in a file
|
||||
.RE
|
||||
.RS
|
||||
-r recursing in a directory
|
||||
.RE
|
||||
.RS
|
||||
-s setting backed-up ACLs
|
||||
.RE
|
||||
.RS
|
||||
-u getting a user mapping proposal
|
||||
.RE
|
||||
.RS
|
||||
-v verbose (very verbose if set twice)
|
||||
.RE
|
||||
.PP
|
||||
and args define the parameters and the set of files acted upon.
|
||||
.PP
|
||||
Typing secaudit with no args will display a summary of available options.
|
||||
.SH DESCRIPTION
|
||||
\fBntfssecaudit\fR
|
||||
displays the ownership and permissions of a set of files on an NTFS
|
||||
file system, and checks their consistency. It can be started in terminal
|
||||
mode only (no graphical user interface is available.)
|
||||
.PP
|
||||
When a \fIvolume\fR is required, it has to be unmounted, and the command
|
||||
has to be issued as \fBroot\fP. The \fIvolume\fR can be either a block
|
||||
device (i.e. a disk partition) or an image file.
|
||||
.PP
|
||||
When acting on a directory or volume, the command may produce a lot
|
||||
of information. It is therefore advisable to redirect the output to
|
||||
a file or pipe it to a text editor for examination.
|
||||
.SH OPTIONS
|
||||
Below are the valid combinations of options and arguments that
|
||||
\fBntfssecaudit\fR accepts. All the indicated arguments are
|
||||
mandatory and must be unique (if wildcards are used, they must
|
||||
resolve to a single name.)
|
||||
.TP
|
||||
\fB-h\fP \fIfile\fP
|
||||
Displays in an human readable form the hexadecimal security descriptors
|
||||
saved in \fIfile\fP. This can be used to turn a verbose output into a very
|
||||
verbose output.
|
||||
.TP
|
||||
\fB-a[rv]\fP \fIvolume\fP
|
||||
Audits the volume : all the global security data on \fIvolume\fP are scanned
|
||||
and errors are displayed. If option \fB-r\fP is present, all files and
|
||||
directories are also scanned and their relations to global security data
|
||||
are checked. This can produce a lot of data.
|
||||
|
||||
This option is not effective on volumes formatted for old NTFS versions (pre
|
||||
NTFS 3.0). Such volumes have no global security data.
|
||||
|
||||
When errors are signalled, it is advisable to repair the volume with an
|
||||
appropriate tool (such as \fBchkdsk\fP on Windows.)
|
||||
.TP
|
||||
\fB[-v]\fP \fIvolume\fP \fIfile\fP
|
||||
Displays the security parameters of \fIfile\fP : its interpreted Linux mode
|
||||
(rwx flags in octal) and Posix ACL[1], its security key if any, and its
|
||||
security descriptor if verbose output.
|
||||
.TP
|
||||
\fB-r[v]\fP \fIvolume\fP \fIdirectory\fP
|
||||
displays the security parameters of all files and subdirectories in
|
||||
\fIdirectory\fP : their interpreted Linux mode (rwx flags in octal) and Posix
|
||||
ACL[1], their security key if any, and their security descriptor if
|
||||
verbose output.
|
||||
.TP
|
||||
.B -b[v] \fIvolume\fP \fI[directory]\fP
|
||||
Recursively extracts to standard output the NTFS ACLs of files in \fIvolume\fP
|
||||
and \fIdirectory\fP.
|
||||
.TP
|
||||
\fB-s[ev]\fP \fIvolume\fP \fI[backup-file]\fP
|
||||
Sets the NTFS ACLS as indicated in \fIbackup-file\fP or standard input. The
|
||||
input data must have been created on Linux. With option \fB-e\fP, also sets
|
||||
extra parameters (currently Windows attrib).
|
||||
.TP
|
||||
\fIvolume\fP \fIperms\fP \fIfile\fP
|
||||
Sets the security parameters of file to perms. Perms is the Linux
|
||||
requested mode (rwx flags, expressed in octal form as in chmod) or
|
||||
a Posix ACL[1] (expressed like in setfacl -m). This sets a new ACL
|
||||
which is effective for Linux and Windows.
|
||||
.TP
|
||||
\fB-r[v]\fP \fIvolume\fP \fIperms\fP \fIdirectory\fP
|
||||
Sets the security parameters of all files and subdirectories in
|
||||
\fIdirectory\fP to \fIperms\fP. Perms is the Linux requested mode (rwx flags,
|
||||
expressed in octal form as in \fBchmod\fP), or a Posix ACL[1] (expressed like
|
||||
in \fBsetfacl -m\fP.) This sets new ACLs which are effective for Linux and
|
||||
Windows.
|
||||
.TP
|
||||
\fB[-v]\fP \fImounted-file\fP
|
||||
Displays the security parameters of \fImounted-file\fP : its interpreted
|
||||
Linux mode (rwx flags in octal) and Posix ACL[1], its security key if any,
|
||||
and its security descriptor if verbose output. This is a special case which
|
||||
acts on a mounted file (or directory) and does not require being root. The
|
||||
Posix ACL interpretation can only be displayed if the full path to
|
||||
\fImounted-file\fP from the root of the global file tree is provided.
|
||||
.TP
|
||||
\fB-u[v]\fP \fImounted-file\fP
|
||||
Displays a proposed contents for a user mapping file, based on the
|
||||
ownership parameters set by Windows on \fImounted-file\fP, assuming
|
||||
this file was created on Windows by the user who should be mapped to the
|
||||
current Linux user. The displayed information has to be copied to the
|
||||
file \fB.NTFS-3G/UserMapping\fP where \fB.NTFS-3G\fP is a hidden
|
||||
subdirectory of the root of the partition for which the mapping is to
|
||||
be defined. This will cause the ownership of files created on that
|
||||
partition to be the same as the original \fImounted-file\fP.
|
||||
.SH NOTE
|
||||
[1] provided the POSIX ACL option was selected at compile time. A Posix ACL
|
||||
specification looks like "\fB[d:]{ugmo}:[id]:[perms],...\fP" where id is a
|
||||
numeric user or group id, and perms an octal digit or a set from the letters
|
||||
r, w and x.
|
||||
.RS
|
||||
Example : "\fBu::7,g::5,o:0,u:510:rwx,g:500:5,d:u:510:7\fP"
|
||||
.SH EXAMPLES
|
||||
Audit the global security data on /dev/sda1
|
||||
.RS
|
||||
.sp
|
||||
.B ntfssecaudit -ar /dev/sda1
|
||||
.sp
|
||||
.RE
|
||||
Display the ownership and permissions parameters for files in directory
|
||||
/audio/music on device /dev/sda5, excluding sub-directories :
|
||||
.RS
|
||||
.sp
|
||||
.B ntfssecaudit /dev/sda5 /audio/music
|
||||
.sp
|
||||
.RE
|
||||
Set all files in directory /audio/music on device /dev/sda5 as writeable
|
||||
by owner and read-only for everybody :
|
||||
.RS
|
||||
.sp
|
||||
.B ntfssecaudit -r /dev/sda5 644 /audio/music
|
||||
.sp
|
||||
.RE
|
||||
.SH EXIT CODES
|
||||
.B ntfssecaudit
|
||||
exits with a value of 0 when no error was detected, and with a value
|
||||
of 1 when an error was detected.
|
||||
.SH KNOWN ISSUES
|
||||
Please see
|
||||
.RS
|
||||
.sp
|
||||
https://github.com/tuxera/ntfs-3g/wiki/NTFS-3G-FAQ/
|
||||
.sp
|
||||
.RE
|
||||
for common questions and known issues.
|
||||
If you would find a new one in the latest release of
|
||||
the software then please send an email describing it
|
||||
in detail. You can contact the
|
||||
development team on the ntfs\-3g\-devel@lists.sf.net
|
||||
address.
|
||||
.SH AUTHORS
|
||||
.B ntfssecaudit
|
||||
has been developed by Jean-Pierre André.
|
||||
.SH THANKS
|
||||
Several people made heroic efforts, often over five or more
|
||||
years which resulted the ntfs-3g driver. Most importantly they are
|
||||
Anton Altaparmakov, Richard Russon, Szabolcs Szakacsits, Yura Pakhuchiy,
|
||||
Yuval Fledel, and the author of the groundbreaking FUSE filesystem development
|
||||
framework, Miklos Szeredi.
|
||||
.SH SEE ALSO
|
||||
.BR ntfsprogs (8),
|
||||
.BR attr (5),
|
||||
.BR getfattr (1)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,124 @@
|
||||
.\" Copyright (c) 2014 Jean-Pierre Andre
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSTRUNCATE 8 "June 2014" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
ntfstruncate \- truncate a file on an NTFS volume
|
||||
.SH SYNOPSIS
|
||||
\fBntfstruncate\fR [\fIoptions\fR] \fIdevice\fR \fIfile\fR \fI[attr-type\fR [\fIattr-name\fR]] \fInew-length\fR
|
||||
.SH DESCRIPTION
|
||||
.B ntfstruncate
|
||||
truncates (or extends) a specified attribute belonging to a
|
||||
file or directory, to a specified length.
|
||||
.SH OPTIONS
|
||||
Below is a summary of all the options that
|
||||
.B ntfstruncate
|
||||
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 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\-l\fR
|
||||
Display licensing information.
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-no-action\fR
|
||||
Simulate the truncation without actually write to device.
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
Suppress some debug/warning/error messages.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Display more debug/warning/error messages.
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
Show the version number, copyright and license of
|
||||
.BR ntfstruncate .
|
||||
.TP
|
||||
\fBattr-type\fR
|
||||
Define a particular attribute type to be truncated (advanced use only).
|
||||
By default, the unnamed $DATA attribute (the contents of a plain file) will
|
||||
be truncated. The attribute has to be specified by a number in decimal
|
||||
or hexadecimal :
|
||||
.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
|
||||
.TP
|
||||
\fBattr-name\fR
|
||||
Define the name of the particular attribute type to be truncated
|
||||
(advanced use only).
|
||||
.sp
|
||||
.TP
|
||||
\fBnew-length\fR
|
||||
Specify the target size of the file.
|
||||
It will be rounded up to a multiple of the cluster size.
|
||||
A suffix of K, M, G, T, P or E may be appended to
|
||||
mean a multiplicative factor of a power of 1000. Similarly a suffix of
|
||||
Ki, Mi, Gi, Ti, Pi or Ei may be appended to mean a multiplicative factor
|
||||
of a power of 1024.
|
||||
.SH EXAMPLES
|
||||
Resize to 100MB the file database.db located in the Data directory
|
||||
which is at the root of an NTFS file system.
|
||||
.RS
|
||||
.sp
|
||||
.B ntfstruncate /dev/sda1 Data/database.db 100M
|
||||
.sp
|
||||
.RE
|
||||
.SH BUGS
|
||||
There are no known problems with
|
||||
.BR ntfstruncate .
|
||||
If you find a bug, please send an email
|
||||
describing the problem to the development team:
|
||||
.br
|
||||
.nh
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfstruncate
|
||||
was written by Anton Altaparmakov.
|
||||
.SH AVAILABILITY
|
||||
.B ntfstruncate
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfs-3g (8),
|
||||
.BR ntfsfallocate (8),
|
||||
.BR ntfsprogs (8).
|
||||
@@ -0,0 +1,812 @@
|
||||
/**
|
||||
* 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 "types.h"
|
||||
#include "attrib.h"
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
#include "utils.h"
|
||||
#include "attrdef.h"
|
||||
/* #include "version.h" */
|
||||
#include "logging.h"
|
||||
|
||||
const char *EXEC_NAME = "ntfstruncate";
|
||||
|
||||
/* Need these global so ntfstruncate_exit can access them. */
|
||||
BOOL success = FALSE;
|
||||
|
||||
char *dev_name;
|
||||
s64 inode;
|
||||
ATTR_TYPES 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(int ret)
|
||||
{
|
||||
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(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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':
|
||||
usage(0);
|
||||
case '?':
|
||||
default:
|
||||
usage(1);
|
||||
}
|
||||
if (optind == argc)
|
||||
usage(1);
|
||||
|
||||
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(1);
|
||||
|
||||
/* 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(1);
|
||||
|
||||
/* 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 = cpu_to_le32(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(s, &attr_name);
|
||||
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(1);
|
||||
} else {
|
||||
attr_name = AT_UNNAMED;
|
||||
attr_name_len = 0;
|
||||
}
|
||||
}
|
||||
ntfs_log_verbose("attribute type = 0x%x\n", (unsigned int)le32_to_cpu(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", (long long)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)
|
||||
{
|
||||
u16 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;
|
||||
VOLUME_FLAGS flags;
|
||||
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);
|
||||
flags = VOL_INF(val)->flags;
|
||||
#undef VOL_INF
|
||||
printf("Volume flags = 0x%x: ", le16_to_cpu(flags));
|
||||
if (!flags) {
|
||||
printf("NONE\n");
|
||||
return;
|
||||
}
|
||||
j = 0;
|
||||
if (flags & VOLUME_MODIFIED_BY_CHKDSK) {
|
||||
j = 1;
|
||||
printf("VOLUME_MODIFIED_BY_CHKDSK");
|
||||
}
|
||||
if (flags & VOLUME_REPAIR_OBJECT_ID) {
|
||||
if (j)
|
||||
printf(" | ");
|
||||
else
|
||||
j = 0;
|
||||
printf("VOLUME_REPAIR_OBJECT_ID");
|
||||
}
|
||||
if (flags & VOLUME_DELETE_USN_UNDERWAY) {
|
||||
if (j)
|
||||
printf(" | ");
|
||||
else
|
||||
j = 0;
|
||||
printf("VOLUME_DELETE_USN_UNDERWAY");
|
||||
}
|
||||
if (flags & VOLUME_MOUNTED_ON_NT4) {
|
||||
if (j)
|
||||
printf(" | ");
|
||||
else
|
||||
j = 0;
|
||||
printf("VOLUME_MOUNTED_ON_NT4");
|
||||
}
|
||||
if (flags & VOLUME_UPGRADE_ON_MOUNT) {
|
||||
if (j)
|
||||
printf(" | ");
|
||||
else
|
||||
j = 0;
|
||||
printf("VOLUME_UPGRADE_ON_MOUNT");
|
||||
}
|
||||
if (flags & VOLUME_RESIZE_LOG_FILE) {
|
||||
if (j)
|
||||
printf(" | ");
|
||||
else
|
||||
j = 0;
|
||||
printf("VOLUME_RESIZE_LOG_FILE");
|
||||
}
|
||||
if (flags & 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;
|
||||
ATTR_FLAGS flags;
|
||||
|
||||
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", le16_to_cpu(a->name_offset),
|
||||
le16_to_cpu(a->name_offset));
|
||||
flags = a->flags;
|
||||
if (a->name_length) {
|
||||
if (ucstos(s, (ntfschar*)((char*)a +
|
||||
le16_to_cpu(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(flags));
|
||||
if (!flags)
|
||||
printf("NONE");
|
||||
else {
|
||||
int first = TRUE;
|
||||
if (flags & ATTR_COMPRESSION_MASK) {
|
||||
if (flags & ATTR_IS_COMPRESSED) {
|
||||
printf("ATTR_IS_COMPRESSED");
|
||||
first = FALSE;
|
||||
}
|
||||
if ((flags & ATTR_COMPRESSION_MASK) & ~ATTR_IS_COMPRESSED) {
|
||||
if (!first)
|
||||
printf(" | ");
|
||||
else
|
||||
first = FALSE;
|
||||
printf("ATTR_UNKNOWN_COMPRESSION");
|
||||
}
|
||||
}
|
||||
if (flags & ATTR_IS_ENCRYPTED) {
|
||||
if (!first)
|
||||
printf(" | ");
|
||||
else
|
||||
first = FALSE;
|
||||
printf("ATTR_IS_ENCRYPTED");
|
||||
}
|
||||
if (flags & 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)sle64_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 == 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_ntfs3x_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 = NTFS_MNT_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)le32_to_cpu(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)le32_to_cpu(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;
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
.\" Copyright (c) 2002\-2005 Richard Russon.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSUNDELETE 8 "November 2005" "ntfs-3g @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 Time Size Filename
|
||||
6038 FN.. 93% 2002\-07\-17 13:42 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', set it to recovered
|
||||
size and put it in the user's home directory.
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsundelete /dev/hda1 \-u \-T \-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
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfsundelete
|
||||
was written by Richard Russon and Holger Ohmacht, with contributions from Anton
|
||||
Altaparmakov.
|
||||
It was ported to ntfs-3g by Erik Larsson and Jean-Pierre Andre.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsundelete
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfsinfo (8),
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* ntfsundelete - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
* Copyright (c) 2007 Yura Pakhuchiy
|
||||
*
|
||||
* 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 "types.h"
|
||||
#include "list.h"
|
||||
#include "runlist.h"
|
||||
#include "utils.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 */
|
||||
};
|
||||
|
||||
struct filename {
|
||||
struct ntfs_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;
|
||||
leMFT_REF parent_mref;
|
||||
char *parent_name;
|
||||
};
|
||||
|
||||
struct data {
|
||||
struct ntfs_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 */
|
||||
};
|
||||
|
||||
struct ufile {
|
||||
long long inode; /* MFT record number */
|
||||
time_t date; /* Last modification date/time */
|
||||
struct ntfs_list_head name; /* A list of filenames */
|
||||
struct ntfs_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 */
|
||||
};
|
||||
|
||||
#endif /* _NTFSUNDELETE_H_ */
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
.\" Copyright (c) 2007-2016 Jean-Pierre André.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSUSERMAP 8 "February 2016" "ntfsusermap 1.2.0"
|
||||
.SH NAME
|
||||
ntfsusermap \- NTFS Building a User Mapping File
|
||||
.SH SYNOPSIS
|
||||
.B ntfsusermap
|
||||
\fIwindows-system-device\fP
|
||||
\fB[\fIother-ntfs-device\fP...\fB]\fR
|
||||
.PP
|
||||
Where \fIwindows-system-device\fP is the device containing the Windows system
|
||||
whose users are to be mapped to current Linux system.
|
||||
.PP
|
||||
And \fIother-ntfs-device\fP is another device containing files which are
|
||||
to be accessed both by the Windows mentioned above and current Linux system.
|
||||
.PP
|
||||
the ntfsusermap command must be started as root, and the designated devices
|
||||
must not be mounted.
|
||||
.PP
|
||||
Typing ntfsusermap with no args will display a summary of command
|
||||
arguments.
|
||||
.SH DESCRIPTION
|
||||
\fBntfsusermap\fR
|
||||
creates the file defining the mapping of Windows accounts to Linux logins for
|
||||
users who owns files which should be visible from both Windows and
|
||||
Linux.
|
||||
.PP
|
||||
It relies on existing files which were created on Windows, trying
|
||||
to locate significant files and asking which Linux user or group should
|
||||
own them. When a Linux owner or group is requested, the reply may be :
|
||||
.PP
|
||||
- the uid or gid (numeric or symbolic) of Linux owner or group of the file.
|
||||
.RS
|
||||
In that situation, no more file with the same Windows owner will be selected.
|
||||
.RE
|
||||
- or no answer, when not able to define the owner or group.
|
||||
.RS
|
||||
In that situation another file owned by the same Windows user or group
|
||||
may be selected later so that a mapping can be defined.
|
||||
.RE
|
||||
.PP
|
||||
The mappings for standard Windows users, such as "Administrator" or
|
||||
"All Users" are defined implicitly. As a consequence a user mapping should
|
||||
never be defined as Linux root.
|
||||
.PP
|
||||
When there are no more significant files, ntfsusermap create the
|
||||
mapping file into the file UserMapping in the current directory. This
|
||||
file has to be moved to the hidden directory .NTFS-3G in the root of
|
||||
all the NTFS file systems to be shared between Windows and Linux. This
|
||||
requires the file system to be mounted, but the created file will not
|
||||
be taken into account if not present at mount time, which means the
|
||||
file system has to be unmounted and mounted again for the new mapping
|
||||
file to be taken into account.
|
||||
.SH OPTIONS
|
||||
No option is defined for ntfsusermap.
|
||||
.SH EXAMPLES
|
||||
Map the users defined on the Windows system present on /dev/sda1 :
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsusermap /dev/sda1
|
||||
.sp
|
||||
.RE
|
||||
.PP
|
||||
.SH EXIT CODES
|
||||
.B ntfsusermap
|
||||
exits with a value of 0 when no error was detected, and with a value
|
||||
of 1 when an error was detected.
|
||||
.SH KNOWN ISSUES
|
||||
Please see
|
||||
.RS
|
||||
.sp
|
||||
https://github.com/tuxera/ntfs-3g/wiki/NTFS-3G-FAQ/
|
||||
.sp
|
||||
.RE
|
||||
for common questions and known issues.
|
||||
If you would find a new one in the latest release of
|
||||
the software then please send an email describing it
|
||||
in detail. You can contact the
|
||||
development team on the ntfs\-3g\-devel@lists.sf.net
|
||||
address.
|
||||
.SH AUTHORS
|
||||
.B ntfs-3g.secaudit
|
||||
has been developed by Jean-Pierre André.
|
||||
.SH THANKS
|
||||
Several people made heroic efforts, often over five or more
|
||||
years which resulted the ntfs-3g driver. Most importantly they are
|
||||
Anton Altaparmakov, Richard Russon, Szabolcs Szakacsits, Yura Pakhuchiy,
|
||||
Yuval Fledel, and the author of the groundbreaking FUSE filesystem development
|
||||
framework, Miklos Szeredi.
|
||||
.SH SEE ALSO
|
||||
.BR ntfsprogs (8),
|
||||
.BR attr (5),
|
||||
.BR getfattr (1)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,134 @@
|
||||
.\" Copyright (c) 2014 Jean-Pierre Andre
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSWIPE 8 "June 2014" "ntfs-3g @VERSION@"
|
||||
.SH NAME
|
||||
ntfswipe \- overwrite unused space on an NTFS volume
|
||||
.SH SYNOPSIS
|
||||
\fBntfswipe\fR [\fIoptions\fR] \fIdevice\fR
|
||||
.SH DESCRIPTION
|
||||
.B ntfswipe
|
||||
clears all or part of unused space on an NTFS volume by overwriting
|
||||
with zeroes or random bytes.
|
||||
.SH OPTIONS
|
||||
Below is a summary of all the options that
|
||||
.B ntfswipe
|
||||
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
|
||||
Wipe all unused space. This may take significant time. If the option
|
||||
\-\-unused-fast (or -U) is also present, the faster wiping method is used.
|
||||
.TP
|
||||
\fB\-b\fR, \fB\-\-bytes\fR BYTE-LIST
|
||||
Define the allowed replacement bytes which are drawn randomly to overwrite
|
||||
the unused space. BYTE-LIST is a comma-separated list of values in
|
||||
range 0-255 expressed in octal, decimal or hexadecimal base.
|
||||
.TP
|
||||
\fB\-c\fR, \fB\-\-count\fR NUM
|
||||
Define the number of times the unused space is to be overwritten. If both
|
||||
options \fB\-\-bytes\fR and \fB\-\-count\fR are set, the space is
|
||||
repeatedly overwritten this number of times by each of the values in the list.
|
||||
.TP
|
||||
\fB\-d\fR, \fB\-\-directory\fR
|
||||
Wipe all the directory indexes, which may contain names of deleted files.
|
||||
.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\-i\fR, \fB\-\-info\fR
|
||||
Display details about unused space, without wiping anything.
|
||||
.TP
|
||||
\fB\-l\fR, \fB\-\-logfile\fR
|
||||
Overwrite the logfile (update journal).
|
||||
.TP
|
||||
\fB\-m\fR, \fB\-\-mft\fR
|
||||
Overwrite the unused space in the MFT (main file table, which contains the
|
||||
file names, and the contents of short files).
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-no-action\fR
|
||||
Executes the wiping process without writing to device.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-pagefile\fR
|
||||
Overwrite the Windows swap space.
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
Suppress some debug/warning/error messages.
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-undel\fR
|
||||
Overwrite the space which had been allocated to a file which has been deleted
|
||||
recently and is still undeletable. This option is not compatible with
|
||||
\fB\-\-bytes\fR and the replacement bytes are random ones or taken from a
|
||||
standard list.
|
||||
.TP
|
||||
\fB\-t\fR, \fB\-\-tails\fR
|
||||
Overwrite the space at the end of files which is unused, but allocated
|
||||
because the allocations are always done by full clusters.
|
||||
.TP
|
||||
\fB\-u\fR, \fB\-\-unused\fR
|
||||
Overwrite the space which is currently not allocated to any file (but
|
||||
may have been used in the past).
|
||||
.TP
|
||||
\fB\-U\fR, \fB\-\-unused-fast\fR
|
||||
Overwrite the space which is currently not allocated to any file, trying
|
||||
not to overwrite the space not written to since the previous wiping.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
Display more debug/warning/error messages. This option may be used twice
|
||||
to display even more messages.
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-version\fR
|
||||
Show the version number, copyright and license of
|
||||
.BR ntfswipe .
|
||||
.SH EXAMPLES
|
||||
Wipe out all unused space in an NTFS volume.
|
||||
.RS
|
||||
.sp
|
||||
.B ntfswipe -a /dev/sda1
|
||||
.sp
|
||||
.RE
|
||||
Wipe out all deleted file names from an NTFS volume.
|
||||
.RS
|
||||
.sp
|
||||
.B ntfswipe -dms /dev/sda1
|
||||
.sp
|
||||
.RE
|
||||
.SH BUGS
|
||||
There are no known problems with
|
||||
.BR ntfswipe .
|
||||
If you find a bug please send an email describing the problem to the
|
||||
development team:
|
||||
.br
|
||||
.nh
|
||||
ntfs\-3g\-devel@lists.sf.net
|
||||
.hy
|
||||
.SH AUTHORS
|
||||
.B ntfswipe
|
||||
was written by Richard Russon, Anton Altaparmakov and Yura Pakhuchiy.
|
||||
It was ported to ntfs-3g by Erik Larsson.
|
||||
.SH AVAILABILITY
|
||||
.B ntfswipe
|
||||
is part of the
|
||||
.B ntfs-3g
|
||||
package and is available from:
|
||||
.br
|
||||
.nh
|
||||
https://github.com/tuxera/ntfs-3g/wiki/
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfs-3g (8),
|
||||
.BR ntfsls (8),
|
||||
.BR ntfsprogs (8)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 "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 */
|
||||
int unused_fast; /* Wipe unused clusters (fast) */
|
||||
int undel; /* Wipe undelete data */
|
||||
};
|
||||
|
||||
#endif /* _NTFSWIPE_H_ */
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,607 @@
|
||||
#include "types.h"
|
||||
#include "layout.h"
|
||||
#include "sd.h"
|
||||
|
||||
/**
|
||||
* init_system_file_sd -
|
||||
*
|
||||
* NTFS 3.1 - System files security decriptors
|
||||
* =====================================================
|
||||
*
|
||||
* Create the security descriptor for system file number @sys_file_no and
|
||||
* return a pointer to the descriptor.
|
||||
*
|
||||
* Note the root directory system file (".") is very different and handled by a
|
||||
* different function.
|
||||
*
|
||||
* The sd is returned in *@sd_val and has length *@sd_val_len.
|
||||
*
|
||||
* Do NOT free *@sd_val as it is static memory. This also means that you can
|
||||
* only use *@sd_val until the next call to this function.
|
||||
*/
|
||||
void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len)
|
||||
{
|
||||
static u8 sd_array[0x68];
|
||||
SECURITY_DESCRIPTOR_RELATIVE *sd;
|
||||
ACL *acl;
|
||||
ACCESS_ALLOWED_ACE *aa_ace;
|
||||
SID *sid;
|
||||
le32 *sub_authorities;
|
||||
|
||||
if (sys_file_no < 0) {
|
||||
*sd_val = NULL;
|
||||
*sd_val_len = 0;
|
||||
return;
|
||||
}
|
||||
*sd_val = sd_array;
|
||||
sd = (SECURITY_DESCRIPTOR_RELATIVE*)&sd_array;
|
||||
sd->revision = 1;
|
||||
sd->alignment = 0;
|
||||
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
|
||||
*sd_val_len = 0x64;
|
||||
sd->owner = const_cpu_to_le32(0x48);
|
||||
sd->group = const_cpu_to_le32(0x54);
|
||||
sd->sacl = const_cpu_to_le32(0);
|
||||
sd->dacl = const_cpu_to_le32(0x14);
|
||||
/*
|
||||
* Now at offset 0x14, as specified in the security descriptor, we have
|
||||
* the DACL.
|
||||
*/
|
||||
acl = (ACL*)((char*)sd + le32_to_cpu(sd->dacl));
|
||||
acl->revision = 2;
|
||||
acl->alignment1 = 0;
|
||||
acl->size = const_cpu_to_le16(0x34);
|
||||
acl->ace_count = const_cpu_to_le16(2);
|
||||
acl->alignment2 = const_cpu_to_le16(0);
|
||||
/*
|
||||
* Now at offset 0x1c, just after the DACL's ACL, we have the first
|
||||
* ACE of the DACL. The type of the ACE is access allowed.
|
||||
*/
|
||||
aa_ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL));
|
||||
aa_ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
aa_ace->flags = 0;
|
||||
aa_ace->size = const_cpu_to_le16(0x14);
|
||||
switch (sys_file_no) {
|
||||
case FILE_AttrDef:
|
||||
case FILE_Boot:
|
||||
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ |
|
||||
FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA;
|
||||
break;
|
||||
default:
|
||||
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_WRITE |
|
||||
FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
|
||||
FILE_WRITE_EA | FILE_READ_EA | FILE_APPEND_DATA |
|
||||
FILE_WRITE_DATA | FILE_READ_DATA;
|
||||
break;
|
||||
}
|
||||
aa_ace->sid.revision = 1;
|
||||
aa_ace->sid.sub_authority_count = 1;
|
||||
aa_ace->sid.identifier_authority.value[0] = 0;
|
||||
aa_ace->sid.identifier_authority.value[1] = 0;
|
||||
aa_ace->sid.identifier_authority.value[2] = 0;
|
||||
aa_ace->sid.identifier_authority.value[3] = 0;
|
||||
aa_ace->sid.identifier_authority.value[4] = 0;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
aa_ace->sid.identifier_authority.value[5] = 5;
|
||||
aa_ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
|
||||
/*
|
||||
* Now at offset 0x30 within security descriptor, just after the first
|
||||
* ACE of the DACL. All system files, except the root directory, have
|
||||
* a second ACE.
|
||||
*/
|
||||
/* The second ACE of the DACL. Type is access allowed. */
|
||||
aa_ace = (ACCESS_ALLOWED_ACE*)((char*)aa_ace +
|
||||
le16_to_cpu(aa_ace->size));
|
||||
aa_ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
aa_ace->flags = 0;
|
||||
aa_ace->size = const_cpu_to_le16(0x18);
|
||||
/* Only $AttrDef and $Boot behave differently to everything else. */
|
||||
switch (sys_file_no) {
|
||||
case FILE_AttrDef:
|
||||
case FILE_Boot:
|
||||
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ |
|
||||
FILE_READ_ATTRIBUTES | FILE_READ_EA |
|
||||
FILE_READ_DATA;
|
||||
break;
|
||||
default:
|
||||
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ |
|
||||
FILE_WRITE_ATTRIBUTES |
|
||||
FILE_READ_ATTRIBUTES | FILE_WRITE_EA |
|
||||
FILE_READ_EA | FILE_APPEND_DATA |
|
||||
FILE_WRITE_DATA | FILE_READ_DATA;
|
||||
break;
|
||||
}
|
||||
aa_ace->sid.revision = 1;
|
||||
aa_ace->sid.sub_authority_count = 2;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
aa_ace->sid.identifier_authority.value[0] = 0;
|
||||
aa_ace->sid.identifier_authority.value[1] = 0;
|
||||
aa_ace->sid.identifier_authority.value[2] = 0;
|
||||
aa_ace->sid.identifier_authority.value[3] = 0;
|
||||
aa_ace->sid.identifier_authority.value[4] = 0;
|
||||
aa_ace->sid.identifier_authority.value[5] = 5;
|
||||
sub_authorities = aa_ace->sid.sub_authority;
|
||||
*sub_authorities++ =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
*sub_authorities =
|
||||
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
/*
|
||||
* Now at offset 0x48 into the security descriptor, as specified in the
|
||||
* security descriptor, we now have the owner SID.
|
||||
*/
|
||||
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
|
||||
sid->revision = 1;
|
||||
sid->sub_authority_count = 1;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
sid->identifier_authority.value[0] = 0;
|
||||
sid->identifier_authority.value[1] = 0;
|
||||
sid->identifier_authority.value[2] = 0;
|
||||
sid->identifier_authority.value[3] = 0;
|
||||
sid->identifier_authority.value[4] = 0;
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
|
||||
/*
|
||||
* Now at offset 0x54 into the security descriptor, as specified in the
|
||||
* security descriptor, we have the group SID.
|
||||
*/
|
||||
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
|
||||
sid->revision = 1;
|
||||
sid->sub_authority_count = 2;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
sid->identifier_authority.value[0] = 0;
|
||||
sid->identifier_authority.value[1] = 0;
|
||||
sid->identifier_authority.value[2] = 0;
|
||||
sid->identifier_authority.value[3] = 0;
|
||||
sid->identifier_authority.value[4] = 0;
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sub_authorities = sid->sub_authority;
|
||||
*sub_authorities++ = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
*sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
}
|
||||
|
||||
/**
|
||||
* init_root_sd -
|
||||
*
|
||||
* Creates the security_descriptor for the root folder on ntfs 3.1 as created
|
||||
* by Windows Vista (when the format is done from the disk management MMC
|
||||
* snap-in, note this is different from the format done from the disk
|
||||
* properties in Windows Explorer).
|
||||
*/
|
||||
void init_root_sd(u8 **sd_val, int *sd_val_len)
|
||||
{
|
||||
SECURITY_DESCRIPTOR_RELATIVE *sd;
|
||||
ACL *acl;
|
||||
ACCESS_ALLOWED_ACE *ace;
|
||||
SID *sid;
|
||||
le32 *sub_authorities;
|
||||
|
||||
static char sd_array[0x102c];
|
||||
*sd_val_len = 0x102c;
|
||||
*sd_val = (u8*)&sd_array;
|
||||
|
||||
//security descriptor relative
|
||||
sd = (SECURITY_DESCRIPTOR_RELATIVE*)sd_array;
|
||||
sd->revision = SECURITY_DESCRIPTOR_REVISION;
|
||||
sd->alignment = 0;
|
||||
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
|
||||
sd->owner = const_cpu_to_le32(0x1014);
|
||||
sd->group = const_cpu_to_le32(0x1020);
|
||||
sd->sacl = const_cpu_to_le32(0);
|
||||
sd->dacl = const_cpu_to_le32(sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
||||
|
||||
//acl
|
||||
acl = (ACL*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
||||
acl->revision = ACL_REVISION;
|
||||
acl->alignment1 = 0;
|
||||
acl->size = const_cpu_to_le16(0x1000);
|
||||
acl->ace_count = const_cpu_to_le16(0x08);
|
||||
acl->alignment2 = const_cpu_to_le16(0);
|
||||
|
||||
//ace1
|
||||
ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = 0;
|
||||
ace->size = const_cpu_to_le16(0x18);
|
||||
ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
|
||||
FILE_LIST_DIRECTORY | FILE_WRITE_DATA |
|
||||
FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA |
|
||||
FILE_TRAVERSE | FILE_DELETE_CHILD |
|
||||
FILE_READ_ATTRIBUTES;
|
||||
ace->sid.revision = SID_REVISION;
|
||||
ace->sid.sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
sub_authorities = ace->sid.sub_authority;
|
||||
*sub_authorities++ =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
*sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
|
||||
//ace2
|
||||
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
|
||||
INHERIT_ONLY_ACE;
|
||||
ace->size = const_cpu_to_le16(0x18);
|
||||
ace->mask = GENERIC_ALL;
|
||||
ace->sid.revision = SID_REVISION;
|
||||
ace->sid.sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
sub_authorities = ace->sid.sub_authority;
|
||||
*sub_authorities++ =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
*sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
|
||||
//ace3
|
||||
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = 0;
|
||||
ace->size = const_cpu_to_le16(0x14);
|
||||
ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
|
||||
FILE_LIST_DIRECTORY | FILE_WRITE_DATA |
|
||||
FILE_ADD_SUBDIRECTORY | FILE_READ_EA | FILE_WRITE_EA |
|
||||
FILE_TRAVERSE | FILE_DELETE_CHILD |
|
||||
FILE_READ_ATTRIBUTES;
|
||||
ace->sid.revision = SID_REVISION;
|
||||
ace->sid.sub_authority_count = 0x01;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
|
||||
|
||||
//ace4
|
||||
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
|
||||
INHERIT_ONLY_ACE;
|
||||
ace->size = const_cpu_to_le16(0x14);
|
||||
ace->mask = GENERIC_ALL;
|
||||
ace->sid.revision = SID_REVISION;
|
||||
ace->sid.sub_authority_count = 0x01;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
|
||||
|
||||
//ace5
|
||||
ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = 0;
|
||||
ace->size = const_cpu_to_le16(0x14);
|
||||
ace->mask = SYNCHRONIZE | READ_CONTROL | DELETE |
|
||||
FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES |
|
||||
FILE_TRAVERSE | FILE_WRITE_EA | FILE_READ_EA |
|
||||
FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE |
|
||||
FILE_LIST_DIRECTORY;
|
||||
ace->sid.revision = SID_REVISION;
|
||||
ace->sid.sub_authority_count = 0x01;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID);
|
||||
|
||||
//ace6
|
||||
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
|
||||
INHERIT_ONLY_ACE;
|
||||
ace->size = const_cpu_to_le16(0x14);
|
||||
ace->mask = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | DELETE;
|
||||
ace->sid.revision = SID_REVISION;
|
||||
ace->sid.sub_authority_count = 0x01;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_AUTHENTICATED_USER_RID);
|
||||
|
||||
//ace7
|
||||
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = 0;
|
||||
ace->size = const_cpu_to_le16(0x18);
|
||||
ace->mask = SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
|
||||
FILE_TRAVERSE | FILE_READ_EA | FILE_LIST_DIRECTORY;
|
||||
ace->sid.revision = SID_REVISION;
|
||||
ace->sid.sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
sub_authorities = ace->sid.sub_authority;
|
||||
*sub_authorities++ =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
*sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS);
|
||||
|
||||
//ace8
|
||||
ace = (ACCESS_ALLOWED_ACE*)((u8*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE |
|
||||
INHERIT_ONLY_ACE;
|
||||
ace->size = const_cpu_to_le16(0x18);
|
||||
ace->mask = GENERIC_READ | GENERIC_EXECUTE;
|
||||
ace->sid.revision = SID_REVISION;
|
||||
ace->sid.sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
sub_authorities = ace->sid.sub_authority;
|
||||
*sub_authorities++ =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
*sub_authorities = const_cpu_to_le32(DOMAIN_ALIAS_RID_USERS);
|
||||
|
||||
//owner sid
|
||||
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
|
||||
sid->revision = 0x01;
|
||||
sid->sub_authority_count = 0x01;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
sid->identifier_authority.value[0] = 0;
|
||||
sid->identifier_authority.value[1] = 0;
|
||||
sid->identifier_authority.value[2] = 0;
|
||||
sid->identifier_authority.value[3] = 0;
|
||||
sid->identifier_authority.value[4] = 0;
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
|
||||
|
||||
//group sid
|
||||
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
|
||||
sid->revision = 0x01;
|
||||
sid->sub_authority_count = 0x01;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
sid->identifier_authority.value[0] = 0;
|
||||
sid->identifier_authority.value[1] = 0;
|
||||
sid->identifier_authority.value[2] = 0;
|
||||
sid->identifier_authority.value[3] = 0;
|
||||
sid->identifier_authority.value[4] = 0;
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sid->sub_authority[0] = const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
|
||||
}
|
||||
|
||||
/**
|
||||
* init_secure_sds -
|
||||
*
|
||||
* NTFS 3.1 - System files security decriptors
|
||||
* ===========================================
|
||||
* Create the security descriptor entries in $SDS data stream like they
|
||||
* are in a partition, newly formatted with windows 2003
|
||||
*/
|
||||
void init_secure_sds(char *sd_val)
|
||||
{
|
||||
SECURITY_DESCRIPTOR_HEADER *sds;
|
||||
SECURITY_DESCRIPTOR_RELATIVE *sd;
|
||||
ACL *acl;
|
||||
ACCESS_ALLOWED_ACE *ace;
|
||||
SID *sid;
|
||||
|
||||
/*
|
||||
* security descriptor #1
|
||||
*/
|
||||
//header
|
||||
sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val);
|
||||
sds->hash = const_cpu_to_le32(0xF80312F0);
|
||||
sds->security_id = const_cpu_to_le32(0x0100);
|
||||
sds->offset = const_cpu_to_le64(0x00);
|
||||
sds->length = const_cpu_to_le32(0x7C);
|
||||
//security descriptor relative
|
||||
sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds +
|
||||
sizeof(SECURITY_DESCRIPTOR_HEADER));
|
||||
sd->revision = 0x01;
|
||||
sd->alignment = 0x00;
|
||||
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
|
||||
sd->owner = const_cpu_to_le32(0x48);
|
||||
sd->group = const_cpu_to_le32(0x58);
|
||||
sd->sacl = const_cpu_to_le32(0x00);
|
||||
sd->dacl = const_cpu_to_le32(0x14);
|
||||
|
||||
//acl
|
||||
acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
||||
acl->revision = 0x02;
|
||||
acl->alignment1 = 0x00;
|
||||
acl->size = const_cpu_to_le16(0x34);
|
||||
acl->ace_count = const_cpu_to_le16(0x02);
|
||||
acl->alignment2 = const_cpu_to_le16(0x00);
|
||||
|
||||
//ace1
|
||||
ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL));
|
||||
ace->type = 0x00;
|
||||
ace->flags = 0x00;
|
||||
ace->size = const_cpu_to_le16(0x14);
|
||||
ace->mask = const_cpu_to_le32(0x120089);
|
||||
ace->sid.revision = 0x01;
|
||||
ace->sid.sub_authority_count = 0x01;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
|
||||
//ace2
|
||||
ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = 0x00;
|
||||
ace->flags = 0x00;
|
||||
ace->size = const_cpu_to_le16(0x18);
|
||||
ace->mask = const_cpu_to_le32(0x120089);
|
||||
ace->sid.revision = 0x01;
|
||||
ace->sid.sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
ace->sid.sub_authority[1] =
|
||||
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
|
||||
//owner sid
|
||||
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
|
||||
sid->revision = 0x01;
|
||||
sid->sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
sid->identifier_authority.value[0] = 0;
|
||||
sid->identifier_authority.value[1] = 0;
|
||||
sid->identifier_authority.value[2] = 0;
|
||||
sid->identifier_authority.value[3] = 0;
|
||||
sid->identifier_authority.value[4] = 0;
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sid->sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] =
|
||||
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
//group sid
|
||||
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
|
||||
sid->revision = 0x01;
|
||||
sid->sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
sid->identifier_authority.value[0] = 0;
|
||||
sid->identifier_authority.value[1] = 0;
|
||||
sid->identifier_authority.value[2] = 0;
|
||||
sid->identifier_authority.value[3] = 0;
|
||||
sid->identifier_authority.value[4] = 0;
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sid->sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] =
|
||||
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
/*
|
||||
* security descriptor #2
|
||||
*/
|
||||
//header
|
||||
sds = (SECURITY_DESCRIPTOR_HEADER*)((char*)sd_val + 0x80);
|
||||
sds->hash = const_cpu_to_le32(0xB32451);
|
||||
sds->security_id = const_cpu_to_le32(0x0101);
|
||||
sds->offset = const_cpu_to_le64(0x80);
|
||||
sds->length = const_cpu_to_le32(0x7C);
|
||||
|
||||
//security descriptor relative
|
||||
sd = (SECURITY_DESCRIPTOR_RELATIVE*)((char*)sds +
|
||||
sizeof(SECURITY_DESCRIPTOR_HEADER));
|
||||
sd->revision = 0x01;
|
||||
sd->alignment = 0x00;
|
||||
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
|
||||
sd->owner = const_cpu_to_le32(0x48);
|
||||
sd->group = const_cpu_to_le32(0x58);
|
||||
sd->sacl = const_cpu_to_le32(0x00);
|
||||
sd->dacl = const_cpu_to_le32(0x14);
|
||||
|
||||
//acl
|
||||
acl = (ACL*)((char*)sd + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
||||
acl->revision = 0x02;
|
||||
acl->alignment1 = 0x00;
|
||||
acl->size = const_cpu_to_le16(0x34);
|
||||
acl->ace_count = const_cpu_to_le16(0x02);
|
||||
acl->alignment2 = const_cpu_to_le16(0x00);
|
||||
|
||||
//ace1
|
||||
ace = (ACCESS_ALLOWED_ACE*)((char*)acl + sizeof(ACL));
|
||||
ace->type = 0x00;
|
||||
ace->flags = 0x00;
|
||||
ace->size = const_cpu_to_le16(0x14);
|
||||
ace->mask = const_cpu_to_le32(0x12019F);
|
||||
ace->sid.revision = 0x01;
|
||||
ace->sid.sub_authority_count = 0x01;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_LOCAL_SYSTEM_RID);
|
||||
//ace2
|
||||
ace = (ACCESS_ALLOWED_ACE*)((char*)ace + le16_to_cpu(ace->size));
|
||||
ace->type = 0x00;
|
||||
ace->flags = 0x00;
|
||||
ace->size = const_cpu_to_le16(0x18);
|
||||
ace->mask = const_cpu_to_le32(0x12019F);
|
||||
ace->sid.revision = 0x01;
|
||||
ace->sid.sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
ace->sid.identifier_authority.value[0] = 0;
|
||||
ace->sid.identifier_authority.value[1] = 0;
|
||||
ace->sid.identifier_authority.value[2] = 0;
|
||||
ace->sid.identifier_authority.value[3] = 0;
|
||||
ace->sid.identifier_authority.value[4] = 0;
|
||||
ace->sid.identifier_authority.value[5] = 5;
|
||||
ace->sid.sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
ace->sid.sub_authority[1] =
|
||||
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
|
||||
//owner sid
|
||||
sid = (SID*)((char*)sd + le32_to_cpu(sd->owner));
|
||||
sid->revision = 0x01;
|
||||
sid->sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
sid->identifier_authority.value[0] = 0;
|
||||
sid->identifier_authority.value[1] = 0;
|
||||
sid->identifier_authority.value[2] = 0;
|
||||
sid->identifier_authority.value[3] = 0;
|
||||
sid->identifier_authority.value[4] = 0;
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sid->sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] =
|
||||
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
|
||||
//group sid
|
||||
sid = (SID*)((char*)sd + le32_to_cpu(sd->group));
|
||||
sid->revision = 0x01;
|
||||
sid->sub_authority_count = 0x02;
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
sid->identifier_authority.value[0] = 0;
|
||||
sid->identifier_authority.value[1] = 0;
|
||||
sid->identifier_authority.value[2] = 0;
|
||||
sid->identifier_authority.value[3] = 0;
|
||||
sid->identifier_authority.value[4] = 0;
|
||||
sid->identifier_authority.value[5] = 5;
|
||||
sid->sub_authority[0] =
|
||||
const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] =
|
||||
const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef _NTFS_SD_H_
|
||||
#define _NTFS_SD_H_
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void init_system_file_sd(int sys_file_no, u8 **sd_val, int *sd_val_len);
|
||||
void init_root_sd(u8 **sd_val, int *sd_val_len);
|
||||
void init_secure_sds(char *sd_val);
|
||||
|
||||
#endif /* _NTFS_SD_H_ */
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 "types.h"
|
||||
#include "layout.h"
|
||||
#include "volume.h"
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
extern const char *ntfs_bugs;
|
||||
extern const char *ntfs_gpl;
|
||||
|
||||
int utils_set_locale(void);
|
||||
int utils_parse_size(const char *value, s64 *size, BOOL scale);
|
||||
int utils_parse_range(const char *string, s64 *start, s64 *finish, BOOL scale);
|
||||
int utils_inode_get_name(ntfs_inode *inode, char *buffer, int bufsize);
|
||||
int utils_attr_get_name(ntfs_volume *vol, ATTR_RECORD *attr, char *buffer, int bufsize);
|
||||
int utils_cluster_in_use(ntfs_volume *vol, long long lcn);
|
||||
int utils_mftrec_in_use(ntfs_volume *vol, MFT_REF mref);
|
||||
int utils_is_metadata(ntfs_inode *inode);
|
||||
void utils_dump_mem(void *buf, int start, int length, int flags);
|
||||
|
||||
ATTR_RECORD * find_attribute(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx);
|
||||
ATTR_RECORD * find_first_attribute(const ATTR_TYPES type, MFT_RECORD *mft);
|
||||
|
||||
int utils_valid_device(const char *name, int force);
|
||||
ntfs_volume * utils_mount_volume(const char *device, unsigned long flags);
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
/*
|
||||
* Macroes to hide the needs to translate formats on older Windows
|
||||
*/
|
||||
#define MAX_FMT 1536
|
||||
char *ntfs_utils_reformat(char *out, int sz, const char *fmt);
|
||||
char *ntfs_utils_unix_path(const char *in);
|
||||
#define ntfs_log_redirect(fn,fi,li,le,d,fmt, args...) \
|
||||
do { char _b[MAX_FMT]; ntfs_log_redirect(fn,fi,li,le,d, \
|
||||
ntfs_utils_reformat(_b,MAX_FMT,fmt), args); } while (0)
|
||||
#define printf(fmt, args...) \
|
||||
do { char _b[MAX_FMT]; \
|
||||
printf(ntfs_utils_reformat(_b,MAX_FMT,fmt), args); } while (0)
|
||||
#define fprintf(str, fmt, args...) \
|
||||
do { char _b[MAX_FMT]; \
|
||||
fprintf(str, ntfs_utils_reformat(_b,MAX_FMT,fmt), args); } while (0)
|
||||
#define vfprintf(file, fmt, args) \
|
||||
do { char _b[MAX_FMT]; vfprintf(file, \
|
||||
ntfs_utils_reformat(_b,MAX_FMT,fmt), args); } while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* linux-ntfs's ntfs_mbstoucs has different semantics, so we emulate it with
|
||||
* ntfs-3g's.
|
||||
*/
|
||||
int ntfs_mbstoucs_libntfscompat(const char *ins,
|
||||
ntfschar **outs, int outs_len);
|
||||
|
||||
/* This simple utility function was missing from libntfs-3g. */
|
||||
static __inline__ ntfschar *ntfs_attr_get_name(ATTR_RECORD *attr)
|
||||
{
|
||||
return (ntfschar*)((u8*)attr + le16_to_cpu(attr->name_offset));
|
||||
}
|
||||
|
||||
#endif /* _NTFS_UTILS_H_ */
|
||||
Reference in new issue
Block a user