Initial commit -- seeded with reiserfsprogs 3.x.0j
This commit is contained in:
commit
e7102bdb66
77 files changed
+33513
No files matched your search
@@ -0,0 +1,11 @@
|
||||
sbin_PROGRAMS = reiserfsck
|
||||
|
||||
reiserfsck_SOURCES = main.c pass0.c pass1.c pass2.c semantic.c pass4.c lost+found.c \
|
||||
ubitmap.c uobjectid.c ustree.c ufile.c check.c check_tree.c journal.c info.c segments.c\
|
||||
fsck.h
|
||||
man_MANS = reiserfsck.8
|
||||
EXTRA_DIST = $(man_MANS)
|
||||
|
||||
LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
|
||||
|
||||
INCLUDES = -I../include -I.
|
||||
@@ -0,0 +1,358 @@
|
||||
# Makefile.in generated automatically by automake 1.4 from Makefile.am
|
||||
|
||||
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
SHELL = @SHELL@
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
bindir = @bindir@
|
||||
sbindir = @sbindir@
|
||||
libexecdir = @libexecdir@
|
||||
datadir = @datadir@
|
||||
sysconfdir = @sysconfdir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
localstatedir = @localstatedir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
mandir = @mandir@
|
||||
includedir = @includedir@
|
||||
oldincludedir = /usr/include
|
||||
|
||||
DESTDIR =
|
||||
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
|
||||
top_builddir = ..
|
||||
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
transform = @program_transform_name@
|
||||
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
CC = @CC@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
PACKAGE = @PACKAGE@
|
||||
RANLIB = @RANLIB@
|
||||
VERSION = @VERSION@
|
||||
|
||||
sbin_PROGRAMS = reiserfsck
|
||||
|
||||
reiserfsck_SOURCES = main.c pass0.c pass1.c pass2.c semantic.c pass4.c lost+found.c ubitmap.c uobjectid.c ustree.c ufile.c check.c check_tree.c journal.c info.c segments.c fsck.h
|
||||
|
||||
man_MANS = reiserfsck.8
|
||||
EXTRA_DIST = $(man_MANS)
|
||||
|
||||
LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
|
||||
|
||||
INCLUDES = -I../include -I.
|
||||
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
|
||||
CONFIG_CLEAN_FILES =
|
||||
PROGRAMS = $(sbin_PROGRAMS)
|
||||
|
||||
|
||||
DEFS = @DEFS@ -I. -I$(srcdir)
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
reiserfsck_OBJECTS = main.o pass0.o pass1.o pass2.o semantic.o pass4.o \
|
||||
lost+found.o ubitmap.o uobjectid.o ustree.o ufile.o check.o \
|
||||
check_tree.o journal.o info.o segments.o
|
||||
reiserfsck_LDADD = $(LDADD)
|
||||
reiserfsck_DEPENDENCIES = ../lib/libmisc.a ../reiserfscore/libcore.a
|
||||
reiserfsck_LDFLAGS =
|
||||
CFLAGS = @CFLAGS@
|
||||
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
|
||||
man8dir = $(mandir)/man8
|
||||
MANS = $(man_MANS)
|
||||
|
||||
NROFF = nroff
|
||||
DIST_COMMON = Makefile.am Makefile.in
|
||||
|
||||
|
||||
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
|
||||
|
||||
TAR = tar
|
||||
GZIP_ENV = --best
|
||||
SOURCES = $(reiserfsck_SOURCES)
|
||||
OBJECTS = $(reiserfsck_OBJECTS)
|
||||
|
||||
all: all-redirect
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .S .c .o .s
|
||||
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
|
||||
cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps fsck/Makefile
|
||||
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
cd $(top_builddir) \
|
||||
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
|
||||
|
||||
|
||||
mostlyclean-sbinPROGRAMS:
|
||||
|
||||
clean-sbinPROGRAMS:
|
||||
-test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS)
|
||||
|
||||
distclean-sbinPROGRAMS:
|
||||
|
||||
maintainer-clean-sbinPROGRAMS:
|
||||
|
||||
install-sbinPROGRAMS: $(sbin_PROGRAMS)
|
||||
@$(NORMAL_INSTALL)
|
||||
$(mkinstalldirs) $(DESTDIR)$(sbindir)
|
||||
@list='$(sbin_PROGRAMS)'; for p in $$list; do \
|
||||
if test -f $$p; then \
|
||||
echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
|
||||
else :; fi; \
|
||||
done
|
||||
|
||||
uninstall-sbinPROGRAMS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
list='$(sbin_PROGRAMS)'; for p in $$list; do \
|
||||
rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
|
||||
done
|
||||
|
||||
.c.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
.s.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
.S.o:
|
||||
$(COMPILE) -c $<
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.o core *.core
|
||||
|
||||
clean-compile:
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
maintainer-clean-compile:
|
||||
|
||||
reiserfsck: $(reiserfsck_OBJECTS) $(reiserfsck_DEPENDENCIES)
|
||||
@rm -f reiserfsck
|
||||
$(LINK) $(reiserfsck_LDFLAGS) $(reiserfsck_OBJECTS) $(reiserfsck_LDADD) $(LIBS)
|
||||
|
||||
install-man8:
|
||||
$(mkinstalldirs) $(DESTDIR)$(man8dir)
|
||||
@list='$(man8_MANS)'; \
|
||||
l2='$(man_MANS)'; for i in $$l2; do \
|
||||
case "$$i" in \
|
||||
*.8*) list="$$list $$i" ;; \
|
||||
esac; \
|
||||
done; \
|
||||
for i in $$list; do \
|
||||
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
|
||||
else file=$$i; fi; \
|
||||
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
|
||||
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
|
||||
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
|
||||
echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \
|
||||
$(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \
|
||||
done
|
||||
|
||||
uninstall-man8:
|
||||
@list='$(man8_MANS)'; \
|
||||
l2='$(man_MANS)'; for i in $$l2; do \
|
||||
case "$$i" in \
|
||||
*.8*) list="$$list $$i" ;; \
|
||||
esac; \
|
||||
done; \
|
||||
for i in $$list; do \
|
||||
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
|
||||
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
|
||||
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
|
||||
echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \
|
||||
rm -f $(DESTDIR)$(man8dir)/$$inst; \
|
||||
done
|
||||
install-man: $(MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
$(MAKE) $(AM_MAKEFLAGS) install-man8
|
||||
uninstall-man:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
$(MAKE) $(AM_MAKEFLAGS) uninstall-man8
|
||||
|
||||
tags: TAGS
|
||||
|
||||
ID: $(HEADERS) $(SOURCES) $(LISP)
|
||||
list='$(SOURCES) $(HEADERS)'; \
|
||||
unique=`for i in $$list; do echo $$i; done | \
|
||||
awk ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
here=`pwd` && cd $(srcdir) \
|
||||
&& mkid -f$$here/ID $$unique $(LISP)
|
||||
|
||||
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS)'; \
|
||||
unique=`for i in $$list; do echo $$i; done | \
|
||||
awk ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
|
||||
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
|
||||
|
||||
mostlyclean-tags:
|
||||
|
||||
clean-tags:
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID
|
||||
|
||||
maintainer-clean-tags:
|
||||
|
||||
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
|
||||
|
||||
subdir = fsck
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@for file in $(DISTFILES); do \
|
||||
d=$(srcdir); \
|
||||
if test -d $$d/$$file; then \
|
||||
cp -pr $$/$$file $(distdir)/$$file; \
|
||||
else \
|
||||
test -f $(distdir)/$$file \
|
||||
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \
|
||||
|| cp -p $$d/$$file $(distdir)/$$file || :; \
|
||||
fi; \
|
||||
done
|
||||
check.o: check.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
check_tree.o: check_tree.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
info.o: info.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
journal.o: journal.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
lost+found.o: lost+found.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
main.o: main.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h
|
||||
pass0.o: pass0.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
pass1.o: pass1.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
pass2.o: pass2.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
pass4.o: pass4.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
segments.o: segments.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
semantic.o: semantic.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
ubitmap.o: ubitmap.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
ufile.o: ufile.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
uobjectid.o: uobjectid.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
ustree.o: ustree.c fsck.h ../include/io.h ../include/misc.h \
|
||||
../include/reiserfs_lib.h ../include/reiserfs_fs.h
|
||||
|
||||
info-am:
|
||||
info: info-am
|
||||
dvi-am:
|
||||
dvi: dvi-am
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
installcheck-am:
|
||||
installcheck: installcheck-am
|
||||
install-exec-am: install-sbinPROGRAMS
|
||||
install-exec: install-exec-am
|
||||
|
||||
install-data-am: install-man
|
||||
install-data: install-data-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
install: install-am
|
||||
uninstall-am: uninstall-sbinPROGRAMS uninstall-man
|
||||
uninstall: uninstall-am
|
||||
all-am: Makefile $(PROGRAMS) $(MANS)
|
||||
all-redirect: all-am
|
||||
install-strip:
|
||||
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
|
||||
installdirs:
|
||||
$(mkinstalldirs) $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8
|
||||
|
||||
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-rm -f Makefile $(CONFIG_CLEAN_FILES)
|
||||
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
|
||||
|
||||
maintainer-clean-generic:
|
||||
mostlyclean-am: mostlyclean-sbinPROGRAMS mostlyclean-compile \
|
||||
mostlyclean-tags mostlyclean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
clean-am: clean-sbinPROGRAMS clean-compile clean-tags clean-generic \
|
||||
mostlyclean-am
|
||||
|
||||
clean: clean-am
|
||||
|
||||
distclean-am: distclean-sbinPROGRAMS distclean-compile distclean-tags \
|
||||
distclean-generic clean-am
|
||||
|
||||
distclean: distclean-am
|
||||
|
||||
maintainer-clean-am: maintainer-clean-sbinPROGRAMS \
|
||||
maintainer-clean-compile maintainer-clean-tags \
|
||||
maintainer-clean-generic distclean-am
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
|
||||
.PHONY: mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS \
|
||||
clean-sbinPROGRAMS maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \
|
||||
install-sbinPROGRAMS mostlyclean-compile distclean-compile \
|
||||
clean-compile maintainer-clean-compile install-man8 uninstall-man8 \
|
||||
install-man uninstall-man tags mostlyclean-tags distclean-tags \
|
||||
clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
|
||||
check-am installcheck-am installcheck install-exec-am install-exec \
|
||||
install-data-am install-data install-am install uninstall-am uninstall \
|
||||
all-redirect all-am all installdirs mostlyclean-generic \
|
||||
distclean-generic clean-generic maintainer-clean-generic clean \
|
||||
mostlyclean distclean maintainer-clean
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright 1996, 1997 Hans Reiser
|
||||
*/
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
|
||||
/* this goes through buffers checking delimiting keys
|
||||
*/
|
||||
|
||||
struct buffer_head * g_left = 0;
|
||||
struct buffer_head * g_right = 0;
|
||||
struct key * g_dkey = 0;
|
||||
|
||||
|
||||
static void check_directory_item (struct item_head * ih, struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
struct reiserfs_de_head * deh;
|
||||
|
||||
for (i = 0, deh = B_I_DEH (bh, ih); i < ih_entry_count (ih) - 1; i ++)
|
||||
if (deh_offset(&deh[i]) > deh_offset(&deh[i + 1]))
|
||||
die ("check_directory_item: entries are not sorted properly");
|
||||
}
|
||||
|
||||
|
||||
static void check_items (struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
struct item_head * ih;
|
||||
|
||||
for (i = 0; i < B_NR_ITEMS (bh); i++)
|
||||
{
|
||||
ih = B_N_PITEM_HEAD (bh, i);
|
||||
|
||||
if (is_direntry_ih (ih))
|
||||
check_directory_item (ih, bh);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void compare_neighboring_leaves_in_pass1 (void)
|
||||
{
|
||||
struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1);
|
||||
|
||||
if (comp_keys (left, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/)
|
||||
die ("compare_neighboring_leaves_in_pass1: left key is greater, that the right one");
|
||||
|
||||
if (/*comp_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) == FIRST_GREATER ||*/
|
||||
comp_keys (g_dkey, B_N_PKEY (g_right, 0))) {
|
||||
reiserfs_panic (0, "compare_neighboring_leaves_in_pass1: dkey %k, first key in right %k",
|
||||
g_dkey, B_N_PKEY (g_right, 0));
|
||||
}
|
||||
|
||||
check_items (g_left);
|
||||
|
||||
/*&&&&&&&&&&&&&&&&&&&&&&&&&&
|
||||
for (i = 0, ih = B_N_PITEM_HEAD (g_left, i); i < B_NR_ITEMS (g_left); i ++, ih ++)
|
||||
if (is_item_accessed (ih) == YES)
|
||||
die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_left");
|
||||
for (i = 0, ih = B_N_PITEM_HEAD (g_right, i); i < B_NR_ITEMS (g_right); i ++, ih ++)
|
||||
if (is_item_accessed (ih) == YES)
|
||||
die ("compare_neighboring_leaves_in_pass1: item marked as accessed in g_right");
|
||||
&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void is_there_unaccessed_items (struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
struct item_head * ih;
|
||||
|
||||
ih = B_N_PITEM_HEAD (bh, 0);
|
||||
for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
|
||||
if (is_objectid_used (fs, ih->ih_key.k_objectid) == 0)
|
||||
die ("is_there_unaccessed_items: %lu is not marked as used", ih->ih_key.k_objectid);
|
||||
|
||||
if (!is_item_reachable (ih)) {
|
||||
die ("is_there_unaccessed_items: block %lu - unaccessed item found",
|
||||
bh->b_blocknr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void compare_neighboring_leaves_after_all (void)
|
||||
{
|
||||
struct item_head * left = B_N_PITEM_HEAD(g_left, B_NR_ITEMS (g_left) - 1);
|
||||
struct item_head * right = B_N_PITEM_HEAD(g_right, 0);
|
||||
/* struct key * left = B_N_PKEY (g_left, B_NR_ITEMS (g_left) - 1);
|
||||
struct key * right = B_N_PKEY (g_right, 0);*/
|
||||
|
||||
/*
|
||||
if (comp_keys (&left->ih_key, B_PRIGHT_DELIM_KEY (g_left)) != SECOND_GREATER)
|
||||
die ("compare_neighboring_leaves_after_all: invalid right delimiting key");
|
||||
*/
|
||||
if (comp_keys (&left->ih_key, B_N_PKEY (g_right, 0)) != -1/*SECOND_GREATER*/)
|
||||
die ("compare_neighboring_leaves_after_all: left key is greater than the right one");
|
||||
|
||||
if (//comp_le_keys (B_PRIGHT_DELIM_KEY (g_left), g_dkey) != KEYS_IDENTICAL ||
|
||||
comp_keys (g_dkey, B_N_PKEY (g_right, 0))) {
|
||||
reiserfs_panic (0, "compare_neighboring_leaves_after all: invalid delimiting keys from left to right (%k %k)",
|
||||
g_dkey, B_N_PKEY (g_right, 0));
|
||||
}
|
||||
|
||||
if (!not_of_one_file (&left->ih_key, &right->ih_key)) {
|
||||
// items of one file: check offset correctness
|
||||
if (is_direct_ih (left) || is_indirect_ih (left))
|
||||
//if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (g_left, left /*B_NR_ITEMS (g_left) - 1*/, 0, CHECK_FREE_BYTES))
|
||||
if (get_offset(&right->ih_key) != get_offset(&left->ih_key) + get_bytes_number (left, g_left->b_size))
|
||||
die ("compare_neighboring_leaves_after all: hole between items or items are overlapped");
|
||||
}
|
||||
is_there_unaccessed_items (g_left);
|
||||
|
||||
}
|
||||
|
||||
|
||||
typedef void (check_function_t)(void);
|
||||
|
||||
|
||||
/* only directory item can be fatally bad */
|
||||
static int is_leaf_bad_xx (struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
struct item_head * ih;
|
||||
|
||||
if (!is_leaf_node (bh))
|
||||
return 0;
|
||||
for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++)
|
||||
if (is_bad_item (bh, ih, B_I_PITEM (bh, ih))) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void reiserfsck_check_tree (int dev, int block, int size, check_function_t comp_func)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
int what_node;
|
||||
|
||||
bh = bread (dev, block, size);
|
||||
if (bh == 0)
|
||||
reiserfs_panic("reiserfsck_check_tree: unable to read %lu block on device 0x%x\n",
|
||||
block, dev);
|
||||
|
||||
if (!B_IS_IN_TREE (bh)) {
|
||||
reiserfs_panic (0, "reiserfsck_check_tree: buffer (%b %z) not in tree", bh, bh);
|
||||
}
|
||||
|
||||
what_node = who_is_this (bh->b_data, bh->b_size);
|
||||
if (what_node != THE_LEAF && what_node != THE_INTERNAL)
|
||||
die ("Not formatted node");
|
||||
|
||||
if (!is_block_used (bh->b_blocknr))
|
||||
die ("Not marked as used");
|
||||
|
||||
if (is_leaf_node (bh) && is_leaf_bad_xx (bh))
|
||||
die ("Bad leaf");
|
||||
|
||||
if (is_internal_node(bh) && is_internal_bad (bh))
|
||||
die ("bad internal");
|
||||
|
||||
if (is_internal_node (bh)) {
|
||||
int i;
|
||||
struct disk_child * dc;
|
||||
|
||||
dc = B_N_CHILD (bh, 0);
|
||||
for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
|
||||
reiserfsck_check_tree (dev, dc->dc_block_number, size, comp_func);
|
||||
g_dkey = B_N_PDELIM_KEY (bh, i);
|
||||
}
|
||||
} else if (is_leaf_node (bh)) {
|
||||
g_right = bh;
|
||||
if (g_left != 0 && g_dkey != 0) {
|
||||
comp_func ();
|
||||
brelse (g_left);
|
||||
}
|
||||
g_left = g_right;
|
||||
return;
|
||||
} else {
|
||||
reiserfs_panic ("reiserfsck_check_tree: block %lu has bad block type (%b)",
|
||||
bh->b_blocknr, bh);
|
||||
}
|
||||
brelse (bh);
|
||||
}
|
||||
|
||||
static void reiserfsck_check_cached_tree (int dev, int block, int size)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
int what_node;
|
||||
|
||||
bh = find_buffer(dev, block, size);
|
||||
if (bh == 0)
|
||||
return;
|
||||
if (!buffer_uptodate (bh)) {
|
||||
die ("reiserfsck_check_cached_tree: found notuptodate buffer");
|
||||
}
|
||||
|
||||
bh->b_count ++;
|
||||
|
||||
if (!B_IS_IN_TREE (bh)) {
|
||||
die ("reiserfsck_check_cached_tree: buffer (%b %z) not in tree", bh, bh);
|
||||
}
|
||||
|
||||
what_node = who_is_this (bh->b_data, bh->b_size);
|
||||
if ((what_node != THE_LEAF && what_node != THE_INTERNAL) ||
|
||||
!is_block_used (bh->b_blocknr) ||
|
||||
(is_leaf_node (bh) && is_leaf_bad (bh)) ||
|
||||
(is_internal_node(bh) && is_internal_bad (bh)))
|
||||
die ("reiserfsck_check_cached_tree: bad node in the tree");
|
||||
if (is_internal_node (bh)) {
|
||||
int i;
|
||||
struct disk_child * dc;
|
||||
|
||||
dc = B_N_CHILD (bh, 0);
|
||||
for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
|
||||
reiserfsck_check_cached_tree (dev, dc->dc_block_number, size);
|
||||
g_dkey = B_N_PDELIM_KEY (bh, i);
|
||||
}
|
||||
} else if (is_leaf_node (bh)) {
|
||||
brelse (bh);
|
||||
return;
|
||||
} else {
|
||||
reiserfs_panic ("reiserfsck_check_cached_tree: block %lu has bad block type (%b)",
|
||||
bh->b_blocknr, bh);
|
||||
}
|
||||
brelse (bh);
|
||||
}
|
||||
|
||||
|
||||
void reiserfsck_tree_check (check_function_t how_to_compare_neighbors)
|
||||
{
|
||||
g_left = 0;
|
||||
g_dkey = 0;
|
||||
reiserfsck_check_tree (fs->s_dev, SB_ROOT_BLOCK(fs), fs->s_blocksize, how_to_compare_neighbors);
|
||||
brelse (g_right);
|
||||
}
|
||||
|
||||
|
||||
void reiserfsck_check_pass1 ()
|
||||
{
|
||||
/* if (opt_check == 1)*/
|
||||
reiserfsck_tree_check (compare_neighboring_leaves_in_pass1);
|
||||
}
|
||||
|
||||
void check_cached_tree ()
|
||||
{
|
||||
reiserfsck_check_cached_tree (fs->s_dev, SB_ROOT_BLOCK (fs), fs->s_blocksize);
|
||||
}
|
||||
|
||||
void reiserfsck_check_after_all ()
|
||||
{
|
||||
reiserfsck_tree_check (compare_neighboring_leaves_after_all);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int is_bad_sd (struct item_head * ih, char * item)
|
||||
{
|
||||
struct stat_data * sd = (struct stat_data *)item;
|
||||
|
||||
if (!S_ISDIR (sd->sd_mode) && !S_ISREG(sd->sd_mode) &&
|
||||
!S_ISCHR (sd->sd_mode) && !S_ISBLK(sd->sd_mode) &&
|
||||
!S_ISLNK (sd->sd_mode) && !S_ISFIFO(sd->sd_mode) &&
|
||||
!S_ISSOCK(sd->sd_mode)) {
|
||||
fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd->sd_mode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
|
||||
int blocks_on_device (int dev, int blocksize)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (ioctl (dev, BLKGETSIZE, &size) >= 0) {
|
||||
return size / (blocksize / 512);
|
||||
}
|
||||
if (ioctl (dev, BLKGETSIZE, &size) >= 0) {
|
||||
return size / (blocksize / 512);
|
||||
} else {
|
||||
struct stat stat_buf;
|
||||
memset(&stat_buf, '\0', sizeof(struct stat));
|
||||
if(fstat(dev, &stat_buf) >= 0) {
|
||||
return stat_buf.st_size / (blocksize / 512);
|
||||
} else {
|
||||
die ("can not calculate device size\n");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_internal_bad (struct buffer_head * bh)
|
||||
{
|
||||
struct key * key;
|
||||
|
||||
int i;
|
||||
|
||||
if (!is_internal_node(bh))
|
||||
return 0;
|
||||
for (i = 0; i < B_NR_ITEMS (bh); i ++) {
|
||||
key = B_N_PDELIM_KEY (bh, i);
|
||||
if (//key->k_dir_id >= key->k_objectid ||
|
||||
key->u.k_offset_v1.k_uniqueness != V1_DIRENTRY_UNIQUENESS && key->u.k_offset_v1.k_uniqueness != V1_DIRECT_UNIQUENESS &&
|
||||
key->u.k_offset_v1.k_uniqueness != V1_INDIRECT_UNIQUENESS && key->u.k_offset_v1.k_uniqueness != V1_SD_UNIQUENESS &&
|
||||
key->u.k_offset_v2.k_type != TYPE_DIRENTRY && key->u.k_offset_v2.k_type != TYPE_DIRECT &&
|
||||
key->u.k_offset_v2.k_type != TYPE_INDIRECT && key->u.k_offset_v2.k_type != TYPE_STAT_DATA //&&
|
||||
// key->u.k_offset_v1.k_uniqueness != V1_ANY_UNIQUENESS && key->u.k_offset_v2.k_type != TYPE_ANY
|
||||
)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,915 @@
|
||||
/*
|
||||
* Copyright 1999 Hans Reiser
|
||||
*/
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// check S+ tree of the file system
|
||||
//
|
||||
// check_fs_tree stops and recommends to run fsck --rebuild-tree when:
|
||||
// 1. read fails
|
||||
// 2. node of wrong level found in the tree
|
||||
// 3. something in the tree points to wrong block number
|
||||
// out of filesystem boundary is pointed by tree
|
||||
// to block marked as free in bitmap
|
||||
// the same block is pointed from more than one place
|
||||
// not data blocks (journal area, super block, bitmaps)
|
||||
// 4. bad formatted node found
|
||||
// 5. delimiting keys are incorrect
|
||||
//
|
||||
|
||||
|
||||
|
||||
/* mark every block we see in the tree in control bitmap, so, when to make
|
||||
sure, that no blocks are pointed to from more than one place we use
|
||||
additional bitmap (control_bitmap). If we see pointer to a block we set
|
||||
corresponding bit to 1. If it is set already - run fsck with --rebuild-tree */
|
||||
static reiserfs_bitmap_t control_bitmap;
|
||||
|
||||
static int tree_scanning_failed = 0;
|
||||
|
||||
|
||||
/* 1 if block is not marked as used in the bitmap */
|
||||
static int is_block_free (reiserfs_filsys_t fs, unsigned long block)
|
||||
{
|
||||
return !reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block);
|
||||
}
|
||||
|
||||
|
||||
/* we have seen this block in the tree, mark corresponding bit in the
|
||||
control bitmap */
|
||||
static void we_met_it (unsigned long block)
|
||||
{
|
||||
reiserfs_bitmap_set_bit (control_bitmap, block);
|
||||
}
|
||||
|
||||
|
||||
/* have we seen this block somewhere in the tree before? */
|
||||
static int did_we_meet_it (unsigned long block)
|
||||
{
|
||||
return reiserfs_bitmap_test_bit (control_bitmap, block);
|
||||
}
|
||||
|
||||
|
||||
static void init_control_bitmap (reiserfs_filsys_t fs)
|
||||
{
|
||||
int i;
|
||||
|
||||
control_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
|
||||
if (!control_bitmap)
|
||||
die ("init_control_bitmap: could not create control bitmap");
|
||||
|
||||
/* skipped and super block */
|
||||
for (i = 0; i <= SB_BUFFER_WITH_SB (fs)->b_blocknr; i ++)
|
||||
we_met_it (i);
|
||||
|
||||
/* bitmaps */
|
||||
for (i = 0; i < SB_BMAP_NR (fs); i ++)
|
||||
we_met_it (SB_AP_BITMAP (fs)[i]->b_blocknr);
|
||||
|
||||
for (i = 0; i < rs_journal_size (fs->s_rs) + 1; i ++)
|
||||
we_met_it (i + SB_JOURNAL_BLOCK (fs));
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void show_diff (int n, char * disk, char * control, int bits)
|
||||
{
|
||||
int i;
|
||||
int last_diff = 0;
|
||||
int from, num;
|
||||
|
||||
fsck_log ("bitmap %d does not match to the correct one\n", n);
|
||||
|
||||
from = 0;
|
||||
num = 0;
|
||||
for (i = 0; i < bits; i ++) {
|
||||
if (test_bit (i, disk) && !test_bit (i, control)) {
|
||||
if (last_diff == 1) {
|
||||
num ++;
|
||||
continue;
|
||||
} else if (last_diff == 2) {
|
||||
fsck_log ("Block [%d-%d] free in disk bitmap, used in control\n", from, from + num - 1);
|
||||
}
|
||||
num = 1;
|
||||
from = n * bits + i;
|
||||
last_diff = 1;
|
||||
continue;
|
||||
}
|
||||
if (!test_bit (i, disk) && test_bit (i, control)) {
|
||||
if (last_diff == 2) {
|
||||
num ++;
|
||||
continue;
|
||||
} else if (last_diff == 1) {
|
||||
fsck_log ("Block [%d-%d] used in disk bitmap, free in control\n", from, from + num - 1);
|
||||
}
|
||||
num = 1;
|
||||
from = n * bits + i;
|
||||
last_diff = 2;
|
||||
continue;
|
||||
}
|
||||
/* the same bits */
|
||||
if (last_diff == 1)
|
||||
fsck_log ("Block [%d-%d] used in disk bitmap, free in control\n", from, from + num - 1);
|
||||
if (last_diff == 2)
|
||||
fsck_log ("Block [%d-%d] free in disk bitmap, used in control\n", from, from + num - 1);
|
||||
|
||||
num = 0;
|
||||
from = 0;
|
||||
last_diff = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* if we managed to complete tree scanning and if control bitmap and/or proper
|
||||
amount of free blocks mismatch with bitmap on disk and super block's
|
||||
s_free_blocks - we can fix that */
|
||||
static void compare_bitmaps (reiserfs_filsys_t fs)
|
||||
{
|
||||
int diff;
|
||||
|
||||
if (tree_scanning_failed) {
|
||||
fsck_progress ("Could not scan whole tree. "
|
||||
"--rebuild-tree is required\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fsck_progress ("Comparing bitmaps..");
|
||||
|
||||
/* check free block counter */
|
||||
if (SB_FREE_BLOCKS (fs) != reiserfs_bitmap_zeros (control_bitmap)) {
|
||||
fsck_log ("free block count %lu mismatches with a correct one %lu. \n",
|
||||
SB_FREE_BLOCKS (fs), reiserfs_bitmap_zeros (control_bitmap));
|
||||
#if 0
|
||||
if (fsck_fix_fixable (fs)) {
|
||||
set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (control_bitmap));
|
||||
mark_buffer_dirty (fs->s_sbh);
|
||||
mark_filesystem_dirty (fs);
|
||||
fsck_log ("Fixed\n");
|
||||
} else {
|
||||
fsck_log ("Can be fixed by --fix-fixable\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
diff = reiserfs_bitmap_compare (fsck_disk_bitmap (fs), control_bitmap);
|
||||
if (diff) {
|
||||
fsck_log ("on-disk bitmap does not match to the correct one. %d bytes differ\n", diff);
|
||||
#if 0
|
||||
if (fsck_fix_fixable (fs)) {
|
||||
reiserfs_flush_bitmap (control_bitmap, fs);
|
||||
mark_filesystem_dirty (fs);
|
||||
fsck_log ("Fixed\n");
|
||||
} else {
|
||||
fsck_log ("Can be fixed by --fix-fixable\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
fsck_progress ("ok\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* is this block legal to be pointed to by some place of the tree? */
|
||||
static int bad_block_number (struct super_block * s, unsigned long block)
|
||||
{
|
||||
if (block >= SB_BLOCK_COUNT (s)) {
|
||||
/*reiserfs_warning ("block out of filesystem boundary found\n");*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (not_data_block (s, block)) {
|
||||
/*reiserfs_warning ("not data block (%lu) is used in the tree\n",
|
||||
block);*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_block_free (s, block)) {
|
||||
fsck_log ("block %lu is not marked as used in the disk bitmap\n", block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int got_already (struct super_block * s, unsigned long block)
|
||||
{
|
||||
if (0/*opt_fsck_mode == FSCK_FAST_REBUILD*/){
|
||||
if (is_block_used(block)){
|
||||
fsck_log ("block %lu is in tree already\n", block);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (did_we_meet_it (block)) {
|
||||
/*fsck_log ("block %lu is in tree already\n", block);*/
|
||||
return 1;
|
||||
}
|
||||
we_met_it (block);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 1 if some of fields in the block head of bh look bad */
|
||||
static int bad_block_head (struct buffer_head * bh)
|
||||
{
|
||||
struct block_head * blkh;
|
||||
|
||||
blkh = B_BLK_HEAD (bh);
|
||||
if (le16_to_cpu (blkh->blk_nr_item) > (bh->b_size - BLKH_SIZE) / IH_SIZE) {
|
||||
fsck_log ("block %lu has wrong blk_nr_items (%z)\n",
|
||||
bh->b_blocknr, bh);
|
||||
return 1;
|
||||
}
|
||||
if (le16_to_cpu (blkh->blk_free_space) >
|
||||
bh->b_size - BLKH_SIZE - IH_SIZE * le16_to_cpu (blkh->blk_nr_item)) {
|
||||
fsck_log ("block %lu has wrong blk_free_space %z\n",
|
||||
bh->b_blocknr, bh);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 1 if it does not look like reasonable stat data */
|
||||
static int bad_stat_data (struct buffer_head * bh, struct item_head * ih)
|
||||
{
|
||||
unsigned long objectid;
|
||||
int pos;
|
||||
|
||||
/*
|
||||
if (opt_fsck_mode == FSCK_FAST_REBUILD)
|
||||
return 0;
|
||||
*/
|
||||
objectid = le32_to_cpu (ih->ih_key.k_objectid);
|
||||
if (!is_objectid_used (fs, objectid)) {
|
||||
/* FIXME: this could be cured right here */
|
||||
fsck_log ("\nbad_stat_data: %lu is marked free, but used by an object %k\n",
|
||||
objectid, &ih->ih_key);
|
||||
}
|
||||
|
||||
if (is_objectid_really_used (proper_id_map (fs), objectid, &pos)) {
|
||||
fsck_log ("\nbad_stat_data: %lu is shared by at least two files\n",
|
||||
objectid);
|
||||
return 0;
|
||||
}
|
||||
mark_objectid_really_used (proper_id_map (fs), objectid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* it looks like we can check item length only */
|
||||
static int bad_direct_item (struct buffer_head * bh, struct item_head * ih)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* for each unformatted node pointer: make sure it points to data area and
|
||||
that it is not in the tree yet */
|
||||
static int bad_indirect_item (reiserfs_filsys_t fs, struct buffer_head * bh,
|
||||
struct item_head * ih)
|
||||
{
|
||||
int i;
|
||||
__u32 * ind = (__u32 *)B_I_PITEM (bh, ih);
|
||||
|
||||
if (ih_item_len (ih) % 4) {
|
||||
fsck_log ("bad_indirect_item: block %lu: item (%H) has bad length\n",
|
||||
bh->b_blocknr, ih);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < I_UNFM_NUM (ih); i ++) {
|
||||
__u32 unfm_ptr;
|
||||
|
||||
unfm_ptr = le32_to_cpu (ind [i]);
|
||||
if (!unfm_ptr)
|
||||
continue;
|
||||
|
||||
/* check unformatted node pointer and mark it used in the
|
||||
control bitmap */
|
||||
if (bad_block_number (fs, unfm_ptr)) {
|
||||
fsck_log ("bad_indirect_item: block %lu: item %H has bad pointer %d: %lu",
|
||||
bh->b_blocknr, ih, i, unfm_ptr);
|
||||
if (fsck_fix_fixable (fs)) {
|
||||
fsck_log (" - fixed");
|
||||
ind [i] = 0;
|
||||
mark_buffer_dirty (bh);
|
||||
}
|
||||
fsck_log ("\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (got_already (fs, unfm_ptr)) {
|
||||
fsck_log ("bad_indirect_item: block %lu: item %H has a pointer %d "
|
||||
"to the block %lu which is in tree already",
|
||||
bh->b_blocknr, ih, i, unfm_ptr);
|
||||
if (fsck_fix_fixable (fs)) {
|
||||
fsck_log (" - fixed");
|
||||
ind [i] = 0;
|
||||
mark_buffer_dirty (bh);
|
||||
}
|
||||
fsck_log ("\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* delete this check for 3.6 */
|
||||
if (ih_free_space (ih) > fs->s_blocksize - 1)
|
||||
fsck_log ("bad_indirect_item: %H has wrong ih_free_space\n", ih);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: this was is_bad_directory from pass0.c */
|
||||
static int bad_directory_item (struct buffer_head * bh, struct item_head * ih)
|
||||
{
|
||||
int i;
|
||||
char * name;
|
||||
int namelen;
|
||||
struct reiserfs_de_head * deh = B_I_DEH (bh, ih);
|
||||
int min_entry_size = 1;/* we have no way to understand whether the
|
||||
filesystem were created in 3.6 format or
|
||||
converted to it. So, we assume that minimal name
|
||||
length is 1 */
|
||||
__u16 state;
|
||||
|
||||
|
||||
/* make sure item looks like a directory */
|
||||
if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih))
|
||||
/* entry count can not be that big */
|
||||
return 1;
|
||||
|
||||
if (deh[ih_entry_count (ih) - 1].deh_location != DEH_SIZE * ih_entry_count (ih))
|
||||
/* last entry should start right after array of dir entry headers */
|
||||
return 1;
|
||||
|
||||
/* check name hashing */
|
||||
for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
|
||||
namelen = name_length (ih, deh, i);
|
||||
name = name_in_entry (deh, i);
|
||||
if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
deh = B_I_DEH (bh, ih);
|
||||
state = 0;
|
||||
set_bit (DEH_Visible, &state);
|
||||
/* ok, items looks like a directory */
|
||||
for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
|
||||
if (deh_state (deh) != state) {
|
||||
fsck_log ("bad_directory_item: block %lu: item %H has entry "
|
||||
"\"%.*s\" with wrong deh_state %o",
|
||||
bh->b_blocknr, ih, name_length (ih, deh, i),
|
||||
name_in_entry (deh, i), deh_state (deh));
|
||||
if (fsck_fix_fixable (fs)) {
|
||||
deh->deh_state = 0;
|
||||
mark_de_visible (deh);
|
||||
mark_buffer_dirty (bh);
|
||||
fsck_log (" - fixed");
|
||||
}
|
||||
fsck_log ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int bad_item (struct super_block * s, struct buffer_head * bh, int i)
|
||||
{
|
||||
struct item_head * ih;
|
||||
|
||||
ih = B_N_PITEM_HEAD (bh, i);
|
||||
if (is_stat_data_ih (ih))
|
||||
return bad_stat_data (bh, ih);
|
||||
|
||||
if (is_direct_ih (ih))
|
||||
return bad_direct_item (bh, ih);
|
||||
|
||||
if (is_indirect_ih(ih))
|
||||
return bad_indirect_item (s, bh, ih);
|
||||
|
||||
return bad_directory_item (bh, ih);
|
||||
}
|
||||
|
||||
|
||||
/* 1 if i-th and (i-1)-th items can not be neighbors in a leaf */
|
||||
int bad_pair (struct super_block * s, struct buffer_head * bh, int i)
|
||||
{
|
||||
struct item_head * ih;
|
||||
|
||||
ih = B_N_PITEM_HEAD (bh, i);
|
||||
|
||||
|
||||
if (comp_keys (&((ih - 1)->ih_key), &ih->ih_key) != -1)
|
||||
return 1;
|
||||
|
||||
if (is_stat_data_ih (ih))
|
||||
/* left item must be of another object */
|
||||
if (comp_short_keys (&((ih - 1)->ih_key), &ih->ih_key) != -1)
|
||||
return 1;
|
||||
|
||||
if (is_direct_ih(ih)) {
|
||||
/* left item must be indirect or stat data item of the same
|
||||
file */
|
||||
if (not_of_one_file (&((ih - 1)->ih_key), &ih->ih_key))
|
||||
return 1;
|
||||
|
||||
if (!((is_stat_data_ih (ih - 1) && get_offset (&ih->ih_key) == 1) ||
|
||||
(is_indirect_ih (ih - 1) &&
|
||||
get_offset (&(ih - 1)->ih_key) + get_bytes_number (ih-1, bh->b_size) == //get_bytes_number (bh, ih - 1, 0, CHECK_FREE_BYTES) ==
|
||||
get_offset (&ih->ih_key))))
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
if (is_indirect_ih (ih) || is_direntry_ih (ih)) {
|
||||
/* left item must be stat data of the same object */
|
||||
if (not_of_one_file (&((ih - 1)->ih_key), &ih->ih_key))
|
||||
return 1;
|
||||
|
||||
if (!is_stat_data_ih (ih - 1))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bad_leaf_2 (struct super_block * s, struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bad_block_head (bh))
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < B_NR_ITEMS (bh); i ++) {
|
||||
if (i && bad_pair (s, bh, i)) {
|
||||
fsck_log ("bad_leaf_2: block %lu has wrong order of items\n",
|
||||
bh->b_blocknr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 1 if block head or any of items is bad */
|
||||
static int bad_leaf (struct super_block * s, struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bad_block_head (bh))
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < B_NR_ITEMS (bh); i ++) {
|
||||
if (bad_item (s, bh, i)) {
|
||||
fsck_log ("bad_leaf: block %lu has invalid item %d: %H\n",
|
||||
bh->b_blocknr, i, B_N_PITEM_HEAD (bh, i));
|
||||
}
|
||||
|
||||
if (i && bad_pair (s, bh, i)) {
|
||||
fsck_log ("bad_leaf: block %lu has wrong order of items\n",
|
||||
bh->b_blocknr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 1 if bh does not look like internal node */
|
||||
static int bad_internal (struct super_block * s, struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= B_NR_ITEMS (bh); i ++)
|
||||
{
|
||||
if (i != B_NR_ITEMS (bh) && i != B_NR_ITEMS (bh) - 1)
|
||||
if (comp_keys (B_N_PDELIM_KEY (bh, i), B_N_PDELIM_KEY (bh, i + 1)) != -1)
|
||||
return 1;
|
||||
if (bad_block_number(s, child_block_number(bh,i))){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* h == 0 for root level. block head's level == 1 for leaf level */
|
||||
static inline int h_to_level (struct super_block * s, int h)
|
||||
{
|
||||
return SB_TREE_HEIGHT (s) - h - 1;
|
||||
}
|
||||
|
||||
|
||||
/* bh must be formatted node. blk_level must be tree_height - h + 1 */
|
||||
static int bad_node (struct super_block * s, struct buffer_head ** path,
|
||||
int h)
|
||||
{
|
||||
struct buffer_head ** pbh = &path[h];
|
||||
|
||||
if (B_LEVEL (*pbh) != h_to_level (s, h)) {
|
||||
fsck_log ("node (%lu) with wrong level (%d) found in the tree (should be %d)\n",
|
||||
(*pbh)->b_blocknr, B_LEVEL (*pbh), h_to_level (s, h));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bad_block_number (s, (*pbh)->b_blocknr)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (got_already (s, (*pbh)->b_blocknr))
|
||||
return 1;
|
||||
|
||||
if (is_leaf_node (*pbh))
|
||||
return bad_leaf (s, *pbh);
|
||||
|
||||
return bad_internal (s, *pbh);
|
||||
}
|
||||
|
||||
|
||||
/* internal node bh must point to block */
|
||||
static int get_pos (struct buffer_head * bh, unsigned long block)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= B_NR_ITEMS (bh); i ++) {
|
||||
if (child_block_number (bh, i) == block)
|
||||
return i;
|
||||
}
|
||||
die ("get_pos: position for block %lu not found", block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* path[h] - leaf node */
|
||||
static struct key * lkey (struct buffer_head ** path, int h)
|
||||
{
|
||||
int pos;
|
||||
|
||||
while (h > 0) {
|
||||
pos = get_pos (path[h - 1], path[h]->b_blocknr);
|
||||
if (pos)
|
||||
return B_N_PDELIM_KEY(path[h - 1], pos - 1);
|
||||
h --;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* path[h] - leaf node */
|
||||
static struct key * rkey (struct buffer_head ** path, int h)
|
||||
{
|
||||
int pos;
|
||||
|
||||
while (h > 0) {
|
||||
pos = get_pos (path[h - 1], path[h]->b_blocknr);
|
||||
if (pos != B_NR_ITEMS (path[h - 1]))
|
||||
return B_N_PDELIM_KEY (path[h - 1], pos);
|
||||
h --;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* are all delimiting keys correct */
|
||||
static int bad_path (struct super_block * s, struct buffer_head ** path, int h1)
|
||||
{
|
||||
int h = 0;
|
||||
struct key * dk;
|
||||
|
||||
while (path[h])
|
||||
h ++;
|
||||
|
||||
h--;
|
||||
|
||||
// path[h] is leaf
|
||||
if (h != h1)
|
||||
die ("bad_path: wrong path");
|
||||
|
||||
dk = lkey (path, h);
|
||||
if (dk && comp_keys (dk, B_N_PKEY (path[h], 0)))
|
||||
// left delimiting key must be equal to the key of 0-th item in the
|
||||
// node
|
||||
return 1;
|
||||
|
||||
dk = rkey (path, h);
|
||||
if (dk && comp_keys (dk, B_N_PKEY (path[h], node_item_number (path[h]) - 1)) != 1)
|
||||
// right delimiting key must be bigger than the key of the last item
|
||||
// in the node
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* pass the S+ tree of filesystem */
|
||||
void check_fs_tree (struct super_block * s)
|
||||
{
|
||||
init_control_bitmap (s);
|
||||
|
||||
proper_id_map (s) = init_id_map ();
|
||||
|
||||
fsck_progress ("Checking S+tree..");
|
||||
|
||||
pass_through_tree (s, bad_node, bad_path);
|
||||
|
||||
/* S+ tree is correct (including all objects have correct
|
||||
sequences of items) */
|
||||
fsck_progress ("ok\n");
|
||||
|
||||
/* compare created bitmap with the original */
|
||||
compare_bitmaps (s);
|
||||
|
||||
free_id_map (&proper_id_map (s));
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
void remove_internal_pointer(struct super_block * s, struct buffer_head ** path)
|
||||
{
|
||||
int h = 0;
|
||||
int pos, items;
|
||||
__u32 block;
|
||||
|
||||
|
||||
while (path[h])
|
||||
h ++;
|
||||
|
||||
h--;
|
||||
block = path[h]->b_blocknr;
|
||||
printf("\nremove pointer to (%d) block", block);
|
||||
brelse(path[h]);
|
||||
path[h] = 0;
|
||||
h--;
|
||||
while (h>=0)
|
||||
{
|
||||
if (B_NR_ITEMS(path[h]) <= 1)
|
||||
{
|
||||
block = path[h]->b_blocknr;
|
||||
brelse(path[h]);
|
||||
path[h] = 0;
|
||||
mark_block_free(block);
|
||||
/*unmark_block_formatted(block);*/
|
||||
used_blocks++;
|
||||
h --;
|
||||
continue;
|
||||
}
|
||||
pos = get_pos (path[h], block);
|
||||
if (pos)
|
||||
{
|
||||
memmove (B_N_CHILD(path[h],pos), B_N_CHILD(path[h],pos+1),
|
||||
s->s_blocksize - BLKH_SIZE - B_NR_ITEMS(path[h])*KEY_SIZE - DC_SIZE*(pos+1));
|
||||
memmove(B_N_PDELIM_KEY(path[h],pos-1), B_N_PDELIM_KEY(path[h],pos),
|
||||
s->s_blocksize - BLKH_SIZE - (pos)*KEY_SIZE);
|
||||
}else{
|
||||
__u32 move_block = path[h]->b_blocknr;
|
||||
int move_to_pos;
|
||||
int height = h;
|
||||
|
||||
while(--height >= 0)
|
||||
{
|
||||
move_to_pos = get_pos (path[height], move_block);
|
||||
if (move_to_pos == 0){
|
||||
move_block = path[height]->b_blocknr;
|
||||
continue;
|
||||
}
|
||||
*B_N_PDELIM_KEY(path[height], move_to_pos-1) = *B_N_PDELIM_KEY(path[h], 0);
|
||||
break;
|
||||
}
|
||||
|
||||
memmove (B_N_CHILD(path[h], 0), B_N_CHILD(path[h], 1),
|
||||
s->s_blocksize - BLKH_SIZE - B_NR_ITEMS(path[h])*KEY_SIZE - DC_SIZE);
|
||||
memmove(B_N_PDELIM_KEY(path[h], 0), B_N_PDELIM_KEY(path[h], 1),
|
||||
s->s_blocksize - BLKH_SIZE - KEY_SIZE);
|
||||
}
|
||||
set_node_item_number(path[h], node_item_number(path[h]) - 1);
|
||||
mark_buffer_dirty(path[h], 1);
|
||||
break;
|
||||
}
|
||||
if (h == -1)
|
||||
{
|
||||
SB_DISK_SUPER_BLOCK(s)->s_root_block = ~0;
|
||||
SB_DISK_SUPER_BLOCK(s)->s_tree_height = ~0;
|
||||
mark_buffer_dirty(SB_BUFFER_WITH_SB(s), 1);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_buffer(struct super_block * s, struct buffer_head * bh)
|
||||
{
|
||||
int i, j;
|
||||
struct item_head * ih;
|
||||
|
||||
if (is_leaf_node (bh))
|
||||
{
|
||||
for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++)
|
||||
{
|
||||
if (is_indirect_ih(ih))
|
||||
for (j = 0; j < I_UNFM_NUM (ih); j ++)
|
||||
if (B_I_POS_UNFM_POINTER(bh,ih,j)){
|
||||
/*mark_block_unformatted(le32_to_cpu(B_I_POS_UNFM_POINTER(bh,ih,j)));*/
|
||||
mark_block_used(le32_to_cpu(B_I_POS_UNFM_POINTER(bh,ih,j)));
|
||||
used_blocks++;
|
||||
}
|
||||
if (is_stat_data_ih (ih)) {
|
||||
/*add_event (STAT_DATA_ITEMS);*/
|
||||
if (ih_key_format(ih) == KEY_FORMAT_1)
|
||||
((struct stat_data_v1 *)B_I_PITEM(bh,ih))->sd_nlink = 0;
|
||||
else
|
||||
((struct stat_data *)B_I_PITEM(bh,ih))->sd_nlink = 0;
|
||||
mark_buffer_dirty(bh, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
mark_block_used(bh->b_blocknr);
|
||||
// we_met_it(s, bh->b_blocknr);
|
||||
used_blocks++;
|
||||
}
|
||||
|
||||
/* bh must be formatted node. blk_level must be tree_height - h + 1 */
|
||||
static int handle_node (struct super_block * s, struct buffer_head ** path, int h)
|
||||
{
|
||||
if (bad_node(s, path, h)){
|
||||
remove_internal_pointer(s, path);
|
||||
return 1;
|
||||
}
|
||||
handle_buffer(s, path[h]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* are all delimiting keys correct */
|
||||
static int handle_path (struct super_block * s, struct buffer_head ** path, int h)
|
||||
{
|
||||
if (bad_path(s, path, h)){
|
||||
remove_internal_pointer(s, path);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//return 1 to run rebuild tree from scratch
|
||||
void check_internal_structure(struct super_block * s)
|
||||
{
|
||||
/* control bitmap is used to keep all blocks we should not put into tree again */
|
||||
/* used bitmap is used to keep all inserted blocks. The same as control bitmap plus unfm blocks */
|
||||
// init_control_bitmap(s);
|
||||
|
||||
printf ("Checking S+tree..");
|
||||
|
||||
pass_through_tree (s, handle_node, handle_path);
|
||||
|
||||
// compare_bitmaps(s);
|
||||
printf ("ok\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int check_sb (struct super_block * s)
|
||||
{
|
||||
int format_sb = 0;
|
||||
int problem = 0;
|
||||
struct reiserfs_super_block * rs;
|
||||
__u32 block_count;
|
||||
|
||||
rs = s->s_rs;
|
||||
// in (REISERFS_DISK_OFFSET_IN_BYTES / 4096) block
|
||||
if (is_reiser2fs_magic_string (rs) &&
|
||||
SB_JOURNAL_BLOCK(s) == get_journal_start_must (rs_blocksize (rs)))
|
||||
{
|
||||
// 3.6 or >=3.5.22
|
||||
printf("\t 3.6.x format SB found\n");
|
||||
format_sb = 1;
|
||||
goto good_format;
|
||||
}
|
||||
|
||||
if (is_reiserfs_magic_string (rs) &&
|
||||
SB_JOURNAL_BLOCK(s) == get_journal_start_must (rs_blocksize (rs)))
|
||||
{
|
||||
// >3.5.9(10) and <=3.5.21
|
||||
printf("\t>=3.5.9 format SB found\n");
|
||||
format_sb = 2;
|
||||
goto good_format;
|
||||
}
|
||||
|
||||
// in 2 block
|
||||
if (is_reiser2fs_magic_string (rs) &&
|
||||
SB_JOURNAL_BLOCK(s) == get_journal_old_start_must (rs))
|
||||
{
|
||||
// <3.5.9(10) converted to new format
|
||||
printf("\t< 3.5.9(10) SB converted to new format found \n");
|
||||
format_sb = 3;
|
||||
goto good_format;
|
||||
}
|
||||
|
||||
if (is_reiserfs_magic_string (rs) &&
|
||||
SB_JOURNAL_BLOCK(s) == get_journal_old_start_must (rs))
|
||||
{
|
||||
// <3.5.9(10)
|
||||
printf("\t< 3.5.9(10) format SB found\n");
|
||||
format_sb = 4;
|
||||
goto good_format;
|
||||
}
|
||||
else
|
||||
die("check SB: wrong SB format found\n");
|
||||
|
||||
good_format:
|
||||
|
||||
printf("\n\t%d-%d\n", SB_BLOCK_COUNT (s), SB_FREE_BLOCKS (s));
|
||||
if (s->s_blocksize != 4096) {
|
||||
fsck_log("check SB: specified block size (%d) is not correct must be 4096\n", s->s_blocksize);
|
||||
problem++;
|
||||
}
|
||||
|
||||
//for 4096 blocksize only
|
||||
if ((rs_tree_height(rs) < DISK_LEAF_NODE_LEVEL) || (rs_tree_height(rs) > MAX_HEIGHT)){
|
||||
fsck_log ("check SB: wrong tree height (%d)\n", rs_tree_height(rs));
|
||||
problem++;
|
||||
}
|
||||
|
||||
block_count = count_blocks ("", s->s_blocksize, s->s_dev);
|
||||
|
||||
if (SB_BLOCK_COUNT(s) > block_count){
|
||||
fsck_log ("check SB: specified block number (%d) is too high\n", SB_BLOCK_COUNT(s));
|
||||
problem++;
|
||||
}
|
||||
|
||||
if ((rs_root_block(rs) >= block_count) || (rs_root_block(rs) < 0)){
|
||||
fsck_log ("check SB: specified root block number (%d) is too high\n", rs_root_block(rs));
|
||||
problem++;
|
||||
}
|
||||
|
||||
if (SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)){
|
||||
fsck_log ("check SB: specified free block number (%d) is too high\n", SB_FREE_BLOCKS(s));
|
||||
problem++;
|
||||
}
|
||||
|
||||
if (SB_REISERFS_STATE(s) != REISERFS_VALID_FS){
|
||||
fsck_log ("check SB: wrong (%d) state\n", SB_REISERFS_STATE(s));
|
||||
problem++;
|
||||
}
|
||||
|
||||
if ( SB_BMAP_NR(s) != SB_BLOCK_COUNT(s) / (s->s_blocksize * 8) +
|
||||
((SB_BLOCK_COUNT(s) % (s->s_blocksize * 8)) ? 1 : 0)){
|
||||
fsck_log("check SB: wrong bitmap number (%d)\n", SB_BMAP_NR(s));
|
||||
problem++;
|
||||
}
|
||||
|
||||
if (SB_VERSION(s) == REISERFS_VERSION_2 || SB_VERSION(s) == REISERFS_VERSION_1)
|
||||
{
|
||||
if (!(SB_VERSION(s) == REISERFS_VERSION_2 && (format_sb == 1 || format_sb == 3)) &&
|
||||
!(SB_VERSION(s) == REISERFS_VERSION_1 && (format_sb == 2 || format_sb == 4))){
|
||||
fsck_log("check SB: wrong SB version == %d, format == %d\n", SB_VERSION(s), format_sb);
|
||||
problem++;
|
||||
}
|
||||
}
|
||||
else{
|
||||
fsck_log ("check SB: wrong SB version (%d)\n", SB_VERSION(s));
|
||||
problem++;
|
||||
}
|
||||
|
||||
if (SB_VERSION(s) == REISERFS_VERSION_2 &&
|
||||
(rs_hash (rs) < 1 || rs_hash (rs) > 3)) {
|
||||
/* FIXME: */
|
||||
fsck_log("check SB: wrong hash (%d)\n", rs_hash (rs));
|
||||
problem++;
|
||||
}
|
||||
|
||||
|
||||
if ((SB_VERSION(s) == REISERFS_VERSION_2) ?
|
||||
(rs_objectid_map_max_size (rs) != ((s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2)) :
|
||||
(rs_objectid_map_max_size (rs) != ((s->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2))) {
|
||||
fsck_log("check SB: objectid map corrupted max_size == %d\n", rs_objectid_map_max_size (rs));
|
||||
problem++;
|
||||
}
|
||||
|
||||
if (rs_objectid_map_size (rs) < 2 ||
|
||||
rs_objectid_map_size (rs) > rs_objectid_map_max_size (rs)) {
|
||||
fsck_log("check SB: objectid map corrupted cur_size == %d\n", rs_objectid_map_size (rs));
|
||||
problem++;
|
||||
}
|
||||
|
||||
if (rs_journal_size(rs) != JOURNAL_BLOCK_COUNT){
|
||||
fsck_log("check SB: specified journal size (%d) is not correct must be %d\n",
|
||||
rs_journal_size(rs), JOURNAL_BLOCK_COUNT);
|
||||
problem++;
|
||||
}
|
||||
|
||||
if (!problem) {
|
||||
fsck_progress ("\t No problem found\n");
|
||||
} else if (fsck_log_file (fs) != stderr)
|
||||
fsck_progress ("Look for super block corruptions in the log file\n");
|
||||
|
||||
return format_sb;
|
||||
}
|
||||
|
||||
|
||||
+425
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright 1996-2001 Hans Reiser
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <asm/types.h>
|
||||
#include <sys/vfs.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <asm/types.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "io.h"
|
||||
#include "misc.h"
|
||||
#include "reiserfs_lib.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/* main.c */
|
||||
extern reiserfs_filsys_t fs;
|
||||
extern reiserfs_bitmap_t uninsertable_leaf_bitmap;
|
||||
int main (int argc, char * argv []);
|
||||
|
||||
|
||||
/*
|
||||
* modes
|
||||
*/
|
||||
#define DO_NOTHING 0 /* -a specified */
|
||||
#define FSCK_CHECK 1
|
||||
#define FSCK_SB 2
|
||||
#define FSCK_REBUILD 3
|
||||
|
||||
/* temporary */
|
||||
#define FSCK_ZERO_FILES 4
|
||||
#define DO_TEST 5
|
||||
|
||||
/*
|
||||
#define FSCK_FAST_REBUILD 4
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* options
|
||||
*/
|
||||
#define OPT_INTERACTIVE 1
|
||||
#define OPT_FIX_FIXABLE 2 /* not default yet */
|
||||
#define OPT_FIX_NON_CRITICAL 4 /* not default yet */
|
||||
#define OPT_QUIET 8
|
||||
#define OPT_SAVE_EXTERN_BITMAP 16
|
||||
#define OPT_SILENT 32
|
||||
|
||||
extern int g_blocks_to_read;
|
||||
|
||||
/* pass 0 and 1 read the device NR_TO_READ block in time */
|
||||
#define NR_TO_READ 8
|
||||
|
||||
/* pass0.c */
|
||||
int pass_0 (reiserfs_filsys_t);
|
||||
int are_there_used_leaves (unsigned long from, int count);
|
||||
int is_used_leaf (unsigned long block);
|
||||
int how_many_leaves_were_there (void);
|
||||
int is_bad_unformatted (unsigned long block);
|
||||
int is_good_unformatted (unsigned long block);
|
||||
void mark_good_unformatted (unsigned long block);
|
||||
int are_there_allocable_blocks (int amout_needed);
|
||||
unsigned long alloc_block (void);
|
||||
void make_allocable (unsigned long block);
|
||||
void register_uninsertable (unsigned long block);
|
||||
unsigned long how_many_uninsertables_were_there (void);
|
||||
void register_saved_item (void);
|
||||
unsigned long how_many_items_were_saved (void);
|
||||
int still_bad_unfm_ptr_1 (unsigned long block);
|
||||
int still_bad_unfm_ptr_2 (unsigned long block);
|
||||
void make_alloc_bitmap (struct super_block * s);
|
||||
|
||||
#define __is_marked(name,block) reiserfs_bitmap_test_bit (name##_bitmap, block)
|
||||
#define __mark(name,block) reiserfs_bitmap_set_bit (name##_bitmap, block)
|
||||
#define __unmark(name,block) reiserfs_bitmap_clear_bit (name##_bitmap, block)
|
||||
|
||||
/* unformatted in tree */
|
||||
extern reiserfs_bitmap_t bad_unfm_in_tree_once_bitmap;
|
||||
#define is_bad_unfm_in_tree_once(block) __is_marked (bad_unfm_in_tree_once, block)
|
||||
#define mark_bad_unfm_in_tree_once(block) __mark (bad_unfm_in_tree_once, block)
|
||||
|
||||
|
||||
|
||||
/* pass1.c */
|
||||
void pass_1_pass_2_build_the_tree (void);
|
||||
struct buffer_head * make_buffer (int dev, int blocknr, int size, char * data);
|
||||
void build_the_tree (void);
|
||||
extern int g_unaccessed_items;
|
||||
int is_item_reachable (struct item_head * ih);
|
||||
void mark_item_reachable (struct item_head * ih, struct buffer_head * bh);
|
||||
void mark_item_unreachable (struct item_head * ih);
|
||||
void rebuild_sb (reiserfs_filsys_t fs);
|
||||
struct si * remove_saved_item (struct si * si);
|
||||
|
||||
|
||||
/* pass2.c */
|
||||
void insert_item_separately (struct item_head * ih, char * item,
|
||||
int was_in_tree);
|
||||
struct si * save_and_delete_file_item (struct si * si, struct path * path);
|
||||
void take_bad_blocks_put_into_tree (void);
|
||||
void rewrite_object (struct item_head * ih, int do_remap);
|
||||
void pass_2_take_bad_blocks_put_into_tree (void);
|
||||
/*int is_remapped (struct item_head * ih);*/
|
||||
void link_relocated_files (void);
|
||||
void relocate_file (struct item_head * ih, int change_ih);
|
||||
void relocate_dir (struct item_head * ih, int change_ih);
|
||||
__u32 objectid_for_relocation (struct key * key);
|
||||
|
||||
/* file.c */
|
||||
struct si {
|
||||
struct item_head si_ih;
|
||||
char * si_dnm_data;
|
||||
struct si * si_next;
|
||||
__u32 si_blocknr;
|
||||
|
||||
// changed by XB;
|
||||
struct si * last_known;
|
||||
};
|
||||
void put_saved_items_into_tree (struct si *);
|
||||
int reiserfsck_file_write (struct item_head * ih, char * item, int);
|
||||
int are_file_items_correct (struct key * key, int key_version, __u64 * size, __u32 * blocks, int mark_passed_items,
|
||||
int symlink, __u64 symlink_size);
|
||||
|
||||
|
||||
/* semantic.c */
|
||||
extern struct key root_dir_key;
|
||||
extern struct key parent_root_dir_key;
|
||||
extern struct key lost_found_dir_key;
|
||||
void pass_3_semantic (void);
|
||||
void semantic_check (void);
|
||||
int check_semantic_tree (struct key * key, struct key * parent, int is_dot_dot, int lost_found, struct item_head * new_ih);
|
||||
void zero_nlink (struct item_head * ih, void * sd);
|
||||
int not_a_directory (void * sd);
|
||||
int is_dot_dot (char * name, int namelen);
|
||||
int is_dot (char * name, int namelen);
|
||||
void create_dir_sd (reiserfs_filsys_t fs,
|
||||
struct path * path, struct key * key);
|
||||
int rebuild_check_regular_file (struct path * path, void * sd,
|
||||
struct item_head * new_ih);
|
||||
int rebuild_semantic_pass (struct key * key, struct key * parent, int is_dot_dot,
|
||||
struct item_head * new_ih);
|
||||
|
||||
/* access to stat data fields */
|
||||
void get_set_sd_field (int field, struct item_head * ih, void * sd,
|
||||
void * value, int set);
|
||||
#define GET_SD_MODE 0
|
||||
#define GET_SD_SIZE 1
|
||||
#define GET_SD_NLINK 2
|
||||
#define GET_SD_BLOCKS 3
|
||||
#define GET_SD_FIRST_DIRECT_BYTE 4
|
||||
|
||||
#define get_sd_mode(ih,sd,pmode) get_set_sd_field (GET_SD_MODE, ih, sd, pmode, 0/*get*/)
|
||||
#define set_sd_mode(ih,sd,pmode) get_set_sd_field (GET_SD_MODE, ih, sd, pmode, 1/*set*/)
|
||||
|
||||
#define get_sd_size(ih,sd,psize) get_set_sd_field (GET_SD_SIZE, ih, sd, psize, 0/*get*/)
|
||||
#define set_sd_size(ih,sd,psize) get_set_sd_field (GET_SD_SIZE, ih, sd, psize, 1/*set*/)
|
||||
|
||||
#define get_sd_blocks(ih,sd,pblocks) get_set_sd_field (GET_SD_BLOCKS, ih, sd, pblocks, 0/*get*/)
|
||||
#define set_sd_blocks(ih,sd,pblocks) get_set_sd_field (GET_SD_BLOCKS, ih, sd, pblocks, 1/*set*/)
|
||||
|
||||
#define get_sd_nlink(ih,sd,pnlink) get_set_sd_field (GET_SD_NLINK, ih, sd, pnlink, 0/*get*/)
|
||||
#define set_sd_nlink(ih,sd,pnlink) get_set_sd_field (GET_SD_NLINK, ih, sd, pnlink, 1/*set*/)
|
||||
|
||||
#define get_sd_first_direct_byte(ih,sd,pfdb) get_set_sd_field (GET_SD_FIRST_DIRECT_BYTE, ih, sd, pfdb, 0/*get*/)
|
||||
#define set_sd_first_direct_byte(ih,sd,pfdb) get_set_sd_field (GET_SD_FIRST_DIRECT_BYTE, ih, sd, pfdb, 1/*set*/)
|
||||
|
||||
|
||||
|
||||
/* lost+found.c */
|
||||
void pass_3a_look_for_lost (reiserfs_filsys_t s);
|
||||
|
||||
|
||||
/* pass4.c */
|
||||
void get_next_key (struct path * path, int i, struct key * key);
|
||||
int pass_4_check_unaccessed_items (void);
|
||||
|
||||
|
||||
/* check.c */
|
||||
int is_leaf_bad (struct buffer_head * bh);
|
||||
int is_internal_bad (struct buffer_head * bh);
|
||||
int is_bad_item (struct buffer_head * bh, struct item_head *, char *);
|
||||
/*int check_file_system (void);*/
|
||||
void reiserfsck_check_pass1 (void);
|
||||
void reiserfsck_check_after_all (void);
|
||||
/*char * bad_name (char * name, int namelen);*/
|
||||
/* to test result of direcotry item recovering on pass 0 */
|
||||
int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize);
|
||||
|
||||
|
||||
//extern int bad_block_number (struct super_block * s, blocknr_t block);
|
||||
|
||||
/* check_tree.c */
|
||||
void check_fs_tree (struct super_block * s);
|
||||
int check_sb (struct super_block * s);
|
||||
int bad_pair (struct super_block * s, struct buffer_head * bh, int i);
|
||||
int bad_leaf_2 (struct super_block * s, struct buffer_head * bh);
|
||||
|
||||
|
||||
|
||||
/* ustree.c */
|
||||
void init_tb_struct (struct tree_balance * tb, struct super_block * s, struct path * path, int size);
|
||||
void reiserfsck_paste_into_item (struct path * path, const char * body, int size);
|
||||
void reiserfsck_insert_item (struct path * path, struct item_head * ih, const char * body);
|
||||
void reiserfsck_delete_item (struct path * path, int temporary);
|
||||
void reiserfsck_cut_from_item (struct path * path, int cut_size);
|
||||
typedef int (comp_function_t)(void * key1, void * key2);
|
||||
typedef int (comp3_function_t)(void * key1, void * key2, int version);
|
||||
/*typedef int (comp_function_t)(struct key * key1, struct key * key2);*/
|
||||
int ubin_search_id(__u32 * id, __u32 * base, __u32 number, __u32 * pos);
|
||||
int usearch_by_key (struct super_block * s, struct key * key, struct path * path);
|
||||
int usearch_by_key_3 (struct super_block * s, struct key * key, struct path * path, int * repeat, int stop_level,
|
||||
comp3_function_t comp_func, int version);
|
||||
int usearch_by_entry_key (struct super_block * s, struct key * key, struct path * path);
|
||||
int usearch_by_position (struct super_block * s, struct key * key, int version, struct path * path);
|
||||
struct key * uget_lkey (struct path * path);
|
||||
struct key * uget_rkey (struct path * path);
|
||||
|
||||
typedef int do_after_read_t (struct super_block * s, struct buffer_head **, int h);
|
||||
typedef int do_on_full_path_t (struct super_block * s, struct buffer_head **, int);
|
||||
void pass_through_tree (struct super_block *, do_after_read_t, do_on_full_path_t);
|
||||
|
||||
//int comp_keys_3 (void * key1, void * key2);
|
||||
//int comp_dir_entries (void * key1, void * key2);
|
||||
inline int ubin_search (void * key, void * base, int num, int width, __u32 *ppos, comp_function_t comp_func);
|
||||
|
||||
|
||||
/* bitmap.c */
|
||||
int reiserfsck_reiserfs_new_blocknrs (reiserfs_filsys_t fs,
|
||||
unsigned long * pblocknrs,
|
||||
unsigned long start_from,
|
||||
int amount_needed);
|
||||
int reiserfsck_reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block);
|
||||
struct buffer_head * reiserfsck_get_new_buffer (unsigned long start);
|
||||
int is_block_used (unsigned long block);
|
||||
int is_to_be_read (reiserfs_filsys_t fs, unsigned long block);
|
||||
void mark_block_used (unsigned long block);
|
||||
void mark_block_uninsertable (unsigned long block);
|
||||
int is_block_uninsertable (unsigned long block);
|
||||
|
||||
|
||||
/* objectid.c */
|
||||
int is_objectid_used (struct super_block * s, __u32 objectid);
|
||||
void mark_objectid_as_used (struct super_block * s, __u32 objectid);
|
||||
void mark_objectid_as_free (struct super_block * s, __u32 objectid);
|
||||
__u32 get_unused_objectid (struct super_block * s);
|
||||
|
||||
struct id_map * init_id_map (void);
|
||||
void free_id_map (struct id_map **);
|
||||
int is_objectid_really_used (struct id_map *, __u32 id, int * ppos);
|
||||
int mark_objectid_really_used (struct id_map *, __u32 id);
|
||||
void flush_objectid_map (struct id_map * map, reiserfs_filsys_t fs);
|
||||
void fetch_objectid_map (struct id_map * map, reiserfs_filsys_t fs);
|
||||
|
||||
|
||||
/* segments.c */
|
||||
struct overwritten_unfm_segment {
|
||||
int ous_begin;
|
||||
int ous_end;
|
||||
struct overwritten_unfm_segment * ous_next;
|
||||
};
|
||||
struct overwritten_unfm * look_for_overwritten_unfm (__u32);
|
||||
struct overwritten_unfm_segment * find_overwritten_unfm (unsigned long unfm, int length, struct overwritten_unfm_segment * segment_to_init);
|
||||
int get_unoverwritten_segment (struct overwritten_unfm_segment * list_head, struct overwritten_unfm_segment * unoverwritten_segment);
|
||||
void save_unfm_overwriting (unsigned long unfm, struct item_head * direct_ih);
|
||||
void free_overwritten_unfms (void);
|
||||
void mark_formatted_pointed_by_indirect (__u32);
|
||||
int is_formatted_pointed_by_indirect (__u32);
|
||||
|
||||
|
||||
|
||||
struct id_map {
|
||||
__u32 * m_begin; /* pointer to map area */
|
||||
unsigned long m_used_slots_count;
|
||||
int m_page_count; /* objectid map expands by one page at
|
||||
time. This is size of objectid map size in
|
||||
pages */
|
||||
unsigned long objectids_marked; /* number of objectids marked used
|
||||
in a map */
|
||||
};
|
||||
|
||||
|
||||
struct fsck_data {
|
||||
unsigned long all_blocks; /* super block's block count */
|
||||
|
||||
/* pass 0 */
|
||||
unsigned long analyzed; /* blocks marked used (not data not included) */
|
||||
unsigned long free; /* free blocks */
|
||||
unsigned long not_data; /* super block, bitmap, journal */
|
||||
unsigned long leaves; /* blocks looking like reiserfs leaves */
|
||||
unsigned long pointed_leaves;
|
||||
unsigned long pointed; /* by indirect items */
|
||||
unsigned long pointed_once;
|
||||
unsigned long pointed_more_than_once;
|
||||
unsigned long allocable;
|
||||
unsigned long wrong_pointers; /* out of range or pointers to free
|
||||
area */
|
||||
unsigned long leaves_corrected;
|
||||
unsigned long all_contents_removed;
|
||||
|
||||
/* pass 1, 2 */
|
||||
unsigned long read_leaves;
|
||||
unsigned long uninsertable_leaves;
|
||||
unsigned long inserted_leaves;
|
||||
unsigned long shared_objectids;
|
||||
unsigned long saved_on_pass1;
|
||||
unsigned long relocated;
|
||||
unsigned long rewritten;
|
||||
|
||||
/* stat of semantic pass */
|
||||
unsigned long regular_files;
|
||||
unsigned long broken_files; /* files having stat data and broken body */
|
||||
unsigned long directories;
|
||||
unsigned long symlinks;
|
||||
unsigned long others;
|
||||
unsigned long fixed_sizes;
|
||||
unsigned long deleted_entries; /* entries pointing to nowhere */
|
||||
unsigned long oid_sharing; /* files relocated due to objectid sharing */
|
||||
unsigned long oid_sharing_files_relocated; /* relocated files */
|
||||
unsigned long oid_sharing_dirs_relocated; /* relocated dirs */
|
||||
unsigned long lost_found;
|
||||
unsigned long empty_lost_dirs;
|
||||
unsigned long lost_found_dirs;
|
||||
unsigned long dir_recovered;
|
||||
unsigned long lost_found_files;
|
||||
|
||||
/* pass 4 */
|
||||
unsigned long deleted_items; /* items which were not touched by
|
||||
semantic pass */
|
||||
|
||||
/* objectid maps */
|
||||
struct id_map * proper_id_map;
|
||||
struct id_map * semantic_id_map; /* this objectid map is used to
|
||||
cure objectid sharing problem */
|
||||
|
||||
/* bitmaps */
|
||||
reiserfs_bitmap_t on_disk_bitmap;
|
||||
reiserfs_bitmap_t new_bitmap;
|
||||
reiserfs_bitmap_t allocable_bitmap;
|
||||
|
||||
char * bitmap_file_name;
|
||||
char * new_bitmap_file_name;
|
||||
|
||||
unsigned short mode;
|
||||
unsigned long options;
|
||||
|
||||
/* log file name and handle */
|
||||
char * log_file_name;
|
||||
FILE * log;
|
||||
|
||||
/* hash hits stat */
|
||||
int hash_amount;
|
||||
unsigned long * hash_hits;
|
||||
|
||||
#define USED_BLOCKS 1
|
||||
#define EXTERN_BITMAP 2
|
||||
#define ALL_BLOCKS 3
|
||||
int scan_area;
|
||||
int test;
|
||||
};
|
||||
|
||||
|
||||
#define stats(s) ((struct fsck_data *)((s)->s_vp))
|
||||
|
||||
#define proper_id_map(s) stats(s)->proper_id_map
|
||||
#define semantic_id_map(s) stats(s)->semantic_id_map
|
||||
|
||||
#define fsck_disk_bitmap(s) stats(s)->on_disk_bitmap
|
||||
#define fsck_new_bitmap(s) stats(s)->new_bitmap
|
||||
#define fsck_allocable_bitmap(s) stats(s)->allocable_bitmap
|
||||
|
||||
#define fsck_interactive(fs) (stats(fs)->options & OPT_INTERACTIVE)
|
||||
#define fsck_fix_fixable(fs) (stats(fs)->options & OPT_FIX_FIXABLE)
|
||||
|
||||
/* change unknown modes (corrupted) to mode of regular files, fix file
|
||||
sizes which are bigger than a real file size, relocate files with
|
||||
shared objectids (this slows fsck down (when there are too many
|
||||
files sharing the same objectid), it will also remove other names
|
||||
pointing to this file */
|
||||
#define fsck_fix_non_critical(fs) (stats(fs)->options & OPT_FIX_NON_CRITICAL)
|
||||
#define fsck_quiet(fs) (stats(fs)->options & OPT_QUIET)
|
||||
#define fsck_silent(fs) (stats(fs)->options & OPT_SILENT)
|
||||
|
||||
#define fsck_save_leaf_bitmap(fs) (stats(fs)->options & OPT_SAVE_EXTERN_BITMAP)
|
||||
|
||||
#define fsck_mode(fs) (stats(fs)->mode)
|
||||
#define fsck_log_file(fs) (stats(fs)->log)
|
||||
|
||||
|
||||
/* ?? */
|
||||
extern inline int change_version (int version)
|
||||
{
|
||||
return (version == 1)?0:1;
|
||||
}
|
||||
|
||||
|
||||
int fsck_user_confirmed (reiserfs_filsys_t fs, char * q, char * a, int default_answer);
|
||||
void stage_report (int, reiserfs_filsys_t fs);
|
||||
|
||||
/* journal.c */
|
||||
int reiserfs_replay_journal (struct super_block * s);
|
||||
|
||||
|
||||
#define fsck_log(fmt, list...) \
|
||||
{\
|
||||
if (!fsck_silent (fs))\
|
||||
reiserfs_warning (fsck_log_file (fs), fmt, ## list);\
|
||||
}
|
||||
|
||||
#define fsck_progress(fmt, list...) \
|
||||
{\
|
||||
reiserfs_warning (stderr, fmt, ## list);\
|
||||
fflush (stderr);\
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
|
||||
/*
|
||||
* Copyright 1996-1999 Hans Reiser
|
||||
*/
|
||||
#include "fsck.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
int fsck_user_confirmed (reiserfs_filsys_t fs, char * q, char * a, int default_answer)
|
||||
{
|
||||
if (!fsck_interactive (fs))
|
||||
return default_answer;
|
||||
|
||||
return user_confirmed (q, a);
|
||||
}
|
||||
|
||||
|
||||
void stage_report (int pass, reiserfs_filsys_t fs)
|
||||
{
|
||||
FILE * fp;
|
||||
struct fsck_data * stat;
|
||||
|
||||
stat = stats (fs);
|
||||
fp = stderr;
|
||||
|
||||
switch (pass) {
|
||||
case 0:
|
||||
fsck_progress ("\tRead blocks (but not data blocks) %lu\n", stat->analyzed);
|
||||
stat->analyzed = 0;
|
||||
fsck_progress ("\t\tLeaves among those %lu\n", stat->leaves);
|
||||
if (stat->leaves_corrected)
|
||||
fsck_progress ("\t\t\t- corrected leaves %lu\n", stat->leaves_corrected);
|
||||
if (stat->all_contents_removed)
|
||||
fsck_progress ("\t\t\t- eaves all contents of which could not be saved and deleted %lu\n", stat->all_contents_removed);
|
||||
if (stat->pointed_leaves)
|
||||
fsck_progress ("\t\t\t- leaves pointed by indirect items %lu\n", stat->pointed_leaves);
|
||||
if (stat->pointed)
|
||||
fsck_progress ("\t\tBlocks pointed by indirect items %lu\n", stat->pointed);
|
||||
if (stat->pointed_once)
|
||||
fsck_progress ("\t\t\t- once %lu\n", stat->pointed_once);
|
||||
if (stat->pointed_more_than_once)
|
||||
fsck_progress ("\t\t\t- more than once %lu\n", stat->pointed_more_than_once);
|
||||
if (stat->wrong_pointers)
|
||||
fsck_progress ("\t\t\t- pointers to wrong area of filesystem (zeroed) %lu\n", stat->wrong_pointers);
|
||||
/* pass1 will calculate how many pointers were zeeros there */
|
||||
stat->wrong_pointers = 0;
|
||||
fsck_progress ("\t\tObjectids found %lu\n", proper_id_map (fs)->objectids_marked);
|
||||
|
||||
/*fsck_progress ("\tblocks marked free %lu\n", stat->free);*/
|
||||
fsck_progress ("\tallocable %lu blocks\n", stat->allocable);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
fsck_progress ("\t%lu leaves read\n", stat->analyzed);
|
||||
fsck_progress ("\t\t%lu inserted\n", stat->inserted_leaves);
|
||||
if (stat->uninsertable_leaves)
|
||||
fsck_progress ("\t\t%lu not inserted\n", stat->uninsertable_leaves);
|
||||
if (stat->saved_on_pass1)
|
||||
fsck_progress ("\tSaved %lu items\n", stat->saved_on_pass1);
|
||||
if (stat->wrong_pointers)
|
||||
fsck_progress ("\tPointers to leaves or non-unique (zeroed) %lu\n",
|
||||
stat->wrong_pointers);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (stat->shared_objectids)
|
||||
fsck_progress ("\t%lu shared objectids\n", stat->shared_objectids);
|
||||
if (stat->relocated)
|
||||
fsck_progress ("\tFiles relocated because of key conflicts w/ a directory %lu\n",
|
||||
stat->relocated);
|
||||
if (stat->rewritten)
|
||||
fsck_progress ("\tFiles rewritten %lu\n",
|
||||
stat->rewritten);
|
||||
return;
|
||||
|
||||
case 3: /* semantic pass */
|
||||
fsck_progress ("\tFiles found: %ld\n", stat->regular_files);
|
||||
fsck_progress ("\tDirectories found: %ld\n", stat->directories);
|
||||
if (stat->symlinks)
|
||||
fsck_progress ("\tSymlinks found: %ld\n", stat->symlinks);
|
||||
if (stat->others)
|
||||
fsck_progress ("\tOthers: %ld\n", stat->others);
|
||||
if (stat->fixed_sizes)
|
||||
fsck_progress ("\tFiles with fixed size: %ld\n", stat->fixed_sizes);
|
||||
if (stat->oid_sharing)
|
||||
fsck_progress ("\tObjects having used objectids: %lu\n", stat->oid_sharing);
|
||||
if (stat->oid_sharing_files_relocated)
|
||||
fsck_progress ("\t\tfiles fixed %lu\n", stat->oid_sharing_files_relocated);
|
||||
if (stat->oid_sharing_dirs_relocated)
|
||||
fsck_progress ("\t\tdirs fixed %lu\n", stat->oid_sharing_dirs_relocated);
|
||||
stat->oid_sharing = 0;
|
||||
stat->oid_sharing_files_relocated = 0;
|
||||
stat->oid_sharing_dirs_relocated = 0;
|
||||
break;
|
||||
|
||||
case 0x3a: /* looking for lost files */
|
||||
if (stat->lost_found)
|
||||
fsck_progress ("\tObjects without names %lu\n",
|
||||
stat->lost_found);
|
||||
if (stat->empty_lost_dirs)
|
||||
fsck_progress ("\tEmpty lost dirs removed %lu\n",
|
||||
stat->empty_lost_dirs);
|
||||
if (stat->lost_found_dirs)
|
||||
fsck_progress ("\tDirs linked to /lost+found: %lu\n",
|
||||
stat->lost_found_dirs);
|
||||
if (stat->dir_recovered)
|
||||
fsck_progress ("\t\tDirs without stat data found %lu\n",
|
||||
stat->dir_recovered);
|
||||
|
||||
if (stat->lost_found_files)
|
||||
fsck_progress ("\tFiles linked to /lost+found %lu\n",
|
||||
stat->lost_found_files);
|
||||
if (stat->oid_sharing)
|
||||
fsck_progress ("\tObjects having used objectids: %lu\n", stat->oid_sharing);
|
||||
if (stat->oid_sharing_files_relocated)
|
||||
fsck_progress ("\t\tfiles fixed %lu\n", stat->oid_sharing_files_relocated);
|
||||
if (stat->oid_sharing_dirs_relocated)
|
||||
fsck_progress ("\t\tdirs fixed %lu\n", stat->oid_sharing_dirs_relocated);
|
||||
break;
|
||||
|
||||
case 4: /* removing of unreachable */
|
||||
if (stat->deleted_items)
|
||||
fsck_progress ("\tDeleted unreachable items %lu\n",
|
||||
stat->deleted_items);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fsck_user_confirmed (fs, "Continue? (Yes):", "Yes\n", 1)) {
|
||||
reiserfs_close (fs);
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+219
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright 2000 Hans Reiser
|
||||
*/
|
||||
|
||||
#include "fsck.h"
|
||||
#include <limits.h>
|
||||
/*#include <stdlib.h>*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define bh_desc(bh) ((struct reiserfs_journal_desc *)((bh)->b_data))
|
||||
#define bh_commit(bh) ((struct reiserfs_journal_commit *)((bh)->b_data))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int next_expected_desc (struct super_block * s, struct buffer_head * d_bh)
|
||||
{
|
||||
int offset;
|
||||
struct reiserfs_journal_desc * desc;
|
||||
|
||||
desc = (struct reiserfs_journal_desc *)d_bh->b_data;
|
||||
offset = d_bh->b_blocknr - SB_JOURNAL_BLOCK (s);
|
||||
return SB_JOURNAL_BLOCK (s) + ((offset + desc->j_len + 1 + 1) % JOURNAL_BLOCK_COUNT);
|
||||
}
|
||||
|
||||
|
||||
static int is_valid_transaction (struct super_block * s, struct buffer_head * d_bh)
|
||||
{
|
||||
struct buffer_head * c_bh;
|
||||
int offset;
|
||||
struct reiserfs_journal_desc *desc = (struct reiserfs_journal_desc *)d_bh->b_data;
|
||||
struct reiserfs_journal_commit *commit ;
|
||||
__u32 block, start_block;
|
||||
|
||||
|
||||
offset = d_bh->b_blocknr - SB_JOURNAL_BLOCK (s);
|
||||
|
||||
/* ok, we have a journal description block, lets see if the transaction was valid */
|
||||
block = next_expected_desc (s, d_bh) - 1;
|
||||
start_block = d_bh->b_blocknr;
|
||||
while(!(c_bh = bread (s->s_dev, block, s->s_blocksize))){
|
||||
if (++block == SB_JOURNAL_BLOCK (s) + JOURNAL_BLOCK_COUNT)
|
||||
block = SB_JOURNAL_BLOCK (s);
|
||||
if (block == start_block)
|
||||
return 0;
|
||||
}
|
||||
|
||||
commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
|
||||
if (does_desc_match_commit (desc, commit)) {
|
||||
// if (journal_compare_desc_commit (s, desc, commit)) {
|
||||
/* printf ("desc and commit block do not match\n");*/
|
||||
brelse (c_bh) ;
|
||||
return 0;
|
||||
}
|
||||
brelse (c_bh);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int reiserfs_replay_journal (struct super_block * s)
|
||||
{
|
||||
struct buffer_head * d_bh, * c_bh, * jh_bh;
|
||||
struct reiserfs_journal_header * j_head;
|
||||
struct reiserfs_journal_desc * j_desc;
|
||||
struct reiserfs_journal_commit * j_commit;
|
||||
unsigned long latest_mount_id;
|
||||
unsigned long j_cur;
|
||||
unsigned long j_start;
|
||||
unsigned long j_size;
|
||||
unsigned long mount_id, trans_id;
|
||||
unsigned long t_first, t_last, t_count, t_flushed;
|
||||
unsigned long t_offset;
|
||||
int i;
|
||||
|
||||
fsck_progress ("Analyzing journal..");
|
||||
|
||||
j_start = SB_JOURNAL_BLOCK (s);
|
||||
j_cur = 0;
|
||||
j_size = rs_journal_size (s->s_rs);
|
||||
t_first = 0;
|
||||
t_last = 0;
|
||||
latest_mount_id = 0;
|
||||
|
||||
/* look for the transactions with the most recent mount_id */
|
||||
for (j_cur = 0; j_cur < j_size; ) {
|
||||
d_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize);
|
||||
if (d_bh && who_is_this (d_bh->b_data, d_bh->b_size) == THE_JDESC && is_valid_transaction (s, d_bh)) {
|
||||
j_desc = (struct reiserfs_journal_desc *)d_bh->b_data;
|
||||
|
||||
mount_id = le32_to_cpu (j_desc->j_mount_id);
|
||||
trans_id = le32_to_cpu (j_desc->j_trans_id);
|
||||
|
||||
if (mount_id > latest_mount_id) {
|
||||
/* more recent mount_id found */
|
||||
latest_mount_id = mount_id;
|
||||
t_first = t_last = trans_id;
|
||||
t_offset = j_cur;
|
||||
t_count = 1;
|
||||
} else if (mount_id == latest_mount_id) {
|
||||
t_count ++;
|
||||
if (trans_id > t_last)
|
||||
t_last = trans_id;
|
||||
if (trans_id < t_first) {
|
||||
t_first = trans_id;
|
||||
t_offset = j_cur;
|
||||
}
|
||||
}
|
||||
j_cur += le32_to_cpu (j_desc->j_len) + 1;
|
||||
}
|
||||
j_cur ++;
|
||||
brelse (d_bh);
|
||||
}
|
||||
|
||||
/* replay only if journal header looks resonable */
|
||||
jh_bh = bread (s->s_dev, j_start + j_size, s->s_blocksize);
|
||||
j_head = (struct reiserfs_journal_header *)(jh_bh->b_data);
|
||||
|
||||
if (latest_mount_id != le32_to_cpu (j_head->j_mount_id)) {
|
||||
fsck_progress ("nothing to replay (no transactions match to latest mount id)\n");
|
||||
brelse (jh_bh);
|
||||
return 0;
|
||||
}
|
||||
/* last transaction flushed - which should not be replayed */
|
||||
t_flushed = le32_to_cpu (j_head->j_last_flush_trans_id);
|
||||
if (t_flushed >= t_last) {
|
||||
fsck_progress ("nothing to replay (no transactions older than last flushed one found)\n");
|
||||
brelse (jh_bh);
|
||||
return 0;
|
||||
}
|
||||
if (t_first > t_flushed + 1) {
|
||||
if (t_flushed)
|
||||
fsck_progress ("last flushed trans %lu, the oldest but newer is %lu\n",
|
||||
t_flushed, t_first);
|
||||
} else {
|
||||
/* start replaying with first not flushed transaction */
|
||||
t_first = t_flushed + 1;
|
||||
t_offset = le32_to_cpu (j_head->j_first_unflushed_offset);
|
||||
}
|
||||
|
||||
fsck_progress ("last flushed trans %lu, mount_id %lu, "
|
||||
"will replay from %lu up to %lu:Yes?",
|
||||
t_flushed, latest_mount_id, t_first, t_last);
|
||||
if (!fsck_user_confirmed (fs, "", "Yes\n", 1))
|
||||
die ("");
|
||||
|
||||
/* replay transactions we have found */
|
||||
for (j_cur = t_offset; t_first <= t_last; t_first ++) {
|
||||
unsigned long offset;
|
||||
|
||||
d_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize);
|
||||
j_desc = (struct reiserfs_journal_desc *)d_bh->b_data;
|
||||
if (who_is_this (d_bh->b_data, d_bh->b_size) != THE_JDESC ||
|
||||
le32_to_cpu (j_desc->j_mount_id) != latest_mount_id ||
|
||||
le32_to_cpu (j_desc->j_trans_id) != t_first)
|
||||
die ("reiserfs_replay_journal: desc block not found");
|
||||
|
||||
offset = j_cur + 1;
|
||||
j_cur += le32_to_cpu (j_desc->j_len) + 1;
|
||||
j_cur %= j_size;
|
||||
c_bh = bread (s->s_dev, j_start + j_cur, s->s_blocksize);
|
||||
j_commit = (struct reiserfs_journal_commit *)c_bh->b_data;
|
||||
if (does_desc_match_commit (j_desc, j_commit))
|
||||
die ("reiserfs_replay_journal: commit block not found");
|
||||
|
||||
fsck_log ("Mount_id %lu, transaction %lu, desc block %lu, commit block %lu: (",
|
||||
latest_mount_id, t_first, d_bh->b_blocknr, c_bh->b_blocknr);
|
||||
|
||||
/* replay one transaction */
|
||||
for (i = 0; i < le32_to_cpu (j_desc->j_len); i ++) {
|
||||
struct buffer_head * in_place, * log;
|
||||
unsigned long block;
|
||||
|
||||
log = bread (s->s_dev, j_start + ((offset + i) % j_size), s->s_blocksize);
|
||||
|
||||
if (i < JOURNAL_TRANS_HALF) {
|
||||
block = le32_to_cpu (j_desc->j_realblock[i]);
|
||||
} else {
|
||||
block = le32_to_cpu (j_commit->j_realblock[i - JOURNAL_TRANS_HALF]);
|
||||
}
|
||||
|
||||
if (not_journalable (s, block)) {
|
||||
fsck_log ("transaction %lu, block %d could not be replayed (%lu)\n",
|
||||
t_first, i, block);
|
||||
} else {
|
||||
fsck_log (" %lu", block);
|
||||
|
||||
in_place = getblk (s->s_dev, block, s->s_blocksize) ;
|
||||
memcpy (in_place->b_data, log->b_data, s->s_blocksize);
|
||||
mark_buffer_dirty (in_place);
|
||||
mark_buffer_uptodate (in_place, 1);
|
||||
bwrite (in_place);
|
||||
brelse (in_place);
|
||||
}
|
||||
brelse (log);
|
||||
|
||||
}
|
||||
fsck_log (")\n");
|
||||
|
||||
brelse (d_bh);
|
||||
brelse (c_bh);
|
||||
j_cur ++;
|
||||
j_cur %= j_size;
|
||||
|
||||
/* update journal header */
|
||||
j_head->j_last_flush_trans_id = cpu_to_le32 (t_first);
|
||||
mark_buffer_dirty (jh_bh);
|
||||
bwrite (jh_bh);
|
||||
}
|
||||
|
||||
brelse (jh_bh);
|
||||
fsck_progress ("Journal replaied\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright 2000-2001 Hans Reiser
|
||||
*/
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
|
||||
/* fixme: search_by_key is not needed after any add_entry */
|
||||
static __u64 _look_for_lost (reiserfs_filsys_t fs, int link_lost_dirs)
|
||||
{
|
||||
struct key key, prev_key, * rdkey;
|
||||
INITIALIZE_PATH (path);
|
||||
int item_pos;
|
||||
struct buffer_head * bh;
|
||||
struct item_head * ih;
|
||||
unsigned long leaves;
|
||||
int is_it_dir;
|
||||
static int lost_files = 0; /* looking for lost dirs we calculate amount of
|
||||
lost files, so that when we will look for
|
||||
lost files we will be able to stop when
|
||||
there are no lost files anymore */
|
||||
int retval;
|
||||
__u64 size;
|
||||
|
||||
key = root_dir_key;
|
||||
|
||||
if (!link_lost_dirs && !lost_files) {
|
||||
/* we have to look for lost files but we know already that there are
|
||||
no any */
|
||||
return 0;
|
||||
}
|
||||
|
||||
fsck_progress ("Looking for lost %s:\n", link_lost_dirs ? "directories" : "files");
|
||||
leaves = 0;
|
||||
|
||||
/* total size of added entries */
|
||||
size = 0;
|
||||
while (1) {
|
||||
retval = usearch_by_key (fs, &key, &path);
|
||||
/* fixme: we assume path ends up with a leaf */
|
||||
bh = get_bh (&path);
|
||||
item_pos = get_item_pos (&path);
|
||||
if (retval != ITEM_FOUND) {
|
||||
if (item_pos == node_item_number (bh)) {
|
||||
rdkey = uget_rkey (&path);
|
||||
if (!rdkey) {
|
||||
pathrelse (&path);
|
||||
break;
|
||||
}
|
||||
key = *rdkey;
|
||||
pathrelse (&path);
|
||||
continue;
|
||||
}
|
||||
/* we are on the item in the buffer */
|
||||
}
|
||||
|
||||
/* print ~ how many leaves were scanned and how fast it was */
|
||||
if (!fsck_quiet (fs))
|
||||
print_how_fast (0, leaves++, 50);
|
||||
|
||||
for (ih = get_ih (&path); item_pos < node_item_number (bh); item_pos ++, ih ++) {
|
||||
if (is_item_reachable (ih))
|
||||
continue;
|
||||
|
||||
/* found item which can not be reached */
|
||||
if (!is_direntry_ih (ih) && !is_stat_data_ih (ih)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_direntry_ih (ih)) {
|
||||
/* if this directory has no stat data - try to recover it */
|
||||
struct key sd;
|
||||
struct path tmp;
|
||||
|
||||
sd = ih->ih_key;
|
||||
set_type_and_offset (KEY_FORMAT_1, &sd, SD_OFFSET, TYPE_STAT_DATA);
|
||||
if (usearch_by_key (fs, &sd, &tmp) == ITEM_FOUND) {
|
||||
/* should not happen - because if there were a stat data -
|
||||
we would have done with the whole directory */
|
||||
pathrelse (&tmp);
|
||||
continue;
|
||||
}
|
||||
stats(fs)->dir_recovered ++;
|
||||
create_dir_sd (fs, &tmp, &sd);
|
||||
key = sd;
|
||||
pathrelse (&path);
|
||||
goto cont;
|
||||
}
|
||||
|
||||
|
||||
/* stat data marked "not having name" found */
|
||||
is_it_dir = ((not_a_directory (B_I_PITEM (bh,ih))) ? 0 : 1);
|
||||
|
||||
if (is_it_dir) {
|
||||
struct key tmp_key;
|
||||
INITIALIZE_PATH (tmp_path);
|
||||
struct item_head * tmp_ih;
|
||||
|
||||
/* there is no need to link empty lost directories into /lost+found */
|
||||
tmp_key = ih->ih_key;
|
||||
set_type_and_offset (KEY_FORMAT_1, &tmp_key, 0xffffffff, TYPE_DIRENTRY);
|
||||
usearch_by_key (fs, &tmp_key, &tmp_path);
|
||||
tmp_ih = get_ih (&tmp_path);
|
||||
tmp_ih --;
|
||||
if (not_of_one_file (&tmp_key, tmp_ih))
|
||||
reiserfs_panic ("not directory found");
|
||||
if (!is_direntry_ih (tmp_ih) ||
|
||||
(deh_offset (B_I_DEH (get_bh (&tmp_path), ih) +
|
||||
ih_entry_count (tmp_ih) - 1) == DOT_DOT_OFFSET)) {
|
||||
/* last directory item is either stat data or empty
|
||||
directory item - do not link this dir into lost+found */
|
||||
stats(fs)->empty_lost_dirs ++;
|
||||
pathrelse (&tmp_path);
|
||||
continue;
|
||||
}
|
||||
pathrelse (&tmp_path);
|
||||
}
|
||||
|
||||
if (link_lost_dirs && !is_it_dir) {
|
||||
/* we are looking for directories and it is not a dir */
|
||||
lost_files ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
stats(fs)->lost_found ++;
|
||||
|
||||
{
|
||||
struct key obj_key = {0, 0, {{0, 0},}};
|
||||
char * lost_name;
|
||||
struct item_head tmp_ih;
|
||||
int pos_in_map;
|
||||
|
||||
/* key to continue */
|
||||
key = ih->ih_key;
|
||||
key.k_objectid ++;
|
||||
|
||||
tmp_ih = *ih;
|
||||
if (is_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid,
|
||||
&pos_in_map)) {
|
||||
/* objectid is used, relocate an object */
|
||||
stats(fs)->oid_sharing ++;
|
||||
if (fsck_fix_non_critical (fs)) {
|
||||
if (is_it_dir) {
|
||||
relocate_dir (&tmp_ih, 1);
|
||||
stats(fs)->oid_sharing_dirs_relocated ++;
|
||||
} else {
|
||||
relocate_file (&tmp_ih, 1);
|
||||
stats(fs)->oid_sharing_files_relocated ++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!is_it_dir)
|
||||
mark_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid);
|
||||
}
|
||||
|
||||
asprintf (&lost_name, "%u_%u", le32_to_cpu (tmp_ih.ih_key.k_dir_id),
|
||||
le32_to_cpu (tmp_ih.ih_key.k_objectid));
|
||||
|
||||
/* entry in lost+found directory will point to this key */
|
||||
obj_key.k_dir_id = tmp_ih.ih_key.k_dir_id;
|
||||
obj_key.k_objectid = tmp_ih.ih_key.k_objectid;
|
||||
|
||||
|
||||
pathrelse (&path);
|
||||
|
||||
/* 0 does not mean anyting - item w/ "." and ".." already
|
||||
exists and reached, so only name will be added */
|
||||
size += reiserfs_add_entry (fs, &lost_found_dir_key, lost_name, &obj_key, 0/*fsck_need*/);
|
||||
|
||||
if (is_it_dir) {
|
||||
/* fixme: we hope that if we will try to pull all the
|
||||
directory right now - then there will be less
|
||||
lost_found things */
|
||||
fsck_progress ("\tChecking lost dir \"%s\":", lost_name);
|
||||
rebuild_semantic_pass (&obj_key, &lost_found_dir_key, /*dot_dot*/0, /*reloc_ih*/0);
|
||||
fsck_progress ("ok\n");
|
||||
stats(fs)->lost_found_dirs ++;
|
||||
} else {
|
||||
if (usearch_by_key (fs, &obj_key, &path) != ITEM_FOUND)
|
||||
reiserfs_panic ("look_for_lost: lost file stat data %K not found",
|
||||
&obj_key);
|
||||
|
||||
/* check_regular_file does not mark stat data reachable */
|
||||
mark_item_reachable (get_ih (&path), get_bh (&path));
|
||||
mark_buffer_dirty (get_bh (&path));
|
||||
|
||||
rebuild_check_regular_file (&path, get_item (&path), 0/*reloc_ih*/);
|
||||
pathrelse (&path);
|
||||
|
||||
stats(fs)->lost_found_files ++;
|
||||
lost_files --;
|
||||
}
|
||||
|
||||
free (lost_name);
|
||||
goto cont;
|
||||
}
|
||||
} /* for */
|
||||
|
||||
prev_key = key;
|
||||
get_next_key (&path, item_pos - 1, &key);
|
||||
if (comp_keys (&prev_key, &key) != -1)
|
||||
reiserfs_panic ("pass_3a: key must grow 2: prev=%k next=%k",
|
||||
&prev_key, &key);
|
||||
pathrelse (&path);
|
||||
|
||||
cont:
|
||||
if (!link_lost_dirs && !lost_files) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pathrelse (&path);
|
||||
|
||||
#if 0
|
||||
/* check names added we just have added to/lost+found. Those names are
|
||||
marked DEH_Lost_found flag */
|
||||
fsck_progress ("Checking lost+found directory.."); fflush (stdout);
|
||||
check_semantic_tree (&lost_found_dir_key, &root_dir_key, 0, 1/* lost+found*/);
|
||||
fsck_progress ("ok\n");
|
||||
#endif
|
||||
|
||||
if (!link_lost_dirs && lost_files)
|
||||
fsck_log ("look_for_lost: %d files seem to left not linked to lost+found\n",
|
||||
lost_files);
|
||||
|
||||
return size;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void pass_3a_look_for_lost (reiserfs_filsys_t fs)
|
||||
{
|
||||
INITIALIZE_PATH (path);
|
||||
struct item_head * ih;
|
||||
void * sd;
|
||||
__u64 size, sd_size;
|
||||
__u32 blocks;
|
||||
|
||||
fsck_progress ("Pass 3a (looking for lost files):\n");
|
||||
|
||||
/* when warnings go not to stderr - separate then in the log */
|
||||
if (fsck_log_file (fs) != stderr)
|
||||
fsck_log ("####### Pass 3a (lost+found pass) #########\n");
|
||||
|
||||
|
||||
/* look for lost dirs first */
|
||||
size = _look_for_lost (fs, 1);
|
||||
|
||||
/* link files which are still lost */
|
||||
size += _look_for_lost (fs, 0);
|
||||
|
||||
/* update /lost+found sd_size and sd_blocks (nlink is correct already) */
|
||||
if (usearch_by_key (fs, &lost_found_dir_key, &path) != ITEM_FOUND)
|
||||
reiserfs_panic ("look_for_lost: /lost+found stat data %K not found",
|
||||
&lost_found_dir_key);
|
||||
ih = get_ih (&path);
|
||||
sd = get_item (&path);
|
||||
get_sd_size (ih, sd, &sd_size);
|
||||
size += sd_size;
|
||||
blocks = dir_size2st_blocks (fs->s_blocksize, size);
|
||||
|
||||
set_sd_size (ih, sd, &size);
|
||||
set_sd_blocks (ih, sd, &blocks);
|
||||
mark_buffer_dirty (get_bh (&path));
|
||||
pathrelse (&path);
|
||||
|
||||
stage_report (0x3a, fs);
|
||||
}
|
||||
|
||||
+709
@@ -0,0 +1,709 @@
|
||||
/*
|
||||
* Copyright 1996-2000 Hans Reiser
|
||||
*/
|
||||
#include "fsck.h"
|
||||
#include <getopt.h>
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
|
||||
|
||||
#define print_usage_and_exit() die ("Usage: %s [options] "\
|
||||
" device\n"\
|
||||
"\n"\
|
||||
"Options:\n\n"\
|
||||
" --check\t\tconsistency checking (default)\n"\
|
||||
" --rebuild-sb\t\tsuper block checking and rebuilding if needed\n"\
|
||||
" --rebuild-tree\tforce fsck to rebuild filesystem from scratch\n"\
|
||||
" \t\t\t(takes a long time)\n"\
|
||||
" --interactive, -i\tmake fsck to stop after every stage\n"\
|
||||
" -l | --logfile logfile\n"\
|
||||
" \t\t\tmake fsck to complain to specifed file\n"\
|
||||
" -b | --scan-marked-in-bitmap file\n"\
|
||||
" \t\t\tbuild tree of blocks marked in the bitmapfile\n"\
|
||||
" -c | --create-bitmap-file\n"\
|
||||
" \t\t\tsave bitmap of found leaves\n"\
|
||||
" -x | --fix-fixable\tfix corruptions which can be fixed w/o --rebuild-tree\n"\
|
||||
" -o | --fix-non-critical\n"\
|
||||
" \t\t\tfix strange modes, file sizes to real size and\n"\
|
||||
" \t\t\trelocate files using busy objectids\n"\
|
||||
" -q | --quiet\t\tno speed info\n"\
|
||||
" -n | --nolog\t\t suppresses all logs\n"\
|
||||
" -V\t\t\tprints version and exits\n"\
|
||||
" -a\t\t\tmakes fsck to do nothing\n"\
|
||||
" -p\t\t\tdo nothing, exist for compatibility with fsck(8)\n"\
|
||||
" -r\n", argv[0]);
|
||||
|
||||
|
||||
|
||||
|
||||
/* fsck is called with one non-optional argument - file name of device
|
||||
containing reiserfs. This function parses other options, sets flags
|
||||
based on parsing and returns non-optional argument */
|
||||
static char * parse_options (struct fsck_data * data, int argc, char * argv [])
|
||||
{
|
||||
int c;
|
||||
static int mode = FSCK_CHECK;
|
||||
|
||||
data->scan_area = USED_BLOCKS;
|
||||
while (1) {
|
||||
static struct option options[] = {
|
||||
/* modes */
|
||||
{"check", no_argument, &mode, FSCK_CHECK},
|
||||
{"rebuild-sb", no_argument, &mode, FSCK_SB},
|
||||
{"rebuild-tree", no_argument, &mode, FSCK_REBUILD},
|
||||
/*
|
||||
{"fast-rebuild", no_argument, &opt_fsck_mode, FSCK_FAST_REBUILD},
|
||||
*/
|
||||
|
||||
/* options */
|
||||
{"logfile", required_argument, 0, 'l'},
|
||||
{"interactive", no_argument, 0, 'i'},
|
||||
{"fix-fixable", no_argument, 0, 'x'},
|
||||
{"fix-non-critical", no_argument, 0, 'o'},
|
||||
{"quiet", no_argument, 0, 'q'},
|
||||
{"nolog", no_argument, 0, 'n'},
|
||||
|
||||
/* if file exists ad reiserfs can be load of it - only
|
||||
blocks marked used in that bitmap will be read */
|
||||
{"scan-marked-in-bitmap", required_argument, 0, 'b'},
|
||||
|
||||
/* */
|
||||
{"create-leaf-bitmap", required_argument, 0, 'c'},
|
||||
|
||||
/* all blocks will be read */
|
||||
{"scan-whole-partition", no_argument, 0, 'S'},
|
||||
|
||||
/* special option: will mark free blocks used, zero all
|
||||
unformatted node pointers and mark them free */
|
||||
{"zero-files", no_argument, &mode, FSCK_ZERO_FILES},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
int option_index;
|
||||
|
||||
c = getopt_long (argc, argv, "iql:b:Sc:xoVaprt:n",
|
||||
options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 0:
|
||||
/* long option specifying fsck mode is found */
|
||||
break;
|
||||
|
||||
case 'i': /* --interactive */
|
||||
data->options |= OPT_INTERACTIVE;
|
||||
break;
|
||||
|
||||
case 'q': /* --quiet */
|
||||
data->options |= OPT_QUIET;
|
||||
break;
|
||||
|
||||
case 'l': /* --logfile */
|
||||
asprintf (&data->log_file_name, "%s", optarg);
|
||||
data->log = fopen (optarg, "w");
|
||||
if (!data->log)
|
||||
fprintf (stderr, "reiserfsck: could not open \'%s\': %m", optarg);
|
||||
|
||||
break;
|
||||
|
||||
case 'b': /* --scan-marked-in-bitmap */
|
||||
/* will try to load a bitmap from a file and read only
|
||||
blocks marked in it. That bitmap could be created by
|
||||
previous run of reiserfsck with -c */
|
||||
asprintf (&data->bitmap_file_name, "%s", optarg);
|
||||
data->scan_area = EXTERN_BITMAP;
|
||||
break;
|
||||
|
||||
case 'S': /* --scan-whole-partition */
|
||||
data->scan_area = ALL_BLOCKS;
|
||||
break;
|
||||
|
||||
case 'c': /* --create-leaf-bitmap */
|
||||
asprintf (&data->new_bitmap_file_name, "%s", optarg);
|
||||
data->options |= OPT_SAVE_EXTERN_BITMAP;
|
||||
break;
|
||||
|
||||
case 'x': /* --fix-fixable */
|
||||
data->options |= OPT_FIX_FIXABLE;
|
||||
break;
|
||||
|
||||
case 'o': /* --fix-non-critical */
|
||||
data->options |= OPT_FIX_NON_CRITICAL;
|
||||
break;
|
||||
|
||||
case 'n': /* --nolog */
|
||||
data->options |= OPT_SILENT;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
case 'p': /* these say reiserfsck to do nothing */
|
||||
case 'r':
|
||||
case 'a':
|
||||
mode = DO_NOTHING;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
mode = DO_TEST;
|
||||
data->test = atoi (optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage_and_exit();
|
||||
}
|
||||
}
|
||||
|
||||
if (optind != argc - 1 && mode != DO_NOTHING)
|
||||
/* only one non-option argument is permitted */
|
||||
print_usage_and_exit();
|
||||
|
||||
data->mode = mode;
|
||||
if (!data->log)
|
||||
data->log = stderr;
|
||||
|
||||
return argv[optind];
|
||||
}
|
||||
|
||||
|
||||
reiserfs_filsys_t fs;
|
||||
|
||||
|
||||
|
||||
static void reset_super_block (reiserfs_filsys_t fs)
|
||||
{
|
||||
set_free_blocks (fs->s_rs, SB_BLOCK_COUNT (fs));
|
||||
set_root_block (fs->s_rs, ~0);
|
||||
set_tree_height (fs->s_rs, ~0);
|
||||
|
||||
/* make file system invalid unless fsck done () */
|
||||
set_state (fs->s_rs, REISERFS_ERROR_FS);
|
||||
|
||||
|
||||
if (is_reiser2fs_magic_string (fs->s_rs)) {
|
||||
set_version (fs->s_rs, REISERFS_VERSION_2);
|
||||
}
|
||||
if (is_reiserfs_magic_string (fs->s_rs)) {
|
||||
set_version (fs->s_rs, REISERFS_VERSION_1);
|
||||
}
|
||||
|
||||
/* can be not set yet. If so, hash function will be set when first dir
|
||||
entry will be found */
|
||||
fs->s_hash_function = code2func (rs_hash (fs->s_rs));
|
||||
|
||||
/* objectid map is not touched */
|
||||
|
||||
mark_buffer_dirty (fs->s_sbh);
|
||||
bwrite (fs->s_sbh);
|
||||
|
||||
}
|
||||
|
||||
|
||||
reiserfs_bitmap_t uninsertable_leaf_bitmap;
|
||||
|
||||
int g_blocks_to_read;
|
||||
|
||||
|
||||
/* on-disk bitmap is read, fetch it. create new bitmap, mark used blocks which
|
||||
are always used (skipped, super block, journal area, bitmaps), create other
|
||||
auxiliary bitmaps */
|
||||
static void init_bitmaps (reiserfs_filsys_t fs)
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned long block_count;
|
||||
unsigned long tmp;
|
||||
|
||||
block_count = SB_BLOCK_COUNT (fs);
|
||||
|
||||
switch (stats (fs)->scan_area) {
|
||||
case ALL_BLOCKS:
|
||||
fsck_disk_bitmap (fs) = reiserfs_create_bitmap (block_count);
|
||||
reiserfs_bitmap_fill (fsck_disk_bitmap (fs));
|
||||
fsck_progress ("Whole device (%d blocks) is to be scanned\n",
|
||||
reiserfs_bitmap_ones (fsck_disk_bitmap (fs)));
|
||||
break;
|
||||
|
||||
case USED_BLOCKS:
|
||||
fsck_progress ("Loading on-disk bitmap .. ");
|
||||
fsck_disk_bitmap (fs) = reiserfs_create_bitmap (block_count);
|
||||
reiserfs_fetch_disk_bitmap (fsck_disk_bitmap (fs), fs);
|
||||
fsck_progress ("%d bits set - done\n",
|
||||
reiserfs_bitmap_ones (fsck_disk_bitmap (fs)));
|
||||
break;
|
||||
|
||||
case EXTERN_BITMAP:
|
||||
fsck_disk_bitmap (fs) = reiserfs_bitmap_load (stats (fs)->bitmap_file_name);
|
||||
if (!fsck_disk_bitmap (fs))
|
||||
reiserfs_panic ("could not load fitmap from \"%s\"",
|
||||
stats (fs)->bitmap_file_name);
|
||||
break;
|
||||
|
||||
default:
|
||||
reiserfs_panic ("No area to scan specified");
|
||||
}
|
||||
|
||||
|
||||
/* pass 0 will skip super block and journal areas and bitmap blocks, find
|
||||
how many blocks have to be read */
|
||||
tmp = 0;
|
||||
for (i = 0; i <= fs->s_sbh->b_blocknr; i ++) {
|
||||
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i))
|
||||
continue;
|
||||
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i);
|
||||
tmp ++;
|
||||
}
|
||||
|
||||
/* unmark bitmaps */
|
||||
for (i = 0; i < rs_bmap_nr (fs->s_rs); i ++) {
|
||||
unsigned long block;
|
||||
|
||||
block = SB_AP_BITMAP (fs)[i]->b_blocknr;
|
||||
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block))
|
||||
continue;
|
||||
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), block);
|
||||
tmp ++;
|
||||
}
|
||||
|
||||
/* unmark journal area */
|
||||
for (i = rs_journal_start (fs->s_rs);
|
||||
i <= rs_journal_start (fs->s_rs) + rs_journal_size (fs->s_rs); i ++) {
|
||||
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i))
|
||||
continue;
|
||||
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i);
|
||||
tmp ++;
|
||||
}
|
||||
reiserfs_warning (stderr, "Skipping %d blocks (super block, journal, "
|
||||
"bitmaps) %d blocks will be read\n",
|
||||
tmp, reiserfs_bitmap_ones (fsck_disk_bitmap (fs)));
|
||||
|
||||
#if 0
|
||||
{
|
||||
int tmp = 0;
|
||||
int tmp2 = 0;
|
||||
int tmp3 = 0;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < block_count; i += 32) {
|
||||
if (i + 32 < block_count && !*(int *)&(fsck_disk_bitmap (fs)->bm_map[i/8])) {
|
||||
tmp2 ++;
|
||||
continue;
|
||||
}
|
||||
tmp3 ++;
|
||||
for (j = 0; j < 32 && ((i + j) < block_count); j ++) {
|
||||
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i + j))
|
||||
continue;
|
||||
if (not_data_block (fs, i + j)) {
|
||||
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i + j);
|
||||
tmp ++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (i = 0; i < block_count; i ++) {
|
||||
if (!fsck_disk_bitmap (fs)->bm_map[i / 8])
|
||||
continue;
|
||||
if (!reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i))
|
||||
continue;
|
||||
if (not_data_block (fs, i)) {
|
||||
|
||||
if (reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), i))
|
||||
tmp ++;
|
||||
reiserfs_bitmap_clear_bit (fsck_disk_bitmap (fs), i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*/
|
||||
reiserfs_warning (stderr, "%d not data blocks cleared (skipped %d checked %d)\n", tmp, tmp2, tmp3);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
fsck_new_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
|
||||
|
||||
/* mark_block_used skips 0, ste the bit explicitly */
|
||||
reiserfs_bitmap_set_bit (fsck_new_bitmap (fs), 0);
|
||||
|
||||
/* mark other skipped blocks and super block used */
|
||||
for (i = 1; i <= SB_BUFFER_WITH_SB (fs)->b_blocknr; i ++)
|
||||
mark_block_used (i);
|
||||
|
||||
/* mark bitmap blocks as used */
|
||||
for (i = 0; i < SB_BMAP_NR (fs); i ++)
|
||||
mark_block_used (SB_AP_BITMAP (fs)[i]->b_blocknr);
|
||||
|
||||
/* mark journal area as used */
|
||||
for (i = 0; i < JOURNAL_BLOCK_COUNT + 1; i ++)
|
||||
mark_block_used (i + SB_JOURNAL_BLOCK (fs));
|
||||
|
||||
|
||||
uninsertable_leaf_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
|
||||
reiserfs_bitmap_fill (uninsertable_leaf_bitmap);
|
||||
|
||||
fsck_allocable_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
|
||||
reiserfs_bitmap_fill (fsck_allocable_bitmap (fs));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define REBUILD_WARNING \
|
||||
"\nThis is an experimental version of reiserfsck, MAKE A BACKUP FIRST!\n\
|
||||
Don't run this program unless something is broken. \n\
|
||||
Some types of random FS damage can be recovered\n\
|
||||
from by this program, which basically throws away the internal nodes\n\
|
||||
of the tree and then reconstructs them. This program is for use only\n\
|
||||
by the desperate, and is of only beta quality. Email\n\
|
||||
reiserfs@devlinux.com with bug reports. \nWill rebuild the filesystem tree\n"
|
||||
|
||||
/*
|
||||
warning #2
|
||||
you seem to be running this automatically. you are almost
|
||||
certainly doing it by mistake as a result of some script that
|
||||
doesn't know what it does. doing nothing, rerun without -p if you
|
||||
really intend to do this. */
|
||||
|
||||
void warn_what_will_be_done (struct fsck_data * data)
|
||||
{
|
||||
fsck_progress ("\n");
|
||||
|
||||
/* warn about fsck mode */
|
||||
switch (data->mode) {
|
||||
case FSCK_CHECK:
|
||||
fsck_progress ("Will read-only check consistency of the partition\n");
|
||||
if (data->options & OPT_FIX_FIXABLE)
|
||||
fsck_progress ("\tWill fix what can be fixed w/o --rebuild-tree\n");
|
||||
break;
|
||||
|
||||
case FSCK_SB:
|
||||
fsck_progress ("Will check SB and rebuild if it is needed\n");
|
||||
break;
|
||||
|
||||
case FSCK_REBUILD:
|
||||
{
|
||||
fsck_progress (REBUILD_WARNING);
|
||||
if (data->options & OPT_INTERACTIVE)
|
||||
fsck_progress ("\tWill stop after every stage and ask for "
|
||||
"confirmation before continuing\n");
|
||||
if (data->options & OPT_SAVE_EXTERN_BITMAP)
|
||||
fsck_progress ("Will save list of found leaves in '%s'\n",
|
||||
data->new_bitmap_file_name);
|
||||
if (data->bitmap_file_name)
|
||||
fsck_progress ("\tWill try to load bitmap of leaves from file '%s'\n",
|
||||
data->bitmap_file_name);
|
||||
if (data->options & OPT_FIX_NON_CRITICAL)
|
||||
fsck_progress ("\tWill fix following non-critical things:\n"
|
||||
"\t\tunknown file modes will be set to regular files\n"
|
||||
"\t\tfile sizes will be set to real file size\n"
|
||||
"\t\tfiles sharing busy inode number will be relocated\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case FSCK_ZERO_FILES:
|
||||
fsck_progress ("Will zero existing files and mark free blocks as used\n");
|
||||
}
|
||||
|
||||
fsck_progress ("Will put log info to '%s'\n", (data->log != stderr) ?
|
||||
data->log_file_name : "stderr");
|
||||
|
||||
if (!user_confirmed ("Do you want to run this program?[N/Yes] (note need to type Yes):", "Yes\n"))
|
||||
exit (0);
|
||||
}
|
||||
|
||||
|
||||
static void start_rebuild (reiserfs_filsys_t fs)
|
||||
{
|
||||
reset_super_block (fs);
|
||||
init_bitmaps (fs);
|
||||
|
||||
proper_id_map (fs) = init_id_map ();
|
||||
semantic_id_map (fs) = init_id_map ();
|
||||
}
|
||||
|
||||
|
||||
/* called before semantic pass starts */
|
||||
static void end_rebuilding (reiserfs_filsys_t fs)
|
||||
{
|
||||
reiserfs_flush_bitmap (fsck_new_bitmap (fs), fs);
|
||||
flush_objectid_map (proper_id_map (fs), fs);
|
||||
set_fsck_state (fs->s_rs, TREE_IS_BUILT);
|
||||
set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (fsck_new_bitmap (fs)));
|
||||
|
||||
mark_buffer_dirty (SB_BUFFER_WITH_SB (fs));
|
||||
|
||||
/* write all dirty blocks */
|
||||
fsck_progress ("Syncing.."); fflush (stdout);
|
||||
reiserfs_flush (fs);
|
||||
fsck_progress ("done\n"); fflush (stdout);
|
||||
|
||||
/* release what will not be needed */
|
||||
reiserfs_delete_bitmap (fsck_disk_bitmap (fs));
|
||||
reiserfs_delete_bitmap (fsck_allocable_bitmap (fs));
|
||||
|
||||
/* FIXME: could be not a bitmap */
|
||||
reiserfs_delete_bitmap (uninsertable_leaf_bitmap);
|
||||
|
||||
if (fsck_user_confirmed (fs, "Tree building completed. "
|
||||
"You can stop now and restart from this point later "
|
||||
"(this is probably not what you need). Do you want to stop? ",
|
||||
"Yes\n", 0/*default*/)) {
|
||||
reiserfs_close (fs);
|
||||
exit (4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int skip_rebuilding (reiserfs_filsys_t fs)
|
||||
{
|
||||
if (fsck_state (fs->s_rs) == TREE_IS_BUILT) {
|
||||
if (fsck_user_confirmed (fs, "S+ tree of filesystem looks built. Skip rebuilding? ", "Yes\n", 0/*default*/)) {
|
||||
|
||||
fsck_new_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
|
||||
reiserfs_fetch_disk_bitmap (fsck_new_bitmap (fs), fs);
|
||||
|
||||
proper_id_map (fs) = init_id_map ();
|
||||
fetch_objectid_map (proper_id_map (fs), fs);
|
||||
|
||||
semantic_id_map (fs) = init_id_map ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void start_continuing (reiserfs_filsys_t fs)
|
||||
{
|
||||
fsck_allocable_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
|
||||
reiserfs_bitmap_copy (fsck_allocable_bitmap (fs), fsck_new_bitmap (fs));
|
||||
}
|
||||
|
||||
|
||||
static void the_end (reiserfs_filsys_t fs)
|
||||
{
|
||||
reiserfs_flush_bitmap (fsck_new_bitmap (fs), fs);
|
||||
flush_objectid_map (proper_id_map (fs), fs);
|
||||
set_fsck_state (fs->s_rs, 0);
|
||||
set_free_blocks (fs->s_rs, reiserfs_bitmap_zeros (fsck_new_bitmap (fs)));
|
||||
set_state (fs->s_rs, REISERFS_VALID_FS);
|
||||
mark_buffer_dirty (SB_BUFFER_WITH_SB (fs));
|
||||
|
||||
/* write all dirty blocks */
|
||||
fsck_progress ("Syncing.."); fflush (stderr);
|
||||
reiserfs_flush (fs);
|
||||
sync ();
|
||||
fsck_progress ("done\n"); fflush (stderr);
|
||||
|
||||
reiserfs_delete_bitmap (fsck_new_bitmap (fs));
|
||||
|
||||
free_id_map (&proper_id_map(fs));
|
||||
if (semantic_id_map(fs))
|
||||
free_id_map (&semantic_id_map(fs));
|
||||
|
||||
reiserfs_close (fs);
|
||||
fsck_progress ("Done\n"); fflush (stderr);
|
||||
}
|
||||
|
||||
|
||||
static void rebuild_tree (reiserfs_filsys_t fs)
|
||||
{
|
||||
if (is_mounted (fs->file_name)) {
|
||||
fsck_progress ("rebuild_tree: can not rebuild tree of mounted filesystem\n");
|
||||
return;
|
||||
}
|
||||
|
||||
reiserfs_reopen (fs, O_RDWR);
|
||||
|
||||
/* FIXME: for regular file take care of of file size */
|
||||
|
||||
/* rebuild starts with journal replaying */
|
||||
reiserfs_replay_journal (fs);
|
||||
|
||||
|
||||
if (!skip_rebuilding (fs)) {
|
||||
fsck_progress ("Rebuilding..\n");
|
||||
start_rebuild (fs);
|
||||
|
||||
pass_0 (fs);
|
||||
|
||||
/* passes 1 and 2. building of the tree */
|
||||
pass_1_pass_2_build_the_tree ();
|
||||
|
||||
end_rebuilding (fs);
|
||||
}
|
||||
|
||||
/* re-building of filesystem tree is now separated of sematic pass of the
|
||||
fsck */
|
||||
start_continuing (fs);
|
||||
|
||||
/* 3. semantic pass */
|
||||
pass_3_semantic ();
|
||||
|
||||
/* if --lost+found is set - link unaccessed directories to lost+found
|
||||
directory */
|
||||
pass_3a_look_for_lost (fs);
|
||||
|
||||
/* 4. look for unaccessed items in the leaves */
|
||||
pass_4_check_unaccessed_items ();
|
||||
|
||||
the_end (fs);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void zero_files (reiserfs_filsys_t fs)
|
||||
{
|
||||
init_bitmaps (fs);
|
||||
reiserfs_reopen (fs, O_RDWR);
|
||||
pass_0 (fs);
|
||||
}
|
||||
|
||||
|
||||
/* check umounted or read-only mounted filesystems only */
|
||||
static void check_fs (reiserfs_filsys_t fs)
|
||||
{
|
||||
if (!is_mounted (fs->file_name)) {
|
||||
/* filesystem is not mounted, replay journal before checking */
|
||||
reiserfs_reopen (fs, O_RDWR);
|
||||
|
||||
reiserfs_replay_journal (fs);
|
||||
|
||||
reiserfs_reopen (fs, O_RDONLY);
|
||||
} else {
|
||||
/* filesystem seems mounted. we do not check filesystems mounted with
|
||||
r/w permissions */
|
||||
if (!is_mounted_read_only (fs->file_name)) {
|
||||
fsck_progress ("Device %s is mounted w/ write permissions, can not check it\n",
|
||||
fs->file_name);
|
||||
reiserfs_close (fs);
|
||||
exit (0);
|
||||
}
|
||||
fsck_progress ("Filesystem seems mounted read-only. Skipping journal replay..\n");
|
||||
|
||||
if (fsck_fix_fixable (fs)) {
|
||||
fsck_progress ("--fix-fixable ignored\n");
|
||||
stats(fs)->options &= ~OPT_FIX_FIXABLE;
|
||||
}
|
||||
}
|
||||
|
||||
fsck_disk_bitmap (fs) = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
|
||||
reiserfs_fetch_disk_bitmap (fsck_disk_bitmap (fs), fs);
|
||||
|
||||
if (fsck_fix_fixable (fs))
|
||||
reiserfs_reopen (fs, O_RDWR);
|
||||
|
||||
/*proper_id_map (fs) = init_id_map ();*/
|
||||
semantic_id_map (fs) = init_id_map ();
|
||||
|
||||
check_fs_tree (fs);
|
||||
|
||||
semantic_check ();
|
||||
|
||||
reiserfs_delete_bitmap (fsck_disk_bitmap (fs));
|
||||
/*free_id_map (proper_id_map (fs));*/
|
||||
free_id_map (&semantic_id_map (fs));
|
||||
reiserfs_close (fs);
|
||||
}
|
||||
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
int main (int argc, char * argv [])
|
||||
{
|
||||
char * file_name;
|
||||
struct fsck_data * data;
|
||||
struct rlimit rlim = {0xffffffff, 0xffffffff};
|
||||
|
||||
print_banner ("reiserfsck");
|
||||
|
||||
/* this is only needed (and works) when running under 2.4 on regural files */
|
||||
if (setrlimit (RLIMIT_FSIZE, &rlim) == -1) {
|
||||
reiserfs_warning (stderr, "could not setrlimit: %m");
|
||||
}
|
||||
|
||||
data = getmem (sizeof (struct fsck_data));
|
||||
|
||||
file_name = parse_options (data, argc, argv);
|
||||
|
||||
if (data->mode == DO_NOTHING) {
|
||||
freemem (data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
warn_what_will_be_done (data); /* and ask confirmation Yes */
|
||||
fs = reiserfs_open (file_name, O_RDONLY, 0, data);
|
||||
if (!fs)
|
||||
die ("reiserfsck: could not open filesystem on \"%s\"", file_name);
|
||||
|
||||
|
||||
if (fsck_mode (fs) == FSCK_SB) {
|
||||
reiserfs_reopen (fs, O_RDWR);
|
||||
rebuild_sb (fs);
|
||||
reiserfs_close (fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (no_reiserfs_found (fs)) {
|
||||
fsck_progress ("reiserfsck: --rebuild-sb may restore reiserfs super block\n");
|
||||
reiserfs_close (fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
fs->block_allocator = reiserfsck_reiserfs_new_blocknrs;
|
||||
fs->block_deallocator = reiserfsck_reiserfs_free_block;
|
||||
|
||||
|
||||
|
||||
if (fsck_mode (fs) == FSCK_CHECK) {
|
||||
check_fs (fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef FAST_REBUILD_READY /* and tested */
|
||||
if (opt_fsck_mode == FSCK_FAST_REBUILD) {
|
||||
__u32 root_block = SB_ROOT_BLOCK(fs);
|
||||
reopen_read_write (file_name);
|
||||
printf ("Replaying log..");
|
||||
reiserfs_replay_journal (fs);
|
||||
printf ("done\n");
|
||||
if (opt_fsck == 1)
|
||||
printf ("ReiserFS : checking %s\n",file_name);
|
||||
else
|
||||
printf ("Rebuilding..\n");
|
||||
|
||||
|
||||
reset_super_block (fs);
|
||||
SB_DISK_SUPER_BLOCK(fs)->s_root_block = cpu_to_le32 (root_block);
|
||||
init_bitmaps (fs);
|
||||
|
||||
/* 1,2. building of the tree */
|
||||
recover_internal_tree(fs);
|
||||
|
||||
/* 3. semantic pass */
|
||||
pass3_semantic ();
|
||||
|
||||
/* if --lost+found is set - link unaccessed directories to
|
||||
lost+found directory */
|
||||
look_for_lost (fs);
|
||||
|
||||
/* 4. look for unaccessed items in the leaves */
|
||||
pass4_check_unaccessed_items ();
|
||||
|
||||
end_fsck ();
|
||||
}
|
||||
#endif /* FAST REBUILD READY */
|
||||
|
||||
|
||||
if (fsck_mode (fs) == FSCK_ZERO_FILES)
|
||||
zero_files (fs);
|
||||
|
||||
if (fsck_mode (fs) != FSCK_REBUILD && fsck_mode (fs) != DO_TEST)
|
||||
return 0;
|
||||
|
||||
|
||||
/* the --rebuild-tree is here */
|
||||
rebuild_tree (fs);
|
||||
return 0;
|
||||
|
||||
}
|
||||
+1502
File diff suppressed because it is too large.
Load diff
+881
@@ -0,0 +1,881 @@
|
||||
/*
|
||||
* Copyright 1996-1999 Hans Reiser
|
||||
*/
|
||||
#include "fsck.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
reiserfs_bitmap_t bad_unfm_in_tree_once_bitmap;
|
||||
|
||||
//int step = 0; // 0 - find stat_data or any item ; 1 - find item ; 2 - already found
|
||||
|
||||
|
||||
/* allocates buffer head and copy buffer content */
|
||||
struct buffer_head * make_buffer (int dev, int blocknr, int size, char * data)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
|
||||
bh = getblk (dev, blocknr, size);
|
||||
if (buffer_uptodate (bh))
|
||||
return bh;
|
||||
// die ("make_buffer: uptodate buffer found");
|
||||
memcpy (bh->b_data, data, size);
|
||||
set_bit (BH_Uptodate, (char *)&bh->b_state);
|
||||
return bh;
|
||||
}
|
||||
|
||||
|
||||
int find_not_of_one_file(struct key * to_find, struct key * key)
|
||||
{
|
||||
if ((to_find->k_objectid != -1) &&
|
||||
(to_find->k_objectid != key->k_objectid))
|
||||
return 1;
|
||||
if ((to_find->k_dir_id != -1) &&
|
||||
(to_find->k_dir_id != key->k_dir_id))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_item_reachable (struct item_head * ih)
|
||||
{
|
||||
return ih_reachable (ih) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
void mark_item_unreachable (struct item_head * ih)
|
||||
{
|
||||
mark_ih_unreachable (ih);
|
||||
|
||||
if (is_indirect_ih (ih))
|
||||
set_free_space (ih, 0);
|
||||
}
|
||||
|
||||
|
||||
void mark_item_reachable (struct item_head * ih, struct buffer_head * bh)
|
||||
{
|
||||
mark_ih_ok (ih);
|
||||
mark_buffer_dirty (bh);
|
||||
}
|
||||
|
||||
|
||||
static void stat_data_in_tree (struct buffer_head *bh,
|
||||
struct item_head * ih)
|
||||
{
|
||||
#if 0
|
||||
__u32 objectid;
|
||||
|
||||
objectid = le32_to_cpu (ih->ih_key.k_objectid);
|
||||
|
||||
if (mark_objectid_really_used (proper_id_map (fs), objectid)) {
|
||||
stat_shared_objectid_found (fs);
|
||||
mark_objectid_really_used (shared_id_map (fs), objectid);
|
||||
}
|
||||
#endif
|
||||
|
||||
zero_nlink (ih, B_I_PITEM (bh, ih));
|
||||
}
|
||||
|
||||
|
||||
/* this just marks blocks pointed by an indirect item as used in the
|
||||
new bitmap */
|
||||
static void indirect_in_tree (struct buffer_head * bh,
|
||||
struct item_head * ih)
|
||||
{
|
||||
int i;
|
||||
__u32 * unp;
|
||||
unsigned long unfm_ptr;
|
||||
|
||||
unp = (__u32 *)B_I_PITEM (bh, ih);
|
||||
|
||||
for (i = 0; i < I_UNFM_NUM (ih); i ++) {
|
||||
unfm_ptr = le32_to_cpu (unp[i]);
|
||||
if (unfm_ptr == 0)
|
||||
continue;
|
||||
|
||||
if (still_bad_unfm_ptr_1 (unfm_ptr))
|
||||
reiserfs_panic ("mark_unformatted_used: (%lu: %k) "
|
||||
"still has bad pointer %lu",
|
||||
bh->b_blocknr, &ih->ih_key, unfm_ptr);
|
||||
|
||||
mark_block_used (unfm_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void leaf_is_in_tree_now (struct buffer_head * bh)
|
||||
{
|
||||
item_action_t actions[] = {stat_data_in_tree, indirect_in_tree, 0, 0};
|
||||
|
||||
mark_block_used ((bh)->b_blocknr);
|
||||
|
||||
for_every_item (bh, mark_item_unreachable, actions);
|
||||
|
||||
stats(fs)->inserted_leaves ++;
|
||||
|
||||
mark_buffer_dirty (bh);
|
||||
}
|
||||
|
||||
|
||||
static void insert_pointer (struct buffer_head * bh, struct path * path)
|
||||
{
|
||||
struct item_head * ih;
|
||||
char * body;
|
||||
int zeros_number;
|
||||
int retval;
|
||||
struct tree_balance tb;
|
||||
|
||||
init_tb_struct (&tb, fs, path, 0x7fff);
|
||||
|
||||
/* fix_nodes & do_balance must work for internal nodes only */
|
||||
ih = 0;
|
||||
|
||||
retval = fix_nodes (/*tb.transaction_handle,*/ M_INTERNAL, &tb, ih);
|
||||
if (retval != CARRY_ON)
|
||||
die ("insert_pointer: fix_nodes failed with retval == %d", retval);
|
||||
|
||||
/* child_pos: we insert after position child_pos: this feature of the insert_child */
|
||||
/* there is special case: we insert pointer after
|
||||
(-1)-st key (before 0-th key) in the parent */
|
||||
if (PATH_LAST_POSITION (path) == 0 && path->pos_in_item == 0)
|
||||
PATH_H_B_ITEM_ORDER (path, 0) = -1;
|
||||
else {
|
||||
if (PATH_H_PPARENT (path, 0) == 0)
|
||||
PATH_H_B_ITEM_ORDER (path, 0) = 0;
|
||||
/* PATH_H_B_ITEM_ORDER (path, 0) = PATH_H_PPARENT (path, 0) ? PATH_H_B_ITEM_ORDER (path, 0) : 0;*/
|
||||
}
|
||||
|
||||
ih = 0;
|
||||
body = (char *)bh;
|
||||
//memmode = 0;
|
||||
zeros_number = 0;
|
||||
|
||||
do_balance (&tb, ih, body, M_INTERNAL, zeros_number);
|
||||
|
||||
leaf_is_in_tree_now (bh);
|
||||
}
|
||||
|
||||
|
||||
/* return 1 if left and right can be joined. 0 otherwise */
|
||||
int balance_condition_fails (struct buffer_head * left, struct buffer_head * right)
|
||||
{
|
||||
if (B_FREE_SPACE (left) >= B_CHILD_SIZE (right) -
|
||||
(are_items_mergeable (B_N_PITEM_HEAD (left, B_NR_ITEMS (left) - 1), B_N_PITEM_HEAD (right, 0), left->b_size) ? IH_SIZE : 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* return 1 if new can be joined with last node on the path or with
|
||||
its right neighbor, 0 otherwise */
|
||||
int balance_condition_2_fails (struct buffer_head * new, struct path * path)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
struct key * right_dkey;
|
||||
int pos, used_space;
|
||||
|
||||
bh = PATH_PLAST_BUFFER (path);
|
||||
|
||||
|
||||
if (balance_condition_fails (bh, new))
|
||||
/* new node can be joined with last buffer on the path */
|
||||
return 1;
|
||||
|
||||
/* new node can not be joined with its left neighbor */
|
||||
|
||||
right_dkey = uget_rkey (path);
|
||||
if (right_dkey == 0)
|
||||
/* there is no right neighbor */
|
||||
return 0;
|
||||
|
||||
pos = PATH_H_POSITION (path, 1);
|
||||
if (pos == B_NR_ITEMS (bh = PATH_H_PBUFFER (path, 1))) {
|
||||
/* we have to read parent of right neighbor. For simplicity we
|
||||
call search_by_key, which will read right neighbor as well */
|
||||
INITIALIZE_PATH(path_to_right_neighbor);
|
||||
|
||||
if (usearch_by_key (fs, right_dkey, &path_to_right_neighbor) != ITEM_FOUND)
|
||||
die ("get_right_neighbor_free_space: invalid right delimiting key");
|
||||
used_space = B_CHILD_SIZE (PATH_PLAST_BUFFER (&path_to_right_neighbor));
|
||||
pathrelse (&path_to_right_neighbor);
|
||||
}
|
||||
else
|
||||
used_space = B_N_CHILD (bh, pos + 1)->dc_size;
|
||||
|
||||
if (B_FREE_SPACE (new) >= used_space -
|
||||
(are_items_mergeable (B_N_PITEM_HEAD (new, B_NR_ITEMS (new) - 1), (struct item_head *)right_dkey, new->b_size) ? IH_SIZE : 0))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void get_max_buffer_key (struct buffer_head * bh, struct key * key)
|
||||
{
|
||||
struct item_head * ih;
|
||||
|
||||
ih = B_N_PITEM_HEAD (bh, B_NR_ITEMS (bh) - 1);
|
||||
copy_key (key, &(ih->ih_key));
|
||||
|
||||
if (is_direntry_key (key)) {
|
||||
/* copy 3-rd and 4-th key components of the last entry */
|
||||
//set_le_key_k_offset (ih_version(ih), key, B_I_DEH (bh, ih)[I_ENTRY_COUNT (ih) - 1].deh_offset);
|
||||
//set_le_key_k_type (ih_version(ih), key, TYPE_DIRENTRY);
|
||||
set_offset (KEY_FORMAT_1, key,
|
||||
le32_to_cpu (B_I_DEH (bh, ih)[ih_entry_count (ih) - 1].deh_offset));
|
||||
|
||||
} else if (!is_stat_data_key (key))
|
||||
/* get key of the last byte, which is contained in the item */
|
||||
set_offset (key_format (key), key, get_offset (key) + get_bytes_number (ih, bh->b_size) - 1);
|
||||
//set_le_key_k_offset(ih_version(ih), key,
|
||||
// le_key_k_offset(ih_version(ih), key) + get_bytes_number (bh, ih, 0, CHECK_FREE_BYTES) - 1 );
|
||||
}
|
||||
|
||||
|
||||
static int tree_is_empty (void)
|
||||
{
|
||||
return (SB_ROOT_BLOCK (fs) == ~0) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static void make_single_leaf_tree (struct buffer_head * bh)
|
||||
{
|
||||
/* tree is empty, make tree root */
|
||||
set_root_block (fs->s_rs, bh->b_blocknr);
|
||||
set_tree_height (fs->s_rs, 2);
|
||||
mark_buffer_dirty (fs->s_sbh);
|
||||
leaf_is_in_tree_now (bh);
|
||||
}
|
||||
|
||||
|
||||
/* inserts pointer to leaf into tree if possible. If not, marks node as
|
||||
uninsertable in special bitmap */
|
||||
static void try_to_insert_pointer_to_leaf (struct buffer_head * new_bh)
|
||||
{
|
||||
INITIALIZE_PATH (path);
|
||||
struct buffer_head * bh; /* last path buffer */
|
||||
struct key * first_bh_key, last_bh_key; /* first and last keys of new buffer */
|
||||
struct key last_path_buffer_last_key, * right_dkey;
|
||||
int ret_value;
|
||||
|
||||
if (tree_is_empty () == 1) {
|
||||
make_single_leaf_tree (new_bh);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
first_bh_key = B_N_PKEY (new_bh, 0);
|
||||
|
||||
/* try to find place in the tree for the first key of the coming node */
|
||||
ret_value = usearch_by_key (fs, first_bh_key, &path);
|
||||
if (ret_value == ITEM_FOUND)
|
||||
goto cannot_insert;
|
||||
|
||||
/* get max key in the new node */
|
||||
get_max_buffer_key (new_bh, &last_bh_key);
|
||||
|
||||
bh = PATH_PLAST_BUFFER (&path);
|
||||
if (comp_keys (B_N_PKEY (bh, 0), &last_bh_key) == 1/* first is greater*/) {
|
||||
/* new buffer falls before the leftmost leaf */
|
||||
if (balance_condition_fails (new_bh, bh))
|
||||
goto cannot_insert;
|
||||
|
||||
if (uget_lkey (&path) != 0 || PATH_LAST_POSITION (&path) != 0)
|
||||
die ("try_to_insert_pointer_to_leaf: bad search result");
|
||||
|
||||
path.pos_in_item = 0;
|
||||
goto insert;
|
||||
}
|
||||
|
||||
/* get max key of buffer, that is in tree */
|
||||
get_max_buffer_key (bh, &last_path_buffer_last_key);
|
||||
if (comp_keys (&last_path_buffer_last_key, first_bh_key) != -1/* second is greater */)
|
||||
/* first key of new buffer falls in the middle of node that is in tree */
|
||||
goto cannot_insert;
|
||||
|
||||
right_dkey = uget_rkey (&path);
|
||||
if (right_dkey && comp_keys (right_dkey, &last_bh_key) != 1 /* first is greater */)
|
||||
goto cannot_insert;
|
||||
|
||||
if (balance_condition_2_fails (new_bh, &path))
|
||||
goto cannot_insert;
|
||||
|
||||
insert:
|
||||
insert_pointer (new_bh, &path);
|
||||
goto out;
|
||||
|
||||
cannot_insert:
|
||||
/* statistic */
|
||||
stats (fs)->uninsertable_leaves ++;
|
||||
|
||||
mark_block_uninsertable (new_bh->b_blocknr);
|
||||
|
||||
out:
|
||||
pathrelse (&path);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* everything should be correct already in the leaf but contents of indirect
|
||||
items. So we only
|
||||
1. zero slots pointing to a leaf
|
||||
2. zero pointers to blocks which are pointed already
|
||||
3. what we should do with directory entries hashed by another hash?
|
||||
they are deleted for now
|
||||
*/
|
||||
static void pass1_correct_leaf (reiserfs_filsys_t s,
|
||||
struct buffer_head * bh)
|
||||
{
|
||||
int i, j;
|
||||
struct item_head * ih;
|
||||
__u32 * ind_item;
|
||||
unsigned long unfm_ptr;
|
||||
int dirty = 0;
|
||||
|
||||
|
||||
ih = B_N_PITEM_HEAD (bh, 0);
|
||||
for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
|
||||
if (is_direntry_ih (ih)) {
|
||||
struct reiserfs_de_head * deh;
|
||||
char * name;
|
||||
int name_len;
|
||||
int hash_code;
|
||||
|
||||
deh = B_I_DEH (bh, ih);
|
||||
for (j = 0; j < ih_entry_count (ih); j ++) {
|
||||
name = name_in_entry (deh + j, j);
|
||||
name_len = name_length (ih, deh + j, j);
|
||||
|
||||
if ((j == 0 && is_dot (name, name_len)) ||
|
||||
(j == 1 && is_dot_dot (name, name_len))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hash_code = find_hash_in_use (name, name_len,
|
||||
GET_HASH_VALUE (deh_offset (deh + j)),
|
||||
rs_hash (fs->s_rs));
|
||||
if (hash_code != rs_hash (fs->s_rs)) {
|
||||
fsck_log ("pass1: block %lu, %H, entry \"%.*s\" "
|
||||
"hashed with %s whereas proper hash is %s\n",
|
||||
bh->b_blocknr, ih, name_len, name,
|
||||
code2name (hash_code), code2name (rs_hash (fs->s_rs)));
|
||||
if (ih_entry_count (ih) == 1) {
|
||||
delete_item (fs, bh, i);
|
||||
i --;
|
||||
ih --;
|
||||
break;
|
||||
} else {
|
||||
cut_entry (fs, bh, i, j, 1);
|
||||
j --;
|
||||
deh = B_I_DEH (bh, ih);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!is_indirect_ih (ih))
|
||||
continue;
|
||||
|
||||
/* correct indirect items */
|
||||
ind_item = (__u32 *)B_I_PITEM (bh, ih);
|
||||
|
||||
for (j = 0; j < I_UNFM_NUM (ih); j ++, ind_item ++) {
|
||||
unfm_ptr = le32_to_cpu (*ind_item);
|
||||
|
||||
if (!unfm_ptr)
|
||||
continue;
|
||||
|
||||
/* this corruption of indirect item had to be fixed in pass0 */
|
||||
if (not_data_block (s, unfm_ptr) || unfm_ptr >= SB_BLOCK_COUNT (s))
|
||||
/*!was_block_used (unfm_ptr))*/
|
||||
reiserfs_panic ("pass1_correct_leaf: (%lu: %k), %d-th slot is not fixed",
|
||||
bh->b_blocknr, &ih->ih_key, j);
|
||||
|
||||
/* 1. zero slots pointing to a leaf */
|
||||
if (is_used_leaf (unfm_ptr)) {
|
||||
dirty ++;
|
||||
*ind_item = 0;
|
||||
stats(fs)->wrong_pointers ++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 2. zero pointers to blocks which are pointed already */
|
||||
if (is_bad_unformatted (unfm_ptr)) {
|
||||
/* this unformatted pointed more than once. Did we see it already? */
|
||||
if (!is_bad_unfm_in_tree_once (unfm_ptr))
|
||||
/* keep first reference to it and mark about that in
|
||||
special bitmap */
|
||||
mark_bad_unfm_in_tree_once (unfm_ptr);
|
||||
else {
|
||||
/* Yes, we have seen this pointer already, zero other pointers to it */
|
||||
dirty ++;
|
||||
*ind_item = 0;
|
||||
stats(fs)->wrong_pointers ++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dirty)
|
||||
mark_buffer_dirty (bh);
|
||||
}
|
||||
|
||||
|
||||
/*######### has to die ##########*/
|
||||
/* append item to end of list. Set head if it is 0. For indirect item
|
||||
set wrong unformatted node pointers to 0 */
|
||||
void save_item (struct si ** head, struct buffer_head * bh, struct item_head * ih, char * item)
|
||||
{
|
||||
struct si * si, * cur;
|
||||
|
||||
if (is_bad_item (bh, ih, item/*, fs->s_blocksize, fs->s_dev*/)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_indirect_ih (ih)) {
|
||||
fsck_progress ("save_item: %H (should not happen)\n", ih);
|
||||
}
|
||||
|
||||
stats(fs)->saved_on_pass1 ++;
|
||||
|
||||
si = getmem (sizeof (*si));
|
||||
si->si_dnm_data = getmem (ih_item_len(ih));
|
||||
/*si->si_blocknr = blocknr;*/
|
||||
memcpy (&(si->si_ih), ih, IH_SIZE);
|
||||
memcpy (si->si_dnm_data, item, ih_item_len(ih));
|
||||
|
||||
// changed by XB
|
||||
si->last_known = NULL;
|
||||
|
||||
if (*head == 0)
|
||||
*head = si;
|
||||
else {
|
||||
cur = *head;
|
||||
// changed by XB
|
||||
// while (cur->si_next)
|
||||
// cur = cur->si_next;
|
||||
|
||||
{
|
||||
int count = 0;
|
||||
int speedcount = 0;
|
||||
|
||||
while (cur->si_next) {
|
||||
if (cur->last_known!=NULL) {
|
||||
cur = cur->last_known; // speed up to the end if the chain
|
||||
speedcount++;
|
||||
} else {
|
||||
cur = cur->si_next;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*head)!=cur) // no self referencing loop please
|
||||
(*head)->last_known = cur;
|
||||
}
|
||||
|
||||
cur->si_next = si;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void save_items (struct si ** head, struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
struct item_head * ih;
|
||||
|
||||
ih = B_N_PITEM_HEAD (bh, 0);
|
||||
for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
|
||||
save_item (head, bh, ih, B_I_PITEM (bh, ih));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct si * remove_saved_item (struct si * si)
|
||||
{
|
||||
struct si * tmp = si->si_next;
|
||||
|
||||
freemem (si->si_dnm_data);
|
||||
freemem (si);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/* insert_item_separately */
|
||||
static void put_saved_items_into_tree_1 (struct si * si)
|
||||
{
|
||||
while (si) {
|
||||
insert_item_separately (&(si->si_ih), si->si_dnm_data,
|
||||
0/*was not in tree*/);
|
||||
si = remove_saved_item (si);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* reads the device by set of 8 blocks, takes leaves and tries to
|
||||
insert them into tree */
|
||||
void pass_1_pass_2_build_the_tree (void)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
int i;
|
||||
int what_node;
|
||||
unsigned long done = 0, total;
|
||||
struct si * saved_items = 0;
|
||||
|
||||
if (fsck_log_file (fs) != stderr)
|
||||
fsck_log ("####### Pass 1 #######\n");
|
||||
|
||||
bad_unfm_in_tree_once_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
|
||||
|
||||
|
||||
/* on pass0 we have found that amount of leaves */
|
||||
total = how_many_leaves_were_there ();
|
||||
|
||||
fsck_progress ("\nPass1:\n");
|
||||
|
||||
/* read all leaves found on the pass 0 */
|
||||
for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) {
|
||||
if (!is_used_leaf (i))
|
||||
continue;
|
||||
|
||||
print_how_far (&done, total, 1, fsck_quiet (fs));
|
||||
|
||||
/* at least one of nr_to_read blocks is to be checked */
|
||||
bh = bread (fs->s_dev, i, fs->s_blocksize);
|
||||
if (!bh) {
|
||||
/* we were reading one block at time, and failed, so mark
|
||||
block bad */
|
||||
fsck_progress ("pass1: reading block %lu failed\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
what_node = who_is_this (bh->b_data, fs->s_blocksize);
|
||||
if ( what_node != THE_LEAF ) {
|
||||
fsck_progress ("build_the_tree: nothing but leaves are expected. "
|
||||
"Block %lu - %s\n", i,
|
||||
(what_node == THE_INTERNAL) ? "internal" : "??");
|
||||
brelse (bh);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_block_used (i))
|
||||
/* block is in new tree already */
|
||||
die ("build_the_tree: leaf (%lu) is in tree already\n", i);
|
||||
|
||||
/* fprintf (block_list, "leaf %d\n", i + j);*/
|
||||
stats(fs)->analyzed ++;
|
||||
|
||||
/* the leaf may still contain indirect items with wrong
|
||||
slots. Fix that */
|
||||
pass1_correct_leaf (fs, bh);
|
||||
|
||||
if (node_item_number (bh) == 0) {
|
||||
/* all items were deleted on pass 0 or pass 1 */
|
||||
mark_buffer_clean (bh);
|
||||
brelse (bh);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_leaf_bad (bh)) {
|
||||
/* FIXME: will die */
|
||||
fsck_log ("pass1: (is_leaf_bad) bad leaf (%lu)\n", bh->b_blocknr);
|
||||
|
||||
/* Save good items only to put them into tree at the
|
||||
end of this pass */
|
||||
save_items (&saved_items, bh);
|
||||
|
||||
brelse (bh);
|
||||
continue;
|
||||
}
|
||||
|
||||
try_to_insert_pointer_to_leaf (bh);
|
||||
brelse (bh);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* read all leaves found on the pass 0 */
|
||||
for (i = 0; i < SB_BLOCK_COUNT (fs); i += nr_to_read) {
|
||||
to_scan = how_many_to_scan (fs, i, nr_to_read);
|
||||
if (to_scan) {
|
||||
print_how_far (&done, total, to_scan, fsck_quiet (fs));
|
||||
|
||||
/* at least one of nr_to_read blocks is to be checked */
|
||||
bbh = bread (fs->s_dev, i / nr_to_read, fs->s_blocksize * nr_to_read);
|
||||
if (bbh) {
|
||||
for (j = 0; j < nr_to_read; j ++) {
|
||||
if (!is_used_leaf (i + j))
|
||||
continue;
|
||||
|
||||
data = bbh->b_data + j * fs->s_blocksize;
|
||||
|
||||
what_node = who_is_this (data, fs->s_blocksize);
|
||||
if ( what_node != THE_LEAF ) {
|
||||
fsck_progress ("build_the_tree: nothing but leaves are expected. "
|
||||
"Block %lu - %s\n", i + j,
|
||||
(what_node == THE_INTERNAL) ? "internal" : "??");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_block_used (i + j))
|
||||
/* block is in new tree already */
|
||||
die ("build_the_tree: leaf (%lu) is in tree already\n",
|
||||
i + j);
|
||||
|
||||
/* fprintf (block_list, "leaf %d\n", i + j);*/
|
||||
|
||||
bh = make_buffer (fs->s_dev, i + j, fs->s_blocksize, data);
|
||||
stats(fs)->analyzed ++;
|
||||
|
||||
/* the leaf may still contain indirect items with wrong
|
||||
slots. Fix that */
|
||||
pass1_correct_leaf (fs, bh);
|
||||
|
||||
if (node_item_number (bh) == 0) {
|
||||
/* all items were deleted on pass 0 or pass 1 */
|
||||
mark_buffer_clean (bh);
|
||||
brelse (bh);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_leaf_bad (bh)) {
|
||||
/* FIXME: will die */
|
||||
fsck_log ("pass1: (is_leaf_bad) bad leaf (%lu)\n", bh->b_blocknr);
|
||||
|
||||
/* Save good items only to put them into tree at the
|
||||
end of this pass */
|
||||
save_items (&saved_items, bh);
|
||||
|
||||
brelse (bh);
|
||||
continue;
|
||||
}
|
||||
|
||||
try_to_insert_pointer_to_leaf (bh);
|
||||
brelse (bh);
|
||||
}
|
||||
|
||||
bforget (bbh);
|
||||
} else {
|
||||
done -= to_scan;
|
||||
|
||||
/* bread failed */
|
||||
if (nr_to_read != 1) {
|
||||
/* we tryied to read bunch of blocks. Try to read them by one */
|
||||
nr_to_read = 1;
|
||||
i --;
|
||||
continue;
|
||||
} else {
|
||||
/* we were reading one block at time, and failed, so mark
|
||||
block bad */
|
||||
fsck_progress ("pass0: block %lu is bad, marked used\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nr_to_read == 1 && ((i + 1) % NR_TO_READ) == 0) {
|
||||
/* we have read NR_TO_READ blocks one at time, switch back to
|
||||
reading NR_TO_READ blocks at time */
|
||||
i -= (NR_TO_READ - 1);
|
||||
nr_to_read = NR_TO_READ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
fsck_progress ("\n");
|
||||
|
||||
/* Pass 1a (this should die) */
|
||||
|
||||
/* put saved items into tree. These items were in leaves, those could not
|
||||
be inserted into tree because some indirect items point to those
|
||||
leaves. Rather than lookup for corresponding unfm pointers in the tree,
|
||||
we save items of those leaves and put them into tree separately */
|
||||
if (how_many_items_were_saved ()) {
|
||||
fsck_progress ("There were %lu saved items\nPass 1a - ",
|
||||
how_many_items_were_saved ());
|
||||
fflush (stdout);
|
||||
put_saved_items_into_tree_1 (saved_items);
|
||||
}
|
||||
|
||||
stage_report (1, fs);
|
||||
/* end of pass 1 */
|
||||
|
||||
|
||||
if (SB_ROOT_BLOCK(fs) == -1)
|
||||
die ("\n\nNo reiserfs metadata found");
|
||||
|
||||
/* pass 2 */
|
||||
pass_2_take_bad_blocks_put_into_tree ();
|
||||
|
||||
flush_buffers ();
|
||||
|
||||
stage_report (2, fs);
|
||||
|
||||
fsck_progress ("Tree is built. Checking it - "); fflush (stdout);
|
||||
reiserfsck_check_pass1 ();
|
||||
fsck_progress ("done\n"); fflush (stdout);
|
||||
|
||||
reiserfs_delete_bitmap (bad_unfm_in_tree_once_bitmap);
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/* pass the S+ tree of filesystem */
|
||||
void recover_internal_tree (struct super_block * s)
|
||||
{
|
||||
check_internal_structure(s);
|
||||
build_the_tree();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void rebuild_sb (reiserfs_filsys_t fs)
|
||||
{
|
||||
int version;
|
||||
struct buffer_head * bh;
|
||||
struct reiserfs_super_block * rs;
|
||||
__u32 blocks;
|
||||
|
||||
|
||||
if (no_reiserfs_found (fs)) {
|
||||
char * answer = 0;
|
||||
size_t n = 0;
|
||||
printf("\nwhat is version of ReiserFS you use[1-4]\n"
|
||||
"\t(1) 3.6.x\n"
|
||||
"\t(2) >=3.5.9\n"
|
||||
"\t(3) < 3.5.9 converted to new format\n"
|
||||
"\t(4) < 3.5.9\n"
|
||||
"\t(X) exit\n");
|
||||
getline (&answer, &n, stdin);
|
||||
version = atoi (answer);
|
||||
if (version < 1 || version > 4)
|
||||
die ("rebuild_sb: wrong version");
|
||||
|
||||
fs->s_blocksize = 4096;
|
||||
|
||||
switch(version){
|
||||
case 1:
|
||||
case 2:
|
||||
bh = getblk (fs->s_dev, (REISERFS_DISK_OFFSET_IN_BYTES / fs->s_blocksize),
|
||||
fs->s_blocksize);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
bh = getblk (fs->s_dev, (2), fs->s_blocksize);
|
||||
break;
|
||||
default:
|
||||
exit(0);
|
||||
}
|
||||
if (!bh)
|
||||
die ("rebuild_sb: can't bread");
|
||||
rs = (struct reiserfs_super_block *)bh->b_data;
|
||||
fs->s_rs = rs;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reiserfs super block is found */
|
||||
version = check_sb(fs);
|
||||
if (!user_confirmed ("\nDo you want to remake your super block\n"
|
||||
"(say no if you use resizer)[Yes/no]: ", "Yes\n"))
|
||||
return;
|
||||
rs = fs->s_rs;
|
||||
bh = fs->s_sbh;
|
||||
}
|
||||
|
||||
// set block number on the device and number of bitmap blocks needed to
|
||||
// address all blocks
|
||||
blocks = (count_blocks ("", fs->s_blocksize, fs->s_dev) / 8) * 8;
|
||||
set_block_count (rs, blocks);
|
||||
//rs->s_block_count = cpu_to_le32(blocks);
|
||||
|
||||
set_bmap_nr (rs, (blocks + (fs->s_blocksize * 8 - 1)) / (fs->s_blocksize * 8));
|
||||
set_journal_size(rs, JOURNAL_BLOCK_COUNT);
|
||||
|
||||
//rs->s_bmap_nr = cpu_to_le16( blocks / (g_sb.s_blocksize * 8) +
|
||||
// ((blocks % (g_sb.s_blocksize * 8)) ? 1 : 0) );
|
||||
|
||||
switch (version){
|
||||
case 1:
|
||||
// super block v2 at 64k offset
|
||||
set_blocksize (rs, fs->s_blocksize);
|
||||
strncpy (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING,
|
||||
strlen(REISER2FS_SUPER_MAGIC_STRING));
|
||||
set_journal_start (rs, get_journal_start_must (fs->s_blocksize));
|
||||
set_version (rs, REISERFS_VERSION_2);
|
||||
set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// super block v1 at 64k offset
|
||||
set_blocksize (rs, fs->s_blocksize);
|
||||
strncpy (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING,
|
||||
strlen(REISERFS_SUPER_MAGIC_STRING));
|
||||
set_journal_start (rs, get_journal_start_must (fs->s_blocksize));
|
||||
set_version (rs, REISERFS_VERSION_1);
|
||||
set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// super block v2 at 8k offset
|
||||
set_blocksize (rs, fs->s_blocksize);
|
||||
strncpy (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING,
|
||||
strlen(REISER2FS_SUPER_MAGIC_STRING));
|
||||
set_journal_start (rs, get_journal_old_start_must (rs));
|
||||
set_version (rs, REISERFS_VERSION_2);
|
||||
set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// super block v1 at 8k offset
|
||||
set_blocksize (rs, fs->s_blocksize);
|
||||
strncpy (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING,
|
||||
strlen(REISERFS_SUPER_MAGIC_STRING));
|
||||
set_journal_start (rs, get_journal_old_start_must (rs));
|
||||
set_version (rs, REISERFS_VERSION_1);
|
||||
set_objectid_map_max_size (rs, (fs->s_blocksize - SB_SIZE_V1) / sizeof(__u32) / 2 * 2);
|
||||
break;
|
||||
}
|
||||
|
||||
print_block (stderr, fs, bh);
|
||||
if (user_confirmed ("Is this ok ? [N/Yes]: ", "Yes\n")) {
|
||||
mark_buffer_uptodate (bh, 1);
|
||||
mark_buffer_dirty (bh);
|
||||
bwrite (bh);
|
||||
fsck_progress ("\nDo not forget to run reiserfsck --rebuild-tree\n\n");
|
||||
} else
|
||||
fsck_progress ("Super block was not written\n");
|
||||
brelse (bh);
|
||||
}
|
||||
|
||||
/*
|
||||
check_sb and rebuild-sb don't touch these fields:
|
||||
__u32 s_journal_dev;
|
||||
__u32 s_journal_trans_max ;
|
||||
__u32 s_journal_block_count ;
|
||||
__u32 s_journal_max_batch ;
|
||||
__u32 s_journal_max_commit_age ;
|
||||
__u32 s_journal_max_trans_age ;
|
||||
|
||||
others are checked and set in either rebuild_sb or rebuild-tree
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+485
@@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Copyright 1996-2001 Hans Reiser
|
||||
*/
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
|
||||
/* on pass2 we take leaves which could not be inserted into tree
|
||||
during pass1 and insert each item separately. It is possible that
|
||||
items of different objects with the same key can be found. We treat
|
||||
that in the following way: we put it into tree with new key and
|
||||
link it into /lost+found directory with name made of dir,oid. When
|
||||
coming item is a directory - we delete object from the tree, put it
|
||||
back with different key, link it to /lost+found directory and
|
||||
insert directory as it is */
|
||||
|
||||
/* relocation rules: we have an item (it is taken from "non-insertable"
|
||||
leaf). It has original key yet. We check to see if object with this
|
||||
key is remapped. Object can be only remapped if it is not a piece
|
||||
of directory */
|
||||
|
||||
|
||||
/* in list of this structures we store what has been
|
||||
relocated. */
|
||||
struct relocated {
|
||||
unsigned long old_dir_id;
|
||||
unsigned long old_objectid;
|
||||
unsigned long new_objectid;
|
||||
/*mode_t mode;*/
|
||||
struct relocated * next;
|
||||
};
|
||||
|
||||
|
||||
/* all relocated files will be linked into lost+found directory at the
|
||||
beginning of semantic pass */
|
||||
struct relocated * relocated_list;
|
||||
|
||||
|
||||
/* return objectid the object has to be remapped with */
|
||||
__u32 objectid_for_relocation (struct key * key)
|
||||
{
|
||||
struct relocated * cur;
|
||||
|
||||
cur = relocated_list;
|
||||
|
||||
while (cur) {
|
||||
if (cur->old_dir_id == key->k_dir_id &&
|
||||
cur->old_objectid == key->k_objectid)
|
||||
/* object is relocated already */
|
||||
return cur->new_objectid;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
cur = getmem (sizeof (struct relocated));
|
||||
cur->old_dir_id = key->k_dir_id;
|
||||
cur->old_objectid = key->k_objectid;
|
||||
cur->new_objectid = get_unused_objectid (fs);
|
||||
cur->next = relocated_list;
|
||||
relocated_list = cur;
|
||||
fsck_log ("relocation: (%K) is relocated to (%lu, %lu)\n",
|
||||
key, key->k_dir_id, cur->new_objectid);
|
||||
return cur->new_objectid;
|
||||
}
|
||||
|
||||
|
||||
/* this item is in tree. All unformatted pointer are correct. Do not
|
||||
check them */
|
||||
static void save_item_2 (struct si ** head, struct item_head * ih,
|
||||
char * item, __u32 blocknr)
|
||||
{
|
||||
struct si * si, * cur;
|
||||
|
||||
si = getmem (sizeof (*si));
|
||||
si->si_dnm_data = getmem (ih_item_len(ih));
|
||||
/*si->si_blocknr = blocknr;*/
|
||||
memcpy (&(si->si_ih), ih, IH_SIZE);
|
||||
memcpy (si->si_dnm_data, item, ih_item_len(ih));
|
||||
|
||||
if (*head == 0)
|
||||
*head = si;
|
||||
else {
|
||||
cur = *head;
|
||||
while (cur->si_next)
|
||||
cur = cur->si_next;
|
||||
cur->si_next = si;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
struct si * save_and_delete_file_item (struct si * si, struct path * path)
|
||||
{
|
||||
struct buffer_head * bh = PATH_PLAST_BUFFER (path);
|
||||
struct item_head * ih = PATH_PITEM_HEAD (path);
|
||||
|
||||
save_item_2 (&si, ih, B_I_PITEM (bh, ih), bh->b_blocknr);
|
||||
|
||||
/* delete item temporary - do not free unformatted nodes */
|
||||
reiserfsck_delete_item (path, 1/*temporary*/);
|
||||
return si;
|
||||
}
|
||||
|
||||
|
||||
/* check whether there are any directory items with this key */
|
||||
static int should_relocate (struct item_head * ih)
|
||||
{
|
||||
struct key key;
|
||||
struct key * rkey;
|
||||
struct path path;
|
||||
struct item_head * path_ih;
|
||||
|
||||
|
||||
/* starting with the leftmost item with this key */
|
||||
key = ih->ih_key;
|
||||
set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA);
|
||||
|
||||
while (1) {
|
||||
usearch_by_key (fs, &key, &path);
|
||||
if (get_item_pos (&path) == B_NR_ITEMS (get_bh (&path))) {
|
||||
rkey = uget_rkey (&path);
|
||||
if (rkey && !not_of_one_file (&key, rkey)) {
|
||||
/* file continues in the right neighbor */
|
||||
key = *rkey;
|
||||
pathrelse (&path);
|
||||
continue;
|
||||
}
|
||||
/* there is no more items with this key */
|
||||
pathrelse (&path);
|
||||
break;
|
||||
}
|
||||
|
||||
path_ih = get_ih (&path);
|
||||
if (not_of_one_file (&key, &(path_ih->ih_key))) {
|
||||
/* there are no more item with this key */
|
||||
pathrelse (&path);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ok, item found, but make sure that it is not a directory one */
|
||||
if ((is_stat_data_ih (path_ih) && !not_a_directory (get_item (&path))) ||
|
||||
(is_direntry_ih (path_ih))) {
|
||||
/* item of directory found. so, we have to relocate the file */
|
||||
pathrelse (&path);
|
||||
return 1;
|
||||
}
|
||||
key = path_ih->ih_key;
|
||||
set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1);
|
||||
pathrelse (&path);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* delete all items (but directory ones) with the same key 'ih' has
|
||||
(including stat data of not a directory) and put them back at the
|
||||
other place */
|
||||
void relocate_file (struct item_head * ih, int change_ih)
|
||||
{
|
||||
struct key key;
|
||||
struct key * rkey;
|
||||
struct path path;
|
||||
struct item_head * path_ih;
|
||||
struct si * si;
|
||||
__u32 new_objectid;
|
||||
|
||||
|
||||
/* starting with the leftmost one - look for all items of file,
|
||||
store them and delete */
|
||||
key = ih->ih_key;
|
||||
set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA);
|
||||
|
||||
si = 0;
|
||||
while (1) {
|
||||
usearch_by_key (fs, &key, &path);
|
||||
if (get_item_pos (&path) == B_NR_ITEMS (get_bh (&path))) {
|
||||
rkey = uget_rkey (&path);
|
||||
if (rkey && !not_of_one_file (&key, rkey)) {
|
||||
/* file continues in the right neighbor */
|
||||
key = *rkey;
|
||||
pathrelse (&path);
|
||||
continue;
|
||||
}
|
||||
/* there is no more items with this key */
|
||||
pathrelse (&path);
|
||||
break;
|
||||
}
|
||||
|
||||
path_ih = get_ih (&path);
|
||||
if (not_of_one_file (&key, &(path_ih->ih_key))) {
|
||||
/* there are no more item with this key */
|
||||
pathrelse (&path);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ok, item found, but make sure that it is not a directory one */
|
||||
if ((is_stat_data_ih (path_ih) && !not_a_directory (get_item (&path))) ||
|
||||
(is_direntry_ih (path_ih))) {
|
||||
/* item of directory found. Leave it in the tree */
|
||||
key = path_ih->ih_key;
|
||||
set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1);
|
||||
pathrelse (&path);
|
||||
continue;
|
||||
}
|
||||
|
||||
si = save_and_delete_file_item (si, &path);
|
||||
}
|
||||
|
||||
|
||||
if (si || change_ih) {
|
||||
int moved_items;
|
||||
struct key old, new;
|
||||
|
||||
/* get new objectid for relocation or get objectid with which file
|
||||
was relocated already */
|
||||
new_objectid = objectid_for_relocation (&ih->ih_key);
|
||||
if (change_ih)
|
||||
ih->ih_key.k_objectid = new_objectid;
|
||||
|
||||
moved_items = 0;
|
||||
|
||||
/* put all items removed back into tree */
|
||||
while (si) {
|
||||
/*fsck_log ("relocate_file: move %H to ", &si->si_ih);*/
|
||||
old = si->si_ih.ih_key;
|
||||
si->si_ih.ih_key.k_objectid = new_objectid;
|
||||
new = si->si_ih.ih_key;
|
||||
/*fsck_log ("%H\n", &si->si_ih);*/
|
||||
insert_item_separately (&(si->si_ih), si->si_dnm_data, 1/*was in tree*/);
|
||||
si = remove_saved_item (si);
|
||||
moved_items ++;
|
||||
}
|
||||
if (moved_items)
|
||||
fsck_log ("relocate_file: %d items of file %K moved to %K\n",
|
||||
moved_items, &old, &new);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* this works for both new and old stat data */
|
||||
#define st_mode(sd) le16_to_cpu(((struct stat_data *)(sd))->sd_mode)
|
||||
|
||||
#define st_mtime_v1(sd) le32_to_cpu(((struct stat_data_v1 *)(sd))->sd_mtime)
|
||||
#define st_mtime_v2(sd) le32_to_cpu(((struct stat_data *)(sd))->sd_mtime)
|
||||
|
||||
static void overwrite_stat_data (struct item_head * new_ih,
|
||||
void * new_item, struct path * path)
|
||||
{
|
||||
if (stat_data_v1 (new_ih)) {
|
||||
if (st_mtime_v1 (new_item) > st_mtime_v1 (get_item (path))) {
|
||||
memcpy (get_item (path), new_item, SD_V1_SIZE);
|
||||
mark_buffer_dirty (get_bh (path));
|
||||
}
|
||||
} else {
|
||||
if (st_mtime_v2 (new_item) > st_mtime_v2 (get_item (path))) {
|
||||
memcpy (get_item (path), new_item, SD_SIZE);
|
||||
mark_buffer_dirty (get_bh (path));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* insert sd item if it does not exist, overwrite it otherwise */
|
||||
static void put_sd_into_tree (struct item_head * new_ih, char * new_item)
|
||||
{
|
||||
struct path path;
|
||||
|
||||
if (!not_a_directory (new_item)) {
|
||||
/* new item is a stat data of a directory. So we have to
|
||||
relocate all items which have the same short key and are of
|
||||
not a directory */
|
||||
relocate_file (new_ih, 0/*do not change new_ih*/);
|
||||
} else {
|
||||
/* new item is a stat data of something else but directory. If
|
||||
there are items of directory - we have to relocate the file */
|
||||
if (should_relocate (new_ih))
|
||||
relocate_file (new_ih, 1/*change new_ih*/);
|
||||
}
|
||||
|
||||
/* if we will have to insert item into tree - it is ready */
|
||||
zero_nlink (new_ih, new_item);
|
||||
mark_item_unreachable (new_ih);
|
||||
|
||||
/* we are sure now that if we are inserting stat data of a
|
||||
directory - there are no items with the same key which are not
|
||||
items of a directory, and that if we are inserting stat data is
|
||||
of not a directory - it either has new key already or there are
|
||||
no items with this key which are items of a directory */
|
||||
if (usearch_by_key (fs, &(new_ih->ih_key), &path) == ITEM_FOUND) {
|
||||
/* this stat data is found */
|
||||
if (ih_key_format (get_ih(&path)) != ih_key_format (new_ih)) {
|
||||
/* in tree stat data and a new one are of different
|
||||
formats */
|
||||
fsck_log ("put_sd_into_tree: inserting stat data %K (%M)..",
|
||||
&(new_ih->ih_key), st_mode (new_item));
|
||||
if (stat_data_v1 (new_ih)) {
|
||||
/* sd to be inserted is of V1, where as sd in the tree
|
||||
is of V2 */
|
||||
fsck_log ("found newer in the tree (%M), skip inserting\n",
|
||||
st_mode (get_item (&path)));
|
||||
} else {
|
||||
/* the stat data in the tree is sd_v1 */
|
||||
fsck_log ("older sd (%M) is replaced with it\n",
|
||||
st_mode (get_item (&path)));
|
||||
reiserfsck_delete_item (&path, 0/*not temporary*/);
|
||||
|
||||
usearch_by_key (fs, &new_ih->ih_key, &path);
|
||||
reiserfsck_insert_item (&path, new_ih, new_item);
|
||||
}
|
||||
} else {
|
||||
/* both stat data are of the same version */
|
||||
overwrite_stat_data (new_ih, new_item, &path);
|
||||
pathrelse (&path);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* item not found, insert a new one */
|
||||
reiserfsck_insert_item (&path, new_ih, new_item);
|
||||
}
|
||||
|
||||
|
||||
/* this tries to put each item entry to the tree, if there is no items
|
||||
of the directory, insert item containing 1 entry */
|
||||
static void put_directory_item_into_tree (struct item_head * comingih, char * item)
|
||||
{
|
||||
struct reiserfs_de_head * deh;
|
||||
int i;
|
||||
char * buf;
|
||||
char * name;
|
||||
int namelen;
|
||||
|
||||
/* if there are anything ith this key but a directory - move it
|
||||
somewhere else */
|
||||
relocate_file (comingih, 0/* do not change ih */);
|
||||
|
||||
deh = (struct reiserfs_de_head *)item;
|
||||
|
||||
for (i = 0; i < ih_entry_count (comingih); i ++, deh ++) {
|
||||
name = name_in_entry (deh, i);
|
||||
namelen = name_length (comingih, deh, i);
|
||||
|
||||
if (!is_properly_hashed (fs, name, namelen, deh_offset (deh)))
|
||||
reiserfs_panic ("put_directory_item_into_tree: should be hashed properly ()");
|
||||
|
||||
asprintf (&buf, "%.*s", namelen, name);
|
||||
/* 1 for fsck is important: if there is no any items of this
|
||||
directory in the tree yet - new item will be inserted
|
||||
marked not reached */
|
||||
reiserfs_add_entry (fs, &(comingih->ih_key), buf, (struct key *)&(deh->deh_dir_id), 1/*fsck_need*/);
|
||||
free (buf);
|
||||
}
|
||||
|
||||
/* make a directory */
|
||||
}
|
||||
|
||||
|
||||
/* relocated files get added into lost+found with slightly different names */
|
||||
static void link_one (struct relocated * file)
|
||||
{
|
||||
char * name;
|
||||
struct key obj_key;
|
||||
|
||||
asprintf (&name, "%lu,%lu", file->old_dir_id, file->new_objectid);
|
||||
obj_key.k_dir_id = file->old_dir_id;
|
||||
obj_key.k_objectid = file->new_objectid;
|
||||
|
||||
/* 0 for fsck_need does not mean too much - it would make effect
|
||||
if there were no this directory yet. But /lost_found is there
|
||||
already */
|
||||
reiserfs_add_entry (fs, &lost_found_dir_key, name, &obj_key, 0/*fsck_need*/);
|
||||
stats(fs)->relocated ++;
|
||||
free (name);
|
||||
}
|
||||
|
||||
|
||||
void link_relocated_files (void)
|
||||
{
|
||||
struct relocated * tmp;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
while (relocated_list) {
|
||||
link_one (relocated_list);
|
||||
tmp = relocated_list;
|
||||
relocated_list = relocated_list->next;
|
||||
freemem (tmp);
|
||||
count ++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void insert_item_separately (struct item_head * ih,
|
||||
char * item, int was_in_tree)
|
||||
{
|
||||
if (ih->ih_key.k_dir_id == ih->ih_key.k_objectid)
|
||||
reiserfs_panic ("insert_item_separately: can not insert bad item %H", ih);
|
||||
|
||||
if (is_stat_data_ih (ih)) {
|
||||
put_sd_into_tree (ih, item);
|
||||
} else if (is_direntry_ih (ih)) {
|
||||
put_directory_item_into_tree (ih, item);
|
||||
} else {
|
||||
if (should_relocate (ih))
|
||||
relocate_file (ih, 1/*change new_ih*/);
|
||||
|
||||
reiserfsck_file_write (ih, item, was_in_tree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void put_items (struct buffer_head * bh)
|
||||
{
|
||||
int i;
|
||||
struct item_head * ih;
|
||||
|
||||
ih = B_N_PITEM_HEAD (bh, 0);
|
||||
for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
|
||||
if (i && bad_pair (fs, bh, i)) {
|
||||
/* skip item if it is in wrong order */
|
||||
continue;
|
||||
}
|
||||
insert_item_separately (ih, B_I_PITEM (bh, ih), 0/*was in tree*/);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* uninsertable blocks are marked by 0s in uninsertable_leaf_bitmap
|
||||
during the pass 1. They must be not in the tree */
|
||||
void pass_2_take_bad_blocks_put_into_tree (void)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
unsigned long j;
|
||||
unsigned long bb_counter = 0;
|
||||
int what_node;
|
||||
|
||||
|
||||
if (!stats(fs)->uninsertable_leaves)
|
||||
return;
|
||||
|
||||
if (fsck_log_file (fs) != stderr)
|
||||
fsck_log ("####### Pass 2 #######\n");
|
||||
|
||||
fsck_progress ("\nPass2:\n");
|
||||
|
||||
j = 0;
|
||||
while (reiserfs_bitmap_find_zero_bit (uninsertable_leaf_bitmap, &j) == 0) {
|
||||
bh = bread (fs->s_dev, j, fs->s_blocksize);
|
||||
if (bh == 0) {
|
||||
fsck_log ("pass_2_take_bad_blocks_put_into_tree: "
|
||||
"unable to read %lu block on device 0x%x\n",
|
||||
j, fs->s_dev);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (is_block_used (bh->b_blocknr)) {
|
||||
fsck_log ("pass_2_take_bad_blocks_put_into_tree: "
|
||||
"block %d can not be in tree\n", bh->b_blocknr);
|
||||
goto next;
|
||||
}
|
||||
/* this must be leaf */
|
||||
what_node = who_is_this (bh->b_data, fs->s_blocksize);
|
||||
if (what_node != THE_LEAF) { // || B_IS_KEYS_LEVEL(bh)) {
|
||||
fsck_log ("take_bad_blocks_put_into_tree: buffer (%b %z) must contain leaf\n", bh, bh);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/*fsck_log ("block %lu is being inserted\n", bh->b_blocknr);*/
|
||||
put_items (bh);
|
||||
|
||||
print_how_far (&bb_counter, stats(fs)->uninsertable_leaves, 1, fsck_quiet (fs));
|
||||
|
||||
next:
|
||||
brelse (bh);
|
||||
j ++;
|
||||
}
|
||||
|
||||
fsck_progress ("\n");
|
||||
|
||||
|
||||
if (bb_counter != stats(fs)->uninsertable_leaves)
|
||||
die ("take_bad_blocks_put_into_tree: found bad block %d, must be %d",
|
||||
bb_counter, stats(fs)->uninsertable_leaves);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 1996, 1997, 1998 Hans Reiser
|
||||
*/
|
||||
#include "fsck.h"
|
||||
|
||||
|
||||
void get_next_key (struct path * path, int i, struct key * key)
|
||||
{
|
||||
struct buffer_head * bh = PATH_PLAST_BUFFER (path);
|
||||
struct key * rkey;
|
||||
|
||||
|
||||
if (i < B_NR_ITEMS (bh) - 1) {
|
||||
/* next item is in this block */
|
||||
copy_key (key, B_N_PKEY (bh, i + 1));
|
||||
return;
|
||||
}
|
||||
|
||||
rkey = uget_rkey (path);
|
||||
if (rkey) {
|
||||
/* got next item key from right delimiting key */
|
||||
copy_key (key, rkey);
|
||||
} else {
|
||||
/* there is no next item */
|
||||
memset (key, 0xff, KEY_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int pass_4_check_unaccessed_items (void)
|
||||
{
|
||||
struct key key;
|
||||
struct path path;
|
||||
int i;
|
||||
struct buffer_head * bh;
|
||||
struct item_head * ih;
|
||||
unsigned long items;
|
||||
|
||||
path.path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
|
||||
key = root_dir_key;
|
||||
|
||||
fsck_progress ("Pass 4 - ");
|
||||
items = 0;
|
||||
|
||||
while (usearch_by_key (fs, &key, &path) == ITEM_FOUND) {
|
||||
bh = PATH_PLAST_BUFFER (&path);
|
||||
|
||||
/* print ~ how many leaves were scanned and how fast it was */
|
||||
if (!fsck_quiet (fs))
|
||||
print_how_fast (0, items++, 50);
|
||||
|
||||
for (i = get_item_pos (&path), ih = get_ih (&path); i < B_NR_ITEMS (bh); i ++, ih ++) {
|
||||
|
||||
|
||||
if (!is_item_reachable (ih)) {
|
||||
|
||||
get_next_key (&path, i, &key);
|
||||
|
||||
stats(fs)->deleted_items ++;
|
||||
|
||||
PATH_LAST_POSITION (&path) = i;
|
||||
reiserfsck_delete_item (&path, 0);
|
||||
|
||||
goto cont;
|
||||
}
|
||||
}
|
||||
get_next_key (&path, i - 1, &key);
|
||||
pathrelse (&path);
|
||||
|
||||
cont:
|
||||
}
|
||||
|
||||
pathrelse (&path);
|
||||
|
||||
fsck_progress ("done\n");
|
||||
stage_report (4, fs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
.\" -*- nroff -*-
|
||||
.\" Copyright 1996-2001 Hans Reiser.
|
||||
.\"
|
||||
.TH REISERFSCK 8 "March 2001" "Reiserfsprogs-3.x.0j"
|
||||
.SH NAME
|
||||
reiserfsck \- check a Linux Reiserfs file system
|
||||
.SH SYNOPSIS
|
||||
.B reiserfsck
|
||||
[
|
||||
.B -arvixoV
|
||||
] [
|
||||
.B -l logfilename
|
||||
] [
|
||||
.B --rebuild-tree
|
||||
] [
|
||||
.B --check
|
||||
] [
|
||||
.B --rebuild-sb
|
||||
] [
|
||||
.B --interactive
|
||||
] [
|
||||
\fB --logfile \fI logfilename
|
||||
] [
|
||||
.B --fix-fixable
|
||||
]
|
||||
.I device
|
||||
.SH DESCRIPTION
|
||||
It looks for reiserfs filesystem on a device, replays transactions
|
||||
which are to be replayed and either check or repair the filesystem
|
||||
.TP
|
||||
.I device
|
||||
is the special file corresponding to the device (e.g /dev/hdXX for
|
||||
IDE disk partition or /dev/sdXX for SCSI disk partition).
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B --check
|
||||
This checks filesystem consistency. This is a default action. It may
|
||||
be used on a filesystem mounted read-only
|
||||
.TP
|
||||
.B --rebuild-tree
|
||||
This rebuilds filesystem tree using leaf nodes found on the
|
||||
device. Normally, you do not need this, but if you have to rebuild
|
||||
tree - please backup whole partition first or at least the most
|
||||
important data if you can mount the partition.
|
||||
.TP
|
||||
.B --rebuild-sb
|
||||
.TP
|
||||
.B --interactive, -i
|
||||
This makes \fBreiserfsck\fR to stop after each pass completed.
|
||||
.TP
|
||||
.B --quiet, -q
|
||||
have \fBreiserfsck\fR to not reflect its progress
|
||||
.TP
|
||||
.B --nolog, -n
|
||||
have \fBreiserfsck\fR to not log anything
|
||||
.TP
|
||||
\fB--logfile \fIfilename\fR, \fB-l \fI filename
|
||||
have \fBreiserfsck\fR to put info about found corruptions in logfile
|
||||
rather than on stderr
|
||||
.TP
|
||||
.B --fix-fixable, -x
|
||||
have \fBreiserfsck\fR to recover corruptions which can be fixed w/o
|
||||
--rebuild-tree when it is runnig in check mode. Corruptions which can
|
||||
be fixed so far: bad pointers to data blocks, wrong directory's
|
||||
st_size and st_blocks, directories entries pointing to nowhere can be
|
||||
deleted
|
||||
.TP
|
||||
.B --fix-non-critical, -o
|
||||
have \fBreiserfsck\fR to fix: file sizes when they are bigger than
|
||||
real file size, set file mode to regular file when mode looks wrong
|
||||
and to try to recover "objectid sharing" problem
|
||||
.TP
|
||||
.B -a
|
||||
When it is set - \fBreiserfsck\fR assumes that it is called by fsck -A
|
||||
and just returns even if filesystem seems not umounted cleanly
|
||||
.TP
|
||||
.B -r
|
||||
ignored
|
||||
.TP
|
||||
.B -V
|
||||
Prints version and exits
|
||||
.SH AUTHOR
|
||||
This version of \fBreiserfsck\fR has been written by Hans Reiser
|
||||
<reiser@idiom.com>.
|
||||
.SH BUGS
|
||||
There are probably few of them. Please, report bugs to Hans Reiser <reiser@idiom.com>.
|
||||
.SH TODO
|
||||
Faster recovering, signal handling, i/o error handling, etc.
|
||||
.SH SEE ALSO
|
||||
.BR mkreiserfs (8),
|
||||
.BR debugreiserfs (8)
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 1998 Hans Reiser
|
||||
*/
|
||||
/*#include <stdio.h>
|
||||
#include <string.h>*/
|
||||
/*#include <asm/bitops.h>
|
||||
#include "../include/reiserfs_fs.h"
|
||||
#include "../include/reiserfs_fs_sb.h"
|
||||
#include "../include/reiserfslib.h"*/
|
||||
#include "fsck.h"
|
||||
|
||||
|
||||
/* there is a situation, when we overwrite contents of unformatted
|
||||
node with direct item. One unformatted node can be overwritten
|
||||
several times by direct items */
|
||||
/*
|
||||
struct overwritten_unfm_segment {
|
||||
int ous_begin;
|
||||
int ous_end;
|
||||
struct overwritten_unfm_segment * ous_next;
|
||||
};
|
||||
*/
|
||||
struct overwritten_unfm {
|
||||
unsigned long ou_unfm_ptr; /* block number of unfm node */
|
||||
unsigned long ou_dir_id;
|
||||
unsigned long ou_objectid; /* key corresponding to an unfm node */
|
||||
unsigned long ou_offset;
|
||||
|
||||
struct overwritten_unfm_segment * ou_segments; /* list of segmens, than have been overwritten in ths unfm node */
|
||||
};
|
||||
|
||||
struct overwritten_unfm ** g_overwritten_unfms;
|
||||
int g_overwritten_unfms_amount; /* number of unformatted nodes, which contain direct items */
|
||||
|
||||
|
||||
/* adds segment to the single linked list of segments sorted by begin
|
||||
field. Retuns pointer to first element of list */
|
||||
static struct overwritten_unfm_segment * add_segment (struct overwritten_unfm_segment * first, int begin, int end)
|
||||
{
|
||||
struct overwritten_unfm_segment * new, * next, * prev;
|
||||
|
||||
new = getmem (sizeof (struct overwritten_unfm_segment));
|
||||
new->ous_begin = begin;
|
||||
new->ous_end = end;
|
||||
new->ous_next = 0;
|
||||
|
||||
next = first;
|
||||
prev = 0;
|
||||
while (next) {
|
||||
if (next->ous_begin > begin)
|
||||
break;
|
||||
prev = next;
|
||||
next = next->ous_next;
|
||||
}
|
||||
|
||||
if (prev == 0) {
|
||||
/* insert into head of list */
|
||||
first = new;
|
||||
} else {
|
||||
prev->ous_next = new;
|
||||
}
|
||||
new->ous_next = next;
|
||||
return first;
|
||||
}
|
||||
|
||||
|
||||
/* input parameter
|
||||
`list_head` - first element of overlapping segments sorted by left edge
|
||||
`unoverwritten_segment` - returned by previous call of get_unoverwritten_segment or (-2,-2) if called first time
|
||||
*/
|
||||
/* returns
|
||||
1 and segment unoverwritten by elements of list `list_head`
|
||||
0 if there isno such segment
|
||||
*/
|
||||
int get_unoverwritten_segment (struct overwritten_unfm_segment * list_head, struct overwritten_unfm_segment * unoverwritten_segment)
|
||||
{
|
||||
int end;
|
||||
|
||||
/* look for segment, which has begin field greater than end of previous interval */
|
||||
while (list_head->ous_begin <= unoverwritten_segment->ous_end) {
|
||||
list_head = list_head->ous_next;
|
||||
}
|
||||
/* look for the end of the continuous region covered by otrezkami */
|
||||
end = list_head->ous_end;
|
||||
while (list_head->ous_next) {
|
||||
if (list_head->ous_next->ous_begin > end + 1)
|
||||
/* intreval found */
|
||||
break;
|
||||
if (list_head->ous_next->ous_end > end)
|
||||
end = list_head->ous_next->ous_end;
|
||||
list_head = list_head->ous_next;
|
||||
}
|
||||
/* ok, between segment and segment->next we have an interval (segment->next != 0) */
|
||||
if (list_head->ous_next != 0) {
|
||||
unoverwritten_segment->ous_begin = end + 1;
|
||||
unoverwritten_segment->ous_end = list_head->ous_next->ous_begin - 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void print_segments (struct overwritten_unfm_segment * list_head)
|
||||
{
|
||||
struct overwritten_unfm_segment * cur;
|
||||
|
||||
cur = list_head;
|
||||
while (cur) {
|
||||
printf ("%s%d %d%s", cur == list_head ? "(" : "", cur->ous_begin, cur->ous_end, cur->ous_next ? ", " : ")\n");
|
||||
cur = cur->ous_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* this prepare list of segments to extracting of unoverwritten segments */
|
||||
struct overwritten_unfm_segment * find_overwritten_unfm (unsigned long unfm, int length, struct overwritten_unfm_segment * segment_to_init)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++)
|
||||
if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm) {
|
||||
if (g_overwritten_unfms[i]->ou_segments == 0)
|
||||
die ("find_overwritten_unfm: no segment found");
|
||||
g_overwritten_unfms[i]->ou_segments = add_segment (g_overwritten_unfms[i]->ou_segments, -1, -1);
|
||||
add_segment (g_overwritten_unfms[i]->ou_segments, length, length);
|
||||
segment_to_init->ous_begin = -2;
|
||||
segment_to_init->ous_end = -2;
|
||||
return g_overwritten_unfms[i]->ou_segments;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct overwritten_unfm * look_for_overwritten_unfm (__u32 unfm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++)
|
||||
if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm)
|
||||
return g_overwritten_unfms[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GROW_BY 10
|
||||
struct overwritten_unfm * add_overwritten_unfm (unsigned long unfm, struct item_head * direct_ih)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i] != 0; i ++) {
|
||||
if (g_overwritten_unfms[i]->ou_unfm_ptr == unfm)
|
||||
return g_overwritten_unfms[i];
|
||||
}
|
||||
|
||||
if (i == g_overwritten_unfms_amount) {
|
||||
g_overwritten_unfms = expandmem (g_overwritten_unfms, sizeof (struct overwritten_unfm *) * i,
|
||||
sizeof (struct overwritten_unfm *) * GROW_BY);
|
||||
g_overwritten_unfms_amount += GROW_BY;
|
||||
}
|
||||
g_overwritten_unfms[i] = getmem (sizeof (struct overwritten_unfm));
|
||||
g_overwritten_unfms[i]->ou_unfm_ptr = unfm;
|
||||
g_overwritten_unfms[i]->ou_dir_id = direct_ih->ih_key.k_dir_id;
|
||||
g_overwritten_unfms[i]->ou_objectid = direct_ih->ih_key.k_objectid;
|
||||
g_overwritten_unfms[i]->ou_offset = get_offset(&direct_ih->ih_key) - (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize;
|
||||
return g_overwritten_unfms[i];
|
||||
}
|
||||
|
||||
|
||||
void save_unfm_overwriting (unsigned long unfm, struct item_head * direct_ih)
|
||||
{
|
||||
struct overwritten_unfm * ov_unfm;
|
||||
|
||||
/* add new overwritten unfm or return existing one */
|
||||
ov_unfm = add_overwritten_unfm (unfm, direct_ih);
|
||||
ov_unfm->ou_segments = add_segment (ov_unfm->ou_segments, (get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize,
|
||||
(get_offset(&direct_ih->ih_key) - 1) % fs->s_blocksize + ih_item_len (direct_ih) - 1);
|
||||
}
|
||||
|
||||
|
||||
void free_overwritten_unfms (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < g_overwritten_unfms_amount && g_overwritten_unfms[i]; i ++) {
|
||||
/* free all segments */
|
||||
while (g_overwritten_unfms[i]->ou_segments) {
|
||||
struct overwritten_unfm_segment * tmp;
|
||||
|
||||
tmp = g_overwritten_unfms[i]->ou_segments->ous_next;
|
||||
freemem (g_overwritten_unfms[i]->ou_segments);
|
||||
g_overwritten_unfms[i]->ou_segments = tmp;
|
||||
}
|
||||
/* free struct overwritten_unfm */
|
||||
freemem (g_overwritten_unfms[i]);
|
||||
}
|
||||
|
||||
/* free array of pointers to overwritten unfms */
|
||||
if (g_overwritten_unfms)
|
||||
freemem (g_overwritten_unfms);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+1346
File diff suppressed because it is too large.
Load diff
+189
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 1996-1999 Hans Reiser
|
||||
*/
|
||||
|
||||
#include "fsck.h"
|
||||
|
||||
/* g_disk_bitmap initially contains copy of disk bitmaps
|
||||
(cautious version of it);
|
||||
|
||||
g_new_bitmap initially has marked only super block, bitmap blocks
|
||||
and bits after the end of bitmap
|
||||
|
||||
in pass 1 we go through g_disk_bitmap.
|
||||
|
||||
If block does not look like formatted node, we skip it.
|
||||
|
||||
If block contains internal node, put 0 in g_disk_bitmap if block is
|
||||
not used in new tree yet.
|
||||
|
||||
If block contains leaf and is used already (by an indirect item
|
||||
handled already to this time) save all items. They will be inserted
|
||||
into tree after pass 1.
|
||||
|
||||
If block looking like leaf is not used in the new tree, try to
|
||||
insert in into tree. If it is not possible, mark block in
|
||||
g_uninsertable_leaf_bitmap. Blocks marked in this bitmap will be inserted into tree in pass 2. They can not be
|
||||
|
||||
This means, that in pass 1 when we have
|
||||
found block containing the internal nodes we mark it in
|
||||
g_disk_bitmap as free (reiserfs_free_internal_block). When block
|
||||
gets into new tree it is marked in g_new_bitmap (mark_block_used)
|
||||
When collecting resources for do_balance, we mark new blocks with
|
||||
mark_block_used. After do_balance we unmark unused new blocks in
|
||||
g_new_bitmap (bitmap.c:/reiserfs_free_block)
|
||||
|
||||
Allocating of new blocks: look for 0 bit in g_disk_bitmap
|
||||
(find_zero_bit_in_bitmap), make sure, that g_new_bitmap contains 0
|
||||
at the corresponding bit (is_block_used).
|
||||
|
||||
*/
|
||||
|
||||
|
||||
int is_to_be_read (reiserfs_filsys_t fs, unsigned long block)
|
||||
{
|
||||
return reiserfs_bitmap_test_bit (fsck_disk_bitmap (fs), block);
|
||||
}
|
||||
|
||||
|
||||
/* is blocks used (marked by 1 in new bitmap) in the tree which is being built
|
||||
(as leaf, internal, bitmap, or unformatted node) */
|
||||
int is_block_used (unsigned long block)
|
||||
{
|
||||
return reiserfs_bitmap_test_bit (fsck_new_bitmap (fs), block);
|
||||
}
|
||||
|
||||
|
||||
void mark_block_used (unsigned long block)
|
||||
{
|
||||
if (!block)
|
||||
return;
|
||||
if (is_block_used (block))
|
||||
die ("mark_block_used: (%lu) used already", block);
|
||||
|
||||
reiserfs_bitmap_set_bit (fsck_new_bitmap (fs), block);
|
||||
}
|
||||
|
||||
|
||||
void mark_block_free (unsigned long block)
|
||||
{
|
||||
if (!is_block_used (block))
|
||||
die ("mark_block_used: (%lu) is free", block);
|
||||
|
||||
reiserfs_bitmap_clear_bit (fsck_new_bitmap (fs), block);
|
||||
}
|
||||
|
||||
|
||||
int is_block_uninsertable (unsigned long block)
|
||||
{
|
||||
return !reiserfs_bitmap_test_bit (uninsertable_leaf_bitmap, block);
|
||||
}
|
||||
|
||||
|
||||
/* uninsertable block is marked by bit clearing */
|
||||
void mark_block_uninsertable (unsigned long block)
|
||||
{
|
||||
if (is_block_uninsertable (block))
|
||||
die ("mark_block_uninsertable: (%lu) is uninsertable already", block);
|
||||
|
||||
reiserfs_bitmap_clear_bit (uninsertable_leaf_bitmap, block);
|
||||
}
|
||||
|
||||
|
||||
int reiserfsck_reiserfs_new_blocknrs (reiserfs_filsys_t fs,
|
||||
unsigned long * free_blocknrs,
|
||||
unsigned long start, int amount_needed)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!are_there_allocable_blocks (amount_needed))
|
||||
die ("out of disk space");
|
||||
for (i = 0; i < amount_needed; i ++) {
|
||||
free_blocknrs[i] = alloc_block ();
|
||||
if (!free_blocknrs[i])
|
||||
die ("reiserfs_new_blocknrs: 0 is allocated");
|
||||
mark_block_used (free_blocknrs[i]);
|
||||
}
|
||||
return CARRY_ON;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: do you check readability of a block? If f_read fails - you
|
||||
// free block in bitmap or if you mark bad blocks used to avoid their
|
||||
// allocation in future you should have bad block counter in a super
|
||||
// block. Another minor issue: users of _get_new_buffer expect buffer
|
||||
// to be filled with 0s
|
||||
struct buffer_head * reiserfsck_get_new_buffer (unsigned long start)
|
||||
{
|
||||
unsigned long blocknr = 0;
|
||||
struct buffer_head * bh = NULL;
|
||||
|
||||
reiserfs_new_blocknrs (fs, &blocknr, start, 1);
|
||||
bh = getblk (fs->s_dev, blocknr, fs->s_blocksize);
|
||||
return bh;
|
||||
}
|
||||
|
||||
|
||||
/* free block in new bitmap */
|
||||
int reiserfsck_reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block)
|
||||
{
|
||||
mark_block_free (block);
|
||||
|
||||
/* put it back to pool of blocks for allocation */
|
||||
make_allocable (block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+1069
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright 1996-2001 Hans Reiser
|
||||
*/
|
||||
#include "fsck.h"
|
||||
|
||||
|
||||
/* when --check fsck builds a map of objectids of files it finds in the tree
|
||||
when --rebuild-tree - fsck builds map of objectids it inserts into tree
|
||||
FIXME: objectid gets into map when stat data item
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* is it marked used in super block's objectid map */
|
||||
int is_objectid_used (reiserfs_filsys_t s, __u32 objectid)
|
||||
{
|
||||
__u32 * objectid_map;
|
||||
int i = 0;
|
||||
|
||||
objectid_map = (__u32 *)((char *)(s->s_rs) + (sb_size(s)));
|
||||
|
||||
while (i < SB_OBJECTID_MAP_SIZE (s)) {
|
||||
if (objectid == objectid_map[i]) {
|
||||
return 1; /* objectid is used */
|
||||
}
|
||||
|
||||
if (objectid > objectid_map[i] && objectid < objectid_map[i+1]) {
|
||||
return 1; /* objectid is used */
|
||||
}
|
||||
|
||||
if (objectid < objectid_map[i])
|
||||
break;
|
||||
|
||||
i += 2;
|
||||
}
|
||||
|
||||
/* objectid is free */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* true objectid map */
|
||||
|
||||
|
||||
/* size of 1 piece of map */
|
||||
#define MAP_SIZE 4096 /* must be n * 2 * sizeof(__u32) */
|
||||
#define MAX_MAP_SIZE 1 /* % of available memory? */
|
||||
|
||||
|
||||
|
||||
/* increase area by MAP_SIZE bytes */
|
||||
static void grow_id_map (struct id_map * map)
|
||||
{
|
||||
if (map->m_page_count && ((map->m_page_count % 5) == 0)) {
|
||||
fsck_log ("grow_id_map: objectid map expanded: used %lu, %d blocks\n",
|
||||
map->m_used_slots_count, map->m_page_count);
|
||||
}
|
||||
map->m_begin = expandmem (map->m_begin, map->m_page_count * MAP_SIZE, MAP_SIZE);
|
||||
map->m_page_count ++;
|
||||
}
|
||||
|
||||
|
||||
static void try_to_shrink_id_map (struct id_map * map)
|
||||
{
|
||||
if (map->m_used_slots_count * sizeof(__u32) <= (map->m_page_count - 1) * MAP_SIZE) {
|
||||
if (map->m_page_count && ((map->m_page_count % 5) == 0))
|
||||
fsck_log ("shrink_id_map: objectid map shrinked: used %lu, %d blocks\n",
|
||||
map->m_used_slots_count, map->m_page_count);
|
||||
map->m_begin = expandmem (map->m_begin, map->m_page_count * MAP_SIZE,
|
||||
-MAP_SIZE);
|
||||
map->m_page_count--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ubin_search_id is used to find id in the map (or proper place to
|
||||
insert the new id). if smth goes wrong or ubin_search_id stops
|
||||
working properly check_id_search_result should help to find raised
|
||||
problems */
|
||||
static void check_id_search_result(struct id_map * map, int res, __u32 pos,
|
||||
__u32 id)
|
||||
{
|
||||
if (res != ITEM_FOUND && res != ITEM_NOT_FOUND)
|
||||
die("check_id_search_result: get wrong result from ubin_search (%d)", res);
|
||||
|
||||
if (res == 1 && *(map->m_begin + pos) != id)
|
||||
die("check_id_search_result: wrong id found %u %u", id, *(map->m_begin + pos));
|
||||
|
||||
if (res == 1)
|
||||
{
|
||||
if (pos > map->m_used_slots_count)
|
||||
die("check_id_search_result: get bad position (%u), used %u",
|
||||
pos, map->m_used_slots_count);
|
||||
if (pos >= 0 && pos <= map->m_used_slots_count && *(map->m_begin + pos - 1) >= id)
|
||||
die("check_id_search_result: previous id (%u) not less than (%u)",
|
||||
*(map->m_begin + pos - 1), id);
|
||||
if (pos >= 0 && pos < map->m_used_slots_count && *(map->m_begin + pos) < id)
|
||||
die("check_id_search_result: found id (%u) not much than (%u)",
|
||||
*(map->m_begin + pos), id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int comp_ids (void * p1, void * p2)
|
||||
{
|
||||
__u32 * id1, * id2;
|
||||
|
||||
id1 = p1;
|
||||
id2 = p2;
|
||||
|
||||
if ( *id1 < *id2 )
|
||||
return -1;
|
||||
if ( *id1 > *id2 )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
struct id_map * init_id_map (void)
|
||||
{
|
||||
struct id_map * map;
|
||||
|
||||
map = getmem (sizeof (struct id_map));
|
||||
map->m_begin = NULL;
|
||||
map->m_used_slots_count = 0;
|
||||
map->m_page_count = 0;
|
||||
mark_objectid_really_used (map, 1);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/* free whole map */
|
||||
void free_id_map (struct id_map ** map)
|
||||
{
|
||||
freemem ((*map)->m_begin);
|
||||
freemem (*map);
|
||||
*map = 0;
|
||||
}
|
||||
|
||||
|
||||
/* return 1 if id is marked used, 0 otherwise */
|
||||
int is_objectid_really_used (struct id_map * map, __u32 id, int * ppos)
|
||||
{
|
||||
int res;
|
||||
|
||||
*ppos = 0;
|
||||
|
||||
if (map->m_begin == NULL)
|
||||
return 0;
|
||||
|
||||
/* smth exists in the map, find proper place to insert or this id */
|
||||
res = ubin_search (&id, map->m_begin, map->m_used_slots_count, sizeof (__u32), ppos, comp_ids);
|
||||
#if 1
|
||||
check_id_search_result (map, res, *ppos, id);
|
||||
#endif
|
||||
/* *ppos is position in objectid map of the element which is equal id
|
||||
or position of an element which is smallest and greater than id */
|
||||
if (res == ITEM_NOT_FOUND)
|
||||
/* id is not found in the map. if returned position is odd -
|
||||
id is marked used */
|
||||
return (*ppos % 2);
|
||||
|
||||
/* if returned position is odd - id is marked free */
|
||||
return !(*ppos % 2);
|
||||
}
|
||||
|
||||
|
||||
static void check_objectid_map (struct id_map * map)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < map->m_used_slots_count; i ++)
|
||||
if (map->m_begin [i - 1] >= map->m_begin [i])
|
||||
die ("check_objectid_map: map corrupted");
|
||||
}
|
||||
|
||||
|
||||
/* returns 1 objectid is marked used already, 0 otherwise */
|
||||
int mark_objectid_really_used (struct id_map * map, __u32 id)
|
||||
{
|
||||
int pos;
|
||||
|
||||
|
||||
/* check whether id is used and get place if used or place to insert if not */
|
||||
if (is_objectid_really_used (map, id, &pos) == 1)
|
||||
return 1;
|
||||
|
||||
map->objectids_marked ++;
|
||||
if (pos % 2 == 0){
|
||||
/* id not found in the map. why? is_id_used() knows */
|
||||
|
||||
if (map->m_begin == NULL)
|
||||
/* map is empty */
|
||||
grow_id_map (map);
|
||||
|
||||
/* id + 1 is used, change id + 1 to id and exit */
|
||||
if ( id + 1 == le32_to_cpu (map->m_begin[pos]) ) {
|
||||
/* we can mark id as used w/o expanding of id map */
|
||||
map->m_begin[pos] = cpu_to_le32 (id);
|
||||
|
||||
check_objectid_map (map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (map->m_page_count * MAP_SIZE == map->m_used_slots_count * sizeof(__u32))
|
||||
/* fixme: do not grow too much */
|
||||
grow_id_map (map);
|
||||
|
||||
if (map->m_used_slots_count - pos > 0)
|
||||
memmove (map->m_begin + pos + 2, map->m_begin + pos, (map->m_used_slots_count - pos) * sizeof (__u32));
|
||||
|
||||
map->m_used_slots_count += 2;
|
||||
map->m_begin[pos] = cpu_to_le32 (id);
|
||||
map->m_begin[pos+1] = cpu_to_le32 (id + 1);
|
||||
|
||||
check_objectid_map (map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* id found in the map. pos is odd position () */
|
||||
map->m_begin[pos] = cpu_to_le32 (id + 1);
|
||||
|
||||
/* if end id of current interval == start id of next interval we
|
||||
eliminated a sequence of unused objectids */
|
||||
if (pos + 1 < map->m_used_slots_count &&
|
||||
map->m_begin[pos + 1] == map->m_begin[pos]) {
|
||||
memmove (map->m_begin + pos, map->m_begin + pos + 2, (map->m_used_slots_count - pos - 2) * sizeof (__u32));
|
||||
map->m_used_slots_count -= 2;
|
||||
try_to_shrink_id_map (map);
|
||||
}
|
||||
|
||||
check_objectid_map (map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static __u32 get_free_id (reiserfs_filsys_t fs)
|
||||
{
|
||||
struct id_map * map;
|
||||
|
||||
map = proper_id_map (fs);
|
||||
|
||||
/* If map is not NULL return the second element (first position in
|
||||
the map). This allocates the first unused objectid. That is to
|
||||
say, the first entry on the objectid map is the first unused
|
||||
objectid. */
|
||||
if (map->m_begin == NULL) {
|
||||
fprintf (stderr, "get_free_id: hmm, 1 is allocated as objectid\n");
|
||||
return 1;
|
||||
}
|
||||
return (le32_to_cpu (map->m_begin[1]));
|
||||
}
|
||||
|
||||
|
||||
__u32 get_unused_objectid (reiserfs_filsys_t fs)
|
||||
{
|
||||
__u32 objectid;
|
||||
|
||||
objectid = get_free_id (fs);
|
||||
if (mark_objectid_really_used (proper_id_map (fs), objectid))
|
||||
die ("get_unused_objectid: could not mark %lu used", objectid);
|
||||
|
||||
return objectid;
|
||||
}
|
||||
|
||||
|
||||
#define objectid_map(fs) ((char *)((char *)((fs)->s_rs) + sb_size (fs)))
|
||||
|
||||
|
||||
#if 0
|
||||
/* returns 0 if on-disk objectid map matches to the correct one, 1
|
||||
otherwise */
|
||||
int compare_id_maps (reiserfs_filsys_t fs)
|
||||
{
|
||||
struct id_map * map;
|
||||
int disk_size;
|
||||
|
||||
map = proper_id_map (fs);
|
||||
|
||||
disk_size = rs_objectid_map_size (fs->s_rs);
|
||||
if (disk_size != map->m_used_slots_count ||
|
||||
memcmp ((char *)((char *)((fs)->s_rs) + sb_size (fs)), map->m_begin, sizeof(__u32) * disk_size)) {
|
||||
fprintf (stderr, "Objectid maps mismatch\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* copy objectid map into buffer containing super block */
|
||||
void correct_objectid_map (reiserfs_filsys_t fs)
|
||||
{
|
||||
struct id_map * map;
|
||||
int size, disk_max;
|
||||
|
||||
map = proper_id_map (fs);
|
||||
|
||||
size = map->m_used_slots_count;
|
||||
disk_max = rs_objectid_map_max_size (fs->s_rs);
|
||||
if (disk_max < size) {
|
||||
size = disk_max;
|
||||
} else {
|
||||
memset (fu_objectid_map (fs) + size, 0, (disk_max - size) * sizeof (__u32));
|
||||
}
|
||||
|
||||
memcpy (fu_objectid_map (fs), map->m_begin, size * sizeof (__u32));
|
||||
set_objectid_map_size (fs->s_rs, size);
|
||||
mark_buffer_dirty (SB_BUFFER_WITH_SB (fs));
|
||||
|
||||
/*
|
||||
if (fs->fu_job->verbose)
|
||||
fprintf (stderr, "Objectid map corrected\n");
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
/* print the map of objectids */
|
||||
void print_objectid_list ()
|
||||
{
|
||||
int i;
|
||||
printf ("\n control id map: all %d, used:%d", id_map.m_page_count * MAP_SIZE, id_map.m_used_slots_count);
|
||||
|
||||
for (i = 0; i < id_map.m_used_slots_count; i += 2)
|
||||
printf ("\n[%u-%u]", id_map.m_begin[i], id_map.m_begin[i + 1] - 1);
|
||||
}
|
||||
|
||||
/* print on-disk map of objectids */
|
||||
void print_disk_objectid_list (void)
|
||||
{
|
||||
int i;
|
||||
__u32 * objectid_map = (__u32 *)((char *)SB_DISK_SUPER_BLOCK (&g_sb) + (sb_size(&g_sb)));
|
||||
printf ("\n on-disk id map. used:%lu", SB_OBJECTID_MAP_SIZE(&g_sb));
|
||||
|
||||
for (i = 0; i < SB_OBJECTID_MAP_SIZE(&g_sb); i += 2)
|
||||
printf ("\n[%u-%u]", objectid_map[i], objectid_map[i + 1] - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void flush_objectid_map (struct id_map * map, reiserfs_filsys_t fs)
|
||||
{
|
||||
int size, max;
|
||||
int sb_size;
|
||||
__u32 * sb_objectid_map;
|
||||
|
||||
sb_size = (is_reiser2fs_magic_string (fs->s_rs) ? SB_SIZE : SB_SIZE_V1);
|
||||
sb_objectid_map = (__u32 *)((char *)(fs->s_rs) + sb_size);
|
||||
|
||||
check_objectid_map (map);
|
||||
|
||||
max = ((fs->s_blocksize - sb_size) >> 3 << 1);
|
||||
set_objectid_map_max_size (fs->s_rs, max);
|
||||
if (map->m_used_slots_count > max)
|
||||
size = max;
|
||||
else
|
||||
size = map->m_used_slots_count;
|
||||
|
||||
memcpy (sb_objectid_map, map->m_begin, size * sizeof (__u32));
|
||||
memset (sb_objectid_map + size, 0, (max - size) * sizeof (__u32));
|
||||
|
||||
set_objectid_map_size (fs->s_rs, size);
|
||||
if (size == max)
|
||||
/*((__u32 *)((char *)(fs->s_rs) + sb_size))*/
|
||||
sb_objectid_map [max - 1] = map->m_begin [map->m_used_slots_count - 1];
|
||||
|
||||
check_objectid_map (map);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void fetch_objectid_map (struct id_map * map, reiserfs_filsys_t fs)
|
||||
{
|
||||
int sb_size;
|
||||
__u32 * sb_objectid_map;
|
||||
|
||||
sb_size = (is_reiser2fs_magic_string (fs->s_rs) ? SB_SIZE : SB_SIZE_V1);
|
||||
sb_objectid_map = (__u32 *)((char *)(fs->s_rs) + sb_size);
|
||||
|
||||
if (map->m_page_count != 1)
|
||||
die ("fetch_objectid_map: can not fetch long map");
|
||||
grow_id_map (map);
|
||||
memcpy (map->m_begin, sb_objectid_map, rs_objectid_map_size (fs->s_rs) * sizeof (__u32));
|
||||
map->m_used_slots_count = rs_objectid_map_size (fs->s_rs);
|
||||
}
|
||||
+704
@@ -0,0 +1,704 @@
|
||||
/*
|
||||
* Copyright 1996-2001 Hans Reiser
|
||||
*/
|
||||
#include "fsck.h"
|
||||
|
||||
|
||||
/* key1 and key2 are pointer to deh_offset of the struct reiserfs_de_head */
|
||||
int comp_dir_entries (void * key1, void * key2)
|
||||
{
|
||||
__u32 off1, off2;
|
||||
|
||||
off1 = le32_to_cpu (*(__u32 *)key1);
|
||||
off2 = le32_to_cpu (*(__u32 *)key2);
|
||||
|
||||
if (off1 < off2)
|
||||
return -1;
|
||||
if (off1 > off2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void init_tb_struct (struct tree_balance * tb, struct super_block * s, struct path * path, int size)
|
||||
{
|
||||
memset (tb, '\0', sizeof(struct tree_balance));
|
||||
tb->tb_sb = s;
|
||||
tb->tb_path = path;
|
||||
|
||||
PATH_OFFSET_PBUFFER(path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL;
|
||||
PATH_OFFSET_POSITION(path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0;
|
||||
tb->insert_size[0] = size;
|
||||
}
|
||||
|
||||
|
||||
struct tree_balance * cur_tb = 0;
|
||||
|
||||
void reiserfsck_paste_into_item (struct path * path, const char * body, int size)
|
||||
{
|
||||
struct tree_balance tb;
|
||||
|
||||
init_tb_struct (&tb, fs, path, size);
|
||||
if (fix_nodes (/*tb.transaction_handle,*/ M_PASTE, &tb, 0/*ih*/) != CARRY_ON)
|
||||
//fix_nodes(options, tree_balance, ih_to_option, body_to_option)
|
||||
|
||||
die ("reiserfsck_paste_into_item: fix_nodes failed");
|
||||
|
||||
do_balance (/*tb.transaction_handle,*/ &tb, 0, body, M_PASTE, 0/*zero num*/);
|
||||
}
|
||||
|
||||
|
||||
void reiserfsck_insert_item (struct path * path, struct item_head * ih, const char * body)
|
||||
{
|
||||
struct tree_balance tb;
|
||||
|
||||
init_tb_struct (&tb, fs, path, IH_SIZE + ih_item_len(ih));
|
||||
if (fix_nodes (/*tb.transaction_handle,*/ M_INSERT, &tb, ih/*, body*/) != CARRY_ON)
|
||||
die ("reiserfsck_insert_item: fix_nodes failed");
|
||||
do_balance (/*tb.transaction_handle,*/ &tb, ih, body, M_INSERT, 0/*zero num*/);
|
||||
}
|
||||
|
||||
|
||||
static void free_unformatted_nodes (struct item_head * ih, struct buffer_head * bh)
|
||||
{
|
||||
__u32 * punfm = (__u32 *)B_I_PITEM (bh, ih);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I_UNFM_NUM (ih); i ++, punfm ++)
|
||||
if (*punfm) {
|
||||
struct buffer_head * to_be_forgotten;
|
||||
|
||||
to_be_forgotten = find_buffer (fs->s_dev, *punfm, fs->s_blocksize);
|
||||
if (to_be_forgotten) {
|
||||
//atomic_inc(&to_be_forgotten->b_count);
|
||||
to_be_forgotten->b_count ++;
|
||||
bforget (to_be_forgotten);
|
||||
}
|
||||
|
||||
reiserfs_free_block (fs, *punfm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void reiserfsck_delete_item (struct path * path, int temporary)
|
||||
{
|
||||
struct tree_balance tb;
|
||||
struct item_head * ih = PATH_PITEM_HEAD (path);
|
||||
|
||||
if (is_indirect_ih (ih) && !temporary)
|
||||
free_unformatted_nodes (ih, PATH_PLAST_BUFFER (path));
|
||||
|
||||
init_tb_struct (&tb, fs, path, -(IH_SIZE + ih_item_len(ih)));
|
||||
|
||||
if (fix_nodes (/*tb.transaction_handle,*/ M_DELETE, &tb, 0/*ih*/) != CARRY_ON)
|
||||
die ("reiserfsck_delete_item: fix_nodes failed");
|
||||
|
||||
do_balance (/*tb.transaction_handle,*/ &tb, 0, 0, M_DELETE, 0/*zero num*/);
|
||||
}
|
||||
|
||||
|
||||
void reiserfsck_cut_from_item (struct path * path, int cut_size)
|
||||
{
|
||||
struct tree_balance tb;
|
||||
struct item_head * ih;
|
||||
|
||||
if (cut_size >= 0)
|
||||
die ("reiserfsck_cut_from_item: cut size == %d", cut_size);
|
||||
|
||||
if (is_indirect_ih (ih = PATH_PITEM_HEAD (path))) {
|
||||
__u32 unfm_ptr = B_I_POS_UNFM_POINTER (PATH_PLAST_BUFFER (path), ih, I_UNFM_NUM (ih) - 1);
|
||||
if (unfm_ptr) {
|
||||
struct buffer_head * to_be_forgotten;
|
||||
|
||||
to_be_forgotten = find_buffer (fs->s_dev, le32_to_cpu (unfm_ptr), fs->s_blocksize);
|
||||
if (to_be_forgotten) {
|
||||
//atomic_inc(&to_be_forgotten->b_count);
|
||||
to_be_forgotten->b_count ++;
|
||||
bforget (to_be_forgotten);
|
||||
}
|
||||
reiserfs_free_block (fs, le32_to_cpu (unfm_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init_tb_struct (&tb, fs, path, cut_size);
|
||||
|
||||
if (fix_nodes (/*tb.transaction_handle,*/ M_CUT, &tb, 0) != CARRY_ON)
|
||||
die ("reiserfsck_cut_from_item: fix_nodes failed");
|
||||
|
||||
do_balance (/*tb.transaction_handle,*/ &tb, 0, 0, M_CUT, 0/*zero num*/);
|
||||
}
|
||||
|
||||
|
||||
/* uget_lkey is utils clone of stree.c/get_lkey */
|
||||
struct key * uget_lkey (struct path * path)
|
||||
{
|
||||
int pos, offset = path->path_length;
|
||||
struct buffer_head * bh;
|
||||
|
||||
if (offset < FIRST_PATH_ELEMENT_OFFSET)
|
||||
die ("uget_lkey: illegal offset in the path (%d)", offset);
|
||||
|
||||
|
||||
/* While not higher in path than first element. */
|
||||
while (offset-- > FIRST_PATH_ELEMENT_OFFSET) {
|
||||
if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset)) )
|
||||
die ("uget_lkey: parent is not uptodate");
|
||||
|
||||
/* Parent at the path is not in the tree now. */
|
||||
if (! B_IS_IN_TREE (bh = PATH_OFFSET_PBUFFER (path, offset)))
|
||||
die ("uget_lkey: buffer on the path is not in tree");
|
||||
|
||||
/* Check whether position in the parent is correct. */
|
||||
if ((pos = PATH_OFFSET_POSITION (path, offset)) > B_NR_ITEMS (bh))
|
||||
die ("uget_lkey: invalid position (%d) in the path", pos);
|
||||
|
||||
/* Check whether parent at the path really points to the child. */
|
||||
if (B_N_CHILD_NUM (bh, pos) != PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr)
|
||||
die ("uget_lkey: invalid block number (%d). Must be %d",
|
||||
B_N_CHILD_NUM (bh, pos), PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr);
|
||||
|
||||
/* Return delimiting key if position in the parent is not equal to zero. */
|
||||
if (pos)
|
||||
return B_N_PDELIM_KEY(bh, pos - 1);
|
||||
}
|
||||
|
||||
/* there is no left delimiting key */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* uget_rkey is utils clone of stree.c/get_rkey */
|
||||
struct key * uget_rkey (struct path * path)
|
||||
{
|
||||
int pos, offset = path->path_length;
|
||||
struct buffer_head * bh;
|
||||
|
||||
if (offset < FIRST_PATH_ELEMENT_OFFSET)
|
||||
die ("uget_rkey: illegal offset in the path (%d)", offset);
|
||||
|
||||
while (offset-- > FIRST_PATH_ELEMENT_OFFSET) {
|
||||
if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset)))
|
||||
die ("uget_rkey: parent is not uptodate");
|
||||
|
||||
/* Parent at the path is not in the tree now. */
|
||||
if (! B_IS_IN_TREE (bh = PATH_OFFSET_PBUFFER (path, offset)))
|
||||
die ("uget_rkey: buffer on the path is not in tree");
|
||||
|
||||
/* Check whether position in the parrent is correct. */
|
||||
if ((pos = PATH_OFFSET_POSITION (path, offset)) > B_NR_ITEMS (bh))
|
||||
die ("uget_rkey: invalid position (%d) in the path", pos);
|
||||
|
||||
/* Check whether parent at the path really points to the child. */
|
||||
if (B_N_CHILD_NUM (bh, pos) != PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr)
|
||||
die ("uget_rkey: invalid block number (%d). Must be %d",
|
||||
B_N_CHILD_NUM (bh, pos), PATH_OFFSET_PBUFFER (path, offset + 1)->b_blocknr);
|
||||
|
||||
/* Return delimiting key if position in the parent is not the last one. */
|
||||
if (pos != B_NR_ITEMS (bh))
|
||||
return B_N_PDELIM_KEY(bh, pos);
|
||||
}
|
||||
|
||||
/* there is no right delimiting key */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline int ubin_search (void * key, void * base, int num, int width, __u32 *ppos, comp_function_t comp_func)
|
||||
{
|
||||
__u32 rbound, lbound, j;
|
||||
|
||||
lbound = 0;
|
||||
|
||||
if (num == 0){
|
||||
*ppos = 0;
|
||||
return ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
rbound = num - 1;
|
||||
|
||||
for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) {
|
||||
switch (comp_func ((void *)((char *)base + j * width), key ) ) {
|
||||
case -1:/* second is greater */
|
||||
lbound = j + 1;
|
||||
continue;
|
||||
|
||||
case 1: /* first is greater */
|
||||
if (j == 0){
|
||||
*ppos = lbound;
|
||||
return ITEM_NOT_FOUND;
|
||||
}
|
||||
rbound = j - 1;
|
||||
continue;
|
||||
|
||||
case 0:
|
||||
*ppos = j;
|
||||
return ITEM_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
*ppos = lbound;
|
||||
return ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/* this searches in tree through items */
|
||||
int usearch_by_key (struct super_block * s, struct key * key, struct path * path)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
unsigned long block = SB_ROOT_BLOCK (s);
|
||||
struct path_element * curr;
|
||||
int retval;
|
||||
|
||||
path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
|
||||
while (1) {
|
||||
curr = PATH_OFFSET_PELEMENT (path, ++ path->path_length);
|
||||
bh = curr->pe_buffer = bread (s->s_dev, block, s->s_blocksize);
|
||||
if (bh == 0)
|
||||
reiserfs_panic ("usearch_by_key: unable to read %lu block on device 0x%x\n",block, s->s_dev);
|
||||
retval = ubin_search (key, B_N_PKEY (bh, 0), B_NR_ITEMS (bh),
|
||||
is_leaf_node (bh) ? IH_SIZE : KEY_SIZE, &(curr->pe_position), comp_keys);
|
||||
if (retval == ITEM_FOUND) {
|
||||
/* key found, return if this is leaf level */
|
||||
if (is_leaf_node (bh)) {
|
||||
path->pos_in_item = 0;
|
||||
return ITEM_FOUND;
|
||||
}
|
||||
curr->pe_position ++;
|
||||
} else {
|
||||
/* key not found in the node */
|
||||
if (is_leaf_node (bh))
|
||||
return ITEM_NOT_FOUND;
|
||||
}
|
||||
block = B_N_CHILD_NUM (bh, curr->pe_position);
|
||||
}
|
||||
die ("search_by_key: you can not get here");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* key is key of directory entry. This searches in tree through items and in
|
||||
the found directory item as well */
|
||||
int usearch_by_entry_key (struct super_block * s, struct key * key, struct path * path)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
struct item_head * ih;
|
||||
struct key tmpkey;
|
||||
|
||||
if (usearch_by_key (s, key, path) == ITEM_FOUND) {
|
||||
/* entry found */
|
||||
path->pos_in_item = 0;
|
||||
return POSITION_FOUND;
|
||||
}
|
||||
|
||||
bh = PATH_PLAST_BUFFER (path);
|
||||
|
||||
if (PATH_LAST_POSITION (path) == 0) {
|
||||
/* previous item does not exist, that means we are in leftmost leaf of
|
||||
the tree */
|
||||
if (uget_lkey (path) != 0)
|
||||
die ("search_by_entry_key: invalid position after search_by_key");
|
||||
|
||||
if (not_of_one_file (B_N_PKEY (bh, 0), key)) {
|
||||
path->pos_in_item = 0;
|
||||
return DIRECTORY_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!is_direntry_ih (get_ih (path))) {
|
||||
fsck_progress ("search_by_entry_key: directory expected to have this key %K\n", key);
|
||||
return REGULAR_FILE_FOUND;
|
||||
}
|
||||
|
||||
/* position for name insertion is found */
|
||||
path->pos_in_item = 0;
|
||||
return POSITION_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* take previous item */
|
||||
PATH_LAST_POSITION (path) --;
|
||||
ih = PATH_PITEM_HEAD (path);
|
||||
if (not_of_one_file (&(ih->ih_key), key) || !is_direntry_ih(ih)) {
|
||||
/* previous item belongs to another object or is stat data, check next
|
||||
item */
|
||||
|
||||
PATH_LAST_POSITION (path) ++;
|
||||
if (PATH_LAST_POSITION (path) < B_NR_ITEMS (bh))
|
||||
{
|
||||
/* found item is not last item of the node */
|
||||
struct item_head * next_ih = B_N_PITEM_HEAD (bh, PATH_LAST_POSITION (path));
|
||||
|
||||
if (not_of_one_file (&(next_ih->ih_key), key))
|
||||
{
|
||||
path->pos_in_item = 0;
|
||||
return DIRECTORY_NOT_FOUND;
|
||||
}
|
||||
if (!is_direntry_ih(next_ih))
|
||||
{
|
||||
/* there is an item in the tree, but it is not a directory item */
|
||||
reiserfs_warning (stderr, "search_by_entry_key: directory expected to have this key %k\n",
|
||||
key);
|
||||
return REGULAR_FILE_FOUND;
|
||||
}
|
||||
} else {
|
||||
/* found item is last item of the node */
|
||||
struct key * next_key = uget_rkey (path);
|
||||
|
||||
if (next_key == 0 || not_of_one_file (next_key, key))
|
||||
{
|
||||
/* there is not any part of such directory in the tree */
|
||||
path->pos_in_item = 0;
|
||||
return DIRECTORY_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!is_direntry_key (next_key))
|
||||
{
|
||||
/* there is an item in the tree, but it is not a directory item */
|
||||
fsck_progress ("search_by_entry_key: directory expected to have this key %k\n",
|
||||
key);
|
||||
return REGULAR_FILE_FOUND;
|
||||
}
|
||||
|
||||
// we got right delimiting key - search for it - the entry will be
|
||||
// pasted in position 0
|
||||
copy_key (&tmpkey, next_key);
|
||||
pathrelse (path);
|
||||
if (usearch_by_key (s, &tmpkey, path) != ITEM_FOUND || PATH_LAST_POSITION (path) != 0)
|
||||
die ("search_by_entry_key: item not found by corresponding delimiting key");
|
||||
}
|
||||
|
||||
/* next item is the part of this directory */
|
||||
path->pos_in_item = 0;
|
||||
|
||||
return POSITION_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* previous item is part of desired directory */
|
||||
if (ubin_search (&(key->u.k_offset_v1.k_offset), B_I_DEH (bh, ih), ih_entry_count (ih),
|
||||
DEH_SIZE, &(path->pos_in_item), comp_dir_entries) == ITEM_FOUND)
|
||||
return POSITION_FOUND;
|
||||
|
||||
return POSITION_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/* key is key of byte in the regular file. This searches in tree
|
||||
through items and in the found item as well */
|
||||
int usearch_by_position (struct super_block * s, struct key * key, int version, struct path * path)
|
||||
{
|
||||
struct buffer_head * bh;
|
||||
struct item_head * ih;
|
||||
|
||||
if (usearch_by_key (s, key, path) == ITEM_FOUND)
|
||||
{
|
||||
ih = PATH_PITEM_HEAD (path);
|
||||
|
||||
if (!is_direct_ih(ih) && !is_indirect_ih(ih))
|
||||
return DIRECTORY_FOUND;
|
||||
path->pos_in_item = 0;
|
||||
return POSITION_FOUND;
|
||||
}
|
||||
|
||||
bh = PATH_PLAST_BUFFER (path);
|
||||
ih = PATH_PITEM_HEAD (path);
|
||||
|
||||
|
||||
if ( (PATH_LAST_POSITION(path) < B_NR_ITEMS (bh)) &&
|
||||
!not_of_one_file (&ih->ih_key, key) &&
|
||||
(get_offset(&ih->ih_key) == get_offset(key)) )
|
||||
{
|
||||
|
||||
if (!is_direct_ih(ih) && !is_indirect_ih(ih))
|
||||
return DIRECTORY_FOUND;
|
||||
path->pos_in_item = 0;
|
||||
|
||||
|
||||
return POSITION_FOUND;
|
||||
}
|
||||
|
||||
if (PATH_LAST_POSITION (path) == 0) {
|
||||
/* previous item does not exist, that means we are in leftmost leaf of the tree */
|
||||
if (!not_of_one_file (B_N_PKEY (bh, 0), key)) {
|
||||
if (!is_direct_ih(ih) && !is_indirect_ih (ih))
|
||||
return DIRECTORY_FOUND;
|
||||
return POSITION_NOT_FOUND;
|
||||
}
|
||||
return FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/* take previous item */
|
||||
PATH_LAST_POSITION (path) --;
|
||||
ih = PATH_PITEM_HEAD (path);
|
||||
|
||||
if (not_of_one_file (&ih->ih_key, key) || is_stat_data_ih(ih)) {
|
||||
struct key * next_key;
|
||||
|
||||
/* previous item belongs to another object or is a stat data, check next item */
|
||||
PATH_LAST_POSITION (path) ++;
|
||||
if (PATH_LAST_POSITION (path) < B_NR_ITEMS (PATH_PLAST_BUFFER (path)))
|
||||
/* next key is in the same node */
|
||||
next_key = B_N_PKEY (PATH_PLAST_BUFFER (path), PATH_LAST_POSITION (path));
|
||||
else
|
||||
next_key = uget_rkey (path);
|
||||
if (next_key == 0 || not_of_one_file (next_key, key)) {
|
||||
/* there is no any part of such file in the tree */
|
||||
path->pos_in_item = 0;
|
||||
return FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (is_direntry_key (next_key)) {
|
||||
fsck_log ("\nusearch_by_position: looking for %k found a directory with the same key\n", next_key);
|
||||
return DIRECTORY_FOUND;
|
||||
}
|
||||
/* next item is the part of this file */
|
||||
path->pos_in_item = 0;
|
||||
if ( get_offset(next_key) == get_offset(key) ) {
|
||||
pathrelse(path);
|
||||
if (usearch_by_key (s, next_key, path) != ITEM_FOUND) {
|
||||
reiserfs_panic ("usearch_by_position: keys must be equals %k %k",
|
||||
next_key, &PATH_PITEM_HEAD (path)->ih_key);
|
||||
}
|
||||
return POSITION_FOUND;
|
||||
}
|
||||
|
||||
return POSITION_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (is_direntry_ih(ih)) {
|
||||
return DIRECTORY_FOUND;
|
||||
}
|
||||
if (is_stat_data_ih(ih)) {
|
||||
PATH_LAST_POSITION (path) ++;
|
||||
return FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* previous item is part of desired file */
|
||||
|
||||
|
||||
//if (is_key_in_item (bh,ih,key,bh->b_size)) {
|
||||
if (I_K_KEY_IN_ITEM (ih, key, bh->b_size)) {
|
||||
path->pos_in_item = get_offset (key) - get_offset (&ih->ih_key);
|
||||
if (is_indirect_ih (ih) )
|
||||
path->pos_in_item /= bh->b_size;
|
||||
return POSITION_FOUND;
|
||||
}
|
||||
|
||||
path->pos_in_item = is_indirect_ih (ih) ? I_UNFM_NUM (ih) : ih_item_len (ih);
|
||||
return POSITION_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long first_child (struct buffer_head * bh)
|
||||
{
|
||||
return child_block_number (bh, 0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned long last_child (struct buffer_head * bh)
|
||||
{
|
||||
return child_block_number (bh, node_item_number (bh));
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long get_child (int pos, struct buffer_head * parent)
|
||||
{
|
||||
if (pos == -1)
|
||||
return -1;
|
||||
|
||||
if (pos > B_NR_ITEMS (parent))
|
||||
die ("get_child: no child found, should not happen: %d of %d", pos, B_NR_ITEMS (parent));
|
||||
return child_block_number (parent, pos);
|
||||
|
||||
/*
|
||||
for (i = 0; i < B_NR_ITEMS (parent); i ++)
|
||||
{
|
||||
if (child_block_number (parent, i) == block)
|
||||
return child_block_number (parent, i + 1);
|
||||
}
|
||||
die ("next_child: no child found: should not happen");
|
||||
return 0;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
static void print (int cur, int total)
|
||||
{
|
||||
printf ("/%3d (of %3d)", cur, total);fflush (stdout);
|
||||
}
|
||||
|
||||
|
||||
/* erase /XXX(of XXX) */
|
||||
static void erase (void)
|
||||
{
|
||||
printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b");
|
||||
printf (" ");
|
||||
printf ("\b\b\b\b\b\b\b\b\b\b\b\b\b");
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void pass_through_tree2 (struct super_block * s, do_after_read_t action1,
|
||||
do_on_full_path_t action2)
|
||||
{
|
||||
struct buffer_head * path[MAX_HEIGHT] = {0,};
|
||||
int total[MAX_HEIGHT] = {0,};
|
||||
int cur[MAX_HEIGHT] = {0,};
|
||||
int h = 0;
|
||||
unsigned long block = SB_ROOT_BLOCK (s);
|
||||
int del_p;
|
||||
|
||||
if (block >= SB_BLOCK_COUNT (s) || not_data_block (s, block))
|
||||
return;
|
||||
|
||||
while ( 1 ) {
|
||||
if (path[h])
|
||||
die ("pass_through_tree: empty slot expected");
|
||||
if (h)
|
||||
print (cur[h - 1], total[h - 1]);
|
||||
|
||||
path[h] = bread (s->s_dev, block, s->s_blocksize);
|
||||
get_child (-1, path[h]);
|
||||
|
||||
if (path[h] == 0)
|
||||
reiserfs_warning ("pass_through_tree: unable to read %lu block on device 0x%x\n",
|
||||
block, s->s_dev);
|
||||
|
||||
del_p = 0;
|
||||
if (path[h] && action1) {
|
||||
if (action1 (s, path, h)) {
|
||||
;
|
||||
#if 0
|
||||
// something wrong with a buffer we just have read
|
||||
if (opt_fsck_mode == FSCK_FAST_REBUILD){
|
||||
//need to change the way we are going on
|
||||
del_p = 1;
|
||||
if (h == 0)
|
||||
break;
|
||||
} else {
|
||||
;
|
||||
//reiserfs_panic (s, "Run reiserfsck with --rebuild-tree\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!path[h] || is_leaf_node (path[h]))
|
||||
{
|
||||
if (path[h] && action2) {
|
||||
if (action2 (s, path, h)) {
|
||||
;
|
||||
#if 0
|
||||
if (opt_fsck_mode == FSCK_FAST_REBUILD) {
|
||||
//need to change the way we are going on
|
||||
del_p = 1;
|
||||
if (h == 0)
|
||||
break;
|
||||
} else {
|
||||
;
|
||||
//reiserfs_panic (s, "Run reiserfsck with --rebuild-tree\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (path[h])
|
||||
brelse (path[h]);
|
||||
if (h)
|
||||
erase ();
|
||||
|
||||
while (h && (!path[h-1] || cur[h-1] == total[h-1] ))
|
||||
{
|
||||
path[h] = 0;
|
||||
h --;
|
||||
if (path[h])
|
||||
brelse (path[h]);
|
||||
if (h)
|
||||
erase ();
|
||||
}
|
||||
|
||||
if (h == 0) {
|
||||
path[h] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (path[h])
|
||||
cur[h - 1] ++;
|
||||
if (del_p){
|
||||
total[h-1]--;
|
||||
del_p = 0;
|
||||
}
|
||||
block = get_child (cur[h - 1] - 1, path[h-1]);
|
||||
path[h] = 0;
|
||||
continue;
|
||||
}
|
||||
total[h] = B_NR_ITEMS (path[h]) + 1;
|
||||
cur[h] = 1;
|
||||
block = first_child (path[h]);
|
||||
h ++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void pass_through_tree (struct super_block * s, do_after_read_t action1,
|
||||
do_on_full_path_t action2)
|
||||
{
|
||||
struct buffer_head * path[MAX_HEIGHT] = {0,};
|
||||
int total[MAX_HEIGHT] = {0,};
|
||||
int cur[MAX_HEIGHT] = {0,};
|
||||
int h = 0;
|
||||
unsigned long block = SB_ROOT_BLOCK (s);
|
||||
|
||||
|
||||
if (block >= SB_BLOCK_COUNT (s) || not_data_block (s, block)) {
|
||||
fsck_progress ("\nBad root block %lu. (--rebuild-tree did not complete)\n", block);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while ( 1 ) {
|
||||
if (path[h])
|
||||
die ("pass_through_tree: empty slot expected");
|
||||
if (h)
|
||||
print (cur[h - 1], total[h - 1]);
|
||||
|
||||
path[h] = bread (s->s_dev, block, s->s_blocksize);
|
||||
if (path[h] == 0)
|
||||
/* FIXME: handle case when read failed */
|
||||
die ("pass_through_tree: unable to read %lu block on device 0x%x\n",
|
||||
block, s->s_dev);
|
||||
|
||||
if (action1)
|
||||
action1 (s, path, h);
|
||||
|
||||
if (is_leaf_node (path[h])) {
|
||||
if (action2)
|
||||
action2 (s, path, h);
|
||||
|
||||
brelse (path[h]);
|
||||
if (h)
|
||||
erase ();
|
||||
|
||||
while (h && (cur[h-1] == total[h-1])) {
|
||||
path[h] = 0;
|
||||
h --;
|
||||
brelse (path[h]);
|
||||
if (h)
|
||||
erase ();
|
||||
}
|
||||
|
||||
if (h == 0) {
|
||||
path[h] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
block = get_child (cur[h - 1], path[h-1]);
|
||||
cur[h - 1] ++;
|
||||
path[h] = 0;
|
||||
continue;
|
||||
}
|
||||
total[h] = B_NR_ITEMS (path[h]) + 1;
|
||||
cur[h] = 1;
|
||||
block = first_child (path[h]);
|
||||
h ++;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user