(Logical change 1.23)
edge.strict_endians
cantab.net!aia21 2002-11-29 12:16:35 +00:00
parent 37676411cb
commit cd29ef7745
22 changed files with 10348 additions and 0 deletions

View File

@ -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) $^

View File

@ -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
};

View File

@ -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 };

View File

@ -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;
}

View File

@ -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)

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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).

View File

@ -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;
}

View File

@ -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/.

View File

@ -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)
{
}*/

View File

@ -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)

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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);
}

View File

@ -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];
}