parent
37676411cb
commit
cd29ef7745
|
@ -0,0 +1,77 @@
|
|||
# Need this to enable 64-bit (device) file access functions and parameters.
|
||||
if DEBUG
|
||||
AM_CFLAGS = -D_FILE_OFFSET_BITS=64 -g -DDEBUG -Wall
|
||||
else
|
||||
AM_CFLAGS = -D_FILE_OFFSET_BITS=64
|
||||
endif
|
||||
|
||||
if REALLYSTATIC
|
||||
AM_LIBS = $(top_srcdir)/libntfs/.libs/libntfs.a
|
||||
AM_LFLAGS = -static
|
||||
STATIC_LINK = $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
else
|
||||
AM_LIBS = $(top_srcdir)/libntfs/libntfs.la
|
||||
AM_LFLAGS = $(all_libraries)
|
||||
LIBTOOL_LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
endif
|
||||
|
||||
# Workaround to make REALLYSTATIC work with automake 1.5.
|
||||
LINK=$(STATIC_LINK) $(LIBTOOL_LINK)
|
||||
|
||||
bin_PROGRAMS = ntfsfix ntfsinfo
|
||||
sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize
|
||||
EXTRA_PROGRAMS = ntfsdump_logfile dumplog ntfswipe
|
||||
|
||||
man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8 ntfsundelete.8 \
|
||||
ntfsresize.8
|
||||
EXTRA_MANS =
|
||||
|
||||
CLEANFILES = $(EXTRA_PROGRAMS)
|
||||
|
||||
linux_ntfsincludedir = -I$(top_srcdir)/include
|
||||
|
||||
# Set the include path.
|
||||
INCLUDES = -I$(top_srcdir)/include $(all_includes)
|
||||
|
||||
ntfsfix_SOURCES = ntfsfix.c
|
||||
ntfsfix_LDADD = $(AM_LIBS)
|
||||
ntfsfix_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
mkntfs_SOURCES = attrdef.c upcase.c boot.c sd.c mkntfs.c
|
||||
mkntfs_LDADD = $(AM_LIBS)
|
||||
mkntfs_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfslabel_SOURCES = ntfslabel.c
|
||||
ntfslabel_LDADD = $(AM_LIBS)
|
||||
ntfslabel_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsinfo_SOURCES = ntfsinfo.c
|
||||
ntfsinfo_LDADD = $(AM_LIBS)
|
||||
ntfsinfo_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsundelete_SOURCES = ntfsundelete.c ntfsundelete.h
|
||||
ntfsundelete_LDADD = $(AM_LIBS)
|
||||
ntfsundelete_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsresize_SOURCES = ntfsresize.c
|
||||
ntfsresize_LDADD = $(AM_LIBS)
|
||||
ntfsresize_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
# We don't distribute these
|
||||
|
||||
ntfswipe_SOURCES = ntfswipe.c ntfswipe.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)
|
||||
|
||||
dumplog_SOURCES = dumplog.c
|
||||
dumplog_LDADD = $(AM_LIBS)
|
||||
dumplog_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
# Extra targets
|
||||
|
||||
strip: $(bin_PROGRAMS) $(sbin_PROGRAMS)
|
||||
$(STRIP) $^
|
|
@ -0,0 +1,153 @@
|
|||
const unsigned char attrdef_ntfs12_array[2400] = {
|
||||
36, 0, 83, 0, 84, 0, 65, 0, 78, 0, 68, 0, 65, 0, 82, 0,
|
||||
68, 0, 95, 0, 73, 0, 78, 0, 70, 0, 79, 0, 82, 0, 77, 0,
|
||||
65, 0, 84, 0, 73, 0, 79, 0, 78, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
|
||||
48, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 65, 0, 84, 0, 84, 0, 82, 0, 73, 0, 66, 0, 85, 0,
|
||||
84, 0, 69, 0, 95, 0, 76, 0, 73, 0, 83, 0, 84, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
36, 0, 70, 0, 73, 0, 76, 0, 69, 0, 95, 0, 78, 0, 65, 0,
|
||||
77, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0,
|
||||
68, 0, 0, 0, 0, 0, 0, 0, 66, 2, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
|
||||
86, 0, 69, 0, 82, 0, 83, 0, 73, 0, 79, 0, 78, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
|
||||
8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 83, 0, 69, 0, 67, 0, 85, 0, 82, 0, 73, 0, 84, 0,
|
||||
89, 0, 95, 0, 68, 0, 69, 0, 83, 0, 67, 0, 82, 0, 73, 0,
|
||||
80, 0, 84, 0, 79, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
|
||||
78, 0, 65, 0, 77, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
|
||||
2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 86, 0, 79, 0, 76, 0, 85, 0, 77, 0, 69, 0, 95, 0,
|
||||
73, 0, 78, 0, 70, 0, 79, 0, 82, 0, 77, 0, 65, 0, 84, 0,
|
||||
73, 0, 79, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
|
||||
12, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 68, 0, 65, 0, 84, 0, 65, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
36, 0, 73, 0, 78, 0, 68, 0, 69, 0, 88, 0, 95, 0, 82, 0,
|
||||
79, 0, 79, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
36, 0, 73, 0, 78, 0, 68, 0, 69, 0, 88, 0, 95, 0, 65, 0,
|
||||
76, 0, 76, 0, 79, 0, 67, 0, 65, 0, 84, 0, 73, 0, 79, 0,
|
||||
78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
36, 0, 66, 0, 73, 0, 84, 0, 77, 0, 65, 0, 80, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
36, 0, 83, 0, 89, 0, 77, 0, 66, 0, 79, 0, 76, 0, 73, 0,
|
||||
67, 0, 95, 0, 76, 0, 73, 0, 78, 0, 75, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
36, 0, 69, 0, 65, 0, 95, 0, 73, 0, 78, 0, 70, 0, 79, 0,
|
||||
82, 0, 77, 0, 65, 0, 84, 0, 73, 0, 79, 0, 78, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0,
|
||||
8, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 69, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
218
ntfsprogs/boot.c
218
ntfsprogs/boot.c
|
@ -0,0 +1,218 @@
|
|||
/* The first 3429 bytes of $Boot. The rest is just zero. Total 8192 bytes. */
|
||||
const unsigned char boot_array[3429] = {
|
||||
235, 91, 144, 78, 84, 70, 83, 32, 32, 32, 32, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 51, 192,
|
||||
142, 208, 188, 0, 124, 251, 184, 192, 7, 142, 216, 199, 6, 84, 0, 0,
|
||||
0, 199, 6, 86, 0, 0, 0, 199, 6, 91, 0, 16, 0, 184, 0, 13,
|
||||
142, 192, 43, 219, 232, 7, 0, 104, 0, 13, 104, 102, 2, 203, 80, 83,
|
||||
81, 82, 6, 102, 161, 84, 0, 102, 3, 6, 28, 0, 102, 51, 210, 102,
|
||||
15, 183, 14, 24, 0, 102, 247, 241, 254, 194, 136, 22, 90, 0, 102, 139,
|
||||
208, 102, 193, 234, 16, 247, 54, 26, 0, 136, 22, 37, 0, 163, 88, 0,
|
||||
161, 24, 0, 42, 6, 90, 0, 64, 59, 6, 91, 0, 118, 3, 161, 91,
|
||||
0, 80, 180, 2, 139, 22, 88, 0, 177, 6, 210, 230, 10, 54, 90, 0,
|
||||
139, 202, 134, 233, 138, 54, 37, 0, 178, 128, 205, 19, 88, 114, 42, 1,
|
||||
6, 84, 0, 131, 22, 86, 0, 0, 41, 6, 91, 0, 118, 11, 193, 224,
|
||||
5, 140, 194, 3, 208, 142, 194, 235, 138, 7, 90, 89, 91, 88, 195, 190,
|
||||
89, 1, 235, 8, 190, 227, 1, 235, 3, 190, 57, 1, 232, 9, 0, 190,
|
||||
173, 1, 232, 3, 0, 251, 235, 254, 172, 60, 0, 116, 9, 180, 14, 187,
|
||||
7, 0, 205, 16, 235, 242, 195, 29, 0, 65, 32, 100, 105, 115, 107, 32,
|
||||
114, 101, 97, 100, 32, 101, 114, 114, 111, 114, 32, 111, 99, 99, 117, 114,
|
||||
114, 101, 100, 46, 13, 10, 0, 41, 0, 65, 32, 107, 101, 114, 110, 101,
|
||||
108, 32, 102, 105, 108, 101, 32, 105, 115, 32, 109, 105, 115, 115, 105, 110,
|
||||
103, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 100, 105, 115, 107, 46,
|
||||
13, 10, 0, 37, 0, 65, 32, 107, 101, 114, 110, 101, 108, 32, 102, 105,
|
||||
108, 101, 32, 105, 115, 32, 116, 111, 111, 32, 100, 105, 115, 99, 111, 110,
|
||||
116, 105, 103, 117, 111, 117, 115, 46, 13, 10, 0, 51, 0, 73, 110, 115,
|
||||
101, 114, 116, 32, 97, 32, 115, 121, 115, 116, 101, 109, 32, 100, 105, 115,
|
||||
107, 101, 116, 116, 101, 32, 97, 110, 100, 32, 114, 101, 115, 116, 97, 114,
|
||||
116, 13, 10, 116, 104, 101, 32, 115, 121, 115, 116, 101, 109, 46, 13, 10,
|
||||
0, 23, 0, 92, 78, 84, 76, 68, 82, 32, 105, 115, 32, 99, 111, 109,
|
||||
112, 114, 101, 115, 115, 101, 100, 46, 13, 10, 0, 0, 0, 0, 85, 170,
|
||||
5, 0, 78, 0, 84, 0, 76, 0, 68, 0, 82, 0, 4, 0, 36, 0,
|
||||
73, 0, 51, 0, 48, 0, 0, 224, 0, 0, 0, 48, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 140, 200, 142, 216, 193, 224, 4, 250, 139, 224,
|
||||
251, 102, 15, 183, 6, 11, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227,
|
||||
102, 163, 78, 2, 102, 139, 14, 64, 0, 128, 249, 0, 15, 143, 14, 0,
|
||||
246, 217, 102, 184, 1, 0, 0, 0, 102, 211, 224, 235, 8, 144, 102, 161,
|
||||
78, 2, 102, 247, 225, 102, 163, 82, 2, 102, 15, 183, 30, 11, 0, 102,
|
||||
51, 210, 102, 247, 243, 102, 163, 86, 2, 232, 44, 4, 102, 139, 14, 74,
|
||||
2, 102, 137, 14, 34, 2, 102, 3, 14, 82, 2, 102, 137, 14, 38, 2,
|
||||
102, 3, 14, 82, 2, 102, 137, 14, 42, 2, 102, 3, 14, 82, 2, 102,
|
||||
137, 14, 58, 2, 102, 3, 14, 82, 2, 102, 137, 14, 66, 2, 102, 184,
|
||||
144, 0, 0, 0, 102, 139, 14, 34, 2, 232, 65, 9, 102, 11, 192, 15,
|
||||
132, 22, 254, 102, 163, 46, 2, 102, 184, 160, 0, 0, 0, 102, 139, 14,
|
||||
38, 2, 232, 40, 9, 102, 163, 50, 2, 102, 184, 176, 0, 0, 0, 102,
|
||||
139, 14, 42, 2, 232, 22, 9, 102, 163, 54, 2, 102, 161, 46, 2, 102,
|
||||
11, 192, 15, 132, 227, 253, 103, 128, 120, 8, 0, 15, 133, 218, 253, 103,
|
||||
102, 141, 80, 16, 103, 3, 66, 4, 103, 102, 15, 182, 72, 12, 102, 137,
|
||||
14, 94, 2, 103, 102, 139, 72, 8, 102, 137, 14, 90, 2, 102, 161, 90,
|
||||
2, 102, 15, 183, 14, 11, 0, 102, 51, 210, 102, 247, 241, 102, 163, 98,
|
||||
2, 102, 161, 66, 2, 102, 3, 6, 90, 2, 102, 163, 70, 2, 102, 131,
|
||||
62, 50, 2, 0, 15, 132, 25, 0, 102, 131, 62, 54, 2, 0, 15, 132,
|
||||
135, 253, 102, 139, 30, 54, 2, 30, 7, 102, 139, 62, 70, 2, 232, 177,
|
||||
1, 102, 15, 183, 14, 0, 2, 102, 184, 2, 2, 0, 0, 232, 153, 6,
|
||||
102, 11, 192, 15, 132, 88, 253, 103, 102, 139, 0, 30, 7, 102, 139, 62,
|
||||
58, 2, 232, 209, 4, 102, 161, 58, 2, 102, 187, 128, 0, 0, 0, 102,
|
||||
185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232, 203, 0, 102, 11,
|
||||
192, 15, 132, 42, 253, 103, 102, 15, 183, 88, 12, 102, 129, 227, 255, 0,
|
||||
0, 0, 15, 133, 30, 253, 102, 139, 216, 104, 0, 32, 7, 102, 43, 255,
|
||||
232, 79, 1, 138, 22, 36, 0, 184, 232, 3, 142, 192, 141, 54, 11, 0,
|
||||
43, 192, 104, 0, 32, 80, 203, 80, 83, 81, 82, 6, 255, 54, 91, 0,
|
||||
255, 54, 84, 0, 255, 54, 86, 0, 139, 195, 193, 232, 4, 140, 193, 3,
|
||||
193, 37, 255, 15, 45, 0, 16, 247, 216, 139, 14, 91, 0, 193, 225, 5,
|
||||
81, 59, 193, 118, 2, 139, 193, 80, 193, 232, 5, 163, 91, 0, 232, 61,
|
||||
252, 88, 89, 43, 200, 118, 11, 140, 194, 3, 208, 142, 194, 184, 0, 16,
|
||||
235, 222, 143, 6, 86, 0, 143, 6, 84, 0, 143, 6, 91, 0, 7, 90,
|
||||
89, 91, 88, 195, 6, 30, 102, 96, 102, 139, 218, 102, 15, 182, 14, 13,
|
||||
0, 102, 247, 225, 102, 163, 84, 0, 102, 139, 195, 102, 247, 225, 163, 91,
|
||||
0, 139, 223, 131, 227, 15, 140, 192, 102, 193, 239, 4, 3, 199, 80, 7,
|
||||
232, 116, 255, 102, 97, 144, 31, 7, 195, 103, 3, 64, 20, 103, 102, 131,
|
||||
56, 255, 15, 132, 76, 0, 103, 102, 57, 24, 15, 133, 51, 0, 102, 11,
|
||||
201, 15, 133, 10, 0, 103, 128, 120, 9, 0, 15, 133, 35, 0, 195, 103,
|
||||
58, 72, 9, 15, 133, 26, 0, 102, 139, 240, 103, 3, 112, 10, 232, 61,
|
||||
5, 102, 81, 30, 7, 102, 139, 250, 243, 167, 102, 89, 15, 133, 1, 0,
|
||||
195, 103, 102, 131, 120, 4, 0, 15, 132, 7, 0, 103, 102, 3, 64, 4,
|
||||
235, 171, 102, 43, 192, 195, 102, 139, 243, 232, 18, 5, 103, 102, 3, 0,
|
||||
103, 247, 64, 12, 2, 0, 15, 133, 52, 0, 103, 102, 141, 80, 16, 103,
|
||||
58, 74, 64, 15, 133, 24, 0, 103, 102, 141, 114, 66, 232, 239, 4, 102,
|
||||
81, 30, 7, 102, 139, 251, 243, 167, 102, 89, 15, 133, 1, 0, 195, 103,
|
||||
131, 120, 8, 0, 15, 132, 6, 0, 103, 3, 64, 8, 235, 194, 102, 51,
|
||||
192, 195, 103, 128, 123, 8, 0, 15, 133, 28, 0, 6, 30, 102, 96, 103,
|
||||
102, 141, 83, 16, 103, 102, 139, 10, 102, 139, 243, 103, 3, 114, 4, 243,
|
||||
164, 102, 97, 144, 31, 7, 195, 103, 102, 141, 83, 16, 103, 102, 139, 74,
|
||||
8, 102, 65, 102, 43, 192, 232, 1, 0, 195, 6, 30, 102, 96, 103, 128,
|
||||
123, 8, 1, 15, 132, 3, 0, 233, 127, 251, 102, 131, 249, 0, 15, 133,
|
||||
6, 0, 102, 97, 144, 31, 7, 195, 102, 83, 102, 80, 102, 81, 102, 87,
|
||||
6, 232, 87, 3, 102, 139, 209, 7, 102, 95, 102, 89, 102, 59, 202, 15,
|
||||
141, 3, 0, 102, 139, 209, 232, 171, 254, 102, 43, 202, 102, 139, 218, 102,
|
||||
139, 194, 102, 15, 182, 22, 13, 0, 102, 247, 226, 102, 15, 183, 22, 11,
|
||||
0, 102, 247, 226, 102, 3, 248, 102, 88, 102, 3, 195, 102, 91, 235, 170,
|
||||
6, 30, 102, 96, 103, 128, 123, 8, 1, 15, 132, 3, 0, 233, 25, 251,
|
||||
102, 131, 249, 0, 15, 133, 6, 0, 102, 97, 144, 31, 7, 195, 102, 83,
|
||||
102, 80, 102, 81, 102, 87, 6, 102, 81, 102, 51, 210, 102, 15, 182, 14,
|
||||
13, 0, 102, 247, 241, 102, 82, 232, 225, 2, 102, 15, 182, 30, 13, 0,
|
||||
102, 247, 227, 102, 90, 102, 3, 194, 102, 80, 102, 15, 182, 6, 13, 0,
|
||||
102, 247, 225, 102, 139, 208, 102, 88, 102, 89, 7, 102, 95, 102, 89, 102,
|
||||
59, 202, 15, 141, 3, 0, 102, 139, 209, 102, 163, 84, 0, 137, 22, 91,
|
||||
0, 6, 30, 102, 96, 139, 223, 131, 227, 15, 140, 192, 102, 193, 239, 4,
|
||||
3, 199, 80, 7, 232, 160, 253, 102, 97, 144, 31, 7, 102, 43, 202, 102,
|
||||
139, 218, 102, 139, 194, 102, 15, 183, 22, 11, 0, 102, 247, 226, 102, 3,
|
||||
248, 102, 88, 102, 3, 195, 102, 91, 233, 101, 255, 6, 30, 102, 96, 38,
|
||||
103, 102, 15, 183, 95, 4, 38, 103, 102, 15, 183, 79, 6, 102, 11, 201,
|
||||
15, 132, 101, 250, 102, 3, 223, 102, 131, 195, 2, 102, 129, 199, 254, 1,
|
||||
0, 0, 102, 73, 102, 11, 201, 15, 132, 23, 0, 38, 103, 139, 3, 38,
|
||||
103, 137, 7, 102, 131, 195, 2, 102, 129, 199, 0, 2, 0, 0, 102, 73,
|
||||
235, 226, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 184, 1, 0,
|
||||
0, 0, 102, 163, 30, 2, 102, 161, 26, 2, 102, 3, 6, 82, 2, 102,
|
||||
163, 74, 2, 102, 161, 48, 0, 102, 15, 182, 30, 13, 0, 102, 247, 227,
|
||||
102, 163, 84, 0, 102, 161, 86, 2, 163, 91, 0, 102, 139, 30, 26, 2,
|
||||
30, 7, 232, 242, 252, 102, 15, 183, 251, 232, 111, 255, 102, 161, 26, 2,
|
||||
102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0,
|
||||
0, 0, 232, 100, 253, 102, 11, 192, 15, 132, 87, 0, 102, 139, 216, 30,
|
||||
7, 102, 139, 62, 22, 2, 232, 249, 253, 102, 139, 30, 22, 2, 103, 102,
|
||||
129, 59, 128, 0, 0, 0, 15, 132, 6, 0, 103, 3, 91, 4, 235, 238,
|
||||
103, 102, 129, 59, 128, 0, 0, 0, 15, 133, 39, 0, 102, 83, 103, 102,
|
||||
139, 67, 16, 102, 139, 62, 74, 2, 30, 7, 232, 9, 1, 102, 91, 102,
|
||||
161, 82, 2, 102, 1, 6, 74, 2, 102, 255, 6, 30, 2, 103, 3, 91,
|
||||
4, 235, 205, 102, 97, 144, 31, 7, 195, 102, 139, 208, 102, 139, 14, 30,
|
||||
2, 102, 161, 26, 2, 102, 82, 102, 80, 102, 81, 102, 82, 102, 187, 128,
|
||||
0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186, 0, 0, 0, 0, 232,
|
||||
215, 252, 102, 11, 192, 15, 132, 64, 249, 102, 139, 216, 102, 88, 232, 42,
|
||||
1, 102, 11, 192, 15, 132, 7, 0, 102, 91, 102, 91, 102, 91, 195, 102,
|
||||
89, 102, 88, 102, 90, 102, 3, 6, 82, 2, 226, 185, 102, 51, 192, 195,
|
||||
6, 30, 102, 96, 102, 80, 102, 81, 102, 51, 210, 102, 15, 182, 30, 13,
|
||||
0, 102, 247, 243, 102, 82, 232, 144, 255, 102, 11, 192, 15, 132, 249, 248,
|
||||
102, 15, 182, 30, 13, 0, 102, 247, 227, 102, 90, 102, 3, 194, 102, 163,
|
||||
84, 0, 102, 89, 102, 15, 182, 30, 13, 0, 102, 59, 203, 15, 142, 19,
|
||||
0, 137, 30, 91, 0, 102, 43, 203, 102, 88, 102, 3, 195, 102, 80, 102,
|
||||
81, 235, 20, 144, 102, 88, 102, 3, 193, 102, 80, 137, 14, 91, 0, 102,
|
||||
185, 0, 0, 0, 0, 102, 81, 6, 102, 87, 139, 223, 131, 227, 15, 140,
|
||||
192, 102, 193, 239, 4, 3, 199, 80, 7, 232, 155, 251, 102, 95, 7, 102,
|
||||
3, 62, 78, 2, 102, 89, 102, 88, 102, 131, 249, 0, 15, 143, 116, 255,
|
||||
102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 247, 38, 86, 2, 102,
|
||||
139, 14, 86, 2, 232, 89, 255, 232, 241, 253, 102, 97, 144, 31, 7, 195,
|
||||
6, 30, 102, 96, 102, 247, 38, 98, 2, 102, 139, 30, 50, 2, 102, 139,
|
||||
14, 98, 2, 30, 7, 102, 139, 62, 66, 2, 232, 35, 253, 232, 203, 253,
|
||||
102, 97, 144, 31, 7, 195, 102, 80, 102, 83, 102, 81, 102, 139, 30, 70,
|
||||
2, 102, 139, 200, 102, 193, 232, 3, 102, 131, 225, 7, 102, 3, 216, 102,
|
||||
184, 1, 0, 0, 0, 102, 211, 224, 103, 132, 3, 15, 132, 4, 0, 248,
|
||||
235, 2, 144, 249, 102, 89, 102, 91, 102, 88, 195, 103, 128, 123, 8, 1,
|
||||
15, 132, 4, 0, 102, 43, 192, 195, 103, 102, 141, 115, 16, 103, 102, 139,
|
||||
86, 8, 102, 59, 194, 15, 135, 11, 0, 103, 102, 139, 22, 102, 59, 194,
|
||||
15, 131, 4, 0, 102, 43, 192, 195, 103, 3, 94, 16, 102, 43, 246, 103,
|
||||
128, 59, 0, 15, 132, 62, 0, 232, 129, 0, 102, 3, 241, 232, 57, 0,
|
||||
102, 3, 202, 102, 59, 193, 15, 140, 33, 0, 102, 139, 209, 102, 80, 103,
|
||||
102, 15, 182, 11, 102, 139, 193, 102, 131, 224, 15, 102, 193, 233, 4, 102,
|
||||
3, 217, 102, 3, 216, 102, 67, 102, 88, 235, 196, 102, 43, 200, 102, 43,
|
||||
194, 102, 3, 198, 195, 102, 43, 192, 195, 102, 43, 201, 103, 138, 11, 128,
|
||||
225, 15, 102, 131, 249, 0, 15, 133, 4, 0, 102, 43, 201, 195, 102, 83,
|
||||
102, 82, 102, 3, 217, 103, 102, 15, 190, 19, 102, 73, 102, 75, 102, 131,
|
||||
249, 0, 15, 132, 13, 0, 102, 193, 226, 8, 103, 138, 19, 102, 75, 102,
|
||||
73, 235, 235, 102, 139, 202, 102, 90, 102, 91, 195, 102, 83, 102, 82, 102,
|
||||
43, 210, 103, 138, 19, 102, 131, 226, 15, 102, 43, 201, 103, 138, 11, 192,
|
||||
233, 4, 102, 131, 249, 0, 15, 133, 8, 0, 102, 43, 201, 102, 90, 102,
|
||||
91, 195, 102, 3, 218, 102, 3, 217, 103, 102, 15, 190, 19, 102, 73, 102,
|
||||
75, 102, 131, 249, 0, 15, 132, 13, 0, 102, 193, 226, 8, 103, 138, 19,
|
||||
102, 75, 102, 73, 235, 235, 102, 139, 202, 102, 90, 102, 91, 195, 102, 11,
|
||||
201, 15, 133, 1, 0, 195, 102, 81, 102, 86, 103, 131, 62, 97, 15, 140,
|
||||
12, 0, 103, 131, 62, 122, 15, 143, 4, 0, 103, 131, 46, 32, 102, 131,
|
||||
198, 2, 226, 230, 102, 94, 102, 89, 195, 102, 80, 102, 81, 102, 139, 208,
|
||||
102, 161, 46, 2, 103, 102, 141, 88, 16, 103, 3, 67, 4, 103, 102, 141,
|
||||
64, 16, 102, 139, 218, 232, 158, 250, 102, 11, 192, 15, 132, 5, 0, 102,
|
||||
89, 102, 89, 195, 102, 161, 50, 2, 102, 11, 192, 15, 133, 8, 0, 102,
|
||||
89, 102, 89, 102, 51, 192, 195, 102, 139, 22, 50, 2, 103, 102, 141, 82,
|
||||
16, 103, 102, 139, 66, 8, 102, 64, 102, 139, 30, 78, 2, 102, 247, 227,
|
||||
102, 51, 210, 102, 247, 54, 90, 2, 102, 80, 102, 88, 102, 11, 192, 15,
|
||||
132, 48, 0, 102, 72, 102, 80, 232, 28, 254, 114, 238, 232, 241, 253, 102,
|
||||
90, 102, 89, 102, 91, 102, 83, 102, 81, 102, 82, 102, 161, 66, 2, 103,
|
||||
102, 141, 64, 24, 232, 47, 250, 102, 11, 192, 116, 206, 102, 89, 102, 89,
|
||||
102, 89, 195, 102, 89, 102, 89, 102, 51, 192, 195, 6, 30, 102, 96, 102,
|
||||
139, 54, 66, 2, 102, 185, 32, 0, 0, 0, 102, 247, 193, 3, 0, 0,
|
||||
0, 15, 133, 3, 0, 232, 13, 0, 102, 173, 232, 105, 0, 226, 235, 102,
|
||||
97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 51, 192, 102, 51, 219, 176,
|
||||
13, 180, 14, 187, 7, 0, 205, 16, 176, 10, 180, 14, 187, 7, 0, 205,
|
||||
16, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 11, 201, 15, 133,
|
||||
9, 0, 232, 208, 255, 102, 97, 144, 31, 7, 195, 102, 51, 192, 102, 51,
|
||||
219, 173, 180, 14, 187, 7, 0, 205, 16, 226, 240, 232, 183, 255, 102, 97,
|
||||
144, 31, 7, 195, 96, 172, 60, 0, 116, 9, 180, 14, 187, 7, 0, 205,
|
||||
16, 235, 242, 97, 144, 195, 6, 30, 102, 96, 102, 185, 8, 0, 0, 0,
|
||||
102, 139, 208, 102, 131, 226, 15, 102, 82, 102, 193, 232, 4, 226, 241, 102,
|
||||
185, 8, 0, 0, 0, 102, 88, 102, 131, 248, 9, 15, 143, 7, 0, 102,
|
||||
131, 192, 48, 235, 9, 144, 102, 131, 232, 10, 102, 131, 192, 65, 102, 51,
|
||||
219, 180, 14, 187, 7, 0, 205, 16, 226, 219, 176, 32, 180, 14, 187, 7,
|
||||
0, 205, 16, 102, 97, 144, 31, 7, 232, 96, 0, 195, 6, 30, 102, 96,
|
||||
102, 190, 22, 13, 0, 0, 232, 79, 245, 102, 97, 144, 31, 7, 195, 6,
|
||||
30, 102, 96, 102, 190, 38, 13, 0, 0, 232, 60, 245, 102, 97, 144, 31,
|
||||
7, 195, 6, 30, 102, 96, 102, 190, 54, 13, 0, 0, 232, 41, 245, 102,
|
||||
97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 190, 70, 13, 0, 0, 232,
|
||||
22, 245, 102, 97, 144, 31, 7, 195, 6, 30, 102, 96, 102, 190, 86, 13,
|
||||
0, 0, 232, 3, 245, 102, 97, 144, 31, 7, 195, 102, 80, 102, 184, 0,
|
||||
0, 245, 255, 102, 64, 102, 11, 192, 117, 249, 102, 88, 195, 102, 81, 102,
|
||||
80, 102, 184, 5, 0, 0, 0, 30, 7, 102, 139, 249, 232, 71, 252, 102,
|
||||
139, 193, 102, 91, 102, 83, 102, 15, 183, 14, 12, 2, 102, 186, 14, 2,
|
||||
0, 0, 232, 68, 248, 102, 91, 102, 89, 102, 11, 192, 15, 133, 47, 0,
|
||||
102, 139, 193, 102, 139, 203, 102, 80, 102, 83, 232, 35, 0, 102, 91, 102,
|
||||
95, 102, 11, 192, 15, 132, 23, 0, 30, 7, 232, 9, 252, 102, 139, 199,
|
||||
102, 15, 183, 14, 12, 2, 102, 186, 14, 2, 0, 0, 232, 10, 248, 195,
|
||||
102, 81, 102, 187, 32, 0, 0, 0, 102, 185, 0, 0, 0, 0, 102, 186,
|
||||
0, 0, 0, 0, 232, 242, 247, 102, 11, 192, 15, 132, 82, 0, 102, 139,
|
||||
216, 30, 7, 102, 139, 62, 22, 2, 232, 135, 248, 30, 7, 102, 139, 30,
|
||||
22, 2, 102, 89, 38, 102, 57, 15, 15, 132, 46, 0, 38, 102, 131, 63,
|
||||
255, 15, 132, 45, 0, 38, 131, 127, 4, 0, 15, 132, 36, 0, 38, 102,
|
||||
15, 183, 71, 4, 3, 216, 139, 195, 37, 0, 128, 116, 215, 140, 192, 5,
|
||||
0, 8, 142, 192, 129, 227, 255, 127, 235, 202, 38, 102, 139, 71, 16, 195,
|
||||
102, 89, 102, 51, 192, 195, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
|
||||
116, 32, 48, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
|
||||
116, 32, 49, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
|
||||
116, 32, 50, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
|
||||
116, 32, 51, 13, 10, 0, 68, 101, 98, 117, 103, 32, 80, 111, 105, 110,
|
||||
116, 32, 52, 13, 10 };
|
||||
|
|
@ -0,0 +1,310 @@
|
|||
const char *EXEC_NAME = "dumplog";
|
||||
const char *EXEC_VERSION = "1.0";
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* DumpLog - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000,2001 Anton Altaparmakov.
|
||||
*
|
||||
* This utility will interpret the contents of the journal ($LogFile) specified
|
||||
* on the command line and display the results on stdout. Errors will be output
|
||||
* to stderr.
|
||||
*
|
||||
* Anton Altaparmakov <aia21@cantab.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the Linux-NTFS source
|
||||
* in the file COPYING); if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "mst.h"
|
||||
#include "logfile.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
s64 l, br;
|
||||
unsigned char *lfd = NULL;
|
||||
RESTART_PAGE_HEADER *rph;
|
||||
RESTART_AREA *rr;
|
||||
RESTART_CLIENT *cr;
|
||||
RECORD_PAGE_HEADER *rcrd_ph;
|
||||
LOG_RECORD *lr;
|
||||
int pass = 1;
|
||||
int i, lps, client;
|
||||
int f = 0;
|
||||
char zero[4096];
|
||||
struct stat sbuf;
|
||||
|
||||
memset(zero, 0, sizeof(zero));
|
||||
printf("\n");
|
||||
if (argc != 2) {
|
||||
printf("%s v%s - Interpret and display information about the "
|
||||
"journal\ngiven on the command line.\n\n"
|
||||
/* Generic copyright / disclaimer. */
|
||||
"Copyright (c) 2001 Anton Altaparmakov.\n\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\nGeneral Public License to be found "
|
||||
"in the file COPYING in the main Linux-NTFS\n"
|
||||
"distribution directory.\n\n"
|
||||
/* Generic part ends here. */
|
||||
"Syntax: dumplog log_file_name\n"
|
||||
" e.g. dumplog /mnt/ntfstest/\\$LogFile\n\n",
|
||||
EXEC_NAME, EXEC_VERSION, EXEC_NAME, EXEC_NAME);
|
||||
fprintf(stderr, "Error: incorrect syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
if (stat(argv[1], &sbuf) == -1) {
|
||||
if (errno == ENOENT)
|
||||
fprintf(stderr, "The file doesn't exist; did you "
|
||||
"specify it correctly?\n");
|
||||
else
|
||||
fprintf(stderr, "Error getting information about %s: "
|
||||
"%s\n", argv[1], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
f = open(argv[1], O_RDONLY);
|
||||
if (f == -1) {
|
||||
perror("Couldn't open file");
|
||||
exit(1);
|
||||
}
|
||||
l = sbuf.st_size;
|
||||
if (l > 0x400000LL) {
|
||||
printf("Only analysing the first four megabytes of the "
|
||||
"logfile (real size = 0x%Lx).\n",
|
||||
(unsigned long long)l);
|
||||
l = 0x400000LL;
|
||||
}
|
||||
lfd = (unsigned char*)calloc(1, l);
|
||||
if (!lfd) {
|
||||
perror("Couldn't allocate internal buffer");
|
||||
goto log_file_error;
|
||||
}
|
||||
/* Read in the $LogFile into the buffer. */
|
||||
if ((br = read(f, lfd, l)) == -1) {
|
||||
perror("Couldn't read file");
|
||||
goto log_file_error;
|
||||
}
|
||||
/* Valid data length in buffer. */
|
||||
l = min(br, l);
|
||||
/* Check restart area. */
|
||||
if (!is_rstr_recordp(lfd)) {
|
||||
s64 _l;
|
||||
|
||||
for (_l = 0LL; _l < l; _l++)
|
||||
if (lfd[_l] != (unsigned char)-1)
|
||||
break;
|
||||
if (_l < l)
|
||||
puts("Logfile contents are corrupt (magic RSTR "
|
||||
"missing)!");
|
||||
else
|
||||
puts("Logfile is empty.");
|
||||
goto log_file_error;
|
||||
}
|
||||
/* Do the interpretation and display now. */
|
||||
rph = (RESTART_PAGE_HEADER*)lfd;
|
||||
lps = le32_to_cpu(rph->log_page_size);
|
||||
pass_loc:
|
||||
if (ntfs_post_read_mst_fixup((NTFS_RECORD*)rph, lps) ||
|
||||
is_baad_record(rph->magic)) {
|
||||
puts("Logfile incomplete multi sector transfer detected! "
|
||||
"Cannot handle this yet!");
|
||||
goto log_file_error;
|
||||
}
|
||||
if ((pass == 2) && !memcmp(lfd, rph, lps)) {
|
||||
printf("2nd restart area fully matches the 1st one. Skipping "
|
||||
"display.\n");
|
||||
goto skip_rstr_pass;
|
||||
}
|
||||
if (le16_to_cpu(rph->major_ver != 1) ||
|
||||
le16_to_cpu(rph->minor_ver != 1)) {
|
||||
fprintf(stderr, "$LogFile version %i.%i! Error: Unknown "
|
||||
"$LogFile version!\n",
|
||||
le16_to_cpu(rph->major_ver),
|
||||
le16_to_cpu(rph->minor_ver));
|
||||
goto log_file_error;
|
||||
}
|
||||
rr = (RESTART_AREA*)((char*)rph + le16_to_cpu(rph->restart_offset));
|
||||
cr = (RESTART_CLIENT*)((char*)rr +
|
||||
le16_to_cpu(rr->client_array_offset));
|
||||
/* Dump of the interpreted $LogFile restart area. */
|
||||
if (pass == 1)
|
||||
printf("\n$LogFile version %i.%i.\n",
|
||||
le16_to_cpu(rph->major_ver),
|
||||
le16_to_cpu(rph->minor_ver));
|
||||
printf("\n%s restart area:\n", pass == 1? "1st": "2nd");
|
||||
printf("magic = RSTR\n");
|
||||
printf("ChkDskLsn = 0x%Lx\n", sle64_to_cpu(rph->chkdsk_lsn));
|
||||
printf("SystemPageSize = %u\n", le32_to_cpu(rph->system_page_size));
|
||||
printf("LogPageSize = %u\n", le32_to_cpu(rph->log_page_size));
|
||||
printf("RestartOffset = 0x%x\n", le16_to_cpu(rph->restart_offset));
|
||||
printf("\n(1st) restart record:\n");
|
||||
printf("CurrentLsn = %Lx\n", sle64_to_cpu(rr->current_lsn));
|
||||
printf("LogClients = %u\n", le16_to_cpu(rr->log_clients));
|
||||
printf("ClientFreeList = %i\n", sle16_to_cpu(rr->client_free_list));
|
||||
printf("ClientInUseList = %i\n", sle16_to_cpu(rr->client_in_use_list));
|
||||
printf("Flags = 0x%x\n", le16_to_cpu(rr->flags));
|
||||
printf("SeqNumberBits = %u (0x%x)\n", le32_to_cpu(rr->seq_number_bits),
|
||||
le32_to_cpu(rr->seq_number_bits));
|
||||
printf("RestartAreaLength = 0x%x\n",
|
||||
le16_to_cpu(rr->restart_area_length));
|
||||
printf("ClientArrayOffset = 0x%x\n",
|
||||
le16_to_cpu(rr->client_array_offset));
|
||||
printf("FileSize = %Lu (0x%Lx)\n", le64_to_cpu(rr->file_size),
|
||||
le64_to_cpu(rr->file_size));
|
||||
printf("LastLsnDataLength = 0x%x\n",
|
||||
le32_to_cpu(rr->last_lsn_data_length));
|
||||
printf("RecordLength = 0x%x\n", le16_to_cpu(rr->record_length));
|
||||
printf("LogPageDataOffset = 0x%x\n",
|
||||
le16_to_cpu(rr->log_page_data_offset));
|
||||
for (client = 0; client < le16_to_cpu(rr->log_clients); client++) {
|
||||
printf("\nRestart client record number %i:\n", client);
|
||||
printf("OldestLsn = 0x%Lx\n", sle64_to_cpu(cr->oldest_lsn));
|
||||
printf("ClientRestartLsn = 0x%Lx\n",
|
||||
sle64_to_cpu(cr->client_restart_lsn));
|
||||
printf("PrevClient = %i\n", sle16_to_cpu(cr->prev_client));
|
||||
printf("NextClient = %i\n", sle16_to_cpu(cr->next_client));
|
||||
printf("SeqNumber = 0x%Lx\n", le64_to_cpu(cr->seq_number));
|
||||
printf("ClientNameLength = 0x%x\n",
|
||||
le32_to_cpu(cr->client_name_length));
|
||||
if (le32_to_cpu(cr->client_name_length)) {
|
||||
// convert to ascii and print out.
|
||||
// printf("ClientName = %u\n", le16_to_cpu(cr->client_name));
|
||||
}
|
||||
/* Size of a restart client record is fixed at 0xa0 bytes. */
|
||||
cr = (RESTART_CLIENT*)((char*)cr + 0xa0);
|
||||
}
|
||||
skip_rstr_pass:
|
||||
if (pass == 1) {
|
||||
rph = (RESTART_PAGE_HEADER*)((char*)rph + lps);
|
||||
++pass;
|
||||
goto pass_loc;
|
||||
}
|
||||
rcrd_ph = (RECORD_PAGE_HEADER*)rph;
|
||||
/* Reuse pass for log record clienter. */
|
||||
pass = 0;
|
||||
printf("\nFinished with restart area. Beginning with log area.\n");
|
||||
rcrd_pass_loc:
|
||||
rcrd_ph = (RECORD_PAGE_HEADER*)((char*)rcrd_ph + lps);
|
||||
if ((char*)rcrd_ph + lps > (char*)lfd + l)
|
||||
goto end_of_rcrd_passes;
|
||||
printf("\nLog record page number %i", pass);
|
||||
if (!is_rcrd_record(rcrd_ph->magic)) {
|
||||
for (i = 0; i < lps; i++)
|
||||
if (((char*)rcrd_ph)[i] != (char)-1)
|
||||
break;
|
||||
if (i < lps)
|
||||
puts(" is corrupt (magic RCRD is missing).");
|
||||
else
|
||||
puts(" is empty.");
|
||||
pass++;
|
||||
goto rcrd_pass_loc;
|
||||
} else
|
||||
printf(":");
|
||||
/* Dump log record page */
|
||||
printf("\nmagic = RCRD\n");
|
||||
printf("copy.last_lsn/file_offset = 0x%Lx\n",
|
||||
le64_to_cpu(rcrd_ph->copy.last_lsn));
|
||||
printf("flags = 0x%x\n", le32_to_cpu(rcrd_ph->flags));
|
||||
printf("page count = %i\n", le16_to_cpu(rcrd_ph->page_count));
|
||||
printf("page position = %i\n", le16_to_cpu(rcrd_ph->page_position));
|
||||
printf("header.next_record_offset = 0x%Lx\n",
|
||||
le64_to_cpu(rcrd_ph->header.packed.next_record_offset));
|
||||
printf("header.last_end_lsn = 0x%Lx\n",
|
||||
le64_to_cpu(rcrd_ph->header.packed.last_end_lsn));
|
||||
/*
|
||||
* Where does the 0x40 come from? Is it just usa_offset +
|
||||
* usa_client * 2 + 7 & ~7 or is it derived from somewhere?
|
||||
*/
|
||||
lr = (LOG_RECORD*)((char*)rcrd_ph + 0x40);
|
||||
client = 0;
|
||||
log_record_pass:
|
||||
printf("\nLog record %i:\n", client);
|
||||
printf("this lsn = 0x%Lx\n", le64_to_cpu(lr->this_lsn));
|
||||
printf("client previous lsn = 0x%Lx\n",
|
||||
le64_to_cpu(lr->client_previous_lsn));
|
||||
printf("client undo next lsn = 0x%Lx\n",
|
||||
le64_to_cpu(lr->client_undo_next_lsn));
|
||||
printf("client data length = 0x%x\n",
|
||||
le32_to_cpu(lr->client_data_length));
|
||||
printf("client_id.seq_number = 0x%x\n",
|
||||
le16_to_cpu(lr->client_id.seq_number));
|
||||
printf("client_id.client_index = 0x%x\n",
|
||||
le16_to_cpu(lr->client_id.client_index));
|
||||
printf("record type = 0x%x\n", le32_to_cpu(lr->record_type));
|
||||
printf("transaction_id = 0x%x\n", le32_to_cpu(lr->transaction_id));
|
||||
printf("flags = 0x%x:", lr->flags);
|
||||
if (!lr->flags)
|
||||
printf(" NONE\n");
|
||||
else {
|
||||
int _b = 0;
|
||||
|
||||
if (lr->flags & LOG_RECORD_MULTI_PAGE) {
|
||||
printf(" LOG_RECORD_MULTI_PAGE");
|
||||
_b = 1;
|
||||
}
|
||||
if (lr->flags & ~LOG_RECORD_MULTI_PAGE) {
|
||||
if (_b)
|
||||
printf(" |");
|
||||
printf(" Unknown flags");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("redo_operation = 0x%x\n", le16_to_cpu(lr->redo_operation));
|
||||
printf("undo_operation = 0x%x\n", le16_to_cpu(lr->undo_operation));
|
||||
printf("redo_offset = 0x%x\n", le16_to_cpu(lr->redo_offset));
|
||||
printf("redo_length = 0x%x\n", le16_to_cpu(lr->redo_length));
|
||||
printf("undo_offset = 0x%x\n", le16_to_cpu(lr->undo_offset));
|
||||
printf("undo_length = 0x%x\n", le16_to_cpu(lr->undo_length));
|
||||
printf("target_attribute = 0x%x\n", le16_to_cpu(lr->target_attribute));
|
||||
printf("lcns_to_follow = 0x%x\n", le16_to_cpu(lr->lcns_to_follow));
|
||||
printf("record_offset = 0x%x\n", le16_to_cpu(lr->record_offset));
|
||||
printf("attribute_offset = 0x%x\n", le16_to_cpu(lr->attribute_offset));
|
||||
printf("target_vcn = 0x%Lx\n", sle64_to_cpu(lr->target_vcn));
|
||||
if (le16_to_cpu(lr->lcns_to_follow) > 0)
|
||||
printf("Array of lcns:\n");
|
||||
for (i = 0; i < le16_to_cpu(lr->lcns_to_follow); i++)
|
||||
printf("lcn_list[%i].lcn = 0x%Lx\n", i,
|
||||
sle64_to_cpu(lr->lcn_list[i].lcn));
|
||||
client++;
|
||||
lr = (LOG_RECORD*)((char*)lr + 0x70);
|
||||
if (((char*)lr + 0x70 <= (char*)rcrd_ph +
|
||||
le64_to_cpu(rcrd_ph->header.packed.next_record_offset)))
|
||||
goto log_record_pass;
|
||||
pass++;
|
||||
goto rcrd_pass_loc;
|
||||
end_of_rcrd_passes:
|
||||
log_file_error:
|
||||
printf("\n");
|
||||
/* Set return code to 0. */
|
||||
i = 0;
|
||||
if (lfd)
|
||||
free(lfd);
|
||||
if (f)
|
||||
close(f);
|
||||
return i;
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
.\" -*- nroff -*-
|
||||
.\" Copyright (c) 2001,2002 Anton Altaparmakov. All Rights Reserved.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\" Adapted from e2fsprogs-1.19/misc/mke2fs.8.in by Theodore Ts'o.
|
||||
.\"
|
||||
.TH MKNTFS 8 "March 2002" "Linux-NTFS version @VERSION@"
|
||||
.SH NAME
|
||||
mkntfs \- create a NTFS 1.2 (Windows NT/2000/XP) file system
|
||||
.SH SYNOPSIS
|
||||
.B mkntfs
|
||||
[
|
||||
.B \-s
|
||||
.I sector-size
|
||||
]
|
||||
[
|
||||
.B \-c
|
||||
.I cluster-size
|
||||
]
|
||||
[
|
||||
.B \-L
|
||||
.I volume-label
|
||||
]
|
||||
[
|
||||
.B \-z
|
||||
.I mft-zone-multiplier
|
||||
]
|
||||
[
|
||||
.B \-f
|
||||
|
|
||||
.B \-Q
|
||||
]
|
||||
[
|
||||
.B -n
|
||||
]
|
||||
[
|
||||
.B \-q
|
||||
]
|
||||
[
|
||||
.B \-v
|
||||
]
|
||||
[
|
||||
.B \-vv
|
||||
]
|
||||
[
|
||||
.B \-C
|
||||
]
|
||||
[
|
||||
.B \-F
|
||||
]
|
||||
[
|
||||
.B \-I
|
||||
]
|
||||
[
|
||||
.B \-V
|
||||
]
|
||||
.I device
|
||||
[
|
||||
.I number-of-sectors
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B mkntfs
|
||||
is used to create a NTFS 1.2 (Windows NT 4.0) file system on a device (usually
|
||||
a disk partition).
|
||||
.I device
|
||||
is the special file corresponding to the device (e.g
|
||||
.IR /dev/hdXX ).
|
||||
.I number-of-sectors
|
||||
is the number of blocks on the device. If omitted,
|
||||
.B mkntfs
|
||||
automagically figures the file system size.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-s " sector-size"
|
||||
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
|
||||
.I sector-size
|
||||
is determined automatically and if that fails a default of 512
|
||||
bytes per sector is used.
|
||||
.TP
|
||||
.BI \-c " cluster-size"
|
||||
Specify the size of clusters in bytes. Valid cluster size values are powers of
|
||||
two, with at least 256, and at most 65536 bytes per cluster. If omitted,
|
||||
.B mkntfs
|
||||
.I cluster-size
|
||||
is determined by the volume size. The value is determined as
|
||||
follows:
|
||||
.TS
|
||||
lB lB lB
|
||||
l l r.
|
||||
Volume size Default cluster
|
||||
0 - 512MB 512 bytes
|
||||
512MB - 1GB 1024 bytes
|
||||
1GB - 2GB 2048 bytes
|
||||
2GB + 4096 bytes
|
||||
.TE
|
||||
|
||||
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
|
||||
.BI \-L " volume-label"
|
||||
Set the volume label for the filesystem.
|
||||
.TP
|
||||
.BI \-z " mft-zone-multiplier"
|
||||
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
|
||||
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
|
||||
.TP
|
||||
.B \-f
|
||||
Same as
|
||||
.BR \-Q .
|
||||
.TP
|
||||
.B \-Q
|
||||
Perform quick format. This will skip both zeroing of the volume and bad sector
|
||||
checking.
|
||||
.TP
|
||||
.B \-n
|
||||
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.
|
||||
.TP
|
||||
.B \-q
|
||||
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
|
||||
.B \-v
|
||||
Verbose execution.
|
||||
.TP
|
||||
.B \-vv
|
||||
Really verbose execution; includes the verbose output from the
|
||||
.B \-v
|
||||
option as well as additional output useful for debugging
|
||||
.B mkntfs.
|
||||
.TP
|
||||
.B \-C
|
||||
Enable compression on the volume.
|
||||
.TP
|
||||
.B \-F
|
||||
Force
|
||||
.B mkntfs
|
||||
to run, even if the specified
|
||||
.I device
|
||||
is not a block special device, or appears to be mounted.
|
||||
.TP
|
||||
.B \-I
|
||||
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
|
||||
.B \-V
|
||||
Print the version number of
|
||||
.B mkntfs
|
||||
and exit.
|
||||
.SH AUTHOR
|
||||
This version of
|
||||
.B mkntfs
|
||||
has been written by Anton Altaparmakov <aia21@cantab.net> (if that fails, use
|
||||
<antona@users.sf.net>).
|
||||
.SH BUGS
|
||||
.B mkntfs
|
||||
writes the backup boot sector to the last sector of the block
|
||||
.I device
|
||||
being formatted. However, current versions of the Linux kernel (all versions
|
||||
up to and including todays 2.4.18) either only report an even number of sectors
|
||||
when the sector size is below 1024 bytes, which is the case for most hard
|
||||
drives today (512 bytes sector size) or they return the correct number but
|
||||
accessing the last sector fails. Either way, this means that when a partition
|
||||
has an odd number of 512-byte sectors, the last sector is either not reported
|
||||
to us at all or it is not writable by us and hence the created NTFS volume
|
||||
will either have the backup boot sector placed one sector ahead of where it
|
||||
should be or it cannot be written at all. For this reason,
|
||||
.B mkntfs
|
||||
marks the NTFS volume dirty, so that when you reboot into Windows, check disk
|
||||
runs automatically and creates a copy of the backup boot sector in the correct
|
||||
location. This also has the benefit of catching any bugs in
|
||||
.B mkntfs
|
||||
as check disk would find any corrupt structures and repair them, as well as
|
||||
report them. - If you do see any problems reported, please report the messages
|
||||
to the author.
|
||||
.br
|
||||
There may be other bugs. Please, report them to the author.
|
||||
.SH AVAILABILITY
|
||||
.B mkntfs
|
||||
is part of the Linux-NTFS project and is available for download from
|
||||
http://sf.net/project/showfiles.php?group_id=13956 in source (tar ball and
|
||||
rpm) and pre-compiled binary (i386 rpm and deb) form.
|
||||
.SH SEE ALSO
|
||||
.BR badblocks (8)
|
||||
|
3554
ntfsprogs/mkntfs.c
3554
ntfsprogs/mkntfs.c
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,371 @@
|
|||
const char *EXEC_NAME = "NtfsDump_LogFile";
|
||||
const char *EXEC_VERSION = "1.0";
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* NtfsDump_LogFile - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000,2001 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.
|
||||
*
|
||||
* Anton Altaparmakov <aia21@cantab.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the Linux-NTFS source
|
||||
* in the file COPYING); if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING: This program might not work on architectures which do not allow
|
||||
* unaligned access. For those, the program would need to start using
|
||||
* get/put_unaligned macros (#include <asm/unaligned.h>), but not doing it yet,
|
||||
* since NTFS really mostly applies to ia32 only, which does allow unaligned
|
||||
* accesses. We might not actually have a problem though, since the structs are
|
||||
* defined as being packed so that might be enough for gcc to insert the
|
||||
* correct code.
|
||||
*
|
||||
* If anyone using a non-little endian and/or an aligned access only CPU tries
|
||||
* this program please let me know whether it works or not!
|
||||
*
|
||||
* Anton Altaparmakov <aia21@cantab.net>
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
#include "mft.h"
|
||||
#include "disk_io.h"
|
||||
#include "logfile.h"
|
||||
#include "mst.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
MFT_RECORD *m = NULL;
|
||||
ATTR_RECORD *a;
|
||||
s64 l;
|
||||
unsigned char *lfd = NULL;
|
||||
ntfs_volume *vol = NULL;
|
||||
ntfs_attr_search_ctx *ctx = NULL;
|
||||
RESTART_PAGE_HEADER *rph;
|
||||
RESTART_AREA *rr;
|
||||
RESTART_CLIENT *cr;
|
||||
RECORD_PAGE_HEADER *rcrd_ph;
|
||||
LOG_RECORD *lr;
|
||||
int pass = 1;
|
||||
int i, lps, client;
|
||||
char zero[4096];
|
||||
|
||||
memset(zero, 0, sizeof(zero));
|
||||
printf("\n");
|
||||
if (argc != 2) {
|
||||
printf("%s v%s - Interpret and display information about the "
|
||||
"journal\n($LogFile) of an NTFS volume.\n\n"
|
||||
/* Generic copyright / disclaimer. */
|
||||
"Copyright (c) 2000, 2001 Anton Altaparmakov.\n\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\nGeneral Public License to be found "
|
||||
"in the file COPYING in the main Linux-NTFS\n"
|
||||
"distribution directory.\n\n"
|
||||
/* Generic part ends here. */
|
||||
"Syntax: ntfsdump_logfile partition_or_file_name\n"
|
||||
" e.g. ntfsdump_logfile /dev/hda6\n\n",
|
||||
EXEC_NAME, EXEC_VERSION, EXEC_NAME, EXEC_NAME);
|
||||
fprintf(stderr, "Error: incorrect syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
vol = ntfs_mount(argv[1], MS_RDONLY);
|
||||
if (!vol) {
|
||||
perror("ntfs_mount(MS_RDONLY) failed");
|
||||
exit(1);
|
||||
}
|
||||
/* Check NTFS version is ok for us. */
|
||||
printf("\nNTFS volume version is %i.%i.\n", vol->major_ver,
|
||||
vol->minor_ver);
|
||||
switch (vol->major_ver) {
|
||||
case 1:
|
||||
if (vol->minor_ver == 1 || vol->minor_ver == 2)
|
||||
break;
|
||||
else
|
||||
goto version_error;
|
||||
case 2: case 3:
|
||||
if (vol->minor_ver == 0)
|
||||
break;
|
||||
/* Fall through on error. */
|
||||
default:
|
||||
version_error:
|
||||
fprintf(stderr, "Error: Unknown NTFS version.\n");
|
||||
goto error_exit;
|
||||
}
|
||||
/* Read in $LogFile. */
|
||||
if (ntfs_read_file_record(vol, FILE_LogFile, &m, NULL)) {
|
||||
fprintf(stderr, "Error reading mft record for $LogFile.\n");
|
||||
goto error_exit;
|
||||
}
|
||||
if (!(m->flags & MFT_RECORD_IN_USE)) {
|
||||
fprintf(stderr, "Error: $LogFile has been deleted. Run chkdsk "
|
||||
"to fix this.\n");
|
||||
goto error_exit;
|
||||
}
|
||||
ctx = ntfs_get_attr_search_ctx(NULL, m);
|
||||
if (!ctx) {
|
||||
perror("Failed to allocate attribute search context");
|
||||
goto error_exit;
|
||||
}
|
||||
/* Find the $DATA attribute of the $LogFile. */
|
||||
if (ntfs_lookup_attr(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
|
||||
fprintf(stderr, "Error: Attribute $DATA was not found in" \
|
||||
"$LogFile!\n");
|
||||
goto log_file_error;
|
||||
}
|
||||
a = ctx->attr;
|
||||
/* Get length of $LogFile contents. */
|
||||
l = get_attribute_value_length(a);
|
||||
if (!l) {
|
||||
puts("$LogFile has zero length, no need to write to disk.");
|
||||
goto log_file_error;
|
||||
}
|
||||
/* Allocate a buffer to hold all of the $LogFile contents. */
|
||||
lfd = (unsigned char*)malloc(l);
|
||||
if (!lfd) {
|
||||
puts("Not enough memory to load $LogFile.");
|
||||
goto log_file_error;
|
||||
}
|
||||
/* Read in the $LogFile into the buffer. */
|
||||
if (l != get_attribute_value(vol, m, a, lfd)) {
|
||||
puts("Amount of data read does not correspond to expected "
|
||||
"length!");
|
||||
free(lfd);
|
||||
goto log_file_error;
|
||||
}
|
||||
/* Check restart area. */
|
||||
if (!is_rstr_recordp(lfd)) {
|
||||
s64 _l;
|
||||
|
||||
for (_l = 0LL; _l < l; _l++)
|
||||
if (lfd[_l] != (unsigned char)-1)
|
||||
break;
|
||||
if (_l < l)
|
||||
puts("$LogFile contents are corrupt (magic RSTR "
|
||||
"missing)!");
|
||||
else
|
||||
puts("$LogFile is empty.");
|
||||
goto log_file_error;
|
||||
}
|
||||
/* Do the interpretation and display now. */
|
||||
rph = (RESTART_PAGE_HEADER*)lfd;
|
||||
lps = le32_to_cpu(rph->log_page_size);
|
||||
pass_loc:
|
||||
if (ntfs_post_read_mst_fixup((NTFS_RECORD*)rph, lps) ||
|
||||
is_baad_record(rph->magic)) {
|
||||
puts("$LogFile incomplete multi sector transfer detected! "
|
||||
"Cannot handle this yet!");
|
||||
goto log_file_error;
|
||||
}
|
||||
if ((pass == 2) && !memcmp(lfd, rph, lps)) {
|
||||
printf("2nd restart area fully matches the 1st one. Skipping "
|
||||
"display.\n");
|
||||
goto skip_rstr_pass;
|
||||
}
|
||||
if (le16_to_cpu(rph->major_ver != 1) ||
|
||||
le16_to_cpu(rph->minor_ver != 1)) {
|
||||
fprintf(stderr, "$LogFile version %i.%i! Error: Unknown "
|
||||
"$LogFile version!\n",
|
||||
le16_to_cpu(rph->major_ver),
|
||||
le16_to_cpu(rph->minor_ver));
|
||||
goto log_file_error;
|
||||
}
|
||||
rr = (RESTART_AREA*)((char*)rph + le16_to_cpu(rph->restart_offset));
|
||||
cr = (RESTART_CLIENT*)((char*)rr +
|
||||
le16_to_cpu(rr->client_array_offset));
|
||||
/* Dump of the interpreted $LogFile restart area. */
|
||||
if (pass == 1)
|
||||
printf("\n$LogFile version %i.%i.\n",
|
||||
le16_to_cpu(rph->major_ver),
|
||||
le16_to_cpu(rph->minor_ver));
|
||||
printf("\n%s restart area:\n", pass == 1? "1st": "2nd");
|
||||
printf("magic = RSTR\n");
|
||||
printf("ChkDskLsn = 0x%Lx\n", sle64_to_cpu(rph->chkdsk_lsn));
|
||||
printf("SystemPageSize = %u\n", le32_to_cpu(rph->system_page_size));
|
||||
printf("LogPageSize = %u\n", le32_to_cpu(rph->log_page_size));
|
||||
printf("RestartOffset = 0x%x\n", le16_to_cpu(rph->restart_offset));
|
||||
printf("\n(1st) restart record:\n");
|
||||
printf("CurrentLsn = %Lx\n", sle64_to_cpu(rr->current_lsn));
|
||||
printf("LogClients = %u\n", le16_to_cpu(rr->log_clients));
|
||||
printf("ClientFreeList = %i\n", sle16_to_cpu(rr->client_free_list));
|
||||
printf("ClientInUseList = %i\n", sle16_to_cpu(rr->client_in_use_list));
|
||||
printf("Flags = 0x%x\n", le16_to_cpu(rr->flags));
|
||||
printf("SeqNumberBits = %u (0x%x)\n", le32_to_cpu(rr->seq_number_bits),
|
||||
le32_to_cpu(rr->seq_number_bits));
|
||||
printf("RestartAreaLength = 0x%x\n",
|
||||
le16_to_cpu(rr->restart_area_length));
|
||||
printf("ClientArrayOffset = 0x%x\n",
|
||||
le16_to_cpu(rr->client_array_offset));
|
||||
printf("FileSize = %Lu (0x%Lx)\n", le64_to_cpu(rr->file_size),
|
||||
le64_to_cpu(rr->file_size));
|
||||
if (le64_to_cpu(rr->file_size) != l)
|
||||
puts("$LogFile restart area indicates a log file size"
|
||||
"different from the actual size!");
|
||||
printf("LastLsnDataLength = 0x%x\n",
|
||||
le32_to_cpu(rr->last_lsn_data_length));
|
||||
printf("RecordLength = 0x%x\n", le16_to_cpu(rr->record_length));
|
||||
printf("LogPageDataOffset = 0x%x\n",
|
||||
le16_to_cpu(rr->log_page_data_offset));
|
||||
for (client = 0; client < le16_to_cpu(rr->log_clients); client++) {
|
||||
printf("\nRestart client record number %i:\n", client);
|
||||
printf("OldestLsn = 0x%Lx\n", sle64_to_cpu(cr->oldest_lsn));
|
||||
printf("ClientRestartLsn = 0x%Lx\n",
|
||||
sle64_to_cpu(cr->client_restart_lsn));
|
||||
printf("PrevClient = %i\n", sle16_to_cpu(cr->prev_client));
|
||||
printf("NextClient = %i\n", sle16_to_cpu(cr->next_client));
|
||||
printf("SeqNumber = 0x%Lx\n", le64_to_cpu(cr->seq_number));
|
||||
printf("ClientNameLength = 0x%x\n",
|
||||
le32_to_cpu(cr->client_name_length));
|
||||
if (le32_to_cpu(cr->client_name_length)) {
|
||||
// convert to ascii and print out.
|
||||
// printf("ClientName = %u\n", le16_to_cpu(cr->client_name));
|
||||
}
|
||||
/* Size of a restart client record is fixed at 0xa0 bytes. */
|
||||
cr = (RESTART_CLIENT*)((char*)cr + 0xa0);
|
||||
}
|
||||
skip_rstr_pass:
|
||||
if (pass == 1) {
|
||||
rph = (RESTART_PAGE_HEADER*)((char*)rph + lps);
|
||||
++pass;
|
||||
goto pass_loc;
|
||||
}
|
||||
rcrd_ph = (RECORD_PAGE_HEADER*)rph;
|
||||
/* Reuse pass for log record clienter. */
|
||||
pass = 0;
|
||||
printf("\nFinished with restart area. Beginning with log area.\n");
|
||||
rcrd_pass_loc:
|
||||
rcrd_ph = (RECORD_PAGE_HEADER*)((char*)rcrd_ph + lps);
|
||||
if ((char*)rcrd_ph + lps > (char*)lfd + l)
|
||||
goto end_of_rcrd_passes;
|
||||
printf("\nLog record page number %i", pass);
|
||||
if (!is_rcrd_record(rcrd_ph->magic)) {
|
||||
for (i = 0; i < lps; i++)
|
||||
if (((char*)rcrd_ph)[i] != (char)-1)
|
||||
break;
|
||||
if (i < lps)
|
||||
puts(" is corrupt (magic RCRD is missing).");
|
||||
else
|
||||
puts(" is empty.");
|
||||
pass++;
|
||||
goto rcrd_pass_loc;
|
||||
} else
|
||||
printf(":");
|
||||
/* Dump log record page */
|
||||
printf("\nmagic = RCRD\n");
|
||||
printf("copy.last_lsn/file_offset = 0x%Lx\n",
|
||||
le64_to_cpu(rcrd_ph->copy.last_lsn));
|
||||
printf("flags = 0x%x\n", le32_to_cpu(rcrd_ph->flags));
|
||||
printf("page count = %i\n", le16_to_cpu(rcrd_ph->page_count));
|
||||
printf("page position = %i\n", le16_to_cpu(rcrd_ph->page_position));
|
||||
printf("header.next_record_offset = 0x%Lx\n",
|
||||
le64_to_cpu(rcrd_ph->header.packed.next_record_offset));
|
||||
printf("header.last_end_lsn = 0x%Lx\n",
|
||||
le64_to_cpu(rcrd_ph->header.packed.last_end_lsn));
|
||||
/*
|
||||
* Where does the 0x40 come from? Is it just usa_offset +
|
||||
* usa_client * 2 + 7 & ~7 or is it derived from somewhere?
|
||||
*/
|
||||
lr = (LOG_RECORD*)((char*)rcrd_ph + 0x40);
|
||||
client = 0;
|
||||
log_record_pass:
|
||||
printf("\nLog record %i:\n", client);
|
||||
printf("this lsn = 0x%Lx\n", le64_to_cpu(lr->this_lsn));
|
||||
printf("client previous lsn = 0x%Lx\n",
|
||||
le64_to_cpu(lr->client_previous_lsn));
|
||||
printf("client undo next lsn = 0x%Lx\n",
|
||||
le64_to_cpu(lr->client_undo_next_lsn));
|
||||
printf("client data length = 0x%x\n",
|
||||
le32_to_cpu(lr->client_data_length));
|
||||
printf("client_id.seq_number = 0x%x\n",
|
||||
le16_to_cpu(lr->client_id.seq_number));
|
||||
printf("client_id.client_index = 0x%x\n",
|
||||
le16_to_cpu(lr->client_id.client_index));
|
||||
printf("record type = 0x%x\n", le32_to_cpu(lr->record_type));
|
||||
printf("transaction_id = 0x%x\n", le32_to_cpu(lr->transaction_id));
|
||||
printf("flags = 0x%x:", lr->flags);
|
||||
if (!lr->flags)
|
||||
printf(" NONE\n");
|
||||
else {
|
||||
int _b = 0;
|
||||
|
||||
if (lr->flags & LOG_RECORD_MULTI_PAGE) {
|
||||
printf(" LOG_RECORD_MULTI_PAGE");
|
||||
_b = 1;
|
||||
}
|
||||
if (lr->flags & ~LOG_RECORD_MULTI_PAGE) {
|
||||
if (_b)
|
||||
printf(" |");
|
||||
printf(" Unknown flags");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("redo_operation = 0x%x\n", le16_to_cpu(lr->redo_operation));
|
||||
printf("undo_operation = 0x%x\n", le16_to_cpu(lr->undo_operation));
|
||||
printf("redo_offset = 0x%x\n", le16_to_cpu(lr->redo_offset));
|
||||
printf("redo_length = 0x%x\n", le16_to_cpu(lr->redo_length));
|
||||
printf("undo_offset = 0x%x\n", le16_to_cpu(lr->undo_offset));
|
||||
printf("undo_length = 0x%x\n", le16_to_cpu(lr->undo_length));
|
||||
printf("target_attribute = 0x%x\n", le16_to_cpu(lr->target_attribute));
|
||||
printf("lcns_to_follow = 0x%x\n", le16_to_cpu(lr->lcns_to_follow));
|
||||
printf("record_offset = 0x%x\n", le16_to_cpu(lr->record_offset));
|
||||
printf("attribute_offset = 0x%x\n", le16_to_cpu(lr->attribute_offset));
|
||||
printf("target_vcn = 0x%Lx\n", sle64_to_cpu(lr->target_vcn));
|
||||
if (le16_to_cpu(lr->lcns_to_follow) > 0)
|
||||
printf("Array of lcns:\n");
|
||||
for (i = 0; i < le16_to_cpu(lr->lcns_to_follow); i++)
|
||||
printf("lcn_list[%i].lcn = 0x%Lx\n", i,
|
||||
sle64_to_cpu(lr->lcn_list[i].lcn));
|
||||
client++;
|
||||
lr = (LOG_RECORD*)((char*)lr + 0x70);
|
||||
if (((char*)lr + 0x70 <= (char*)rcrd_ph +
|
||||
le64_to_cpu(rcrd_ph->header.packed.next_record_offset)))
|
||||
goto log_record_pass;
|
||||
pass++;
|
||||
goto rcrd_pass_loc;
|
||||
end_of_rcrd_passes:
|
||||
log_file_error:
|
||||
printf("\n");
|
||||
/* Set return code to 0. */
|
||||
i = 0;
|
||||
final_exit:
|
||||
if (lfd)
|
||||
free(lfd);
|
||||
if (ctx)
|
||||
ntfs_put_attr_search_ctx(ctx);
|
||||
if (m)
|
||||
free(m);
|
||||
if (vol && ntfs_umount(vol, 0))
|
||||
ntfs_umount(vol, 1);
|
||||
return i;
|
||||
error_exit:
|
||||
i = 1;
|
||||
goto final_exit;
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH NTFSFIX 8 "July 2001" "Linux-NTFS version @VERSION@"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
.\" .nh disable hyphenation
|
||||
.\" .hy enable hyphenation
|
||||
.\" .ad l left justify
|
||||
.\" .ad b justify to both left and right margins
|
||||
.\" .nf disable filling
|
||||
.\" .fi enable filling
|
||||
.\" .br insert line break
|
||||
.\" .sp <n> insert n+1 empty lines
|
||||
.\" for manpage-specific macros, see man(7)
|
||||
.SH NAME
|
||||
ntfsfix \- tool for fixing NTFS partitions altered by the Linux kernel NTFS driver.
|
||||
.SH SYNOPSIS
|
||||
.B ntfsfix
|
||||
.I device
|
||||
.SH DESCRIPTION
|
||||
This manual page documents briefly the
|
||||
.B ntfsfix
|
||||
command.
|
||||
.PP
|
||||
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
|
||||
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
|
||||
.\" respectively.
|
||||
\fBntfsfix\fP is a program that fixes NTFS partitions altered in any
|
||||
manner with the Linux NTFS driver. \fBntfsfix\fP is \fBNOT\fP a Linux
|
||||
version of chkdsk. It only tries to leave the NTFS partition in a
|
||||
not-so-inconsistent state after the NTFS driver has written to it.
|
||||
.sp
|
||||
\fBntfsfix\fP appeared because MS chkdsk is well known for its
|
||||
stupidity when fixing altered partitions. Because the main problems
|
||||
are journal files, \fBntfsfix\fP aims to fix those issues.
|
||||
.sp
|
||||
Running ntfsfix after mounting NTFS partitions read-write is recommended
|
||||
for reducing the chance of severe data loss when NT/W2K tries to remount
|
||||
the affected partition(s).
|
||||
.sp
|
||||
In order to use \fBntfsfix\fP you must unmount the NTFS partition, and run
|
||||
ntfsfix device, where device is the NTFS partition. After this, you can
|
||||
safely reboot into NT/W2K. Please note that \fBntfsfix\fP is not a
|
||||
chkdsk-like tool, and so is not guaranteed that it could fix all the
|
||||
alterations provoked by the NTFS driver.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR mkntfs (8).
|
||||
.br
|
||||
.SH AUTHOR
|
||||
This manual page was written by David Martínez Moreno
|
||||
<david.martinez@rediris.es>, for the Debian GNU/Linux
|
||||
system (but may be used by others).
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* NtfsFix - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2002 Anton Altaparmakov.
|
||||
*
|
||||
* This utility will attempt to fix a partition that has been damaged by the
|
||||
* current Linux-NTFS driver. It should be run after dismounting a NTFS
|
||||
* partition that has been mounted read-write under Linux and before rebooting
|
||||
* into Windows NT/2000. NtfsFix can be run even after Windows has had mounted
|
||||
* the partition, but it might be too late and irreversible damage to the data
|
||||
* might have been done already.
|
||||
*
|
||||
* Anton Altaparmakov <aia21@cantab.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the Linux-NTFS source
|
||||
* in the file COPYING); if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* WARNING: This program might not work on architectures which do not allow
|
||||
* unaligned access. For those, the program would need to start using
|
||||
* get/put_unaligned macros (#include <asm/unaligned.h>), but not doing it yet,
|
||||
* since NTFS really mostly applies to ia32 only, which does allow unaligned
|
||||
* accesses. We might not actually have a problem though, since the structs are
|
||||
* defined as being packed so that might be enough for gcc to insert the
|
||||
* correct code.
|
||||
*
|
||||
* If anyone using a non-little endian and/or an aligned access only CPU tries
|
||||
* this program please let me know whether it works or not!
|
||||
*
|
||||
* Anton Altaparmakov <aia21@cantab.net>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "attrib.h"
|
||||
#include "mft.h"
|
||||
#include "disk_io.h"
|
||||
#include "logfile.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
s64 l, br;
|
||||
const char *EXEC_NAME = "NtfsFix";
|
||||
const char *OK = "OK";
|
||||
const char *FAILED = "FAILED";
|
||||
unsigned char *m = NULL, *m2 = NULL;
|
||||
ntfs_volume *vol;
|
||||
unsigned long mnt_flags;
|
||||
int i;
|
||||
u16 flags;
|
||||
BOOL done, force = FALSE;
|
||||
|
||||
printf("\n");
|
||||
if (argc != 2 || !argv[1]) {
|
||||
printf("%s v%s - Attempt to fix an NTFS partition that "
|
||||
"has been damaged by the\nLinux NTFS driver. Note that "
|
||||
"you should run it every time after you have used\nthe "
|
||||
"Linux NTFS driver to write to an NTFS partition to "
|
||||
"prevent massive data\ncorruption from happening when "
|
||||
"Windows mounts the partition.\nIMPORTANT: Run this "
|
||||
"only *after* unmounting the partition in Linux but "
|
||||
"*before*\nrebooting into Windows NT/2000/XP or you "
|
||||
"*will* suffer! - You have been warned!\n\n"
|
||||
/* Generic copyright / disclaimer. */
|
||||
"Copyright (c) 2000-2002 Anton Altaparmakov.\n\n"
|
||||
"%s is free software, released under the GNU "
|
||||
"General Public License and you\nare welcome to "
|
||||
"redistribute it under certain conditions.\n"
|
||||
"%s comes with ABSOLUTELY NO WARRANTY; for details "
|
||||
"read the file GNU\nGeneral Public License to be found "
|
||||
"in the file COPYING in the main Linux-NTFS\n"
|
||||
"distribution directory.\n\n"
|
||||
/* Generic part ends here. */
|
||||
"Syntax: ntfsfix partition_or_file_name\n"
|
||||
" e.g. ntfsfix /dev/hda6\n\n", EXEC_NAME,
|
||||
VERSION, EXEC_NAME, EXEC_NAME);
|
||||
fprintf(stderr, "Error: incorrect syntax\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!ntfs_check_if_mounted(argv[1], &mnt_flags)) {
|
||||
if ((mnt_flags & NTFS_MF_MOUNTED) &&
|
||||
!(mnt_flags & NTFS_MF_READONLY) && !force) {
|
||||
fprintf(stderr, "Refusing to operate on read-write "
|
||||
"mounted device %s.\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
} else
|
||||
fprintf(stderr, "Failed to determine whether %s is mounted: "
|
||||
"%s\n", argv[1], strerror(errno));
|
||||
/* Attempt a full mount first. */
|
||||
printf("Mounting volume... ");
|
||||
vol = ntfs_mount(argv[1], 0);
|
||||
if (vol) {
|
||||
puts(OK);
|
||||
printf("\nProcessing of $MFT and $MFTMirr completed "
|
||||
"successfully.\n\n");
|
||||
goto mount_ok;
|
||||
}
|
||||
puts(FAILED);
|
||||
|
||||
puts("Attempting to correct errors.");
|
||||
|
||||
vol = ntfs_startup_volume(argv[1], 0);
|
||||
if (!vol) {
|
||||
puts(FAILED);
|
||||
perror("Failed to startup volume");
|
||||
fprintf(stderr, "Volume is corrupt. You should run chkdsk.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
puts("Processing $MFT and $MFTMirr.");
|
||||
|
||||
/* Load data from $MFT and $MFTMirr and compare the contents. */
|
||||
m = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
|
||||
m2 = (u8*)malloc(vol->mftmirr_size << vol->mft_record_size_bits);
|
||||
if (!m || !m2) {
|
||||
perror("Failed to allocate memory");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
printf("Reading $MFT... ");
|
||||
l = ntfs_attr_mst_pread(vol->mft_na, 0, vol->mftmirr_size,
|
||||
vol->mft_record_size, m);
|
||||
if (l != vol->mftmirr_size) {
|
||||
puts(FAILED);
|
||||
if (l != -1)
|
||||
errno = EIO;
|
||||
perror("Failed to read $MFT");
|
||||
goto error_exit;
|
||||
}
|
||||
puts(OK);
|
||||
|
||||
printf("Reading $MFTMirr... ");
|
||||
l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
|
||||
vol->mft_record_size, m2);
|
||||
if (l != vol->mftmirr_size) {
|
||||
puts(FAILED);
|
||||
if (l != -1)
|
||||
errno = EIO;
|
||||
perror("Failed to read $MFTMirr");
|
||||
goto error_exit;
|
||||
}
|
||||
puts(OK);
|
||||
|
||||
/*
|
||||
* FIXME: Need to actually check the $MFTMirr for being real. Otherwise
|
||||
* we might corrupt the partition if someone is experimenting with
|
||||
* software RAID and the $MFTMirr is not actually in the position we
|
||||
* expect it to be... )-:
|
||||
* FIXME: We should emit a warning it $MFTMirr is damaged and ask
|
||||
* user whether to recreate it from $MFT or whether to abort. - The
|
||||
* warning needs to include the danger of software RAID arrays.
|
||||
* Maybe we should go as far as to detect whether we are running on a
|
||||
* MD disk and if yes then bomb out right at the start of the program?
|
||||
*/
|
||||
|
||||
printf("Comparing $MFTMirr to $MFT... ");
|
||||
done = FALSE;
|
||||
for (i = 0; i < vol->mftmirr_size; ++i) {
|
||||
const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
|
||||
"$Volume", "$AttrDef", "root directory", "$Bitmap",
|
||||
"$Boot", "$BadClus", "$Secure", "$UpCase", "$Extend" };
|
||||
const char *s;
|
||||
|
||||
if (i < 12)
|
||||
s = ESTR[i];
|
||||
else if (i < 16)
|
||||
s = "system file";
|
||||
else
|
||||
s = "mft record";
|
||||
|
||||
if (is_baad_recordp(m + i * vol->mft_record_size)) {
|
||||
puts("FAILED");
|
||||
fprintf(stderr, "$MFT error: Incomplete multi sector "
|
||||
"transfer detected in %s.\nCannot "
|
||||
"handle this yet. )-:\n", s);
|
||||
goto error_exit;
|
||||
}
|
||||
if (!is_mft_recordp(m + i * vol->mft_record_size)) {
|
||||
puts("FAILED");
|
||||
fprintf(stderr, "$MFT error: Invalid mft record for "
|
||||
"%s.\nCannot handle this yet. )-:\n",
|
||||
s);
|
||||
goto error_exit;
|
||||
}
|
||||
if (is_baad_recordp(m2 + i * vol->mft_record_size)) {
|
||||
puts("FAILED");
|
||||
fprintf(stderr, "$MFTMirr error: Incomplete multi "
|
||||
"sector transfer detected in %s.\n", s);
|
||||
goto error_exit;
|
||||
}
|
||||
if (!is_mft_recordp(m2 + i * vol->mft_record_size)) {
|
||||
puts("FAILED");
|
||||
fprintf(stderr, "$MFTMirr error: Invalid mft record "
|
||||
"for %s.\n", s);
|
||||
goto error_exit;
|
||||
}
|
||||
if (memcmp((u8*)m + i * vol->mft_record_size, (u8*)m2 +
|
||||
i * vol->mft_record_size,
|
||||
ntfs_get_mft_record_data_size((MFT_RECORD*)(
|
||||
(u8*)m + i * vol->mft_record_size)))) {
|
||||
if (!done) {
|
||||
done = TRUE;
|
||||
puts(FAILED);
|
||||
printf("Correcting differences in "
|
||||
"$MFTMirr... ");
|
||||
}
|
||||
br = ntfs_write_mft_record(vol, i, (MFT_RECORD*)(m +
|
||||
i * vol->mft_record_size));
|
||||
if (br) {
|
||||
puts(FAILED);
|
||||
perror("Error correcting $MFTMirr");
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
puts(OK);
|
||||
|
||||
free(m);
|
||||
free(m2);
|
||||
m = m2 = NULL;
|
||||
|
||||
printf("Processing of $MFT and $MFTMirr completed successfully.\n\n");
|
||||
if (ntfs_umount(vol, 0))
|
||||
ntfs_umount(vol, 1);
|
||||
vol = ntfs_mount(argv[1], 0);
|
||||
if (!vol) {
|
||||
perror("Remount failed");
|
||||
goto error_exit;
|
||||
}
|
||||
mount_ok:
|
||||
m = NULL;
|
||||
|
||||
/* Check NTFS version is ok for us (in $Volume) */
|
||||
printf("NTFS volume version is %i.%i.\n\n", vol->major_ver,
|
||||
vol->minor_ver);
|
||||
if (ntfs_is_version_supported(vol)) {
|
||||
fprintf(stderr, "Error: Unknown NTFS version.\n");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
printf("Setting required flags on partition... ");
|
||||
/*
|
||||
* Set chkdsk flag, i.e. mark the partition dirty so chkdsk will run
|
||||
* and fix it for us.
|
||||
*/
|
||||
flags = vol->flags | VOLUME_IS_DIRTY;
|
||||
/* If NTFS volume version >= 2.0 then set mounted on NT4 flag. */
|
||||
if (vol->major_ver >= 2)
|
||||
flags |= VOLUME_MOUNTED_ON_NT4;
|
||||
if (ntfs_set_volume_flags(vol, flags)) {
|
||||
puts(FAILED);
|
||||
fprintf(stderr, "Error setting volume flags.\n");
|
||||
goto error_exit;
|
||||
}
|
||||
puts(OK);
|
||||
printf("\n");
|
||||
|
||||
printf("Going to empty the journal ($LogFile)... ");
|
||||
if (ntfs_reset_logfile(vol)) {
|
||||
puts(FAILED);
|
||||
perror("Failed to reset $LogFile");
|
||||
goto error_exit;
|
||||
}
|
||||
puts(OK);
|
||||
printf("\n");
|
||||
|
||||
if (vol->major_ver >= 3) {
|
||||
/* FIXME: If on NTFS 3.0+, check for presence of the usn journal and
|
||||
disable it (if present) as Win2k might be unhappy otherwise and Bad
|
||||
Things(TM) could happen depending on what applications are actually
|
||||
using it for. */
|
||||
}
|
||||
|
||||
/* FIXME: Should we be marking the quota out of date, too? */
|
||||
|
||||
/* That's all for now! */
|
||||
printf("NTFS partition %s was processed successfully.\n",
|
||||
vol->dev_name);
|
||||
/* Set return code to 0. */
|
||||
i = 0;
|
||||
final_exit:
|
||||
if (m)
|
||||
free(m);
|
||||
if (m2)
|
||||
free(m2);
|
||||
if (vol && ntfs_umount(vol, 0))
|
||||
ntfs_umount(vol, 1);
|
||||
return i;
|
||||
error_exit:
|
||||
i = 1;
|
||||
goto final_exit;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
.\" -*- nroff -*-
|
||||
.\" Copyright (c) 2002 Anton Altaparmakov. All Rights Reserved.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSINFO 8 "May 2002" "Linux-NTFS version @VERSION@"
|
||||
.SH NAME
|
||||
ntfsinfo \- dump a file's attributes
|
||||
.SH SYNOPSIS
|
||||
.B ntfsinfo
|
||||
.I device
|
||||
.I inode-number
|
||||
.SH DESCRIPTION
|
||||
.B ntfsinfo
|
||||
will dump the attributes of inode
|
||||
.IR inode-number .
|
||||
.PP
|
||||
.SH AUTHOR
|
||||
.B ntfsinfo
|
||||
was written by Matthew J. Fanto (fanto1mj@cmich.edu).
|
||||
.SH AVAILABILITY
|
||||
.B ntfsinfo
|
||||
is part of the linux-ntfs package and is available from
|
||||
http://linux-ntfs.sourceforge.net/.
|
||||
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/*z
|
||||
* $Id$
|
||||
*
|
||||
* ntfsinfo - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Matthew J. Fanto
|
||||
* Copyright (c) 2002 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This utility will dump a file's attributes.
|
||||
*
|
||||
* 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"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <asm/types.h>
|
||||
#include "mft.h"
|
||||
#include "attrib.h"
|
||||
#include "layout.h"
|
||||
#include "inode.h"
|
||||
|
||||
void get_file_attribute_value(const char *dev, long int i);
|
||||
void print_standard_information_attr(ntfs_attr_search_ctx * ctx);
|
||||
void print_file_name_attr(ntfs_attr_search_ctx * ctx);
|
||||
|
||||
|
||||
#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *AUTHOR = "Matthew J. Fanto";
|
||||
const char *EXEC_NAME = "ntfsinfo";
|
||||
const char *locale;
|
||||
long i;
|
||||
|
||||
locale = setlocale(LC_ALL, "");
|
||||
if (!locale) {
|
||||
char *locale;
|
||||
|
||||
locale = setlocale(LC_ALL, NULL);
|
||||
printf("Failed to set locale, using default (%s).\n", locale);
|
||||
} else
|
||||
printf("Using locale %s.\n", locale);
|
||||
|
||||
if (argc < 3 || argc > 4) {
|
||||
fprintf(stderr, "%s v%s - %s\n", EXEC_NAME, VERSION, AUTHOR);
|
||||
fprintf(stderr, "Usage: ntfsinfo device inode\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
else {
|
||||
i = atoll(argv[2]);
|
||||
get_file_attribute_value(argv[1], i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void get_file_attribute_value(const char *dev, long int i)
|
||||
{
|
||||
|
||||
MFT_REF mref;
|
||||
MFT_RECORD *mrec = NULL;
|
||||
//ATTR_RECORD *attr = NULL;
|
||||
//FILE_NAME_ATTR *file_name_attr = NULL;
|
||||
//STANDARD_INFORMATION *standard_information = NULL;
|
||||
//SECURITY_DESCRIPTOR_RELATIVE *security_descriptor = NULL;
|
||||
ntfs_attr_search_ctx *ctx = NULL;
|
||||
ntfs_volume *vol = NULL;
|
||||
//char *file_name;
|
||||
ntfs_inode *inode = NULL;
|
||||
|
||||
vol = ntfs_mount(dev, 0);
|
||||
|
||||
mref = (MFT_REF) i;
|
||||
inode = ntfs_open_inode(vol, mref);
|
||||
|
||||
if (ntfs_read_file_record(vol, mref, &mrec, NULL)) {
|
||||
perror("Error reading file record!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ctx = ntfs_get_attr_search_ctx(inode, mrec);
|
||||
|
||||
// print_file_name_attr(ctx);
|
||||
|
||||
// ctx = ntfs_get_attr_search_ctx(inode, mrec); //need to fix this
|
||||
|
||||
print_standard_information_attr(ctx);
|
||||
}
|
||||
|
||||
|
||||
s64 ntfs2time(s64 time)
|
||||
{
|
||||
s64 t;
|
||||
printf("Original Time: %Li\n",time);
|
||||
t = time - NTFS_TIME_OFFSET;
|
||||
t = t / 10000000;
|
||||
return t;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void print_standard_information_attr(ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
ATTR_RECORD *attr = NULL;
|
||||
STANDARD_INFORMATION *standard_information_attr = NULL;
|
||||
|
||||
if (ntfs_lookup_attr
|
||||
(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
|
||||
perror("Error looking up $STANDARD_INFORMATION!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
attr = ctx->attr;
|
||||
|
||||
standard_information_attr =
|
||||
(STANDARD_INFORMATION *) ((char *) attr +
|
||||
le16_to_cpu(attr->value_offset));
|
||||
|
||||
printf("Creation time: %Li\n",
|
||||
ntfs2time(standard_information_attr->creation_time));
|
||||
/* printf("Last Data Change Time: %Li\n",
|
||||
ntfs2time(standard_information_attr->last_data_change_time));
|
||||
printf("Last MFT Change Time: %Li\n",
|
||||
ntfs2time(standard_information_attr->last_mft_change_time));
|
||||
printf("Last Access Time: %Li\n",
|
||||
ntfs2time(standard_information_attr->last_access_time));
|
||||
printf("Maxium Versions: %d\n",
|
||||
standard_information_attr->maximum_versions);
|
||||
printf("Version Number: %d\n",
|
||||
standard_information_attr->version_number);
|
||||
printf("Class ID: %d\n",
|
||||
standard_information_attr->class_id);
|
||||
printf("Owner ID: %d\n",
|
||||
standard_information_attr->owner_id);
|
||||
printf("Security ID: %d\n",
|
||||
standard_information_attr->security_id);
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
void print_file_name_attr(ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
ATTR_RECORD *attr = NULL;
|
||||
ntfs_attr_search_ctx *c = ctx;
|
||||
FILE_NAME_ATTR *file_name_attr = NULL;
|
||||
char *file_name;
|
||||
|
||||
if (ntfs_lookup_attr(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
|
||||
perror("Error looking up $FILE_NAME_ATTR!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
attr = ctx->attr;
|
||||
ctx = c;
|
||||
|
||||
file_name_attr =
|
||||
(FILE_NAME_ATTR *) ((char *) attr +
|
||||
le16_to_cpu(attr->value_offset));
|
||||
|
||||
file_name = malloc(file_name_attr->file_name_length * sizeof (char));
|
||||
|
||||
ntfs_ucstombs(file_name_attr->file_name,
|
||||
file_name_attr->file_name_length, &file_name,
|
||||
file_name_attr->file_name_length);
|
||||
|
||||
printf("File Name: %s\n", file_name);
|
||||
printf("File Name Length: %d\n", file_name_attr->file_name_length);
|
||||
printf("Allocated Size: %Li\n",sle64_to_cpu(file_name_attr->allocated_size));
|
||||
printf("Data Size: %Li\n",sle64_to_cpu(file_name_attr->data_size));
|
||||
}
|
||||
|
||||
/*void print_security_descriptor_attr(SECURITY_DESCRIPTOR_RELATIVE *security_descriptor)
|
||||
{
|
||||
|
||||
}*/
|
|
@ -0,0 +1,54 @@
|
|||
.\" -*- nroff -*-
|
||||
.\" Copyright (c) 2002 Anton Altaparmakov. All Rights Reserved.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\" Adapted from e2fsprogs-1.26/misc/e2label.8.in by Theodore Ts'o.
|
||||
.\"
|
||||
.TH NTFSLABEL 8 "April 2002" "Linux-NTFS version @VERSION@"
|
||||
.SH NAME
|
||||
ntfslabel \- display/change the label on an ntfs file system
|
||||
.SH SYNOPSIS
|
||||
.B ntfslabel
|
||||
.I device
|
||||
[
|
||||
.I new-label
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B ntfslabel
|
||||
will display or change the file system label on the ntfs file system located on
|
||||
.IR device .
|
||||
.PP
|
||||
If the optional argument
|
||||
.I new-label
|
||||
is not present,
|
||||
.B ntfslabel
|
||||
will simply display the current file system label.
|
||||
.PP
|
||||
If the optional argument
|
||||
.I new-label
|
||||
is present, then
|
||||
.B ntfslabel
|
||||
will set the file system label to be
|
||||
.IR new-label .
|
||||
NTFS file system labels can be at most 128 Unicode characters long; if
|
||||
.I new-label
|
||||
is longer than 128 Unicode characters,
|
||||
.B ntfslabel
|
||||
will truncate it and print a warning message.
|
||||
.PP
|
||||
It is also possible to set the file system label using the
|
||||
.B \-L
|
||||
option of
|
||||
.BR mkntfs (8)
|
||||
during creation of the file system.
|
||||
.PP
|
||||
.SH AUTHOR
|
||||
.B ntfslabel
|
||||
was written by Matthew J. Fanto (fanto1mj@cmich.edu). This man page was written
|
||||
by Anton Altaparmakov (aia21@cantab.net).
|
||||
.SH AVAILABILITY
|
||||
.B ntfslabel
|
||||
is part of the linux-ntfs package and is available from
|
||||
http://linux-ntfs.sourceforge.net/.
|
||||
.SH SEE ALSO
|
||||
.BR mkntfs (8)
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* ntfslabel - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Matthew J. Fanto
|
||||
* Copyright (c) 2002 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This utility will display/change the label on an NTFS partition.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the Linux-NTFS
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "mft.h"
|
||||
|
||||
/*
|
||||
* 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 to stdout.
|
||||
*/
|
||||
void print_label(const char *dev, const unsigned long mnt_flags,
|
||||
const char *mnt_point)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
|
||||
if (mnt_point) {
|
||||
// Try ioctl and finish if present.
|
||||
// goto finished;
|
||||
}
|
||||
if ((mnt_flags & (NTFS_MF_MOUNTED | NTFS_MF_READONLY)) ==
|
||||
NTFS_MF_MOUNTED) {
|
||||
fprintf(stderr, "%s is mounted read-write, results may be "
|
||||
"unreliable.\n", dev);
|
||||
}
|
||||
vol = ntfs_mount(dev, MS_RDONLY);
|
||||
if (!vol) {
|
||||
fprintf(stderr, "ntfs_mount() on device %s failed: %s\n", dev,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
//finished:
|
||||
printf("%s\n", vol->vol_name);
|
||||
if (ntfs_umount(vol, 0))
|
||||
ntfs_umount(vol, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* resize_resident_attribute_value - resize a resident attribute
|
||||
* @m: mft record containing attribute to resize
|
||||
* @a: attribute record (inside @m) which to resize
|
||||
* @new_vsize: the new attribute value size to resize the attribute to
|
||||
*
|
||||
* Return 0 on success and -1 with errno = ENOSPC if not enough space in the
|
||||
* mft record.
|
||||
*/
|
||||
int resize_resident_attribute_value(MFT_RECORD *m, ATTR_RECORD *a,
|
||||
const u32 new_vsize)
|
||||
{
|
||||
int new_alen, new_muse;
|
||||
|
||||
/* New attribute length and mft record bytes used. */
|
||||
new_alen = (le16_to_cpu(a->value_offset) + new_vsize + 7) & ~7;
|
||||
new_muse = le32_to_cpu(m->bytes_in_use) - le32_to_cpu(a->length) +
|
||||
new_alen;
|
||||
/* Check for sufficient space. */
|
||||
if (new_muse > le32_to_cpu(m->bytes_allocated)) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
/* Move attributes behind @a to their new location. */
|
||||
memmove((char*)a + new_alen, (char*)a + le32_to_cpu(a->length),
|
||||
le32_to_cpu(m->bytes_in_use) - ((char*)a - (char*)m) -
|
||||
le32_to_cpu(a->length));
|
||||
/* Adjust @m to reflect change in used space. */
|
||||
m->bytes_in_use = cpu_to_le32(new_muse);
|
||||
/* Adjust @a to reflect new value size. */
|
||||
a->length = cpu_to_le32(new_alen);
|
||||
a->value_length = cpu_to_le32(new_vsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* change_label - change the current label on a device
|
||||
* @dev: device to change the label on
|
||||
* @mnt_flags: mount flags of the device or 0 if not mounted
|
||||
* @mnt_point: mount point of the device or NULL
|
||||
* @label: the new label
|
||||
*
|
||||
* Change the label on the device @dev to @label.
|
||||
*/
|
||||
void change_label(const char *dev, const unsigned long mnt_flags,
|
||||
const char *mnt_point, char *label, BOOL force)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx = NULL;
|
||||
uchar_t *new_label = NULL;
|
||||
MFT_RECORD *mrec = NULL;
|
||||
ATTR_RECORD *a;
|
||||
ntfs_volume *vol;
|
||||
int label_len, err = 1;
|
||||
|
||||
if (mnt_point) {
|
||||
// Try ioctl and return if present.
|
||||
// return;
|
||||
}
|
||||
if (mnt_flags & NTFS_MF_MOUNTED) {
|
||||
/* If not the root fs or mounted read/write, refuse change. */
|
||||
if (!(mnt_flags & NTFS_MF_ISROOT) ||
|
||||
!(mnt_flags & NTFS_MF_READONLY)) {
|
||||
if (!force) {
|
||||
fprintf(stderr, "Refusing to change label on "
|
||||
"read-%s mounted device %s.\n",
|
||||
mnt_flags & NTFS_MF_READONLY ?
|
||||
"only" : "write", dev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
vol = ntfs_mount(dev, 0);
|
||||
if (!vol) {
|
||||
fprintf(stderr, "ntfs_mount() on device %s failed: %s\n", dev,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (ntfs_read_file_record(vol, (MFT_REF)FILE_Volume, &mrec, NULL)) {
|
||||
perror("Error reading file record");
|
||||
goto err_out;
|
||||
}
|
||||
if (!(mrec->flags & MFT_RECORD_IN_USE)) {
|
||||
fprintf(stderr, "Error: $Volume has been deleted. Run "
|
||||
"chkdsk to fix this.\n");
|
||||
goto err_out;
|
||||
}
|
||||
ctx = ntfs_get_attr_search_ctx(NULL, mrec);
|
||||
if (!ctx) {
|
||||
perror("Failed to get attribute search context");
|
||||
goto err_out;
|
||||
}
|
||||
if (ntfs_lookup_attr(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
|
||||
perror("Lookup of $VOLUME_NAME attribute failed");
|
||||
goto err_out;
|
||||
}
|
||||
a = ctx->attr;
|
||||
if (a->non_resident) {
|
||||
fprintf(stderr, "Error: Attribute $VOLUME_NAME must be "
|
||||
"resident.\n");
|
||||
goto err_out;
|
||||
}
|
||||
label_len = ntfs_mbstoucs(label, &new_label, 0);
|
||||
if (label_len == -1) {
|
||||
perror("Unable to convert label string to Unicode");
|
||||
goto err_out;
|
||||
}
|
||||
label_len *= sizeof(uchar_t);
|
||||
if (label_len > 0x100) {
|
||||
fprintf(stderr, "New label is too long. Maximum %i characters "
|
||||
"allowed. Truncating excess characters.\n",
|
||||
0x100 / sizeof(uchar_t));
|
||||
label_len = 0x100;
|
||||
new_label[label_len / sizeof(uchar_t)] = cpu_to_le16(L'\0');
|
||||
}
|
||||
if (resize_resident_attribute_value(mrec, a, label_len)) {
|
||||
perror("Error resizing resident attribute");
|
||||
goto err_out;
|
||||
}
|
||||
memcpy((char*)a + le16_to_cpu(a->value_offset), new_label, label_len);
|
||||
if (ntfs_write_mft_record(vol, (MFT_REF)FILE_Volume, mrec)) {
|
||||
perror("Error writing MFT Record to disk");
|
||||
goto err_out;
|
||||
}
|
||||
err = 0;
|
||||
err_out:
|
||||
if (new_label)
|
||||
free(new_label);
|
||||
if (mrec)
|
||||
free(mrec);
|
||||
if (ntfs_umount(vol, 0))
|
||||
ntfs_umount(vol, 1);
|
||||
if (err)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *AUTHOR = "Matthew Fanto";
|
||||
char *EXEC_NAME = "ntfslabel";
|
||||
char *locale, *mnt_point = NULL;
|
||||
unsigned long mnt_flags;
|
||||
int err;
|
||||
// FIXME:Implement option -F meaning force the change.
|
||||
BOOL force = 0;
|
||||
|
||||
locale = setlocale(LC_ALL, "");
|
||||
if (!locale) {
|
||||
char *locale;
|
||||
|
||||
locale = setlocale(LC_ALL, NULL);
|
||||
Dprintf("Failed to set locale, using default (%s).\n", locale);
|
||||
} else
|
||||
Dprintf("Using locale %s.\n", locale);
|
||||
if (argc && *argv)
|
||||
EXEC_NAME = *argv;
|
||||
if (argc < 2 || argc > 3) {
|
||||
fprintf(stderr, "%s v%s - %s\n", EXEC_NAME, VERSION, AUTHOR);
|
||||
fprintf(stderr, "Usage: ntfslabel device [newlabel]\n");
|
||||
exit(1);
|
||||
}
|
||||
err = ntfs_check_if_mounted(argv[1], &mnt_flags);
|
||||
if (err)
|
||||
fprintf(stderr, "Failed to determine whether %s is mounted: "
|
||||
"%s\n", argv[1], strerror(errno));
|
||||
else if (mnt_flags & NTFS_MF_MOUNTED) {
|
||||
// Not implemented yet. Will be used for ioctl interface to driver.
|
||||
// mnt_point = ntfs_get_mount_point(argv[1]);
|
||||
}
|
||||
if (argc == 2)
|
||||
print_label(argv[1], mnt_flags, mnt_point);
|
||||
else
|
||||
change_label(argv[1], mnt_flags, mnt_point, argv[2], force);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
.\" -*- nroff -*-
|
||||
.\" Copyright 2002 by Szabolcs Szakacsits All Rights Reserved.
|
||||
.\"
|
||||
.TH NTFSRESIZE 8 "November 2002" "Linux\-NTFS @VERSION@"
|
||||
.SH NAME
|
||||
ntfsresize \- resize an NTFS filesystem
|
||||
.SH SYNOPSIS
|
||||
.B ntfsresize
|
||||
[\fB\-fhin\fR]
|
||||
[\fB\-s \fIsize\fR[\fBk\fR|\fBM\fR|\fBG\fR]]
|
||||
.I device
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B ntfsresize
|
||||
program non-destructively resizes Windows NT4, 2000, XP or .NET
|
||||
NTFS filesystems. At present it can be used to shrink a
|
||||
defragmented NTFS filesystem located on an unmounted
|
||||
.I device
|
||||
(usually a disk partition). The new volume will have
|
||||
.I size
|
||||
bytes.
|
||||
The
|
||||
.I size
|
||||
parameter may have one of the optional modifiers
|
||||
\fBk\fR, \fBM\fR, \fBG\fR, 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.
|
||||
.PP
|
||||
The
|
||||
.B ntfsresize
|
||||
program does not manipulate the size of partitions.
|
||||
If you wish to shrink an NTFS partition, first use
|
||||
.B ntfsresize
|
||||
to shrink the size of the filesystem. Then you may use
|
||||
.BR fdisk (8)
|
||||
to shrink the size of the partition by deleting the
|
||||
partition and recreating it with the smaller size.
|
||||
.PP
|
||||
.B IMPORTANT!
|
||||
When recreating the partition with
|
||||
.BR fdisk (8)
|
||||
make sure you create it with the same starting
|
||||
disk cylinder and partition type
|
||||
as before and you do not make it smaller than the new size
|
||||
of the NTFS filesystem! Otherwise you may lose your entire filesystem.
|
||||
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!
|
||||
.PP
|
||||
Note,
|
||||
.B ntfsresize
|
||||
schedules 'chkdsk' to make an NTFS consistency check
|
||||
when you will boot Windows. If your partition was a
|
||||
system partition than Windows may intentionally reboot after
|
||||
the successful consistency check.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B -f
|
||||
Forces ntfsresize to proceed with the filesystem resize operation, overriding
|
||||
some safety checks which
|
||||
.B ntfsresize
|
||||
normally enforces. You can use this
|
||||
parameter multiply times if you want to overcome every single safety checks.
|
||||
.TP
|
||||
.B -h
|
||||
Display help and exit.
|
||||
.TP
|
||||
.B -i
|
||||
Using this option you can calculate the smallest shrunken volume size supported.
|
||||
This option will not make any changes to the filesystem.
|
||||
.TP
|
||||
.B -n
|
||||
You can 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.
|
||||
.TP
|
||||
.B -s \fIsize\fR[\fBk\fR|\fBM\fR|\fBG\fR]
|
||||
Shrink volume to \fIsize\fR[\fBk\fR|\fBM\fR|\fBG\fR] bytes.
|
||||
The optional modifiers \fBk\fR, \fBM\fR, \fBG\fR 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.
|
||||
.SH BUGS
|
||||
No bugs are known or has been reported so far in the current version.
|
||||
If you find otherwise, please report it to <linux-ntfs-dev@lists.sf.net>
|
||||
(no subscription needed). It's also strongly advised you
|
||||
.B MAKE SURE YOU HAVE A BACKUP
|
||||
of your important data in case of an unexpected failure.
|
||||
.PP
|
||||
Future work is planned to include support for volume enlargement
|
||||
and resizing fragmented NTFS volumes.
|
||||
Please note, Windows 2000, XP and .NET have built in NTFS defragmenter.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsresize
|
||||
is part of the linux-ntfs package and is available from
|
||||
http://linux-ntfs.sf.net/ as source and pre-compiled binary.
|
||||
.SH AUTHOR
|
||||
.B ntfsresize
|
||||
has been written by
|
||||
Szabolcs Szakacsits <szaka@sienet.hu>.
|
||||
.SH ACKNOWLEDGEMENT
|
||||
Many thanks to Anton Altaparmakov and Richard Russon (FlatCap)
|
||||
for libntfs, excellent documentation, comments, testing and fixes,
|
||||
moreover to Theodore Ts'o whose
|
||||
.BR resize2fs (8)
|
||||
man page formed the basis of this page.
|
||||
.SH SEE ALSO
|
||||
.BR fdisk (8),
|
||||
.BR cfdisk (8),
|
||||
.BR sfdisk (8),
|
||||
.BR parted (8),
|
||||
.BR mkntfs (8)
|
|
@ -0,0 +1,914 @@
|
|||
/**
|
||||
* ntfsresize - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Szabolcs Szakacsits
|
||||
*
|
||||
* This utility will resize 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"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "types.h"
|
||||
#include "support.h"
|
||||
#include "endians.h"
|
||||
#include "bootsect.h"
|
||||
#include "disk_io.h"
|
||||
#include "attrib.h"
|
||||
#include "volume.h"
|
||||
#include "mft.h"
|
||||
#include "bitmap.h"
|
||||
#include "inode.h"
|
||||
#include "runlist.h"
|
||||
|
||||
const char *EXEC_NAME = "ntfsresize";
|
||||
|
||||
static const char *ntfs_report_banner =
|
||||
"\nReport bugs to linux-ntfs-dev@lists.sf.net. "
|
||||
"Homepage: http://linux-ntfs.sf.net\n";
|
||||
|
||||
static const char *resize_warning_msg =
|
||||
"WARNING: Every sanity check passed and only the DANGEROUS operations left.\n"
|
||||
"Please make sure all your important data had been backed up in case of an\n"
|
||||
"unexpected failure!\n";
|
||||
|
||||
static const char *resize_important_msg =
|
||||
"NTFS had been successfully resized on device '%s'.\n"
|
||||
"You can go on to resize the device e.g. with 'fdisk'.\n"
|
||||
"IMPORTANT: When recreating the partition, make sure you\n"
|
||||
" 1) create it with the same starting disk cylinder\n"
|
||||
" 2) create it with the same partition type (usually 7, HPFS/NTFS)\n"
|
||||
" 3) do not make it smaller than the new NTFS filesystem size\n"
|
||||
" 4) set the bootable flag for the partition if it existed before\n"
|
||||
"Otherwise you may lose your data or can't boot your computer from the disk!\n";
|
||||
|
||||
static const char *fragmented_volume_msg =
|
||||
"The volume end is fragmented, this case is not yet supported. Defragment it\n"
|
||||
"(Windows 2000, XP and .NET have built in defragmentation tool) and try again.\n";
|
||||
|
||||
struct {
|
||||
int verbose;
|
||||
int debug;
|
||||
int ro_flag;
|
||||
int force;
|
||||
int info;
|
||||
s64 bytes;
|
||||
char *volume;
|
||||
} opt;
|
||||
|
||||
struct bitmap {
|
||||
u8 *bm;
|
||||
s64 size;
|
||||
};
|
||||
|
||||
struct progress_bar {
|
||||
u64 start;
|
||||
u64 stop;
|
||||
int resolution;
|
||||
float unit;
|
||||
};
|
||||
|
||||
ntfs_volume *vol = NULL;
|
||||
struct bitmap lcn_bitmap;
|
||||
|
||||
#define NTFS_MBYTE (1000 * 1000)
|
||||
|
||||
#define ERR_PREFIX "ERROR"
|
||||
#define PERR_PREFIX ERR_PREFIX "(%d): "
|
||||
#define NERR_PREFIX ERR_PREFIX ": "
|
||||
|
||||
#define rounded_up_division(a, b) (((a) + (b - 1)) / (b))
|
||||
|
||||
|
||||
void perr_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int eo = errno;
|
||||
|
||||
fprintf(stdout, PERR_PREFIX, eo);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
printf(": %s\n", strerror(eo));
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
||||
int err_exit(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stdout, NERR_PREFIX);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int perr_exit(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int eo = errno;
|
||||
|
||||
fprintf(stdout, PERR_PREFIX, eo);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
printf(": %s\n", strerror(eo));
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("\n");
|
||||
printf ("Usage: %s [-fhin] [-s size[k|M|G]] device\n", EXEC_NAME);
|
||||
printf("Shrink a defragmented NTFS volume.\n");
|
||||
printf("\n");
|
||||
Dprintf(" -d Show debug information\n");
|
||||
printf (" -f Force to progress (DANGEROUS)\n");
|
||||
printf (" -h This help text\n");
|
||||
printf (" -i Calculate the smallest shrunken size supported (read-only)\n");
|
||||
printf (" -n Make a test run without write operations (read-only)\n");
|
||||
printf (" -s size[k|M|G] Shrink volume to size[k|M|G] bytes (k=10^3, M=10^6, G=10^9)\n");
|
||||
/* printf (" -v Verbose operation\n"); */
|
||||
printf(ntfs_report_banner);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Copy-paste from e2fsprogs */
|
||||
void proceed_question(void)
|
||||
{
|
||||
char buf[256];
|
||||
const char *short_yes = "yY";
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
printf("Are you sure you want to proceed (y/[n])? ");
|
||||
buf[0] = 0;
|
||||
fgets(buf, sizeof(buf), stdin);
|
||||
if (strchr(short_yes, buf[0]) == 0) {
|
||||
printf("OK quitting. NO CHANGES has been made to your NTFS volume.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
s64 get_new_volume_size(char *s)
|
||||
{
|
||||
s64 size;
|
||||
char *suffix;
|
||||
|
||||
size = strtoll(s, &suffix, 10);
|
||||
if (size <= 0 || errno == ERANGE)
|
||||
err_exit("Illegal new volume size\n");
|
||||
|
||||
if (!*suffix)
|
||||
return size;
|
||||
|
||||
if (strlen(suffix) > 1)
|
||||
usage();
|
||||
|
||||
/* We follow the SI prefixes:
|
||||
http://physics.nist.gov/cuu/Units/prefixes.html
|
||||
http://physics.nist.gov/cuu/Units/binary.html
|
||||
Disk partitioning tools use prefixes as,
|
||||
k M G
|
||||
old fdisk 2^10 2^20 10^3*2^20
|
||||
recent fdisk 10^3 10^6 10^9
|
||||
cfdisk 10^3 10^6 10^9
|
||||
sfdisk 2^10 2^20
|
||||
parted 2^10 2^20 (may change)
|
||||
fdisk (DOS) 2^10 2^20
|
||||
*/
|
||||
/* FIXME: check for overflow */
|
||||
switch (*suffix) {
|
||||
case 'G':
|
||||
size *= 1000;
|
||||
case 'M':
|
||||
size *= 1000;
|
||||
case 'k':
|
||||
size *= 1000;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
void parse_options(int argc, char **argv)
|
||||
{
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
printf("%s v%s\n", EXEC_NAME, VERSION);
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
|
||||
while ((i = getopt(argc, argv, "dfhins:")) != EOF)
|
||||
switch (i) {
|
||||
case 'd':
|
||||
opt.debug = 1;
|
||||
break;
|
||||
case 'f':
|
||||
opt.force++;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
case 'i':
|
||||
opt.info = 1;
|
||||
break;
|
||||
case 'n':
|
||||
opt.ro_flag = MS_RDONLY;
|
||||
break;
|
||||
case 's':
|
||||
opt.bytes = get_new_volume_size(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
opt.verbose++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
if (optind == argc)
|
||||
usage();
|
||||
opt.volume = argv[optind++];
|
||||
if (optind < argc)
|
||||
usage();
|
||||
|
||||
stderr = stdout;
|
||||
if (!opt.debug)
|
||||
if (!(stderr = fopen("/dev/null", "rw")))
|
||||
perr_exit("Couldn't open /dev/null");
|
||||
|
||||
|
||||
/* If no '-s size' then estimate smallest shrunken volume size */
|
||||
if (!opt.bytes)
|
||||
opt.info = 1;
|
||||
|
||||
if (opt.info) {
|
||||
if (opt.bytes) {
|
||||
printf(NERR_PREFIX "It makes no sense to use -i and "
|
||||
"-s together.\n");
|
||||
usage();
|
||||
}
|
||||
opt.ro_flag = MS_RDONLY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
s64 nr_clusters_to_bitmap_byte_size(s64 nr_clusters)
|
||||
{
|
||||
s64 bm_bsize;
|
||||
|
||||
bm_bsize = rounded_up_division(nr_clusters, 8);
|
||||
|
||||
/* Needs to be multiple of 8 bytes */
|
||||
bm_bsize = (bm_bsize + 7) & ~7;
|
||||
Dprintf("Bitmap byte size : %lld (%lld clusters)\n",
|
||||
bm_bsize, rounded_up_division(bm_bsize, vol->cluster_size));
|
||||
|
||||
return bm_bsize;
|
||||
}
|
||||
|
||||
|
||||
void build_lcn_usage_bitmap(ATTR_RECORD *a)
|
||||
{
|
||||
run_list *rl;
|
||||
int i, j;
|
||||
|
||||
if (!a->non_resident)
|
||||
return;
|
||||
|
||||
if (!(rl = ntfs_decompress_mapping_pairs(vol, a, NULL)))
|
||||
perr_exit("ntfs_decompress_mapping_pairs");
|
||||
|
||||
for (i = 0; rl[i].length; i++) {
|
||||
if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
|
||||
continue;
|
||||
for (j = 0; j < rl[i].length; j++) {
|
||||
u64 k = (u64)rl[i].lcn + j;
|
||||
if (ntfs_get_and_set_bit(lcn_bitmap.bm, k, 1))
|
||||
err_exit("Cluster %lu referenced twice!\n"
|
||||
"You didn't shutdown your Windows"
|
||||
"properly?", k);
|
||||
}
|
||||
}
|
||||
free(rl);
|
||||
}
|
||||
|
||||
|
||||
void walk_attributes(MFT_RECORD *mr)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
if (!(ctx = ntfs_get_attr_search_ctx(NULL, mr)))
|
||||
perr_exit("ntfs_get_attr_search_ctx");
|
||||
|
||||
while (!ntfs_walk_attrs(ctx)) {
|
||||
if (ctx->attr->type == AT_END)
|
||||
break;
|
||||
build_lcn_usage_bitmap(ctx->attr);
|
||||
}
|
||||
|
||||
ntfs_put_attr_search_ctx(ctx);
|
||||
}
|
||||
|
||||
|
||||
void get_bitmap_data(ntfs_volume *vol, struct bitmap *bm)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
|
||||
if (!(ni = ntfs_open_inode(vol, (MFT_REF)FILE_Bitmap)))
|
||||
perr_exit("ntfs_open_inode");
|
||||
|
||||
if (!(ctx = ntfs_get_attr_search_ctx(ni, NULL)))
|
||||
perr_exit("ntfs_get_attr_search_ctx");
|
||||
|
||||
if (ntfs_lookup_attr(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx))
|
||||
perr_exit("ntfs_lookup_attr");
|
||||
|
||||
/* FIXME: get_attribute_value_length() can't handle extents */
|
||||
bm->size = get_attribute_value_length(ctx->attr);
|
||||
|
||||
if (!(bm->bm = (u8 *)malloc(bm->size)))
|
||||
perr_exit("get_bitmap_data");
|
||||
|
||||
if (get_attribute_value(vol, ni->mrec, ctx->attr, bm->bm) != bm->size)
|
||||
perr_exit("Couldn't get $Bitmap $DATA\n");
|
||||
|
||||
ntfs_put_attr_search_ctx(ctx);
|
||||
ntfs_close_inode(ni);
|
||||
}
|
||||
|
||||
|
||||
void compare_bitmaps(struct bitmap *a, struct bitmap *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (a->size != b->size)
|
||||
err_exit("$Bitmap file size doesn't match "
|
||||
"calculated size ((%d != %d)\n", a->size, b->size);
|
||||
|
||||
for (i = 0; i < a->size; i++)
|
||||
if (a->bm[i] != b->bm[i])
|
||||
err_exit("Cluster bitmaps differ at %d (%d != %d)\n"
|
||||
"You didn't shutdown your Windows properly?",
|
||||
i, a->bm[i], b->bm[i]);
|
||||
}
|
||||
|
||||
|
||||
void progress_init(struct progress_bar *p, u64 start, u64 stop, int res)
|
||||
{
|
||||
p->start = start;
|
||||
p->stop = stop;
|
||||
p->unit = 100.0 / (stop - start);
|
||||
p->resolution = res;
|
||||
}
|
||||
|
||||
|
||||
void progress_update(struct progress_bar *p, u64 current)
|
||||
{
|
||||
float percent = p->unit * current;
|
||||
|
||||
if (current != p->stop) {
|
||||
if ((current - p->start) % p->resolution)
|
||||
return;
|
||||
printf("%6.2f percent completed\r", percent);
|
||||
} else
|
||||
printf("100.00 percent completed\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void walk_inodes()
|
||||
{
|
||||
s32 inode = 0;
|
||||
s64 last_mft_rec;
|
||||
MFT_REF mref;
|
||||
MFT_RECORD *mrec = NULL;
|
||||
struct progress_bar progress;
|
||||
|
||||
printf("Scanning volume ...\n");
|
||||
|
||||
last_mft_rec = vol->nr_mft_records - 1;
|
||||
progress_init(&progress, inode, last_mft_rec, 100);
|
||||
|
||||
for (; inode <= last_mft_rec; inode++) {
|
||||
progress_update(&progress, inode);
|
||||
|
||||
mref = (MFT_REF)inode;
|
||||
if (ntfs_read_file_record(vol, mref, &mrec, NULL)) {
|
||||
/* FIXME: continue only if it make sense, e.g.
|
||||
MFT record not in use based on $MFT bitmap */
|
||||
if (errno == EIO)
|
||||
continue;
|
||||
perr_exit("Reading inode %ld failed", inode);
|
||||
}
|
||||
if (!(mrec->flags & MFT_RECORD_IN_USE))
|
||||
continue;
|
||||
|
||||
walk_attributes(mrec);
|
||||
}
|
||||
if (mrec)
|
||||
free(mrec);
|
||||
}
|
||||
|
||||
|
||||
void advise_on_resize()
|
||||
{
|
||||
u64 i, old_b, new_b, g_b, old_mb, new_mb, g_mb;
|
||||
int fragmanted_end;
|
||||
|
||||
for (i = vol->nr_clusters - 1; i > 0; i--)
|
||||
if (ntfs_get_bit(lcn_bitmap.bm, i))
|
||||
break;
|
||||
|
||||
i += 2; /* first free + we reserve one for the backup boot sector */
|
||||
fragmanted_end = (i >= vol->nr_clusters) ? 1 : 0;
|
||||
|
||||
if (fragmanted_end || !opt.info) {
|
||||
printf(fragmented_volume_msg);
|
||||
if (fragmanted_end)
|
||||
exit(1);
|
||||
printf("Now ");
|
||||
}
|
||||
|
||||
old_b = vol->nr_clusters * vol->cluster_size;
|
||||
old_mb = rounded_up_division(old_b, NTFS_MBYTE);
|
||||
new_b = i * vol->cluster_size;
|
||||
new_mb = rounded_up_division(new_b, NTFS_MBYTE);
|
||||
g_b = (vol->nr_clusters - i) * vol->cluster_size;
|
||||
g_mb = g_b / NTFS_MBYTE;
|
||||
|
||||
printf("You could resize at %lld bytes ", new_b);
|
||||
|
||||
if ((new_mb * NTFS_MBYTE) < old_b)
|
||||
printf("or %lld MB ", new_mb);
|
||||
|
||||
printf("(freeing ");
|
||||
|
||||
if (g_mb && (old_mb - new_mb))
|
||||
printf("%lld MB", old_mb - new_mb);
|
||||
else
|
||||
printf("%lld bytes", g_b);
|
||||
|
||||
printf(").\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void look_for_bad_sector(ATTR_RECORD *a)
|
||||
{
|
||||
run_list *rl;
|
||||
int i;
|
||||
|
||||
rl = ntfs_decompress_mapping_pairs(vol, a, NULL);
|
||||
if (!rl)
|
||||
perr_exit("ntfs_decompress_mapping_pairs");
|
||||
|
||||
for (i = 0; rl[i].length; i++)
|
||||
if (rl[i].lcn != LCN_HOLE)
|
||||
err_exit("Device has bad sectors, not supported\n");
|
||||
|
||||
free(rl);
|
||||
}
|
||||
|
||||
|
||||
void rl_set(run_list *rl, VCN vcn, LCN lcn, s64 len)
|
||||
{
|
||||
rl->vcn = vcn;
|
||||
rl->lcn = lcn;
|
||||
rl->length = len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Bitmap can overlap the end of the volume. Any bits in this region
|
||||
* must be set. This region also encompasses the backup boot sector.
|
||||
*/
|
||||
void bitmap_file_data_fixup(s64 cluster, struct bitmap *bm)
|
||||
{
|
||||
for (; cluster < bm->size << 3; cluster++)
|
||||
ntfs_set_bit(bm->bm, (u64)cluster, 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FIXME: this function should go away and instead using a generalized
|
||||
* "truncate_bitmap_unnamed_attr()"
|
||||
*/
|
||||
void truncate_badclust_bad_attr(ATTR_RECORD *a, s64 nr_clusters)
|
||||
{
|
||||
run_list *rl_bad;
|
||||
int mp_size;
|
||||
char *mp;
|
||||
|
||||
if (!a->non_resident)
|
||||
/* FIXME: handle resident attribute value */
|
||||
perr_exit("Resident attribute in $BadClust not supported!");
|
||||
|
||||
if (!(rl_bad = (run_list *)malloc(2 * sizeof(run_list))))
|
||||
perr_exit("Couldn't get memory");
|
||||
|
||||
rl_set(rl_bad, 0LL, (LCN)LCN_HOLE, nr_clusters);
|
||||
rl_set(rl_bad + 1, nr_clusters, -1LL, 0LL);
|
||||
|
||||
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl_bad);
|
||||
|
||||
if (!(mp = (char *)calloc(1, mp_size)))
|
||||
perr_exit("Couldn't get memory");
|
||||
|
||||
if (ntfs_build_mapping_pairs(vol, mp, mp_size, rl_bad))
|
||||
exit(1);
|
||||
|
||||
memcpy((char *)a + a->mapping_pairs_offset, mp, mp_size);
|
||||
a->highest_vcn = cpu_to_le64(nr_clusters - 1LL);
|
||||
a->allocated_size = cpu_to_le64(nr_clusters * vol->cluster_size);
|
||||
a->data_size = cpu_to_le64(nr_clusters * vol->cluster_size);
|
||||
|
||||
free(rl_bad);
|
||||
free(mp);
|
||||
}
|
||||
|
||||
|
||||
void truncate_bitmap_unnamed_attr(ATTR_RECORD *a, s64 nr_clusters)
|
||||
{
|
||||
run_list *rl;
|
||||
s64 bm_bsize, size;
|
||||
s64 nr_bm_clusters;
|
||||
int i, j, mp_size;
|
||||
int trunc_at = -1; /* FIXME: -1 means unset */
|
||||
char *mp;
|
||||
|
||||
|
||||
if (!a->non_resident)
|
||||
/* FIXME: handle resident attribute value */
|
||||
perr_exit("Resident data attribute in $Bitmap not supported!");
|
||||
|
||||
bm_bsize = nr_clusters_to_bitmap_byte_size(nr_clusters);
|
||||
nr_bm_clusters = rounded_up_division(bm_bsize, vol->cluster_size);
|
||||
|
||||
if (!(rl = ntfs_decompress_mapping_pairs(vol, a, NULL)))
|
||||
perr_exit("ntfs_decompress_mapping_pairs");
|
||||
|
||||
/* Unallocate truncated clusters in $Bitmap */
|
||||
for (i = 0; rl[i].length; i++) {
|
||||
if (rl[i].vcn + rl[i].length <= nr_bm_clusters)
|
||||
continue;
|
||||
if (trunc_at == -1)
|
||||
trunc_at = i;
|
||||
if (rl[i].lcn == LCN_HOLE || rl[i].lcn == LCN_RL_NOT_MAPPED)
|
||||
continue;
|
||||
for (j = 0; j < rl[i].length; j++)
|
||||
if (rl[i].vcn + j >= nr_bm_clusters) {
|
||||
u64 k = (u64)rl[i].lcn + j;
|
||||
ntfs_set_bit(lcn_bitmap.bm, k, 0);
|
||||
Dprintf("Unallocate cluster: "
|
||||
"%llu (%llx)\n", k, k);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: realloc lcn_bitmap.bm (if it's worth the risk) */
|
||||
lcn_bitmap.size = bm_bsize;
|
||||
bitmap_file_data_fixup(nr_clusters, &lcn_bitmap);
|
||||
|
||||
if (trunc_at != -1) {
|
||||
/* NOTE: 'i' always > 0 */
|
||||
i = nr_bm_clusters - rl[trunc_at].vcn;
|
||||
rl[trunc_at].length = i;
|
||||
rl_set(rl + trunc_at + 1, nr_bm_clusters, -1LL, 0LL);
|
||||
|
||||
Dprintf("Runlist truncated at index %d, "
|
||||
"new cluster length %d\n", trunc_at, i);
|
||||
}
|
||||
|
||||
if (!opt.ro_flag) {
|
||||
size = ntfs_rl_pwrite(vol, rl, 0, bm_bsize, lcn_bitmap.bm);
|
||||
if (bm_bsize != size) {
|
||||
if (size == -1)
|
||||
perr_exit("Couldn't write $Bitmap");
|
||||
printf("Couldn't write full $Bitmap file "
|
||||
"(%lld from %lld)\n", size, bm_bsize);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl);
|
||||
|
||||
if (!(mp = (char *)calloc(1, mp_size)))
|
||||
perr_exit("Couldn't get memory");
|
||||
|
||||
if (ntfs_build_mapping_pairs(vol, mp, mp_size, rl))
|
||||
exit(1);
|
||||
|
||||
memcpy((char *)a + a->mapping_pairs_offset, mp, mp_size);
|
||||
a->highest_vcn = cpu_to_le64(nr_bm_clusters - 1LL);
|
||||
a->allocated_size = cpu_to_le64(nr_bm_clusters * vol->cluster_size);
|
||||
a->data_size = cpu_to_le64(bm_bsize);
|
||||
a->initialized_size = cpu_to_le64(bm_bsize);
|
||||
|
||||
free(rl);
|
||||
free(mp);
|
||||
}
|
||||
|
||||
|
||||
void lookup_data_attr(MFT_REF mref, char *aname, ntfs_attr_search_ctx **ctx)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
uchar_t *ustr = NULL;
|
||||
int len = 0;
|
||||
|
||||
if (!(ni = ntfs_open_inode(vol, mref)))
|
||||
perr_exit("ntfs_open_inode");
|
||||
|
||||
if (NInoAttrList(ni))
|
||||
perr_exit("Attribute list attribute not yet supported");
|
||||
|
||||
if (!(*ctx = ntfs_get_attr_search_ctx(ni, NULL)))
|
||||
perr_exit("ntfs_get_attr_search_ctx");
|
||||
|
||||
if (aname && ((len = ntfs_mbstoucs(aname, &ustr, 0)) == -1))
|
||||
perr_exit("Unable to convert string to Unicode");
|
||||
|
||||
if (!ustr || !len) {
|
||||
ustr = AT_UNNAMED;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (ntfs_lookup_attr(AT_DATA, ustr, len, 0, 0, NULL, 0, *ctx))
|
||||
perr_exit("ntfs_lookup_attr");
|
||||
|
||||
if (ustr != AT_UNNAMED)
|
||||
free(ustr);
|
||||
}
|
||||
|
||||
|
||||
int write_mft_record(ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
if (opt.ro_flag)
|
||||
return 0;
|
||||
|
||||
return ntfs_write_mft_record(vol, ctx->ntfs_ino->mft_no, ctx->mrec);
|
||||
}
|
||||
|
||||
|
||||
void truncate_badclust_file(s64 nr_clusters)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx = NULL;
|
||||
|
||||
printf("Updating $BadClust file ...\n");
|
||||
|
||||
lookup_data_attr((MFT_REF)FILE_BadClus, "$Bad", &ctx);
|
||||
look_for_bad_sector(ctx->attr);
|
||||
/* FIXME: sanity_check_attr(ctx->attr); */
|
||||
/* FIXME: should use an "extended" truncate_bitmap_unnamed_attr() */
|
||||
truncate_badclust_bad_attr(ctx->attr, nr_clusters);
|
||||
|
||||
if (write_mft_record(ctx))
|
||||
perr_exit("Couldn't update $BadClust");
|
||||
|
||||
/* FIXME: clean up API => ntfs_put_attr_search_ctx() also closes ni */
|
||||
ntfs_put_attr_search_ctx(ctx);
|
||||
}
|
||||
|
||||
|
||||
void truncate_bitmap_file(s64 nr_clusters)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx = NULL;
|
||||
|
||||
printf("Updating $Bitmap file ...\n");
|
||||
|
||||
lookup_data_attr((MFT_REF)FILE_Bitmap, NULL, &ctx);
|
||||
/* FIXME: sanity_check_attr(ctx->attr); */
|
||||
truncate_bitmap_unnamed_attr(ctx->attr, nr_clusters);
|
||||
|
||||
if (write_mft_record(ctx))
|
||||
perr_exit("Couldn't update $Bitmap");
|
||||
|
||||
ntfs_put_attr_search_ctx(ctx);
|
||||
}
|
||||
|
||||
|
||||
void setup_lcn_bitmap()
|
||||
{
|
||||
/* Determine lcn bitmap byte size and allocate it. */
|
||||
lcn_bitmap.size = nr_clusters_to_bitmap_byte_size(vol->nr_clusters);
|
||||
|
||||
if (!(lcn_bitmap.bm = (unsigned char *)calloc(1, lcn_bitmap.size)))
|
||||
perr_exit("Failed to allocate internal buffer");
|
||||
|
||||
bitmap_file_data_fixup(vol->nr_clusters, &lcn_bitmap);
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: should be done using ntfs_* functions */
|
||||
void update_bootsector(s64 nr_clusters)
|
||||
{
|
||||
NTFS_BOOT_SECTOR bs;
|
||||
|
||||
printf("Updating Boot record ...\n");
|
||||
|
||||
if (lseek(vol->fd, 0, SEEK_SET) == (off_t)-1)
|
||||
perr_exit("lseek");
|
||||
|
||||
if (read(vol->fd, &bs, sizeof(NTFS_BOOT_SECTOR)) == -1)
|
||||
perr_exit("read() error");
|
||||
|
||||
bs.number_of_sectors = nr_clusters * bs.bpb.sectors_per_cluster;
|
||||
bs.number_of_sectors = cpu_to_le64(bs.number_of_sectors);
|
||||
|
||||
if (lseek(vol->fd, 0, SEEK_SET) == (off_t)-1)
|
||||
perr_exit("lseek");
|
||||
|
||||
if (!opt.ro_flag)
|
||||
if (write(vol->fd, &bs, sizeof(NTFS_BOOT_SECTOR)) == -1)
|
||||
perr_exit("write() error");
|
||||
}
|
||||
|
||||
|
||||
void print_volume_size(char *str, ntfs_volume *v, s64 nr_clusters)
|
||||
{
|
||||
s64 b; /* volume size in bytes */
|
||||
|
||||
b = nr_clusters * v->cluster_size;
|
||||
printf("%s: %lld bytes (%lld MB)\n",
|
||||
str, b, rounded_up_division(b, NTFS_MBYTE));
|
||||
}
|
||||
|
||||
|
||||
void mount_volume()
|
||||
{
|
||||
unsigned long mntflag;
|
||||
|
||||
if (ntfs_check_if_mounted(opt.volume, &mntflag))
|
||||
perr_exit("Failed to check '%s' mount state", opt.volume);
|
||||
|
||||
if (mntflag & NTFS_MF_MOUNTED) {
|
||||
if (!(mntflag & NTFS_MF_READONLY))
|
||||
err_exit("Device %s is mounted read-write. "
|
||||
"You must 'umount' it first.\n", opt.volume);
|
||||
if (!opt.ro_flag)
|
||||
err_exit("Device %s is mounted. "
|
||||
"You must 'umount' it first.\n", opt.volume);
|
||||
}
|
||||
|
||||
if (!(vol = ntfs_mount(opt.volume, opt.ro_flag))) {
|
||||
|
||||
int err = errno;
|
||||
|
||||
perr_printf("ntfs_mount failed");
|
||||
if (errno == EINVAL) {
|
||||
printf("Apparently device '%s' doesn't have a "
|
||||
"valid NTFS. Maybe you selected\nthe whole "
|
||||
"disk instead of a partition (e.g. /dev/hda, "
|
||||
"not /dev/hda8)?\n", opt.volume);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (vol->flags & VOLUME_IS_DIRTY)
|
||||
if (opt.force-- <= 0)
|
||||
err_exit("Volume is dirty. Run chkdsk and "
|
||||
"please try again (or see -f option).\n");
|
||||
|
||||
printf("NTFS volume version: %d.%d\n", vol->major_ver, vol->minor_ver);
|
||||
if (ntfs_is_version_supported(vol))
|
||||
perr_exit("Unknown NTFS version");
|
||||
|
||||
Dprintf("Cluster size : %u\n", vol->cluster_size);
|
||||
print_volume_size("Current volume size", vol, vol->nr_clusters);
|
||||
}
|
||||
|
||||
|
||||
void prepare_volume_fixup()
|
||||
{
|
||||
if (!opt.ro_flag) {
|
||||
u16 flags;
|
||||
|
||||
flags = vol->flags | VOLUME_IS_DIRTY;
|
||||
if (vol->major_ver >= 2)
|
||||
flags |= VOLUME_MOUNTED_ON_NT4;
|
||||
|
||||
printf("Schedule chkdsk NTFS consistency check at Windows boot time ...\n");
|
||||
if (ntfs_set_volume_flags(vol, flags))
|
||||
perr_exit("Failed to set $Volume dirty");
|
||||
|
||||
printf("Resetting $LogFile ... "
|
||||
"(this might take a while)\n");
|
||||
if (ntfs_reset_logfile(vol))
|
||||
perr_exit("Failed to reset $LogFile");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct bitmap on_disk_lcn_bitmap;
|
||||
s64 new_volume_size = 0; /* in clusters */
|
||||
int i;
|
||||
|
||||
parse_options(argc, argv);
|
||||
|
||||
mount_volume();
|
||||
|
||||
if (opt.bytes) {
|
||||
/* Take the integer part: when shrinking we don't want
|
||||
to make the volume to be bigger than requested.
|
||||
Later on we will also decrease this value to save
|
||||
room for the backup boot sector */
|
||||
new_volume_size = opt.bytes / vol->cluster_size;
|
||||
print_volume_size("New volume size ", vol, new_volume_size);
|
||||
}
|
||||
|
||||
setup_lcn_bitmap();
|
||||
|
||||
walk_inodes();
|
||||
|
||||
get_bitmap_data(vol, &on_disk_lcn_bitmap);
|
||||
compare_bitmaps(&on_disk_lcn_bitmap, &lcn_bitmap);
|
||||
free(on_disk_lcn_bitmap.bm);
|
||||
|
||||
if (opt.info)
|
||||
advise_on_resize();
|
||||
|
||||
/* FIXME: check new_volume_size validity */
|
||||
|
||||
/* Backup boot sector at the end of device isn't counted in NTFS
|
||||
volume size thus we have to reserve space for. We don't trust
|
||||
the user does this for us: better to be on the safe side ;) */
|
||||
if (new_volume_size)
|
||||
--new_volume_size;
|
||||
|
||||
if (new_volume_size > vol->nr_clusters)
|
||||
err_exit("Volume enlargement not yet supported\n");
|
||||
else if (new_volume_size == vol->nr_clusters) {
|
||||
printf("Nothing to do: NTFS volume size is already OK.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (i = new_volume_size; i < vol->nr_clusters; i++)
|
||||
if (ntfs_get_bit(lcn_bitmap.bm, (u64)i)) {
|
||||
/* FIXME: relocate cluster */
|
||||
advise_on_resize();
|
||||
}
|
||||
|
||||
if (opt.force-- <= 0 && !opt.ro_flag) {
|
||||
printf(resize_warning_msg);
|
||||
proceed_question();
|
||||
}
|
||||
|
||||
prepare_volume_fixup();
|
||||
|
||||
truncate_badclust_file(new_volume_size);
|
||||
truncate_bitmap_file(new_volume_size);
|
||||
update_bootsector(new_volume_size);
|
||||
|
||||
/* We don't create backup boot sector because we don't know where the
|
||||
partition will be split. The scheduled chkdsk will fix it anyway */
|
||||
|
||||
if (opt.ro_flag) {
|
||||
printf("The read-only test run ended successfully.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
printf("Syncing device ...\n");
|
||||
if (fsync(vol->fd) == -1)
|
||||
perr_exit("fsync");
|
||||
|
||||
printf(resize_important_msg, vol->dev_name);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
.\" Copyright (c) 2002 Richard Russon. All Rights Reserved.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFSUNDELETE 8 "June 2002" "Linux\-NTFS version @VERSION@"
|
||||
.SH NAME
|
||||
ntfsundelete \- recover a deleted file from an NTFS volume.
|
||||
.SH SYNOPSIS
|
||||
.B ntfsundelete
|
||||
[
|
||||
.I options
|
||||
]
|
||||
.B device
|
||||
.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 inode and recovers as much of the data as possible. It save 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.
|
||||
.SH OPTIONS
|
||||
Below is a summary of all the options that
|
||||
.B ntfsundelete
|
||||
accepts. All options have two equivalent names. The short name is preceded by
|
||||
.BR \-
|
||||
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.
|
||||
.BR \-fv
|
||||
is equivalent to
|
||||
.BR "\-f \-v" .
|
||||
Long named options can be abbreviated to any unique prefix of their name.
|
||||
.TP
|
||||
.BI "\-b " num
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-byte " num
|
||||
If any clusters of the file cannot be recovered, the missing parts will be
|
||||
filled with this byte. The default is zeros.
|
||||
.TP
|
||||
.B \-C
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.B \-\-case
|
||||
When scanning an NTFS volume, any filename matching (using the
|
||||
.B \-\-match
|
||||
option) is case\-insensitive. This option makes the maching case\-sensitive.
|
||||
.TP
|
||||
.BI "\-c " range
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-copy " 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
|
||||
.BI "\-d " dir
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-destination " dir
|
||||
This option controls where to put the output file of the
|
||||
.B \-\-undelete
|
||||
and
|
||||
.B \-\-copy
|
||||
options.
|
||||
.TP
|
||||
.B \-f
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.B \-\-force
|
||||
This will override some sensible defaults, such as not overwriting an existing
|
||||
file. Use this option with caution.
|
||||
.TP
|
||||
.B \-h
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.B \-\-help
|
||||
Show a list of options with a brief description of each one.
|
||||
.TP
|
||||
.BI "\-m " pattern
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-match " pattern
|
||||
Filter the output of the
|
||||
.B \-\-scan
|
||||
option, 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
|
||||
.BI "\-o " file
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-output " file
|
||||
Use this option to set name of output file that
|
||||
.B \-\-undelete
|
||||
or
|
||||
.B \-\-copy
|
||||
will create.
|
||||
.TP
|
||||
.BI "\-p " num
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-percentage " 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
|
||||
.BI \-q
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI \-\-quiet
|
||||
Reduce the amount of output to a minimum. Naturally, it doesn't make sense to
|
||||
combine this option with
|
||||
.BR \-\-scan .
|
||||
.TP
|
||||
.B \-s
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.B \-\-scan
|
||||
Search through an NTFS volume and print a list of files that could be recovered.
|
||||
This is the default action of
|
||||
.BR ntfsundelete .
|
||||
This list can be filtered by filename, size, percentage recoverable or last
|
||||
modification time, using the
|
||||
.BR \-\-match ,
|
||||
.BR \-\-size ,
|
||||
.B \-\-percent
|
||||
and
|
||||
.B \-\-time
|
||||
options, respectively.
|
||||
.sp
|
||||
The output of scan will be:
|
||||
.sp
|
||||
.nf
|
||||
Inode Flags %age Date Size Filename
|
||||
6038 FN.. 93% 2002-07-17 26629 thesis.doc
|
||||
.fi
|
||||
.TS
|
||||
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
|
||||
.RS
|
||||
.sp
|
||||
.br
|
||||
The percentage field shows how much of the file can potentially be recovered.
|
||||
.sp
|
||||
.br
|
||||
.RE
|
||||
.BI "\-S " range
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-size " 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
|
||||
.BI "\-t " since
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-time " 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
|
||||
.BI "\-u " num
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI "\-\-undelete " num
|
||||
Recover the file with this inode number. This option can be combined with
|
||||
.BR \-\-output ,
|
||||
.BR \-\-destination ,
|
||||
and
|
||||
.BR \-\-byte .
|
||||
.TP
|
||||
.B \-v
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.B \-\-verbose
|
||||
Increase the amount of output that
|
||||
.B ntfsundelete
|
||||
prints.
|
||||
.TP
|
||||
.B \-V
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.B \-\-version
|
||||
Show the version number, copyright and license
|
||||
.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 inode number 3689, call the file 'work.doc' and put it in the user's
|
||||
home directory.
|
||||
.RS
|
||||
.sp
|
||||
.B ntfsundelete /dev/hda1 \-u 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
|
||||
.RE
|
||||
.SH BUGS
|
||||
There are some small limitations to this program, but currently no known bugs.
|
||||
If you find one, please send an email to
|
||||
.nh
|
||||
<linux-ntfs-dev@lists.sf.net>
|
||||
.hy
|
||||
.SH AUTHOR
|
||||
.B ntfsundelete
|
||||
was written by Richard Russon (FlatCap) <ntfs@flatcap.org>
|
||||
.br
|
||||
If you find this tool useful, make FlatCap happy and send him an email.
|
||||
.SH AVAILABILITY
|
||||
.B ntfsundelete
|
||||
is part of the linux\-ntfs package and is available from
|
||||
.br
|
||||
.nh
|
||||
http://linux\-ntfs.sourceforge.net/downloads.html
|
||||
.hy
|
||||
This manual page is available online at:
|
||||
.br
|
||||
.nh
|
||||
http://linux\-ntfs.sourceforge.net/tools/ntfsundelete.html
|
||||
.hy
|
||||
.SH SEE ALSO
|
||||
.BR ntfsinfo(8)
|
||||
.br
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* ntfsundelete - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Richard Russon <ntfs@flatcap.org>
|
||||
*
|
||||
* 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"
|
||||
|
||||
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 fillbyte; /* Use for unrecoverable sections */
|
||||
char *match; /* Pattern for filename matching */
|
||||
int match_case; /* Case sensitive matching */
|
||||
int quiet; /* Less output */
|
||||
int verbose; /* Extra output */
|
||||
int force; /* Override common sense */
|
||||
time_t since; /* Since this time */
|
||||
long long size_begin; /* Range for file size */
|
||||
long long size_end;
|
||||
long long mft_begin; /* Range for mft copy */
|
||||
long long mft_end;
|
||||
};
|
||||
|
||||
struct filename {
|
||||
struct list_head list; /* Previous/Next links */
|
||||
char *name; /* Filename in current locale */
|
||||
FILE_NAME_TYPE_FLAGS name_space;
|
||||
uchar_t *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_t date_a;
|
||||
time_t date_m;
|
||||
time_t date_r;
|
||||
};
|
||||
|
||||
struct data {
|
||||
struct list_head list; /* Previous/Next links */
|
||||
char *name; /* Stream name in current locale */
|
||||
uchar_t *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 */
|
||||
run_list_element*run_list; /* Decoded data runs */
|
||||
int percent; /* Amont 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 list_head name; /* A list of filenames */
|
||||
struct list_head data; /* A list of data streams */
|
||||
char *pref_name; /* Preferred 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,732 @@
|
|||
/**
|
||||
* ntfswipe - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Richard Russon <ntfs@flatcap.org>
|
||||
*
|
||||
* This utility will overwrite usused 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
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <libintl.h>
|
||||
#include <stdarg.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ntfswipe.h"
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
|
||||
static const char *AUTHOR = "Richard Russon (FlatCap)";
|
||||
static const char *EXEC_NAME = "ntfswipe";
|
||||
static struct options opts;
|
||||
|
||||
/**
|
||||
* Eprintf - Print error messages
|
||||
*/
|
||||
void Eprintf (const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start (va, format);
|
||||
vfprintf (stderr, format, va);
|
||||
va_end (va);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iprintf - Print informative messages
|
||||
*/
|
||||
void Iprintf (const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
#ifndef DEBUG
|
||||
if (opts.quiet)
|
||||
return;
|
||||
#endif
|
||||
va_start (va, format);
|
||||
vfprintf (stdout, format, va);
|
||||
va_end (va);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vprintf - Print verbose messages
|
||||
*/
|
||||
void Vprintf (const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
#ifndef DEBUG
|
||||
if (!opts.verbose)
|
||||
return;
|
||||
#endif
|
||||
va_start (va, format);
|
||||
vfprintf (stdout, format, va);
|
||||
va_end (va);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dprintf - Print debug messages
|
||||
*/
|
||||
#ifndef DEBUG
|
||||
#define Dprintf(...)
|
||||
#else
|
||||
void Dprintf (const char *format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start (va, format);
|
||||
vfprintf (stdout, format, va);
|
||||
va_end (va);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* wipe_unused - Wipe unused clusters
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
* @byte: Overwrite with this value
|
||||
*
|
||||
* Read $Bitmap and wipe any clusters that are marked as not in use.
|
||||
*
|
||||
* Return: 1 Success, the clusters were wiped
|
||||
* 0 Error, something went wrong
|
||||
*/
|
||||
int wipe_unused (ntfs_volume *vol, int byte)
|
||||
{
|
||||
if (!vol || (byte < 0))
|
||||
return 0;
|
||||
|
||||
Iprintf ("wipe_unused 0x%02x\n", byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* wipe_tails - Wipe the file tails
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
* @byte: Overwrite with this value
|
||||
*
|
||||
* Disk space is allocated in clusters. If a file isn't an exact multiple of
|
||||
* the cluster size, there is some slack space at the end. Wipe this space.
|
||||
*
|
||||
* Return: 1 Success, the clusters were wiped
|
||||
* 0 Error, something went wrong
|
||||
*/
|
||||
int wipe_tails (ntfs_volume *vol, int byte)
|
||||
{
|
||||
if (!vol || (byte < 0))
|
||||
return 0;
|
||||
|
||||
Iprintf ("wipe_tails 0x%02x\n", byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* wipe_mft - Wipe the MFT slack space
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
* @byte: Overwrite with this value
|
||||
*
|
||||
* MFT Records are 1024 bytes long, but some of this space isn't used. Wipe any
|
||||
* unused space at the end of the record and wipe any unused records.
|
||||
*
|
||||
* Return: 1 Success, the clusters were wiped
|
||||
* 0 Error, something went wrong
|
||||
*/
|
||||
int wipe_mft (ntfs_volume *vol, int byte)
|
||||
{
|
||||
if (!vol || (byte < 0))
|
||||
return 0;
|
||||
|
||||
Iprintf ("wipe_mft 0x%02x\n", byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* wipe_directory - Wipe the directiry indexes
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
* @byte: Overwrite with this value
|
||||
*
|
||||
* Directories are kept in sorted B+ Trees. Index blocks may not be full. Wipe
|
||||
* the unused space at the ends of these blocks.
|
||||
*
|
||||
* Return: 1 Success, the clusters were wiped
|
||||
* 0 Error, something went wrong
|
||||
*/
|
||||
int wipe_directory (ntfs_volume *vol, int byte)
|
||||
{
|
||||
if (!vol || (byte < 0))
|
||||
return 0;
|
||||
|
||||
Iprintf ("wipe_directory 0x%02x\n", byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* wipe_logfile - Wipe the logfile (journal)
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
* @byte: Overwrite with this value
|
||||
*
|
||||
* The logfile journals the metadata to give the volume fault-tolerance. If the
|
||||
* volume is in a consistant state, then this information can be erased.
|
||||
*
|
||||
* Return: 1 Success, the clusters were wiped
|
||||
* 0 Error, something went wrong
|
||||
*/
|
||||
int wipe_logfile (ntfs_volume *vol, int byte)
|
||||
{
|
||||
if (!vol || (byte < 0))
|
||||
return 0;
|
||||
|
||||
Iprintf ("wipe_logfile 0x%02x\n", byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* wipe_pagefile - Wipe the pagefile (swap space)
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
* @byte: Overwrite with this value
|
||||
*
|
||||
* pagefile.sys is used by Windows as extra virtual memory (swap space).
|
||||
* Windows recreates the file at bootup, so it can be wiped without harm.
|
||||
*
|
||||
* Return: 1 Success, the clusters were wiped
|
||||
* 0 Error, something went wrong
|
||||
*/
|
||||
int wipe_pagefile (ntfs_volume *vol, int byte)
|
||||
{
|
||||
if (!vol || (byte < 0))
|
||||
return 0;
|
||||
|
||||
Iprintf ("wipe_pagefile 0x%02x\n", byte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_info - Display information about the NTFS Volume
|
||||
* @vol: An ntfs volume obtained from ntfs_mount
|
||||
*
|
||||
* Tell the user how much could be cleaned up. List the number of free
|
||||
* clusters, MFT records, etc.
|
||||
*
|
||||
* Return: 1 Success, displayed some info
|
||||
* 0 Error, something went wrong
|
||||
*/
|
||||
int ntfs_info (ntfs_volume *vol)
|
||||
{
|
||||
if (!vol)
|
||||
return 0;
|
||||
|
||||
Iprintf ("ntfs_info\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* version - Print version information about the program
|
||||
*
|
||||
* Print a copyright statement and a brief description of the program.
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void version (void)
|
||||
{
|
||||
Iprintf ("%s v%s Copyright (C) 2002 %s\nOverwrite the unused space on "
|
||||
"an NTFS Volume\n\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\nGeneral Public License "
|
||||
"to be found in the file COPYING in the main\nLinux-NTFS "
|
||||
"distribution directory.\n\n",
|
||||
EXEC_NAME, VERSION, AUTHOR, EXEC_NAME, EXEC_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* usage - Print a list of the parameters to the program
|
||||
*
|
||||
* Print a list of the parameters and options for the program.
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void usage (void)
|
||||
{
|
||||
Iprintf ("Usage: %s [options] device\n"
|
||||
" -i --info Show volume information (default)\n"
|
||||
"\n"
|
||||
" -d --directory Wipe directory indexes\n"
|
||||
" -l --logfile Wipe the logfile (journal)\n"
|
||||
" -m --mft Wipe mft space\n"
|
||||
" -p --pagefile Wipe pagefile (swap space)\n"
|
||||
" -t --tails Wipe file tails\n"
|
||||
" -u --unused Wipe unused clusters\n"
|
||||
"\n"
|
||||
" -a --all Wipe all unused space\n"
|
||||
"\n"
|
||||
" -c num --count num Number of times to write (default = 1)\n"
|
||||
" -b list --bytes list List of values to write (default = 0)\n"
|
||||
"\n"
|
||||
" -n --no-action Do not write to disk\n"
|
||||
" -f --force Use less caution\n"
|
||||
" -q --quiet Less output\n"
|
||||
" -v --verbose More output\n"
|
||||
" -V --version Version information\n"
|
||||
" -h --help Print this help\n\n",
|
||||
EXEC_NAME);
|
||||
Iprintf ("Please report bugs to: linux-ntfs-dev@lists.sf.net\n\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_list - Read a comma-separated list of numbers
|
||||
* @list: The comma-separated list of numbers
|
||||
* @result: Store the parsed list here (must be freed by caller)
|
||||
*
|
||||
* Read a comma-separated list of numbers and allocate an array of ints to store
|
||||
* them in. The numbers can be in decimal, octal or hex.
|
||||
*
|
||||
* N.B. The caller must free the memory returned in @result.
|
||||
* N.B. If the function fails, @result is not changed.
|
||||
*
|
||||
* Return: 0 Error, invalid string
|
||||
* n Success, the count of numbers parsed
|
||||
*/
|
||||
int parse_list (const char *list, int **result)
|
||||
{
|
||||
const char *ptr;
|
||||
char *end;
|
||||
int i;
|
||||
int count;
|
||||
int *mem = NULL;
|
||||
|
||||
if (!list || !result)
|
||||
return 0;
|
||||
|
||||
for (count = 0, ptr = list; ptr; ptr = strchr (ptr+1, ','))
|
||||
count++;
|
||||
|
||||
mem = malloc ((count+1) * sizeof (int));
|
||||
if (!mem) {
|
||||
Eprintf ("Couldn't allocate memory in parse_list().\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset (mem, 0xFF, (count+1) * sizeof (int));
|
||||
|
||||
for (ptr = list, i = 0; i < count; i++) {
|
||||
|
||||
end = NULL;
|
||||
mem[i] = strtol (ptr, &end, 0);
|
||||
|
||||
if (!end || (end == ptr) || ((*end != ',') && (*end != 0))) {
|
||||
Eprintf ("Invalid list '%s'\n", list);
|
||||
free (mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((mem[i] < 0) || (mem[i] > 255)) {
|
||||
Eprintf ("Bytes must be in range 0-255.\n");
|
||||
free (mem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = end + 1;
|
||||
}
|
||||
|
||||
Dprintf ("Parsing list '%s' - ", list);
|
||||
for (i = 0; i <= count; i++)
|
||||
Dprintf ("0x%02x ", mem[i]);
|
||||
Dprintf ("\n");
|
||||
|
||||
*result = mem;
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
int parse_options (int argc, char *argv[])
|
||||
{
|
||||
static const char *sopt = "-ab:c:dfhilmnpqtuvV";
|
||||
static const struct option lopt[] = {
|
||||
{ "all", no_argument, NULL, 'a' },
|
||||
{ "bytes", required_argument, NULL, 'b' },
|
||||
{ "count", required_argument, NULL, 'c' },
|
||||
{ "directory", no_argument, NULL, 'd' },
|
||||
{ "force", no_argument, NULL, 'f' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "info", no_argument, NULL, 'i' },
|
||||
{ "logfile", no_argument, NULL, 'l' },
|
||||
{ "mft", no_argument, NULL, 'm' },
|
||||
{ "no-action", no_argument, NULL, 'n' },
|
||||
{ "pagefile", no_argument, NULL, 'p' },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "tails", no_argument, NULL, 't' },
|
||||
{ "unused", no_argument, NULL, 'u' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
char c = -1;
|
||||
char *end;
|
||||
int err = 0;
|
||||
int ver = 0;
|
||||
int help = 0;
|
||||
|
||||
opterr = 0; /* We'll handle the errors, thank you. */
|
||||
|
||||
opts.count = 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 'a':
|
||||
opts.directory++;
|
||||
opts.logfile++;
|
||||
opts.mft++;
|
||||
opts.pagefile++;
|
||||
opts.tails++;
|
||||
opts.unused++;
|
||||
break;
|
||||
case 'b':
|
||||
if (!opts.bytes) {
|
||||
if (!parse_list (argv[optind-1], &opts.bytes))
|
||||
err++;
|
||||
} else {
|
||||
err++;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (opts.count == 1) {
|
||||
end = NULL;
|
||||
opts.count = strtol (optarg, &end, 0);
|
||||
if (end && *end)
|
||||
err++;
|
||||
} else {
|
||||
err++;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
opts.directory++;
|
||||
break;
|
||||
case 'f':
|
||||
opts.force++;
|
||||
break;
|
||||
case 'h':
|
||||
help++;
|
||||
break;
|
||||
case 'i':
|
||||
opts.info++;
|
||||
break;
|
||||
case 'l':
|
||||
opts.logfile++;
|
||||
break;
|
||||
case 'm':
|
||||
opts.mft++;
|
||||
break;
|
||||
case 'n':
|
||||
opts.noaction++;
|
||||
break;
|
||||
case 'p':
|
||||
opts.pagefile++;
|
||||
break;
|
||||
case 'q':
|
||||
opts.quiet++;
|
||||
break;
|
||||
case 't':
|
||||
opts.tails++;
|
||||
break;
|
||||
case 'u':
|
||||
opts.unused++;
|
||||
break;
|
||||
case 'v':
|
||||
opts.verbose++;
|
||||
break;
|
||||
case 'V':
|
||||
ver++;
|
||||
break;
|
||||
default:
|
||||
if ((optopt == 'b') || (optopt == 'c')) {
|
||||
Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]);
|
||||
} else {
|
||||
Eprintf ("Unknown option '%s'.\n", argv[optind-1]);
|
||||
}
|
||||
err++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (help || ver) {
|
||||
opts.quiet = 0;
|
||||
} else {
|
||||
if (opts.device == NULL) {
|
||||
Eprintf ("You must specify exactly one device.\n");
|
||||
err++;
|
||||
}
|
||||
|
||||
if ((opts.quiet) && (opts.verbose)) {
|
||||
Eprintf ("You may not use --quiet and --verbose at the same time.\n");
|
||||
err++;
|
||||
}
|
||||
|
||||
if (opts.info && (opts.unused || opts.tails || opts.mft || opts.directory)) {
|
||||
Eprintf ("You may not use any other options with --info.\n");
|
||||
err++;
|
||||
}
|
||||
|
||||
if ((opts.count < 1) || (opts.count > 100)) {
|
||||
Eprintf ("The iteration count must be between 1 and 100.\n");
|
||||
err++;
|
||||
}
|
||||
|
||||
/*if (opts.bytes && (opts.count > 0)) {
|
||||
Eprintf ("You may not use both --bytes and --count.\n");
|
||||
err++;
|
||||
}*/
|
||||
|
||||
/* Create a default list */
|
||||
if (!opts.bytes) {
|
||||
opts.bytes = malloc (2 * sizeof (int));
|
||||
if (opts.bytes) {
|
||||
opts.bytes[0] = 0;
|
||||
opts.bytes[1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.directory && !opts.logfile && !opts.mft &&
|
||||
!opts.pagefile && !opts.tails && !opts.unused) {
|
||||
opts.info = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ver)
|
||||
version();
|
||||
if (help || err)
|
||||
usage();
|
||||
|
||||
return (!err && !help && !ver);
|
||||
}
|
||||
|
||||
/**
|
||||
* valid_device - Perform some safety checks on the device, before we start
|
||||
* @name: Full pathname of the device/file to work with
|
||||
* @force: Continue regardless of problems
|
||||
*
|
||||
* Check that the name refers to a device and that is isn't already mounted.
|
||||
* These checks can be overridden by using the force option.
|
||||
*
|
||||
* Return: 1 Success, we can continue
|
||||
* 0 Error, we cannot use this device
|
||||
*/
|
||||
int valid_device (const char *name, int force)
|
||||
{
|
||||
unsigned long mnt_flags = 0;
|
||||
struct stat st;
|
||||
|
||||
if (stat (name, &st) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
Eprintf ("The device %s doesn't exist\n", name);
|
||||
} else {
|
||||
Eprintf ("Error getting information about %s: %s\n", name, strerror (errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISBLK (st.st_mode)) {
|
||||
Vprintf ("%s is not a block device.\n", name);
|
||||
if (!force) {
|
||||
Eprintf ("Use the force option to work with files.\n");
|
||||
return 0;
|
||||
}
|
||||
Vprintf ("Forced to continue.\n");
|
||||
}
|
||||
|
||||
/* Make sure the file system is not mounted. */
|
||||
if (ntfs_check_if_mounted (name, &mnt_flags)) {
|
||||
Vprintf ("Failed to determine whether %s is mounted: %s\n", name, strerror (errno));
|
||||
if (!force) {
|
||||
Eprintf ("Use the force option to ignore this error.\n");
|
||||
return 0;
|
||||
}
|
||||
Vprintf ("Forced to continue.\n");
|
||||
} else if (mnt_flags & NTFS_MF_MOUNTED) {
|
||||
Vprintf ("The device %s, is mounted.\n", name);
|
||||
if (!force) {
|
||||
Eprintf ("Use the force option to work a mounted filesystem.\n");
|
||||
return 0;
|
||||
}
|
||||
Vprintf ("Forced to continue.\n");
|
||||
}
|
||||
|
||||
Dprintf ("Device %s, will be used\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* print_summary - Tell the use what we are about to do
|
||||
*
|
||||
* List the operations about to be performed. The output will be silenced by
|
||||
* the --quiet option.
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void print_summary (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (opts.noaction)
|
||||
Iprintf ("%s is in 'no-action' mode, it will NOT write to disk."
|
||||
"\n\n", EXEC_NAME);
|
||||
|
||||
Iprintf ("%s is about to wipe:\n", EXEC_NAME);
|
||||
if (opts.unused)
|
||||
Iprintf ("\tunused disk space\n");
|
||||
if (opts.tails)
|
||||
Iprintf ("\tfile tails\n");
|
||||
if (opts.mft)
|
||||
Iprintf ("\tunused mft areas\n");
|
||||
if (opts.directory)
|
||||
Iprintf ("\tunused directory index space\n");
|
||||
if (opts.logfile)
|
||||
Iprintf ("\tthe logfile (journal)\n");
|
||||
if (opts.pagefile)
|
||||
Iprintf ("\tthe pagefile (swap space)\n");
|
||||
|
||||
Iprintf ("\n%s will overwrite these areas with: ", EXEC_NAME);
|
||||
if (opts.bytes) {
|
||||
for (i = 0; opts.bytes[i] >= 0; i++)
|
||||
Iprintf ("0x%02x ", opts.bytes[i]);
|
||||
}
|
||||
Iprintf ("\n");
|
||||
|
||||
if (opts.count > 1)
|
||||
Iprintf ("%s will repeat these operations %d times.\n", EXEC_NAME, opts.count);
|
||||
Iprintf ("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* main - Begin here
|
||||
*
|
||||
* Start from here.
|
||||
*
|
||||
* Return: 0 Success, the program worked
|
||||
* 1 Error, something went wrong
|
||||
*/
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
const char *locale;
|
||||
ntfs_volume *vol;
|
||||
int result = 1;
|
||||
int flags = 0;
|
||||
int i, j;
|
||||
|
||||
locale = setlocale (LC_ALL, "");
|
||||
if (!locale) {
|
||||
locale = setlocale (LC_ALL, NULL);
|
||||
Vprintf ("Failed to set locale, using default '%s'.\n", locale);
|
||||
} else {
|
||||
Vprintf ("Using locale '%s'.\n", locale);
|
||||
}
|
||||
|
||||
if (!parse_options (argc, argv))
|
||||
return 1;
|
||||
|
||||
if (!valid_device (opts.device, opts.force)) {
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (!opts.info)
|
||||
print_summary();
|
||||
|
||||
if (opts.info || opts.noaction)
|
||||
flags = MS_RDONLY;
|
||||
vol = ntfs_mount (opts.device, flags);
|
||||
if (!vol) {
|
||||
Eprintf ("Couldn't mount device '%s': %s\n", opts.device, strerror (errno));
|
||||
goto free;
|
||||
}
|
||||
|
||||
if (vol->flags & VOLUME_IS_DIRTY) {
|
||||
Iprintf ("Volume is dirty.\n");
|
||||
if (!opts.force) {
|
||||
Eprintf ("Run chkdsk and try again, or use the --force option.\n");
|
||||
goto umount;
|
||||
}
|
||||
Iprintf ("Forced to continue.\n");
|
||||
}
|
||||
|
||||
if (opts.info) {
|
||||
ntfs_info (vol);
|
||||
result = 0;
|
||||
goto umount;
|
||||
}
|
||||
|
||||
/* Even if the output it quieted, you still get 5 seconds to abort. */
|
||||
if (!opts.force) {
|
||||
Iprintf ("\n%s will begin in 5 seconds, press CTRL-C to abort.\n", EXEC_NAME);
|
||||
sleep (5);
|
||||
}
|
||||
|
||||
if (!opts.bytes) {
|
||||
Eprintf ("Internal error, byte list is empty\n");
|
||||
goto umount;
|
||||
}
|
||||
|
||||
for (i = 0; i < opts.count; i++) {
|
||||
int byte;
|
||||
for (j = 0; byte = opts.bytes[j], byte >= 0; j++) {
|
||||
if (opts.unused && !wipe_unused (vol, byte))
|
||||
goto umount;
|
||||
if (opts.tails && !wipe_tails (vol, byte))
|
||||
goto umount;
|
||||
if (opts.mft && !wipe_mft (vol, byte))
|
||||
goto umount;
|
||||
if (opts.directory && !wipe_directory (vol, byte))
|
||||
goto umount;
|
||||
if (opts.logfile && !wipe_logfile (vol, byte))
|
||||
goto umount;
|
||||
if (opts.pagefile && !wipe_pagefile (vol, byte))
|
||||
goto umount;
|
||||
}
|
||||
}
|
||||
|
||||
result = 0;
|
||||
umount:
|
||||
ntfs_umount (vol, FALSE);
|
||||
free:
|
||||
if (opts.bytes)
|
||||
free (opts.bytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* ntfswipe - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002 Richard Russon <ntfs@flatcap.org>
|
||||
*
|
||||
* This utility will overwrite usused 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"
|
||||
|
||||
struct options {
|
||||
char *device; /* Device/File to work with */
|
||||
int info; /* Show volume info */
|
||||
int force; /* Override common sense */
|
||||
int quiet; /* Less output */
|
||||
int verbose; /* Extra output */
|
||||
int noaction; /* Do not write to disk */
|
||||
int count; /* Number of iterations */
|
||||
int *bytes; /* List of overwrite characters */
|
||||
int directory; /* Wipe directory indexes */
|
||||
int logfile; /* Wipe the logfile (journal) */
|
||||
int mft; /* Wipe mft slack space */
|
||||
int pagefile; /* Wipe pagefile (swap space) */
|
||||
int tails; /* Wipe file tails */
|
||||
int unused; /* Wipe unused clusters */
|
||||
};
|
||||
|
||||
#endif /* _NTFSWIPE_H_ */
|
||||
|
200
ntfsprogs/sd.c
200
ntfsprogs/sd.c
|
@ -0,0 +1,200 @@
|
|||
#include "types.h"
|
||||
#include "layout.h"
|
||||
|
||||
/*
|
||||
* NTFS 1.2 - System files security decriptors
|
||||
* ===========================================
|
||||
*
|
||||
* Create the security descriptor for system file number @sys_file_no and
|
||||
* return a pointer to the descriptor.
|
||||
*
|
||||
* $MFT, $MFTMirr, $LogFile, $AttrDef, $Bitmap, $Boot, $BadClus, and $UpCase
|
||||
* are the same.
|
||||
*
|
||||
* $Volume, $Quota, and system files 0xb-0xf are the same. They are almost the
|
||||
* same as the above, the only difference being that the two SIDs present in
|
||||
* the DACL grant GENERIC_WRITE and GENERIC_READ equivalent priviledges while
|
||||
* the above only grant GENERIC_READ equivalent priviledges. (For some reason
|
||||
* the flags for GENERIC_READ/GENERIC_WRITE are not set by NT4, even though
|
||||
* the permissions are equivalent, so we comply.
|
||||
*
|
||||
* Root directory system file (".") is different altogether.
|
||||
*
|
||||
* The sd is recturned 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, char **sd_val, int *sd_val_len)
|
||||
{
|
||||
static char sd_array[0x68];
|
||||
SECURITY_DESCRIPTOR_RELATIVE *sd;
|
||||
ACL *acl;
|
||||
ACCESS_ALLOWED_ACE *aa_ace;
|
||||
SID *sid;
|
||||
|
||||
if (sys_file_no < 0 || sys_file_no > 0xf) {
|
||||
*sd_val = NULL;
|
||||
*sd_val_len = 0;
|
||||
return;
|
||||
}
|
||||
*sd_val = (char*)&sd_array;
|
||||
sd = (SECURITY_DESCRIPTOR_RELATIVE*)&sd_array;
|
||||
sd->revision = 1;
|
||||
sd->alignment = 0;
|
||||
sd->control = SE_SELF_RELATIVE | SE_DACL_PRESENT;
|
||||
if (sys_file_no == FILE_root) {
|
||||
*sd_val_len = 0x50;
|
||||
sd->owner = cpu_to_le32(0x30);
|
||||
sd->group = cpu_to_le32(0x40);
|
||||
} else {
|
||||
*sd_val_len = 0x68;
|
||||
sd->owner = cpu_to_le32(0x48);
|
||||
sd->group = cpu_to_le32(0x58);
|
||||
}
|
||||
sd->sacl = cpu_to_le32(0);
|
||||
sd->dacl = 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;
|
||||
if (sys_file_no == FILE_root) {
|
||||
acl->size = cpu_to_le16(0x1c);
|
||||
acl->ace_count = cpu_to_le16(1);
|
||||
} else {
|
||||
acl->size = cpu_to_le16(0x34);
|
||||
acl->ace_count = cpu_to_le16(2);
|
||||
}
|
||||
acl->alignment2 = 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;
|
||||
if (sys_file_no == FILE_root)
|
||||
aa_ace->flags = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
|
||||
else
|
||||
aa_ace->flags = 0;
|
||||
aa_ace->size = cpu_to_le16(0x14);
|
||||
switch (sys_file_no) {
|
||||
case FILE_MFT: case FILE_MFTMirr: case FILE_LogFile:
|
||||
case FILE_AttrDef: case FILE_Bitmap: case FILE_Boot:
|
||||
case FILE_BadClus: case FILE_UpCase:
|
||||
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ |
|
||||
FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA;
|
||||
break;
|
||||
case FILE_Volume: case FILE_Secure: case 0xb ... 0xf:
|
||||
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;
|
||||
case FILE_root:
|
||||
aa_ace->mask = STANDARD_RIGHTS_ALL | FILE_WRITE_ATTRIBUTES |
|
||||
FILE_READ_ATTRIBUTES | FILE_DELETE_CHILD |
|
||||
FILE_TRAVERSE | FILE_WRITE_EA | FILE_READ_EA |
|
||||
FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE |
|
||||
FILE_LIST_DIRECTORY;
|
||||
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;
|
||||
if (sys_file_no == FILE_root) {
|
||||
/* SECURITY_WORLD_SID_AUTHORITY (S-1-1) */
|
||||
aa_ace->sid.identifier_authority.value[5] = 1;
|
||||
aa_ace->sid.sub_authority[0] =
|
||||
cpu_to_le32(SECURITY_WORLD_RID);
|
||||
/* This is S-1-1-0, the WORLD_SID. */
|
||||
} else {
|
||||
/* SECURITY_NT_SID_AUTHORITY (S-1-5) */
|
||||
aa_ace->sid.identifier_authority.value[5] = 5;
|
||||
aa_ace->sid.sub_authority[0] =
|
||||
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.
|
||||
*/
|
||||
if (sys_file_no != FILE_root) {
|
||||
/* 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 = cpu_to_le16(0x18);
|
||||
switch (sys_file_no) {
|
||||
case FILE_MFT: case FILE_MFTMirr:
|
||||
case FILE_LogFile: case FILE_AttrDef:
|
||||
case FILE_Bitmap: case FILE_Boot:
|
||||
case FILE_BadClus: case FILE_UpCase:
|
||||
aa_ace->mask = SYNCHRONIZE | STANDARD_RIGHTS_READ |
|
||||
FILE_READ_ATTRIBUTES | FILE_READ_EA |
|
||||
FILE_READ_DATA;
|
||||
break;
|
||||
case FILE_Volume: case FILE_Secure:
|
||||
case 0xb ... 0xf:
|
||||
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;
|
||||
aa_ace->sid.sub_authority[0] =
|
||||
cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
aa_ace->sid.sub_authority[1] =
|
||||
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 = 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;
|
||||
sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
/*
|
||||
* Now at offset 0x40 or 0x58 (root directory and the other system
|
||||
* files, respectively) 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;
|
||||
sid->sub_authority[0] = cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
|
||||
sid->sub_authority[1] = cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2001 Richard Russon <ntfs@flatcap.org>
|
||||
* Copyright (c) 2001-2002 Anton Altaparmakov <aia21@cantab.net>
|
||||
*
|
||||
* Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the Linux-NTFS source
|
||||
* in the file COPYING); if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void init_upcase_table(uchar_t *uc, u32 uc_len)
|
||||
{
|
||||
static int uc_run_table[][3] = { /* Start, End, Add */
|
||||
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
|
||||
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
|
||||
{0x00F8, 0x00FF, -32}, {0x0561, 0x0587, -48}, {0x1F76, 0x1F78, 100},
|
||||
{0x0256, 0x0258, -205}, {0x1F00, 0x1F08, 8}, {0x1F78, 0x1F7A, 128},
|
||||
{0x028A, 0x028C, -217}, {0x1F10, 0x1F16, 8}, {0x1F7A, 0x1F7C, 112},
|
||||
{0x03AC, 0x03AD, -38}, {0x1F20, 0x1F28, 8}, {0x1F7C, 0x1F7E, 126},
|
||||
{0x03AD, 0x03B0, -37}, {0x1F30, 0x1F38, 8}, {0x1FB0, 0x1FB2, 8},
|
||||
{0x03B1, 0x03C2, -32}, {0x1F40, 0x1F46, 8}, {0x1FD0, 0x1FD2, 8},
|
||||
{0x03C2, 0x03C3, -31}, {0x1F51, 0x1F52, 8}, {0x1FE0, 0x1FE2, 8},
|
||||
{0x03C3, 0x03CC, -32}, {0x1F53, 0x1F54, 8}, {0x1FE5, 0x1FE6, 7},
|
||||
{0x03CC, 0x03CD, -64}, {0x1F55, 0x1F56, 8}, {0x2170, 0x2180, -16},
|
||||
{0x03CD, 0x03CF, -63}, {0x1F57, 0x1F58, 8}, {0x24D0, 0x24EA, -26},
|
||||
{0x0430, 0x0450, -32}, {0x1F60, 0x1F68, 8}, {0xFF41, 0xFF5B, -32},
|
||||
{0}
|
||||
};
|
||||
static int uc_dup_table[][2] = { /* Start, End */
|
||||
{0x0100, 0x012F}, {0x01A0, 0x01A6}, {0x03E2, 0x03EF}, {0x04CB, 0x04CC},
|
||||
{0x0132, 0x0137}, {0x01B3, 0x01B7}, {0x0460, 0x0481}, {0x04D0, 0x04EB},
|
||||
{0x0139, 0x0149}, {0x01CD, 0x01DD}, {0x0490, 0x04BF}, {0x04EE, 0x04F5},
|
||||
{0x014A, 0x0178}, {0x01DE, 0x01EF}, {0x04BF, 0x04BF}, {0x04F8, 0x04F9},
|
||||
{0x0179, 0x017E}, {0x01F4, 0x01F5}, {0x04C1, 0x04C4}, {0x1E00, 0x1E95},
|
||||
{0x018B, 0x018B}, {0x01FA, 0x0218}, {0x04C7, 0x04C8}, {0x1EA0, 0x1EF9},
|
||||
{0}
|
||||
};
|
||||
static int uc_byte_table[][2] = { /* Offset, Value */
|
||||
{0x00FF, 0x0178}, {0x01AD, 0x01AC}, {0x01F3, 0x01F1}, {0x0269, 0x0196},
|
||||
{0x0183, 0x0182}, {0x01B0, 0x01AF}, {0x0253, 0x0181}, {0x026F, 0x019C},
|
||||
{0x0185, 0x0184}, {0x01B9, 0x01B8}, {0x0254, 0x0186}, {0x0272, 0x019D},
|
||||
{0x0188, 0x0187}, {0x01BD, 0x01BC}, {0x0259, 0x018F}, {0x0275, 0x019F},
|
||||
{0x018C, 0x018B}, {0x01C6, 0x01C4}, {0x025B, 0x0190}, {0x0283, 0x01A9},
|
||||
{0x0192, 0x0191}, {0x01C9, 0x01C7}, {0x0260, 0x0193}, {0x0288, 0x01AE},
|
||||
{0x0199, 0x0198}, {0x01CC, 0x01CA}, {0x0263, 0x0194}, {0x0292, 0x01B7},
|
||||
{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
|
||||
{0}
|
||||
};
|
||||
int i, r;
|
||||
|
||||
memset((char*)uc, 0, uc_len);
|
||||
uc_len >>= 1;
|
||||
for (i = 0; i < uc_len; i++)
|
||||
uc[i] = i;
|
||||
for (r = 0; uc_run_table[r][0]; r++)
|
||||
for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
|
||||
uc[i] += uc_run_table[r][2];
|
||||
for (r = 0; uc_dup_table[r][0]; r++)
|
||||
for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
|
||||
uc[i + 1]--;
|
||||
for (r = 0; uc_byte_table[r][0]; r++)
|
||||
uc[uc_byte_table[r][0]] = uc_byte_table[r][1];
|
||||
}
|
||||
|
Loading…
Reference in New Issue