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:
maksw committed 2026-09-16 10:33:20 +02:00
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
@@ -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;
}
@@ -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_ */