Initial commit -- seeded with reiserfsprogs 3.x.0j
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/AUTHORS
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..5a06c97
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,120 @@
+2001-03-31
+	* reiserfsck
+		empty lost directories do not get linked into /lost+found
+2001-03-28
+	* reiserfsck
+		--nolog option is added
+	
+2001-03-26
+	* called 3.x.0j
+	* reiserfsck
+		with -o it tries to fix "objectid sharing" problem
+	* reiserfsprogs.spec (Anthon van der Neut)
+		rpm can be built as non-root
+		link from reiserfsck to fsck.reiserfs
+		rpm -e reiserfsprogs should now work w/o rmdir of /
+2001-03-13
+	* reiserfsck
+		--quiet option is added
+		--fix-bogus-files option is added to fix transprently
+		corrupted modes and to fix sizes which are longer that
+		real file size
+		directory item verifying changed
+		-u has been replaced with -b to pass reiserfsck the list
+		of block to build tree off
+		-c is added to have pass 0 to save bitmap fo leaves found
+
+2001-03-10
+	* called 3.x.0h
+	* configure.in
+		RPM_OPT_FLASG is added to CFLAGS (Anthon van der Neut)
+	* reiserfsck
+		-u option is added. It should save time when repeating
+		--rebuild-tree
+		hash hits statistic is added on pass 0
+	
+2001-03-07
+	* reiserfsck
+		-V option to print version and exit added
+		--fix-fixable changed: directory's sd_size and st_blocks
+		corrections, removing of entries pointing to nowhere
+	
+	* resize_reiserfs
+		man page is added
+
+2001-03-05
+	* resize_reiserfs
+		Marcel Waldvogel <mwa@arlq.wustl.edu>'s user interface and
+		error messages improvements
+
+2001-03-01
+	* mkreiserfs
+		-q option is added (Larry Auton <lda@winux.com>)
+	* reiserfsck
+		--fix-fixable changed: bitmap correction commented
+		out. Correction of broken slots of indirect items and
+		corrections of dir entry state added
+	
+2001-02-23
+	* called 3.x.0e
+	* reiserfsck
+		not tested on 2.2
+		is now able to work with regular file (2.4.x is needed for that)
+		lost+found fixed: it now first links directories then
+		files. Still not good as it can not pull out deep directory
+
+2001-02-19
+	* called 3.x.0c
+	* reiserfsck
+		--fix-fixable option is added. So far it only repairs bitmaps
+		and free block count when they mismatch
+	* library
+		reiserfs_find/add_entry added
+	
+2001-02-05
+	* mkreiserfs
+		can make filesystem with 1 data block
+		3.6 format is now default
+
+2001-01-20
+	* portability
+		Zam ran the reiserfsprogs on alpha
+	* resizer
+		Zam managed to resize few partitions.
+	* reiserfsck
+		pass0 deletes items which are out of order, tries to fix
+		items with zeroed k_objectid or k_dir_id and to throw
+		items which are transparently out of order and tries to
+		fix "." and ".." of directory items. Pass0 corrects also
+		corruptions in directory items
+	* man pages:
+		get included into dist when doing 'make dist'
+	* mkreisrefs
+		explains what is mininal size of reiserfs partition which
+		can be created		
+	
+2001-01-12
+	* reiserfsck:
+		--interactive option is added
+	* debugreiserfs:
+		few bugs fixed
+	
+2001-01-07
+	* reiserfs library:
+		started with reiserfs_open, reiserfs_close, bitmap tools
+	* reiserfsck:
+		filesystem mounted read-only can be checked
+		number of options decreased
+		journal replay fixed
+		pass 0 added.
+		fsck can be stopped after the tree is built. (should safe time when debugging)
+		a lot of work still left
+	* debugreiserfs:
+		metadata packing changed
+		added a feature to intentionally corrupt filesystem (should be useful for fsck debugging)
+	* resizer:
+		not updated yet
+	
+	* man pages:
+		updated for all three progs
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  You can give `configure'
+initial values for variables by setting them in the environment.  Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+     CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+     env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory.  After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on.  Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+     CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+   If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+     Use and save the results of the tests in FILE instead of
+     `./config.cache'.  Set FILE to `/dev/null' to disable caching, for
+     debugging `configure'.
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..2e88813
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = include lib reiserfscore mkreiserfs fsck debugreiserfs resize_reiserfs
+
+EXTRA_DIST = version.h reiserfsprogs.spec
+
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..5f9f214
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,318 @@
+# 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@
+
+SUBDIRS = include lib reiserfscore mkreiserfs fsck debugreiserfs resize_reiserfs
+
+EXTRA_DIST = version.h reiserfsprogs.spec
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+DIST_COMMON =  README AUTHORS COPYING ChangeLog INSTALL Makefile.am \
+Makefile.in NEWS aclocal.m4 configure configure.in install-sh missing \
+mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4):  configure.in 
+	cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+	cd $(srcdir) && $(AUTOCONF)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+#     (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive  \
+check-recursive installcheck-recursive info-recursive dvi-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+	@set fnord $(MAKEFLAGS); amf=$$2; \
+	dot_seen=no; \
+	rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
+	  rev="$$subdir $$rev"; \
+	  test "$$subdir" = "." && dot_seen=yes; \
+	done; \
+	test "$$dot_seen" = "no" && rev=". $$rev"; \
+	target=`echo $@ | sed s/-recursive//`; \
+	for subdir in $$rev; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	   || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+	done && test -z "$$fail"
+tags-recursive:
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+	done
+
+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: tags-recursive $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+   if test "$$subdir" = .; then :; else \
+	    test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
+   fi; \
+	done; \
+	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 = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	-rm -rf $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+	mkdir $(distdir)/=build
+	mkdir $(distdir)/=inst
+	dc_install_base=`cd $(distdir)/=inst && pwd`; \
+	cd $(distdir)/=build \
+	  && ../configure --srcdir=.. --prefix=$$dc_install_base \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist
+	-rm -rf $(distdir)
+	@banner="$(distdir).tar.gz is ready for distribution"; \
+	dashes=`echo "$$banner" | sed s/./=/g`; \
+	echo "$$dashes"; \
+	echo "$$banner"; \
+	echo "$$dashes"
+dist: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+dist-all: distdir
+	-chmod -R a+r $(distdir)
+	GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+	-rm -rf $(distdir)
+distdir: $(DISTFILES)
+	-rm -rf $(distdir)
+	mkdir $(distdir)
+	-chmod 777 $(distdir)
+	@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
+	for subdir in $(SUBDIRS); do \
+	  if test "$$subdir" = .; then :; else \
+	    test -d $(distdir)/$$subdir \
+	    || mkdir $(distdir)/$$subdir \
+	    || exit 1; \
+	    chmod 777 $(distdir)/$$subdir; \
+	    (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+info-am:
+info: info-recursive
+dvi-am:
+dvi: dvi-recursive
+check-am: all-am
+check: check-recursive
+installcheck-am:
+installcheck: installcheck-recursive
+install-exec-am:
+install-exec: install-exec-recursive
+
+install-data-am:
+install-data: install-data-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-recursive
+uninstall-am:
+uninstall: uninstall-recursive
+all-am: Makefile
+all-redirect: all-recursive
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs: installdirs-recursive
+installdirs-am:
+
+
+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-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-recursive
+
+clean-am:  clean-tags clean-generic mostlyclean-am
+
+clean: clean-recursive
+
+distclean-am:  distclean-tags distclean-generic clean-am
+
+distclean: distclean-recursive
+	-rm -f config.status
+
+maintainer-clean-am:  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-recursive
+	-rm -f config.status
+
+.PHONY: install-data-recursive uninstall-data-recursive \
+install-exec-recursive uninstall-exec-recursive installdirs-recursive \
+uninstalldirs-recursive all-recursive check-recursive \
+installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive 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-am \
+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:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..4254a42
--- /dev/null
+++ b/README
@@ -0,0 +1,157 @@
+[LICENSING] 
+
+ReiserFS is hereby licensed under the GNU General
+Public License version 2.
+
+Source code files that contain the phrase "licensing governed by
+reiserfs/README" are "governed files" throughout this file.  Governed
+files are licensed under the GPL.  The portions of them owned by Hans
+Reiser, or authorized to be licensed by him, have been in the past,
+and likely will be in the future, licensed to other parties under
+other licenses.  If you add your code to governed files, and don't
+want it to be owned by Hans Reiser, put your copyright label on that
+code so the poor blight and his customers can keep things straight.
+All portions of governed files not labeled otherwise are owned by Hans
+Reiser, and by adding your code to it, widely distributing it to
+others or sending us a patch, and leaving the sentence in stating that
+licensing is governed by the statement in this file, you accept this.
+It will be a kindness if you identify whether Hans Reiser is allowed
+to license code labeled as owned by you on your behalf other than
+under the GPL, because he wants to know if it is okay to do so and put
+a check in the mail to you (for non-trivial improvements) when he
+makes his next sale.  He makes no guarantees as to the amount if any,
+though he feels motivated to motivate contributors, and you can surely
+discuss this with him before or after contributing.  You have the
+right to decline to allow him to license your code contribution other
+than under the GPL.
+
+Further licensing options are available for commercial and/or other
+interests directly from Hans Reiser: hans@reiser.to.  If you interpret
+the GPL as not allowing those additional licensing options, you read
+it wrongly, and Richard Stallman agrees with me, when carefully read
+you can see that those restrictions on additional terms do not apply
+to the owner of the copyright, and my interpretation of this shall
+govern for this license.  
+
+Finally, nothing in this license shall be interpreted to allow you to
+fail to fairly credit me, or to remove my credits, without my
+permission, unless you are an end user not redistributing to others.
+If you have doubts about how to properly do that, or about what is
+fair, ask.  (Last I spoke with him Richard was contemplating how best
+to address the fair crediting issue in the next GPL version.)
+
+[END LICENSING]
+
+Reiserfs is a file system based on balanced tree algorithms, which is
+described at http://www.namesys.com .
+
+Stop reading here.  Go there, then return.
+
+Send bug reports to yura@namesys.botik.ru.
+
+mkreiserfs and other utilities are in reiserfs/utils, or wherever your
+Linux provider put them.  There is some disagreement about how useful
+it is for users to get their fsck and mkreiserfs out of sync with the
+version of reiserfs that is in their kernel, with many important
+distributors wanting them out of sync.:-) Please try to remember to
+recompile and reinstall fsck and mkreiserfs with every update of
+reiserfs, this is a common source of confusion.  Note that some of the
+utilities cannot be compiled without accessing the balancing code
+which is in the kernel code, and relocating the utilities may require
+you to specify where that code can be found.
+
+Yes, if you update your reiserfs kernel module you do have to
+recompile your kernel, most of the time.  The errors you get will be
+quite cryptic if your forget to do so.
+
+Real users, as opposed to folks who want to hack and then understand
+what went wrong, will want REISERFS_CHECK off.
+
+Hideous Commercial Pitch: Spread your development costs across other OS
+vendors.  Select from the best in the world, not the best in your
+building, by buying from third party OS component suppliers.  Leverage
+the software component development power of the internet.  Be the most
+aggressive in taking advantage of the commercial possibilities of
+decentralized internet development, and add value through your branded
+integration that you sell as an operating system.  Let your competitors
+be the ones to compete against the entire internet by themselves.  Be
+hip, get with the new economic trend, before your competitors do.  Send
+email to hans@reiser.to.
+
+To understand the code, after reading the website, start reading the
+code by reading reiserfs_fs.h first.
+
+Hans Reiser was the project initiator, primary architect, source of all
+funding for the first 5.5 years, and one of the programmers.  He owns
+the copyright.
+
+Vladimir Saveljev was one of the programmers, and he worked long hours
+writing the cleanest code.  He always made the effort to be the best he
+could be, and to make his code the best that it could be.  What resulted
+was quite remarkable. I don't think that money can ever motivate someone
+to work the way he did, he is one of the most selfless men I know.
+
+Yura helps with benchmarking, coding hashes, and block pre-allocation
+code.
+
+Anatoly Pinchuk is a former member of our team who worked closely with
+Vladimir throughout the project's development.  He wrote a quite
+substantial portion of the total code.  He realized that there was a
+space problem with packing tails of files for files larger than a node
+that start on a node aligned boundary (there are reasons to want to node
+align files), and he invented and implemented indirect items and
+unformatted nodes as the solution.
+
+Konstantin Shvachko, with the help of the Russian version of a VC,
+tried to put me in a position where I was forced into giving control
+of the project to him.  (Fortunately, as the person paying the money
+for all salaries from my dayjob I owned all copyrights, and you can't
+really force takeovers of sole proprietorships.)  This was something
+curious, because he never really understood the value of our project,
+why we should do what we do, or why innovation was possible in
+general, but he was sure that he ought to be controlling it.  Every
+innovation had to be forced past him while he was with us.  He added
+two years to the time required to complete reiserfs, and was a net
+loss for me.  Mikhail Gilula was a brilliant innovator who also left
+in a destructive way that erased the value of his contributions, and
+that he was shown much generosity just makes it more painful.
+
+Grigory Zaigralin was an extremely effective system administrator for
+our group.
+
+Igor Krasheninnikov was wonderful at hardware procurement, repair, and
+network installation.
+
+Jeremy Fitzhardinge wrote the teahash.c code, and he gives credit to a
+textbook he got the algorithm from in the code.  Note that his analysis
+of how we could use the hashing code in making 32 bit NFS cookies work
+was probably more important than the actual algorithm.  Colin Plumb also
+contributed to it.
+
+Chris Mason dived right into our code, and in just a few months produced
+the journaling code that dramatically increased the value of ReiserFS.
+He is just an amazing programmer.
+
+Igor Zagorovsky is writing much of the new item handler and extent code
+for our next major release.
+
+Alexander Zarochentcev (sometimes known as zam, or sasha), wrote the
+resizer, and is hard at work on implementing allocate on flush.  SGI
+implemented allocate on flush before us for XFS, and generously took
+the time to convince me we should do it also.  They are great people,
+and a great company.
+
+Yuri Shevchuk and Nikita Danilov are doing squid cache optimization.
+
+Vitaly Fertman is doing fsck.
+
+SuSE, IntegratedLinux.com, Ecila, MP3.com, bigstorage.com, and the
+Alpha PC Company made it possible for me to not have a day job
+anymore, and to dramatically increase our staffing.  Ecila funded
+hypertext feature development, MP3.com funded journaling, SuSE funded
+core development, IntegratedLinux.com funded squid web cache
+appliances, bigstorage.com funded HSM, and the alpha PC company funded
+the alpha port.  Many of these tasks were helped by sponsors other
+than the ones just named.  SuSE has helped in much more than just
+funding....
+
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..9f8add8
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,104 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Do all the work for Automake.  This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "[$]*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "[$]*" != "X $srcdir/configure conftestfile" \
+      && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "[$]2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+   $1=$2
+   AC_MSG_RESULT(found)
+else
+   $1="$3/missing $2"
+   AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
diff --git a/configure b/configure
new file mode 100755
index 0000000..59577f1
--- /dev/null
+++ b/configure
@@ -0,0 +1,2066 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13 
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_default_prefix=/
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  case "$ac_option" in
+  -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ac_optarg= ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case "$ac_option" in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir="$ac_optarg" ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build="$ac_optarg" ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file="$ac_optarg" ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir="$ac_optarg" ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    eval "enable_${ac_feature}=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+    fi
+    ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix="$ac_optarg" ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he)
+    # Omit some internal or obsolete options to make the list less imposing.
+    # This message is too long to be a string in the A/UX 3.1 sh.
+    cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+  --cache-file=FILE       cache test results in FILE
+  --help                  print this message
+  --no-create             do not create output files
+  --quiet, --silent       do not print \`checking...' messages
+  --version               print the version of autoconf that created configure
+Directory and file names:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [same as prefix]
+  --bindir=DIR            user executables in DIR [EPREFIX/bin]
+  --sbindir=DIR           system admin executables in DIR [EPREFIX/sbin]
+  --libexecdir=DIR        program executables in DIR [EPREFIX/libexec]
+  --datadir=DIR           read-only architecture-independent data in DIR
+                          [PREFIX/share]
+  --sysconfdir=DIR        read-only single-machine data in DIR [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data in DIR
+                          [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data in DIR [PREFIX/var]
+  --libdir=DIR            object code libraries in DIR [EPREFIX/lib]
+  --includedir=DIR        C header files in DIR [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc in DIR [/usr/include]
+  --infodir=DIR           info documentation in DIR [PREFIX/info]
+  --mandir=DIR            man documentation in DIR [PREFIX/man]
+  --srcdir=DIR            find the sources in DIR [configure dir or ..]
+  --program-prefix=PREFIX prepend PREFIX to installed program names
+  --program-suffix=SUFFIX append SUFFIX to installed program names
+  --program-transform-name=PROGRAM
+                          run sed PROGRAM on installed program names
+EOF
+    cat << EOF
+Host type:
+  --build=BUILD           configure for building on BUILD [BUILD=HOST]
+  --host=HOST             configure for HOST [guessed]
+  --target=TARGET         configure for TARGET [TARGET=HOST]
+Features and packages:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --x-includes=DIR        X include files are in DIR
+  --x-libraries=DIR       X library files are in DIR
+EOF
+    if test -n "$ac_help"; then
+      echo "--enable and --with options recognized:$ac_help"
+    fi
+    exit 0 ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host="$ac_optarg" ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir="$ac_optarg" ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir="$ac_optarg" ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir="$ac_optarg" ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir="$ac_optarg" ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir="$ac_optarg" ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir="$ac_optarg" ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir="$ac_optarg" ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix="$ac_optarg" ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix="$ac_optarg" ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix="$ac_optarg" ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name="$ac_optarg" ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir="$ac_optarg" ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir="$ac_optarg" ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site="$ac_optarg" ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir="$ac_optarg" ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir="$ac_optarg" ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target="$ac_optarg" ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers)
+    echo "configure generated by autoconf version 2.13"
+    exit 0 ;;
+
+  -with-* | --with-*)
+    ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case "$ac_option" in
+      *=*) ;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_${ac_package}='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+    # Reject names that are not valid shell variable names.
+    if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+      { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+    fi
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    eval "with_${ac_package}=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes="$ac_optarg" ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries="$ac_optarg" ;;
+
+  -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+    ;;
+
+  *)
+    if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+      echo "configure: warning: $ac_option: invalid host type" 1>&2
+    fi
+    if test "x$nonopt" != xNONE; then
+      { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+    fi
+    nonopt="$ac_option"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+  exec 6>/dev/null
+else
+  exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+  case "$ac_arg" in
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c) ;;
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+  *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+  ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+  *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+  esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set.  These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}"   = set; then LANG=C;   export LANG;   fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=version.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_prog=$0
+  ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+  test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+  else
+    { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+  fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    echo "loading site script $ac_site_file"
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  echo "loading cache $cache_file"
+  . $cache_file
+else
+  echo "creating cache $cache_file"
+  > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+  # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+  if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+    ac_n= ac_c='
+' ac_t='	'
+  else
+    ac_n=-n ac_c= ac_t=
+  fi
+else
+  ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+  if test -f $ac_dir/install-sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f $ac_dir/install.sh; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:558: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    IFS="${IFS= 	}"; ac_save_IFS="$IFS"; IFS=":"
+  for ac_dir in $PATH; do
+    # Account for people who put trailing slashes in PATH elements.
+    case "$ac_dir/" in
+    /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+    *)
+      # OSF1 and SCO ODT 3.0 have their own names for install.
+      # Don't use installbsd from OSF since it installs stuff as root
+      # by default.
+      for ac_prog in ginstall scoinst install; do
+        if test -f $ac_dir/$ac_prog; then
+	  if test $ac_prog = install &&
+            grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  else
+	    ac_cv_path_install="$ac_dir/$ac_prog -c"
+	    break 2
+	  fi
+	fi
+      done
+      ;;
+    esac
+  done
+  IFS="$ac_save_IFS"
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL="$ac_cv_path_install"
+  else
+    # As a last resort, use the slow shell script.  We don't cache a
+    # path for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the path is relative.
+    INSTALL="$ac_install_sh"
+  fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:611: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t $srcdir/configure conftestfile`
+   fi
+   if test "$*" != "X $srcdir/configure conftestfile" \
+      && test "$*" != "X conftestfile $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { echo "configure: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+   fi
+
+   test "$2" = conftestfile
+   )
+then
+   # Ok.
+   :
+else
+   { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+  program_transform_name=
+else
+  # Double any \ or $.  echo might interpret backslashes.
+  cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+  program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+  rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+  program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:668: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftestmake <<\EOF
+all:
+	@echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+  eval ac_cv_prog_make_${ac_make}_set=yes
+else
+  eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  SET_MAKE=
+else
+  echo "$ac_t""no" 1>&6
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=reiserfsprogs
+
+VERSION=3.x.0j
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+  { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:714: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+   ACLOCAL=aclocal
+   echo "$ac_t""found" 1>&6
+else
+   ACLOCAL="$missing_dir/missing aclocal"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:727: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+   AUTOCONF=autoconf
+   echo "$ac_t""found" 1>&6
+else
+   AUTOCONF="$missing_dir/missing autoconf"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:740: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+   AUTOMAKE=automake
+   echo "$ac_t""found" 1>&6
+else
+   AUTOMAKE="$missing_dir/missing automake"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:753: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+   AUTOHEADER=autoheader
+   echo "$ac_t""found" 1>&6
+else
+   AUTOHEADER="$missing_dir/missing autoheader"
+   echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:766: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf.  Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+   MAKEINFO=makeinfo
+   echo "$ac_t""found" 1>&6
+else
+   MAKEINFO="$missing_dir/missing makeinfo"
+   echo "$ac_t""missing" 1>&6
+fi
+
+
+
+
+
+PRESET_CFLAGS=$CFLAGS
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:786: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="gcc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:816: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_prog_rejected=no
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+        ac_prog_rejected=yes
+	continue
+      fi
+      ac_cv_prog_CC="cc"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# -gt 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    set dummy "$ac_dir/$ac_word" "$@"
+    shift
+    ac_cv_prog_CC="$@"
+  fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+  if test -z "$CC"; then
+    case "`uname -s`" in
+    *win32* | *WIN32*)
+      # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:867: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_CC="cl"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+  echo "$ac_t""$CC" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+ ;;
+    esac
+  fi
+  test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:899: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 910 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  ac_cv_prog_cc_works=yes
+  # If we can't run a trivial program, we are probably using a cross compiler.
+  if (./conftest; exit) 2>/dev/null; then
+    ac_cv_prog_cc_cross=no
+  else
+    ac_cv_prog_cc_cross=yes
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+  { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:941: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:946: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.c <<EOF
+#ifdef __GNUC__
+  yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:955: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+  ac_cv_prog_gcc=yes
+else
+  ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:974: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+  ac_cv_prog_cc_g=yes
+else
+  ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+
+if test -z $PRESET_CFLAGS; then
+    CFLAGS="${RPM_OPT_FLAGS} -g -O2 -Wall"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1012: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+  IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+  ac_dummy="$PATH"
+  for ac_dir in $ac_dummy; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$ac_word; then
+      ac_cv_prog_RANLIB="ranlib"
+      break
+    fi
+  done
+  IFS="$ac_save_ifs"
+  test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+  echo "$ac_t""$RANLIB" 1>&6
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1042: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1057 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1063: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1074 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1080: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1091 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1097: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1122: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1127 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1135: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  ac_cv_header_stdc=yes
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1152 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "memchr" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1170 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "free" >/dev/null 2>&1; then
+  :
+else
+  rm -rf conftest*
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+  :
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1191 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1202: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  :
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+  cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in fcntl.h limits.h malloc.h sys/ioctl.h unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1229: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1234 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1239: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1267: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1272 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this.  */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this.  */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this.  */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+   It does not let you subtract one const X* pointer from another in an arm
+   of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this.  */
+  char *t;
+  char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+  *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+  int x[] = {25, 17};
+  const int *foo = &x[0];
+  ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+  typedef const int *iptr;
+  iptr p = 0;
+  ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+  struct s { int j; const int *ap[3]; };
+  struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+  const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1321: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_const=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+  cat >> confdefs.h <<\EOF
+#define const 
+EOF
+
+fi
+
+echo $ac_n "checking for inline""... $ac_c" 1>&6
+echo "configure:1342: checking for inline" >&5
+if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat > conftest.$ac_ext <<EOF
+#line 1349 "configure"
+#include "confdefs.h"
+
+int main() {
+} $ac_kw foo() {
+; return 0; }
+EOF
+if { (eval echo configure:1356: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+done
+
+fi
+
+echo "$ac_t""$ac_cv_c_inline" 1>&6
+case "$ac_cv_c_inline" in
+  inline | yes) ;;
+  no) cat >> confdefs.h <<\EOF
+#define inline 
+EOF
+ ;;
+  *)  cat >> confdefs.h <<EOF
+#define inline $ac_cv_c_inline
+EOF
+ ;;
+esac
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&6
+echo "configure:1382: checking for size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1387 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_type_size_t=yes
+else
+  rm -rf conftest*
+  ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&6
+if test $ac_cv_type_size_t = no; then
+  cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for st_rdev in struct stat""... $ac_c" 1>&6
+echo "configure:1415: checking for st_rdev in struct stat" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_st_rdev'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1420 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+int main() {
+struct stat s; s.st_rdev;
+; return 0; }
+EOF
+if { (eval echo configure:1428: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  ac_cv_struct_st_rdev=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  ac_cv_struct_st_rdev=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_st_rdev" 1>&6
+if test $ac_cv_struct_st_rdev = yes; then
+  cat >> confdefs.h <<\EOF
+#define HAVE_ST_RDEV 1
+EOF
+
+fi
+
+
+if test $ac_cv_prog_gcc = yes; then
+    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
+echo "configure:1451: checking whether ${CC-cc} needs -traditional" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat > conftest.$ac_ext <<EOF
+#line 1457 "configure"
+#include "confdefs.h"
+#include <sgtty.h>
+Autoconf TIOCGETP
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+else
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+  if test $ac_cv_prog_gcc_traditional = no; then
+    cat > conftest.$ac_ext <<EOF
+#line 1475 "configure"
+#include "confdefs.h"
+#include <termio.h>
+Autoconf TCGETA
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "$ac_pattern" >/dev/null 2>&1; then
+  rm -rf conftest*
+  ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+  fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
+echo "configure:1497: checking for 8-bit clean memcmp" >&5
+if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  ac_cv_func_memcmp_clean=no
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1505 "configure"
+#include "confdefs.h"
+
+main()
+{
+  char c0 = 0x40, c1 = 0x80, c2 = 0x81;
+  exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
+}
+
+EOF
+if { (eval echo configure:1515: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_func_memcmp_clean=yes
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -fr conftest*
+  ac_cv_func_memcmp_clean=no
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6
+test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}"
+
+echo $ac_n "checking for strftime""... $ac_c" 1>&6
+echo "configure:1533: checking for strftime" >&5
+if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1538 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char strftime(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strftime();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_strftime) || defined (__stub___strftime)
+choke me
+#else
+strftime();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1561: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_strftime=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+# strftime is in -lintl on SCO UNIX.
+echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6
+echo "configure:1583: checking for strftime in -lintl" >&5
+ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lintl  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1591 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char strftime();
+
+int main() {
+strftime()
+; return 0; }
+EOF
+if { (eval echo configure:1602: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_STRFTIME 1
+EOF
+
+LIBS="-lintl $LIBS"
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:1629: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1634 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char vprintf(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1657: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:1681: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1686 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char _doprnt(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1709: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+for ac_func in strerror strstr strtol
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1736: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1741 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func(); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1764: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+ 
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs.  It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already.  You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+  case `(ac_space=' '; set | grep ac_space) 2>&1` in
+  *ac_space=\ *)
+    # `set' does not quote correctly, so add quotes (double-quote substitution
+    # turns \\\\ into \\, and sed turns \\ into \).
+    sed -n \
+      -e "s/'/'\\\\''/g" \
+      -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+    ;;
+  *)
+    # `set' quotes correctly as required by POSIX, so do not add quotes.
+    sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+    ;;
+  esac >> confcache
+if cmp -s $cache_file confcache; then
+  :
+else
+  if test -w $cache_file; then
+    echo "updating cache $cache_file"
+    cat confcache > $cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[ 	]*VPATH[ 	]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ 	`~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+  case "\$ac_option" in
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+    exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+  -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+    echo "$CONFIG_STATUS generated by autoconf version 2.13"
+    exit 0 ;;
+  -help | --help | --hel | --he | --h)
+    echo "\$ac_cs_usage"; exit 0 ;;
+  *) echo "\$ac_cs_usage"; exit 1 ;;
+  esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "include/Makefile mkreiserfs/Makefile resize_reiserfs/Makefile fsck/Makefile lib/Makefile Makefile reiserfscore/Makefile debugreiserfs/Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@RANLIB@%$RANLIB%g
+s%@CPP@%$CPP%g
+s%@LIBOBJS@%$LIBOBJS%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+  if test $ac_beg -gt 1; then
+    sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+  else
+    sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+  fi
+  if test ! -s conftest.s$ac_file; then
+    ac_more_lines=false
+    rm -f conftest.s$ac_file
+  else
+    if test -z "$ac_sed_cmds"; then
+      ac_sed_cmds="sed -f conftest.s$ac_file"
+    else
+      ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+    fi
+    ac_file=`expr $ac_file + 1`
+    ac_beg=$ac_end
+    ac_end=`expr $ac_end + $ac_max_sed_cmds`
+  fi
+done
+if test -z "$ac_sed_cmds"; then
+  ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"include/Makefile mkreiserfs/Makefile resize_reiserfs/Makefile fsck/Makefile lib/Makefile Makefile reiserfscore/Makefile debugreiserfs/Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case "$ac_file" in
+  *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+       ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+  *) ac_file_in="${ac_file}.in" ;;
+  esac
+
+  # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+  # Remove last slash and all that follows it.  Not all systems have dirname.
+  ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+  if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+    # The file is in a subdirectory.
+    test ! -d "$ac_dir" && mkdir "$ac_dir"
+    ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+    # A "../" for each directory in $ac_dir_suffix.
+    ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+  else
+    ac_dir_suffix= ac_dots=
+  fi
+
+  case "$ac_given_srcdir" in
+  .)  srcdir=.
+      if test -z "$ac_dots"; then top_srcdir=.
+      else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+  /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+  *) # Relative path.
+    srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+    top_srcdir="$ac_dots$ac_given_srcdir" ;;
+  esac
+
+  case "$ac_given_INSTALL" in
+  [/$]*) INSTALL="$ac_given_INSTALL" ;;
+  *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+  esac
+
+  echo creating "$ac_file"
+  rm -f "$ac_file"
+  configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+  case "$ac_file" in
+  *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+  *) ac_comsub= ;;
+  esac
+
+  ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+  sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
+
+
+
+
+
+
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..476aee4
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,48 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(version.h)
+
+AM_INIT_AUTOMAKE(reiserfsprogs, 3.x.0j)
+
+dnl We install in /sbin, the utils are to be available on boot
+AC_PREFIX_DEFAULT(/)
+
+PRESET_CFLAGS=$CFLAGS
+AC_PROG_CC
+if test -z $PRESET_CFLAGS; then
+dnl    CFLAGS="${RPM_OPT_FLAGS} $CFLAGS -Wall"
+    CFLAGS="${RPM_OPT_FLAGS} -g -O2 -Wall"
+fi
+
+dnl Checks for programs.
+AC_PROG_RANLIB
+dnl AC_PROG_AWK
+dnl AC_PROG_INSTALL
+dnl AC_PROG_LN_S
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h limits.h malloc.h sys/ioctl.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_STRUCT_ST_RDEV
+
+dnl Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_MEMCMP
+AC_FUNC_STRFTIME
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS(strerror strstr strtol)
+
+AC_OUTPUT(include/Makefile mkreiserfs/Makefile resize_reiserfs/Makefile fsck/Makefile lib/Makefile Makefile reiserfscore/Makefile debugreiserfs/Makefile)
+
+
+
+
+
+
+
diff --git a/debugreiserfs/Makefile.am b/debugreiserfs/Makefile.am
new file mode 100644
index 0000000..a5b1124
--- /dev/null
+++ b/debugreiserfs/Makefile.am
@@ -0,0 +1,10 @@
+sbin_PROGRAMS = debugreiserfs unpack
+
+debugreiserfs_SOURCES = debugreiserfs.c pack.c
+unpack_SOURCES = unpack.c debugreiserfs.h
+man_MANS = debugreiserfs.8
+EXTRA_DIST = $(man_MANS)
+
+LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
+
+INCLUDES = -I../include
diff --git a/debugreiserfs/Makefile.in b/debugreiserfs/Makefile.in
new file mode 100644
index 0000000..c73aa68
--- /dev/null
+++ b/debugreiserfs/Makefile.in
@@ -0,0 +1,339 @@
+# 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 = debugreiserfs unpack
+
+debugreiserfs_SOURCES = debugreiserfs.c pack.c
+unpack_SOURCES = unpack.c debugreiserfs.h
+man_MANS = debugreiserfs.8
+EXTRA_DIST = $(man_MANS)
+
+LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
+
+INCLUDES = -I../include
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(sbin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+debugreiserfs_OBJECTS =  debugreiserfs.o pack.o
+debugreiserfs_LDADD = $(LDADD)
+debugreiserfs_DEPENDENCIES =  ../lib/libmisc.a ../reiserfscore/libcore.a
+debugreiserfs_LDFLAGS = 
+unpack_OBJECTS =  unpack.o
+unpack_LDADD = $(LDADD)
+unpack_DEPENDENCIES =  ../lib/libmisc.a ../reiserfscore/libcore.a
+unpack_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 = $(debugreiserfs_SOURCES) $(unpack_SOURCES)
+OBJECTS = $(debugreiserfs_OBJECTS) $(unpack_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 debugreiserfs/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:
+
+debugreiserfs: $(debugreiserfs_OBJECTS) $(debugreiserfs_DEPENDENCIES)
+	@rm -f debugreiserfs
+	$(LINK) $(debugreiserfs_LDFLAGS) $(debugreiserfs_OBJECTS) $(debugreiserfs_LDADD) $(LIBS)
+
+unpack: $(unpack_OBJECTS) $(unpack_DEPENDENCIES)
+	@rm -f unpack
+	$(LINK) $(unpack_LDFLAGS) $(unpack_OBJECTS) $(unpack_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 = debugreiserfs
+
+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
+debugreiserfs.o: debugreiserfs.c debugreiserfs.h ../include/io.h \
+	../include/misc.h ../include/reiserfs_lib.h \
+	../include/reiserfs_fs.h ../version.h
+pack.o: pack.c debugreiserfs.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h
+unpack.o: unpack.c debugreiserfs.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.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:
diff --git a/debugreiserfs/debugreiserfs.8 b/debugreiserfs/debugreiserfs.8
new file mode 100644
index 0000000..9de473f
--- /dev/null
+++ b/debugreiserfs/debugreiserfs.8
@@ -0,0 +1,68 @@
+.\" -*- nroff -*-
+.\" Copyright 1996-2001 Hans Reiser.
+.\" 
+.TH DEBUGREISERFS 8 "March 2001" "Reiserfsprogs 3.x.0j"
+.SH NAME
+debugreiserfs
+.SH SYNOPSIS
+.B debugreiserfs
+[
+.B -jdcmos
+] [
+.B -b \fIblocknumber
+] [
+.B -p \fIfilename.bmp
+] [
+.B -P \fIfilename.bmp
+]
+.I device
+.SH DESCRIPTION
+It helps sometimes to solve problems with reiserfs filesystems. Being
+called w/o options it prints super block of reiserfs filesystem found
+on the \fIdevice\fR.
+.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
+\fB-j
+print contents of journal
+.TP
+\fB-d
+print formatted nodes of the filesystem
+.TP
+\fB-c
+print contents of direct items
+.TP
+\fB-m
+print contents of bitmap (not very useful)
+.TP
+\fB-o
+print objectid map (not very useful)
+.TP
+\fB-s
+scans the partition and prints a line when any kind of reiserfs formatted nodes found
+.TP
+\fB-b \fIblocknumber
+print specified block of the filesystem
+.TP
+\fB-p \fIfilename
+\fB-P \fIfilename
+
+Makes \fBdebugreiserfs\fR to find filesystem metadata 
+These exist to help reiserfsck debugging. If reiserfsck fails -
+you may extract filesystem metadata with  \fBdebugreiserfs\fR -p filename /dev/xxx |gzip
+-c > xxx.gz. We download that data and make the filesystem similar
+to your with gunzip -c xxx.gz | unpack /dev/xxx (unpack is included
+into reiserfsprogs package). This usually allows to reproduce and
+debug the problem quickly. When data file is not too large.
+-P will cause  \fBdebugreiserfs\fR to find and pack metadata from all the device whereas with -p it will only go through blocks marked used in filesystem bitmaps
+
+.SH AUTHOR
+This version of \fBdebugreiserfs\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 SEE ALSO
+.BR reiserfsck (8),
+.BR mkreiserfs (8)
diff --git a/debugreiserfs/debugreiserfs.c b/debugreiserfs/debugreiserfs.c
new file mode 100644
index 0000000..ad6abf8
--- /dev/null
+++ b/debugreiserfs/debugreiserfs.c
@@ -0,0 +1,1044 @@
+/*
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+#include "debugreiserfs.h"
+
+reiserfs_filsys_t fs;
+
+#define print_usage_and_exit() die ("Usage: %s [-b block-to-print][-idc] device\n\
+-i Causes to print all items of a leaf\n\
+-d                 content of directory items\n\
+-c                 content of direct items\n\
+-m                 bitmap blocks\n\
+-t\n\
+-C\n\
+-p\n\
+-s                 \n\
+-n                 scan for name\n\
+-p [filename]\n\
+-P [filename]\n\
+..etc\n", argv[0]);
+
+
+
+#if 1
+struct reiserfs_fsstat {
+    int nr_internals;
+    int nr_leaves;
+    int nr_files;
+    int nr_directories;
+    int nr_unformatted;
+} g_stat_info;
+#endif
+
+
+int mode = DO_DUMP;
+
+/*
+ *  options
+ */
+int opt_print_regular_file_content = 0;/* -c */
+int opt_print_details = 0;	/* -d */
+int opt_print_leaf_items = 0;	/* -i */
+int opt_print_objectid_map = 0;	/* -o */
+int opt_print_block_map = 0;	/* -m */
+int opt_print_journal;		/* -j */
+
+/* when you want print one block specify -b # */
+int opt_block_to_print = -1;
+
+/* when you want to corrupt block specify -C # */
+int opt_block_to_corrupt = -1;
+
+int opt_pack = 0;
+int opt_quiet = 0;
+
+int print_mode (void)
+{
+    int mode = 0;
+
+    if (opt_print_leaf_items == 1)
+	mode |= PRINT_LEAF_ITEMS;
+    if (opt_print_details == 1)
+	mode |= (PRINT_LEAF_ITEMS | PRINT_ITEM_DETAILS);
+    if (opt_print_regular_file_content == 1)
+	mode |= (PRINT_LEAF_ITEMS | PRINT_DIRECT_ITEMS);
+    return mode;
+}
+
+
+static void print_disk_tree (reiserfs_filsys_t fs, int block_nr)
+{
+    struct buffer_head * bh;
+
+    bh = bread (fs->s_dev, block_nr, fs->s_blocksize);
+    if (!bh) {
+	die ("Could not read block %d\n", block_nr);
+    }
+    if (is_internal_node (bh)) {
+	int i;
+	struct disk_child * dc;
+
+	g_stat_info.nr_internals ++;
+	print_block (stdout, fs, bh, print_mode (), -1, -1);
+      
+	dc = B_N_CHILD (bh, 0);
+	for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++)
+	    print_disk_tree (fs, dc->dc_block_number);
+      
+    } else if (is_leaf_node (bh)) {
+	g_stat_info.nr_leaves ++;
+	print_block (stdout, fs, bh, print_mode (), -1, -1);
+    } else {
+	print_block (stdout, fs, bh, print_mode (), -1, -1);
+	die ("print_disk_tree: bad block type");
+    }
+    brelse (bh);
+}
+
+
+
+void pack_one_block (reiserfs_filsys_t fs, unsigned long block);
+static void print_one_block (reiserfs_filsys_t fs, int block)
+{
+    struct buffer_head * bh;
+    
+    if (test_bit (block % (fs->s_blocksize * 8), 
+		  SB_AP_BITMAP (fs)[block / (fs->s_blocksize * 8)]->b_data))
+	fprintf (stderr, "%d is used in true bitmap\n", block);
+    else
+	fprintf (stderr, "%d is free in true bitmap\n", block);
+    
+    bh = bread (fs->s_dev, block, fs->s_blocksize);
+    if (!bh) {
+	printf ("print_one_block: bread fialed\n");
+	return;
+    }
+
+    if (opt_pack) {
+	pack_one_block (fs, bh->b_blocknr);
+	brelse (bh);
+	return;
+    }
+
+    if (who_is_this (bh->b_data, fs->s_blocksize) != THE_UNKNOWN)
+	print_block (stdout, fs, bh, PRINT_LEAF_ITEMS | PRINT_ITEM_DETAILS | 
+		     (opt_print_regular_file_content == 1 ? PRINT_DIRECT_ITEMS : 0), -1, -1);
+    else
+	printf ("Looks like unformatted\n");
+    brelse (bh);
+    return;
+}
+
+
+static void corrupt_clobber_hash (char * name, struct item_head * ih, 
+				  struct reiserfs_de_head * deh)
+{
+    printf ("\tCorrupting deh_offset of entry \"%s\" of [%u %u]\n", name,
+	    ih->ih_key.k_dir_id, ih->ih_key.k_objectid);
+    deh->deh_offset = 700;
+}
+
+
+/* this reads list of desired corruptions from stdin and perform the
+   corruptions. Format of that list:
+   A hash_code
+   C name objectid     - 'C'ut entry 'name' from directory item with 'objectid'
+   H name objectid     - clobber 'H'hash of entry 'name' of directory 'objectid'
+   I item_num pos_in_item  make pos_in_item-th slot of indirect item to point out of device
+   O item_num          - destroy item 'O'rder - make 'item_num'-th to have key bigger than 'item_num' + 1-th item
+   D item_num          - 'D'elete item_num-th item
+   S item_num value    - change file size (item_num-th item must be stat data)
+   F item_num value    - change sd_first_direct_byte of stat data
+   J item_num objectid
+   E name objectid new - change entry's deh_objectid to new
+   P                   - print the block
+*/
+static void do_corrupt_one_block (reiserfs_filsys_t fs, int block)
+{
+    struct buffer_head * bh;
+    int i, j;
+    struct item_head * ih;
+    int item_num;
+    char * line = 0;
+    int n = 0;
+    char code, name [100];
+    __u32 objectid, new_objectid;
+    int value;
+    int hash_code;
+    int pos_in_item;
+
+    if (test_bit (block % (fs->s_blocksize * 8), 
+		  SB_AP_BITMAP (fs)[block / (fs->s_blocksize * 8)]->b_data))
+	fprintf (stderr, "%d is used in true bitmap\n", block);
+    else
+	fprintf (stderr, "%d is free in true bitmap\n", block);
+    
+    bh = bread (fs->s_dev, block, fs->s_blocksize);
+    if (!bh) {
+	printf ("corrupt_one_block: bread fialed\n");
+	return;
+    }
+
+    if (who_is_this (bh->b_data, fs->s_blocksize) != THE_LEAF) {
+	printf ("Can not corrupt not a leaf node\n");
+	brelse (bh);
+	return;
+    }
+
+    printf ("Corrupting block %lu..\n", bh->b_blocknr);
+
+    while (getline (&line, &n, stdin) != -1) {
+	switch (line[0]) {
+	case '#':
+	case '\n':
+	    continue;
+	case '?':
+	    printf ("A hash_code     - reset hAsh code in super block\n"
+		    "C name objectid - Cut entry 'name' from directory item with 'objectid'\n"
+		    "H name objectid - clobber Hash of entry 'name' of directory 'objectid'\n"
+		    "I item_num pos_in_item  make pos_in_tem-th slot of Indirect item to point out of device\n"
+		    "O item_num      - destroy item Order - make 'item_num'-th to have key bigger than 'item_num' + 1-th item\n"
+		    "D item_num      - Delete item_num-th item\n"
+		    "S item_num value - change file Size (item_num-th item must be stat data)\n"
+		    "F item_num value - change sd_First_direct_byte of stat data\n"
+		    "J item_num objectid - set 'obJectid' of 'item_num'-th item\n"
+		    "E name objectid objectid - set deh_objectid of an entry to objectid\n");
+
+	    continue;
+
+	case 'P':
+	    print_block (stderr, fs, bh, 3, -1, -1);
+	    break;
+	    
+	case 'A':
+	    /* corrupt hash record in super block */
+	    if (sscanf (line, "%c %d\n", &code, &hash_code) != 2) {
+		printf ("Wrong format \'%c\'\n", line [0]);
+		continue;
+	    }
+	    break;
+	    
+	case 'C': /* cut entry */
+	case 'H': /* make hash wrong */
+	    if (sscanf (line, "%c %s %u\n", &code, name, &objectid) != 3) {
+		printf ("Wrong format \'%c\'\n", line [0]);
+		continue;
+	    }
+	    break;
+
+	case 'J': /* set objectid : used to simulate objectid sharing problem */
+	    if (sscanf (line, "%c %d %d\n", &code, &item_num, &objectid) != 3) {
+		printf ("Wrong format \'%c\'\n", line [0]);
+		continue;
+	    }
+	    break;
+
+	case 'E': /* set objectid : used to simulate objectid sharing problem */
+	    if (sscanf (line, "%c %s %u %d\n", &code, name, &objectid, &new_objectid) != 4) {
+		printf ("Wrong format \'%c\'\n", line [0]);
+		continue;
+	    }
+	    break;
+
+	case 'I': /* break unformatted node pointer */
+	    if (sscanf (line, "%c %d %d\n", &code, &item_num, &pos_in_item) != 3) {
+		printf ("Wrong format \'%c\'\n", line [0]);
+		continue;
+	    }
+	    break;
+	    
+	case 'D': /* delete item */
+	case 'O': /* make item out of order */
+	    if (sscanf (line, "%c %d\n", &code, &item_num) != 2) {
+		printf ("Wrong format \'%c\'\n", line [0]);
+		continue;
+	    }
+	    break;
+	    
+	case 'S': /* corrupt st_size */
+	case 'F': /*         st_first_direct_byte */
+	    if (sscanf (line, "%c %d %d\n", &code, &item_num, &value) != 3) {
+		printf ("Wrong format \'%c\'\n", line [0]);
+		continue;
+	    }
+	    break;
+	}
+	
+	if (code == 'A') {
+	    reiserfs_warning (stderr, "Changing %s to %s\n", code2name (rs_hash (fs->s_rs)),
+			       code2name (hash_code));
+	    set_hash (fs->s_rs, hash_code);
+	    mark_buffer_dirty (fs->s_sbh);
+	    continue;
+	}
+
+	ih = B_N_PITEM_HEAD (bh, 0);
+	for (i = 0; i < node_item_number (bh); i ++, ih ++) {
+	    struct reiserfs_de_head * deh;
+
+	    if (code == 'I' && i == item_num) {
+		if (!is_indirect_ih (ih) || pos_in_item >= I_UNFM_NUM (ih)) {
+		    reiserfs_warning (stderr, "Not an indirect item or there is "
+				       "not so many unfm ptrs in it\n");
+		    continue;
+		}
+		* ((__u32 *)B_I_PITEM (bh, ih) + pos_in_item) = SB_BLOCK_COUNT(fs) + 100;
+		mark_buffer_dirty (bh);
+		goto cont;
+	    }
+
+	    if (code == 'J' && i == item_num) {
+		ih->ih_key.k_objectid = objectid;
+		mark_buffer_dirty (bh);
+		goto cont;
+	    }
+
+	    if (code == 'S' && i == item_num) {
+		/* fixme: old stat data only */
+		struct stat_data_v1 * sd;
+
+		sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih); 
+		reiserfs_warning (stderr, "Changing sd_size of %k from %d to %d\n",
+				   &ih->ih_key, sd->sd_size, value);
+		sd->sd_size = value;
+		mark_buffer_dirty (bh);
+		goto cont;		
+	    }
+
+	    if (code == 'F' && i == item_num) {
+		/* fixme: old stat data only */
+		struct stat_data_v1 * sd;
+
+		sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih); 
+		reiserfs_warning (stderr, "Changing sd_first_direct_byte of %k from %d to %d\n",
+				   &ih->ih_key, sd->sd_first_direct_byte, value);		
+		sd->sd_first_direct_byte = value;
+		mark_buffer_dirty (bh);
+		goto cont;		
+	    }
+
+	    if (code == 'D' && i == item_num) {
+		delete_item (fs, bh, item_num);
+		mark_buffer_dirty (bh);
+		goto cont;
+	    }
+
+	    if (code == 'O' && i == item_num) {
+		/* destroy item order */
+		struct key * key;
+		if (i == node_item_number (bh) - 1) {
+		    printf ("can not destroy order\n");
+		    continue;
+		}
+		key = &(ih + 1)->ih_key;
+		ih->ih_key.k_dir_id = key->k_dir_id + 1;
+		mark_buffer_dirty (bh);
+	    }
+
+	    if (ih->ih_key.k_objectid != objectid || !is_direntry_ih (ih))
+		continue;
+
+	    deh = B_I_DEH (bh, ih);
+
+	    for (j = 0; j < ih_entry_count (ih); j ++, deh ++) {
+		/* look for proper entry */
+		if (name_length (ih, deh, j) != strlen (name) ||
+		    strncmp (name, name_in_entry (deh, j), strlen (name)))
+		    continue;
+
+		/* ok, required entry found, make a corruption */
+		switch (code) {
+		case 'C': /* cut entry */
+		    cut_entry (fs, bh, i, j, 1);
+		    mark_buffer_dirty (bh);
+
+		    if (!B_IS_IN_TREE (bh)) {
+			printf ("NOTE: block is deleted from the tree\n");
+			exit (0);
+		    }
+		    goto cont;
+		    break;
+
+		case 'H': /* clobber hash */
+		    corrupt_clobber_hash (name, ih, deh);
+		    goto cont;
+		    break;
+
+		case 'E': /* change entry's deh_objectid */
+		    deh->deh_objectid = new_objectid;
+		    break;
+
+		default:
+		    printf ("Unknown command found\n");
+		}
+		mark_buffer_dirty (bh);
+	    }
+	}
+    cont:
+    }
+    free (line);
+    printf ("Done\n");
+    brelse (bh);
+    return;
+}
+
+
+/* this reads stdin and recover file of given key:  */
+/* the input has to be in the follwong format:
+   K dirid objectid
+   N name
+   B blocknumber
+   ..
+   then recover_file will read every block, look there specified file and put it into
+*/
+static void do_recover (reiserfs_filsys_t fs)
+{
+    char name [100];
+    char * line = 0;
+    int n = 0;
+    int fd;
+    struct key key = {0, 0, };
+    struct buffer_head * bh;
+    struct item_head * ih;
+    unsigned long block;
+    char code;
+    loff_t recovered = 0;
+    int i, j;
+    reiserfs_bitmap_t bitmap;
+    int used, not_used;
+
+    bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
+    reiserfs_fetch_disk_bitmap (bitmap, fs);
+    /* we check how many blocks recoverd items point to are free or used */
+    used = 0;
+    not_used = 0;
+
+    fd = 0;
+    while (getline (&line, &n, stdin) != -1) {
+	if (line [0] == '#' || line [0] == '\n')
+	    continue;
+	switch (line [0]) {
+	case 'K':
+	    /* get a key of file which is to be recovered */
+	    if (sscanf (line, "%c %u %u\n", &code, &key.k_dir_id, &key.k_objectid) != 3) {
+		die ("recover_file: wrong input K format");
+	    }
+	    printf ("Recovering file (%u, %u)\n", key.k_dir_id, key.k_objectid);
+	    break;
+
+	case 'N':
+	    /* get a file name */
+	    recovered = 0;
+	    if (sscanf (line, "%c %s\n", &code, name) != 2) {
+		die ("recover_file: wrong input N format");
+	    }
+	    fd = open (name, O_RDWR | O_CREAT | O_EXCL, 0644);
+	    if (fd == -1)
+		die ("recover_file: could not create file %s: %s",
+		     name,strerror (errno));
+	    printf ("Recovering file %s..\n", name);
+	    break;
+
+	case 'B':
+	    if (!fd)
+		die ("recover_file: file name is not specified");
+	    if (sscanf (line, "%c %lu\n", &code, &block) != 2) {
+		die ("recover_file: wrong input B format");
+	    }
+	    bh = bread (fs->s_dev, block, fs->s_blocksize);
+	    if (!bh) {
+		printf ("reading block %lu failed\n", block);
+		continue;
+	    }
+
+	    printf ("working with block %lu..\n", block);
+
+	    ih = B_N_PITEM_HEAD (bh, 0);
+	    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
+		__u32 * indirect;
+		struct buffer_head * tmp_bh;
+
+		if (!is_indirect_ih (ih) || key.k_dir_id != ih->ih_key.k_dir_id ||
+		    key.k_objectid != ih->ih_key.k_objectid)
+		    continue;
+
+		indirect = (__u32 *)B_I_PITEM (bh, ih);
+		for (j = 0; j < I_UNFM_NUM (ih); j ++) {
+		    block = le32_to_cpu (indirect [j]);
+		    if (!block)
+			continue;
+		    tmp_bh = bread (fs->s_dev, block, fs->s_blocksize);
+		    if (!tmp_bh) {
+			printf ("reading block %Lu failed\n", (loff_t)block * fs->s_blocksize);
+			continue;
+		    }
+		    if (lseek64 (fd, get_offset (&ih->ih_key) + j * fs->s_blocksize - 1,
+				 SEEK_SET) == (loff_t)-1) {
+			printf ("llseek failed to pos %Ld\n", (loff_t)block * fs->s_blocksize);
+			brelse (tmp_bh);
+			continue;
+		    }
+		    if (reiserfs_bitmap_test_bit (bitmap, block))
+			used ++;
+		    else
+			not_used ++;
+		    /*printf ("block of file %Ld gets block %lu\n",
+		      (get_offset (&ih->ih_key) - 1) / fs->s_blocksize + j, block);*/
+		    if (write (fd, tmp_bh->b_data, tmp_bh->b_size) != tmp_bh->b_size) {
+			printf ("write failed to pos %Ld\n", (loff_t)block * fs->s_blocksize);
+			brelse (tmp_bh);
+			continue;
+		    }
+		    recovered += fs->s_blocksize;
+		    brelse (tmp_bh);
+		}
+	    }
+	    brelse (bh);
+	    break;
+	}
+    }
+    printf ("recover_file: %Ld bytes recovered of file %s, key %u %u, %d blocks are free and %d are used\n",
+	    recovered, name, key.k_dir_id, key.k_objectid, not_used, used);
+}
+
+
+/* debugreiserfs -p or -P compresses reiserfs meta data: super block, journal,
+   bitmap blocks and blocks looking like leaves. It may save "bitmap" of
+   blocks they packed in the file of special format. Reiserfsck can then load
+   "bitmap" saved in that file and build the tree of blocks marked used in
+   that "bitmap" */
+char * where_to_save;
+
+
+static char * parse_options (int argc, char * argv [])
+{
+    int c;
+    char * tmp;
+  
+    while ((c = getopt (argc, argv, "b:C:icdmoMp:P:l:jsnrtu:q")) != EOF) {
+	switch (c) {
+	case 'b':	/* print a single node */
+	    opt_block_to_print = strtol (optarg, &tmp, 0);
+	    if (*tmp)
+		die ("parse_options: bad block number");
+	    break;
+	case 'C':
+	    mode = DO_CORRUPT;
+	    opt_block_to_corrupt = strtol (optarg, &tmp, 0);
+	    if (*tmp)
+		die ("parse_options: bad block number");
+	    break;
+	    
+	case 'p':
+	    mode = DO_PACK;
+	    if (optarg)
+		/* save bitmap of packed blocks in the file 'optarg' */
+		asprintf (&where_to_save, "%s", optarg);
+	    break;
+
+	case 'P':
+	    /* scan whole device and pack all blocks looking like a leaf */
+	    mode = DO_PACK_ALL;
+	    fprintf (stderr, "optarg %s\n", optarg);
+	    if (optarg)
+		/* save bitmap of packed blocks in the file 'optarg' */
+		asprintf (&where_to_save, "%s", optarg);
+	    break;
+
+	case 'i':	/* print items of a leaf */
+	    opt_print_leaf_items = 1; break;
+
+	case 'd':	/* print directories */
+	    opt_print_details = 1; break;
+
+	case 'c':	/* print contents of a regular file */
+	    opt_print_regular_file_content = 1; break;
+
+	case 'o':	/* print a objectid map */
+	    opt_print_objectid_map = 1; break;
+
+	case 'm':	/* print a block map */
+	    opt_print_block_map = 1;  break;
+
+	case 'M':	/* print a block map with details */
+	    opt_print_block_map = 2;  break;
+
+	case 'j':
+	    opt_print_journal = 1; break; /* print journal */
+	    
+	case 's':
+	    mode = DO_SCAN; break; /* read the device and print what reiserfs blocks were found */
+
+	case 'n':
+	    mode = DO_SCAN_FOR_NAME; break;
+
+	case 'r':
+	    mode = DO_RECOVER; break;
+
+	case 't':
+	    mode = DO_TEST; break;
+
+	case 'q':
+	    /* this makes packing to not show speed info during -p or -P */
+	    opt_quiet = 1;
+	    break;
+	}
+    }
+    if (optind != argc - 1)
+	/* only one non-option argument is permitted */
+	print_usage_and_exit();
+  
+    return argv[optind];
+}
+
+
+
+/* print all valid transactions and found dec blocks */
+static void print_journal (struct super_block * s)
+{
+    struct buffer_head * d_bh, * c_bh;
+    struct reiserfs_journal_desc * desc ;
+    struct reiserfs_journal_commit *commit ;
+    int end_journal;
+    int start_journal;
+    int i, j;
+    int first_desc_block = 0;
+    int wrapped = 0;
+    int valid_transactions = 0;
+
+    start_journal = SB_JOURNAL_BLOCK (s);
+    end_journal = start_journal + JOURNAL_BLOCK_COUNT;
+    reiserfs_warning (stdout, "Start scanning from %d\n", start_journal);
+
+    d_bh = 0;
+    desc = 0;
+    for (i = start_journal; i < end_journal; i ++) {
+	d_bh = bread (s->s_dev, i, s->s_blocksize);
+	if (who_is_this (d_bh->b_data, d_bh->b_size) == THE_JDESC) {
+	    int commit_block;
+
+	    if (first_desc_block == 0)
+		/* store where first desc block found */
+		first_desc_block = i;
+
+	    print_block (stdout, s, d_bh); /* reiserfs_journal_desc structure will be printed */
+	    desc = (struct reiserfs_journal_desc *)(d_bh->b_data);
+
+	    commit_block = d_bh->b_blocknr + desc->j_len + 1;
+	    if (commit_block >= end_journal) {
+		reiserfs_warning (stdout, "-- wrapped?");
+		wrapped = 1;
+		break;
+	    }
+
+	    c_bh = bread (s->s_dev, commit_block, s->s_blocksize);
+	    commit = bh_commit (c_bh);
+	    if (does_desc_match_commit (desc, commit)) {
+		reiserfs_warning (stdout, "commit block %d (trans_id %ld, j_len %ld) does not match\n", commit_block,
+				  commit->j_trans_id, commit->j_len);
+		brelse (c_bh) ;
+		brelse (d_bh);
+		continue;
+	    }
+
+	    valid_transactions ++;
+	    reiserfs_warning (stdout, "(commit block %d) - logged blocks (", commit_block);
+#if 1
+	    for (j = 0; j < desc->j_len; j ++) {
+		unsigned long block;
+
+		if (j < JOURNAL_TRANS_HALF)
+		    block = le32_to_cpu (desc->j_realblock[j]);
+		else
+		    block = le32_to_cpu (commit->j_realblock[i - JOURNAL_TRANS_HALF]);
+			
+		if (not_journalable (s, block))
+		    reiserfs_warning (stdout, " xxxx");
+		else {
+		    reiserfs_warning (stdout, " %ld", desc->j_realblock[j]);
+		    if (block_of_bitmap (s, desc->j_realblock[j]))
+			reiserfs_warning (stdout, "(bmp)");
+		}
+		if (j && (j + 1) % 10 == 0)
+		    reiserfs_warning (stdout, "\n");
+	    }
+#endif
+	    reiserfs_warning (stdout, ")\n");
+	    i += desc->j_len + 1;
+	    brelse (c_bh);
+	}
+	brelse (d_bh);
+    }
+    
+    if (wrapped) {
+	c_bh = bread (s->s_dev, first_desc_block - 1, s->s_blocksize);
+	commit = bh_commit (c_bh);
+	if (does_desc_match_commit (desc, commit)) {
+	    reiserfs_warning (stdout, "No! commit block %d (trans_id %ld, j_len %ld) does not match\n",
+			       first_desc_block - 1, commit->j_trans_id, commit->j_len);
+	} else {
+	    reiserfs_warning (stdout, "Yes! (commit block %d) - logged blocks (\n", first_desc_block - 1);
+#if 1
+	    for (j = 0; j < desc->j_len; j ++) {
+		unsigned long block;
+
+		if (j < JOURNAL_TRANS_HALF)
+		    block = le32_to_cpu (desc->j_realblock[j]);
+		else
+		    block = le32_to_cpu (commit->j_realblock[i - JOURNAL_TRANS_HALF]);
+			
+		if (not_journalable (s, block))
+		    reiserfs_warning (stdout, " xxxx");
+		else {
+		    reiserfs_warning (stdout, " %ld", desc->j_realblock[j]);
+		    if (block_of_bitmap (s, desc->j_realblock[j]))
+			reiserfs_warning (stdout, "(bmp)");
+		}
+	    }
+#endif
+	    reiserfs_warning (stdout, "\n");
+	}
+	brelse (c_bh) ;
+	brelse (d_bh);
+    }
+
+    reiserfs_warning (stdout, "%d valid transactions found\n", valid_transactions);
+
+    {
+	struct buffer_head * bh;
+	struct reiserfs_journal_header * j_head;
+
+	bh = bread (s->s_dev, SB_JOURNAL_BLOCK (s) + rs_journal_size (s->s_rs),
+		    s->s_blocksize);
+	j_head = (struct reiserfs_journal_header *)(bh->b_data);
+
+	reiserfs_warning (stdout, "#######################\nJournal header:\n"
+			  "j_last_flush_trans_id %ld\n"
+			  "j_first_unflushed_offset %ld\n"
+			  "j_mount_id %ld\n", j_head->j_last_flush_trans_id, j_head->j_first_unflushed_offset,
+			  j_head->j_mount_id);
+	brelse (bh);
+    }
+}
+
+
+void pack_partition (reiserfs_filsys_t fs);
+
+static void do_pack (reiserfs_filsys_t fs)
+{
+    if (opt_block_to_print != -1)
+	pack_one_block (fs, opt_block_to_print);
+    else
+	pack_partition (fs);
+	
+}
+
+/* FIXME: statistics does not work */
+static void do_dump_tree (reiserfs_filsys_t fs)
+{
+    if (opt_block_to_print != -1) {
+	print_one_block (fs, opt_block_to_print);
+	return;
+    }
+
+    print_block (stdout, fs, SB_BUFFER_WITH_SB (fs));
+    
+    if (opt_print_journal)
+	print_journal (fs);
+    
+    if (opt_print_objectid_map == 1)
+	print_objectid_map (stdout, fs);
+    
+    if (opt_print_block_map)
+	print_bmap (stdout, fs, opt_print_block_map == 1 ? 1 : 0);
+    
+    if (opt_print_regular_file_content || opt_print_details ||
+	opt_print_leaf_items) {
+	print_disk_tree (fs, SB_ROOT_BLOCK (fs));
+	
+	/* print the statistic */
+	printf ("File system uses %d internal + %d leaves + %d unformatted nodes = %d blocks\n",
+		g_stat_info.nr_internals, g_stat_info.nr_leaves, g_stat_info.nr_unformatted, 
+		g_stat_info.nr_internals + g_stat_info.nr_leaves + g_stat_info.nr_unformatted);
+    }
+}
+
+FILE * log;
+
+static void look_for_key (struct buffer_head * bh, struct key * key)
+{
+    int i, j;
+    struct item_head * ih;
+    struct reiserfs_de_head * deh;
+
+
+    ih = B_N_PITEM_HEAD (bh, 0);
+    for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
+	if ((ih->ih_key.k_dir_id == key->k_dir_id || (int)key->k_dir_id == -1) &&
+	    ih->ih_key.k_objectid == key->k_objectid) {
+	    reiserfs_warning (log, "%d-th item of block %lu is item of file %K: %H\n",
+			      i, bh->b_blocknr, key, ih);
+	}
+	if (!is_direntry_ih (ih))
+	    continue;
+	deh = B_I_DEH (bh, ih);
+	for (j = 0; j < ih_entry_count (ih); j ++, deh ++) {
+	    if ((deh->deh_dir_id == key->k_dir_id || (int)key->k_dir_id == -1) &&
+		deh->deh_objectid == key->k_objectid) {
+		reiserfs_warning (log, "dir item %d (%H) of block %lu has "
+				  "entry (%d-th) %.*s pointing to %K\n",
+				  i, ih, bh->b_blocknr, j,
+				  name_length (ih, deh, j), name_in_entry (deh, j), key);
+	    }
+	}	
+    }
+    return;
+}
+
+
+static void look_for_name (struct buffer_head * bh, char * name)
+{
+    int i, j;
+    struct item_head * ih;
+    struct reiserfs_de_head * deh;
+    int namelen;
+    char * p;
+
+    ih = B_N_PITEM_HEAD (bh, 0);
+    for (i = 0; i < B_NR_ITEMS (bh); i ++, ih ++) {
+	if (!is_direntry_ih (ih))
+	    continue;
+	deh = B_I_DEH (bh, ih);
+	for (j = 0; j < ih_entry_count (ih); j ++, deh ++) {
+	    p = name_in_entry (deh, j);
+	    namelen = name_length (ih, deh, j);
+	    if (namelen == strlen (name) && !strncmp (name, p, namelen)) {
+		fprintf (log, "block %lu, item %d, entry %d is %s\n", bh->b_blocknr, i, j, name);fflush (log);
+	    }
+	}
+    }
+    return;
+}
+
+
+
+
+static void do_scan (reiserfs_filsys_t fs)
+{
+    unsigned long i;
+    struct buffer_head * bh;
+    int type;
+    char * answer = 0;
+    size_t n = 0;
+    struct key key = {0, 0, };
+    unsigned long done, total;
+    reiserfs_bitmap_t bitmap;
+
+
+    bitmap = reiserfs_bitmap_load (".bitmap");
+    total = reiserfs_bitmap_ones (bitmap);
+/*
+    bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
+    reiserfs_fetch_disk_bitmap (bitmap, fs);
+*/
+
+    log = fopen ("scan.log", "w+");
+
+    if (mode == DO_SCAN_FOR_NAME) {
+	printf ("What name do you want to look for?");
+	getline (&answer, &n, stdin);
+	answer [strlen (answer) - 1] = 0;
+	printf ("Looking for name \"%s\"..\n", answer);
+	key.k_dir_id = 1;
+    } else {
+	printf ("What key do you want to find: dirid?");
+	getline (&answer, &n, stdin);
+	key.k_dir_id = atoi (answer);
+	printf ("objectid?");
+	getline (&answer, &n, stdin);
+	key.k_objectid = atoi (answer);
+	printf ("looking for (%u %u)\n", key.k_dir_id, key.k_objectid);
+    }
+
+    done = 0;
+    for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) {
+	if (!reiserfs_bitmap_test_bit (bitmap, i))
+	    continue;
+	bh = bread (fs->s_dev, i, fs->s_blocksize);
+	if (!bh) {
+	    printf ("could not read block %lu\n", i);
+	    continue;
+	}
+	type = who_is_this (bh->b_data, bh->b_size);
+	switch (type) {
+	case THE_JDESC:
+	    if (!key.k_dir_id)
+		printf ("block %lu is journal descriptor\n", i);
+	    break;
+	case THE_SUPER:
+	    if (!key.k_dir_id)
+		printf ("block %lu is reiserfs super block\n", i);
+	    break;
+	case THE_INTERNAL:
+	    if (!key.k_dir_id)
+		printf ("block %lu is reiserfs internal node\n", i);
+	    break;
+	case THE_LEAF:
+	    if (mode == DO_SCAN_FOR_NAME) {
+		look_for_name (bh, answer);
+	    } else if (key.k_dir_id) {
+		look_for_key (bh, &key);
+	    } else {
+		printf ("block %lu is reiserfs leaf node\n", i);
+	    }
+	    break;
+	}
+	brelse (bh);
+	print_how_far (&done, total, 1, 0);
+    }
+}
+
+
+
+#if 0
+static void do_test (reiserfs_filsys_t fs, unsigned long block)
+{
+    struct buffer_head * bh;
+
+    fprintf (stderr, "=========== BLock %lu ============\n", block);
+    bh = bread (fs->s_dev, block, fs->s_blocksize);
+    if (!bh)
+	die ("do_test: bread failed");
+    if (is_leaf_bad (bh))
+	fprintf (stderr, "\n######### BAD before repairing ############\n");
+    else
+	fprintf (stderr, "\n========= OK before repairing ==================\n");
+    print_block (fs, bh, 3, -1, -1);
+
+    fprintf (stderr, "\n>>> repairing >>>>........\n\n");
+
+    /* function to test */pass0_correct_leaf (fs, bh);
+    if (is_leaf_bad (bh))
+	fprintf (stderr, "\n######### still BAD after repairing ############\n");
+    else
+	fprintf (stderr, "\n========= OK  after repairing ==================\n");
+    print_block (fs, bh, 3, -1, -1);
+    brelse (bh);
+}
+#endif
+
+static void do_test (reiserfs_filsys_t fs)
+{
+    struct key root_dir_key = {REISERFS_ROOT_PARENT_OBJECTID,
+			       REISERFS_ROOT_OBJECTID, {{0, 0},}};
+    int gen_counter;
+
+    if (reiserfs_find_entry (fs, &root_dir_key, "lost+found", &gen_counter))
+	reiserfs_add_entry (fs, &root_dir_key, "lost+found", &root_dir_key, 0);
+}
+
+
+/* FIXME: need to open reiserfs filesystem first */
+int main (int argc, char * argv[])
+{
+    char * file_name;
+    int error;
+
+    print_banner ("debugreiserfs");
+ 
+    file_name = parse_options (argc, argv);
+
+    fs = reiserfs_open (file_name, O_RDONLY, &error, 0);
+    if (!fs) {
+	fprintf (stderr, "\n\ndumpreiserfs: can not open reiserfs on \"%s\": %s\n\n",
+		 file_name, error ? strerror (error) : "there is no one");
+	return 0;
+    }
+
+    switch (mode) {
+    case DO_PACK:
+    case DO_PACK_ALL:
+	do_pack (fs);
+	break;
+
+    case DO_CORRUPT:
+	reiserfs_reopen (fs, O_RDWR);
+	do_corrupt_one_block (fs, opt_block_to_corrupt);
+	break;
+
+    case DO_DUMP:
+	do_dump_tree (fs);
+	break;
+
+    case DO_SCAN:
+    case DO_SCAN_FOR_NAME:
+	do_scan (fs);
+	break;
+
+    case DO_RECOVER:
+	do_recover (fs);
+	break;
+
+    case DO_TEST:
+    {
+	do_test (fs);
+
+#if 0
+	int i;
+	int arr[] = {53033};
+
+	if (opt_block_to_print != -1) {
+	    do_test (fs, opt_block_to_print);
+	    break;
+	}	    
+
+bad blocks found on Joop partition
+
+53033, 
+179201, 
+844702,
+844913,
+877768,
+879067,
+907631,
+925323,
+2241275,
+2241343,
+2241397,
+2241511,
+2241553,
+2241635,
+2241644,
+2241654,
+2241711,
+2241721,
+2241727,
+2241740,
+2241762,
+2241766,
+2241770,
+2241812,
+2241820,
+2241827,
+2241831,
+2241878,
+2241886,
+2241971
+	};
+	/* blocks containing broken directory items on Joop's filesystem */
+	int arr[] = {/*53033,*/ 838396/*, 1597036*//*, 1919589, 2715962*/};
+ 
+	
+	
+	for (i = 0; i < sizeof (arr) / sizeof (arr[0]); i ++)
+	    do_test (fs, arr[i]);
+	break;
+#endif
+
+    }
+    }
+
+    reiserfs_close (fs);
+    return 0;
+}
diff --git a/debugreiserfs/debugreiserfs.h b/debugreiserfs/debugreiserfs.h
new file mode 100644
index 0000000..2d754b5
--- /dev/null
+++ b/debugreiserfs/debugreiserfs.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "io.h"
+#include "misc.h"
+#include "reiserfs_lib.h"
+#include "../version.h"
+
+
+
+/*
+ *  modes
+ */
+#define DO_DUMP 1  /* not a real dump, just printing to stdout contents of
+                      tree nodes */
+#define DO_CORRUPT 2 /* used to make filesystem corruption and then test fsck */
+#define DO_SCAN 3
+#define DO_SCAN_FOR_NAME 4
+#define DO_RECOVER 5
+#define DO_TEST 6
+#define DO_PACK 7  /* -p extract meta data of reiserfs filesystem */
+#define DO_PACK_ALL 8 /* -p */
+
+extern int opt_quiet;
+extern int mode;
+
+
+// the leaf is stored in compact form: 
+// start magic number
+// block number __u32
+// item number __u16
+// struct packed_item
+// ..
+// end magic number
+
+/* we store hash code in high byte of 16 bits */
+#define LEAF_START_MAGIC 0xa5
+#define LEAF_END_MAGIC 0x5a
+
+
+
+#define FULL_BLOCK_START_MAGIC 0xb6
+#define FULL_BLOCK_END_MAGIC 0x6b
+#define UNFORMATTED_BITMAP_START_MAGIC 0xc7
+#define UNFORMATTED_BITMAP_END_MAGIC 0x7c
+#define END_MAGIC 0x8d
+#define INTERNAL_START_MAGIC
+#define INTERNAL_START_MAGIC
+
+
+#define ITEM_START_MAGIC 0x476576
+#define ITEM_END_MAGIC 0x2906504
+
+/* flags in packed item mask */
+#define NEW_FORMAT 1  // 0 here means - old format, 1 - new format
+#define DIR_ID 2
+#define OBJECT_ID 4
+#define OFFSET_BITS_32 8
+#define OFFSET_BITS_64 16
+#define ENTRY_COUNT 32 // shows whether ih_free_space/ih_entry_count is stored
+
+#define INDIRECT_ITEM 64
+#define DIRENTRY_ITEM 128
+#define DIRECT_ITEM 256
+#define STAT_DATA_ITEM 512
+
+#define ITEM_BODY 1024
+#define WHOLE_INDIRECT 128
+#define WITH_SD_FIRST_DIRECT_BYTE 8192 /* for old stat data first_direct_byte
+                                          is stored */
+#define NLINK_BITS_32 8192 /* nlinks stored in 32 bits */
+#define SIZE_BITS_64 16384 /* size has to be stored in 64 bit */
+
+struct packed_item {
+    /*__u16 length;*/ // length of the area we store item in
+    __u16 mask; // what is stored: dirid, objectid, 32 bit offset or 64 bit offset, type
+    __u16 item_len;
+};
+
+#define HAS_DIR_ID 1
+#define HAS_GEN_COUNTER 2
+#define HAS_STATE 4
+#define YURA 8
+#define TEA 16
+#define R5 32
+struct packed_dir_entry {
+    __u8 mask;
+    __u16 entrylen;
+};
+
+
+#define fread8(pv) fread (pv, sizeof (__u8), 1, stdin)
+#define fread16(pv) fread (pv, sizeof (__u16), 1, stdin)
+#define fread32(pv) fread (pv, sizeof (__u32), 1, stdin)
+#define fread64(pv) fread (pv, sizeof (__u64), 1, stdin)
+
+#define fwrite8(pv) {\
+if (fwrite (pv, sizeof (__u8), 1, stdout) != 1)\
+    reiserfs_panic ("fwrite8 failed: %m");\
+}
+#define fwrite16(pv) {\
+if (fwrite (pv, sizeof (__u16), 1, stdout) != 1)\
+    reiserfs_panic ("fwrite16 failed: %m");\
+}
+#define fwrite32(pv) {\
+if (fwrite (pv, sizeof (__u32), 1, stdout) != 1)\
+    reiserfs_panic ("fwrite32 failed: %m");\
+}
+#define fwrite64(pv) {\
+if (fwrite (pv, sizeof (__u64), 1, stdout) != 1)\
+    reiserfs_panic ("fwrite64 failed: %m");\
+}
+/*
+#define fwrite16(pv) fwrite (pv, sizeof (__u16), 1, stdout)
+#define fwrite32(pv) fwrite (pv, sizeof (__u32), 1, stdout)
+#define fwrite64(pv) fwrite (pv, sizeof (__u64), 1, stdout)
+*/
+
+
+#define BLOCKS_PER_READ 8
+extern char * where_to_save;
diff --git a/debugreiserfs/pack.c b/debugreiserfs/pack.c
new file mode 100644
index 0000000..e40b204
--- /dev/null
+++ b/debugreiserfs/pack.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+
+#include "debugreiserfs.h"
+
+
+
+
+
+reiserfs_bitmap_t what_to_pack;
+reiserfs_bitmap_t what_packed;
+
+int packed_leaves, bad_leaves, full_blocks, internals, descs, full_of_journal;
+
+
+/* these are to calculate compression */
+unsigned long sent; /* how many bytes sent to stdout */
+unsigned long had_to_be_sent; /* how many bytes were to be sent */
+
+
+
+static void pack_key (struct packed_item * pi, struct item_head * ih)
+{
+    if (pi->mask & DIR_ID) {
+	fwrite32 (&ih->ih_key.k_dir_id);
+	sent += sizeof (__u32);
+    }
+
+    if (pi->mask & OBJECT_ID) {
+	fwrite32 (&ih->ih_key.k_objectid);
+	sent += sizeof (__u32);
+    }
+
+    if (pi->mask & OFFSET_BITS_64) {
+	__u64 offset;
+
+	offset = get_offset (&ih->ih_key);
+	fwrite64 (&offset);
+	sent += sizeof (__u64);
+    }
+
+    if (pi->mask & OFFSET_BITS_32) {
+	__u32 offset;
+
+	offset = get_offset (&ih->ih_key);
+	fwrite32 (&offset);
+	sent += sizeof (__u32);
+    }
+}
+
+
+static void pack_direct (struct packed_item * pi, struct buffer_head * bh, 
+			  struct item_head * ih)
+{
+    pi->mask |= DIRECT_ITEM;
+
+    /* send packed item header to stdout */
+    fwrite (pi, sizeof (*pi), 1, stdout);
+    sent += sizeof (*pi);
+    
+    /* send key components which are to be sent */
+    pack_key (pi, ih);
+}
+
+
+/* if there is at least one extent longer than 2 - it is worth packing */
+static int should_pack_indirect (__u32 * ind_item, int unfm_num)
+{
+    int i, len;
+
+    for (i = 1, len = 1; i < unfm_num; i ++) {
+	if ((!ind_item [i] && !ind_item [i - 1]) || /* hole continues */
+	    ind_item [i] == ind_item [i - 1] + 1) { /* subsequent blocks */
+	    len ++;
+	    if (len > 2)
+		return 1;
+	} else {
+	    /* sequence of blocks or hole broke */
+	    len = 1;
+	}
+    }
+    return 0;
+}
+
+
+/* indirect item can be either packed using "extents" (when it is
+   worth doing) or be stored as is. Size of item in packed form is not
+   stored. Unpacking will stop when full item length is reached */
+static void pack_indirect (struct packed_item * pi, struct buffer_head * bh, 
+			   struct item_head * ih)
+{
+    int i;
+    __u32 * ind_item;
+    __u16 len;
+
+    pi->mask |= INDIRECT_ITEM;
+    if (ih_entry_count (ih))
+	pi->mask |= ENTRY_COUNT;
+    
+    ind_item = (__u32 *)B_I_PITEM (bh, ih);
+    if (!should_pack_indirect (ind_item, I_UNFM_NUM (ih)))
+	pi->mask |= WHOLE_INDIRECT;
+    
+    /* send packed item header to stdout */
+    fwrite (pi, sizeof (*pi), 1, stdout);
+    sent += sizeof (*pi);
+
+    /* send key components which are to be sent */
+    pack_key (pi, ih);
+
+    if (pi->mask & ENTRY_COUNT) {
+	__u16 ih_free_space;
+
+	ih_free_space = ih_entry_count (ih);
+	fwrite16 (&ih_free_space);
+	sent += sizeof (__u16);
+    }
+
+    if (pi->mask & WHOLE_INDIRECT) {
+	fwrite (ind_item, ih_item_len (ih), 1, stdout);
+	sent += ih_item_len (ih);
+	return;
+    }
+
+    fwrite32 (&ind_item [0]);
+    sent += sizeof (__u32);
+    for (i = 1, len = 1; i < I_UNFM_NUM (ih); i ++) {
+	if ((!ind_item [i] && !ind_item [i - 1]) || /* hole continues */
+	    ind_item [i] == ind_item[ i - 1] + 1) { /* subsequent blocks */
+	    len ++;
+	} else {
+	    fwrite16 (&len);
+	    fwrite32 (&ind_item[i]);
+	    sent += (sizeof (__u32) + sizeof (__u16));
+	    len = 1;
+	}
+    }
+    fwrite16 (&len);
+    sent += sizeof (__u16);
+
+    return;
+}
+
+
+/* directory item is packed:
+   entry count - 16 bits
+   for each entry
+   	mask (8 bits) - it shows whether there are any of (deh_dir_id, gen counter, deh_state)
+	entry length 16 bits
+	entry itself
+	deh_objectid - 32 bits
+		maybe deh_dir_id (32 bits)
+		maybe gencounter (16)
+		maybe deh_state (16)
+*/
+static void pack_direntry (reiserfs_filsys_t fs, struct packed_item * pi,
+			   struct buffer_head * bh,
+			   struct item_head * ih)
+{
+    int i;
+    struct reiserfs_de_head * deh;
+    struct packed_dir_entry pe;
+    __u16 entry_count, gen_counter;
+
+
+    pi->mask |= (DIRENTRY_ITEM | ENTRY_COUNT);
+
+    /* send packed item header to stdout */
+    fwrite (pi, sizeof (*pi), 1, stdout);
+    sent += sizeof (*pi);
+
+    /* send key components which are to be sent */
+    pack_key (pi, ih);
+
+    /* entry count is sent unconditionally */
+    entry_count = ih_entry_count (ih);
+    fwrite16 (&entry_count);
+
+    deh = B_I_DEH (bh, ih);
+    for (i = 0; i < entry_count; i ++, deh ++) {
+	pe.entrylen = entry_length (ih, deh, i);
+	pe.mask = 0;
+	if (deh_dir_id (deh) != le32_to_cpu (ih->ih_key.k_objectid))
+	    /* entry points to name of another directory, store deh_dir_id */
+	    pe.mask |= HAS_DIR_ID;
+
+	gen_counter = GET_GENERATION_NUMBER (deh_offset (deh));
+	if (gen_counter != 0)
+	    /* store generation counter if it is != 0 */
+	    pe.mask |= HAS_GEN_COUNTER;
+
+	if (le16_to_cpu (deh->deh_state) != 4)
+	    /* something unusual in deh_state. Store it */
+	    pe.mask |= HAS_STATE;
+
+	fwrite8 (&pe.mask);
+	fwrite16 (&pe.entrylen);
+	fwrite (name_in_entry (deh, i), pe.entrylen, 1, stdout);
+	fwrite32 (&(deh->deh_objectid));
+	sent += (sizeof (__u8) + sizeof (__u16) + pe.entrylen + sizeof (__u32));
+	
+	if (pe.mask & HAS_DIR_ID) {
+	    fwrite32 (&deh->deh_dir_id);
+	    sent += sizeof (__u32);
+	}
+
+	if (pe.mask & HAS_GEN_COUNTER) {
+	    fwrite16 (&gen_counter);
+	    sent += sizeof (__u16);
+	}
+
+	if (pe.mask & HAS_STATE) {
+	    fwrite16 (&deh->deh_state);
+	    sent += sizeof (__u16);
+	}
+    }
+}
+
+
+static void pack_stat_data (struct packed_item * pi, struct buffer_head * bh,
+			    struct item_head * ih)
+{
+    pi->mask |= STAT_DATA_ITEM;
+
+    if (stat_data_v1 (ih)) {
+	/* for old stat data: we take
+	   mode - 16 bits
+	   nlink - 16 bits
+	   size - 32 bits
+	   blocks/rdev - 32 bits
+	   maybe first_direct byte 32 bits
+	*/
+	struct stat_data_v1 * sd_v1;
+
+	sd_v1 = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
+	if (sd_v1->sd_first_direct_byte != 0xffffffff)
+	    pi->mask |= WITH_SD_FIRST_DIRECT_BYTE;
+
+	/* we are done with packed_item send packed it to stdout */
+	fwrite (pi, sizeof (*pi), 1, stdout);
+	sent += sizeof (*pi);
+	
+	/* send key components which are to be sent */
+	pack_key (pi, ih);
+	
+	fwrite16 (&sd_v1->sd_mode);
+	fwrite16 (&sd_v1->sd_nlink);
+	fwrite32 (&sd_v1->sd_size);
+	fwrite32 (&sd_v1->u.sd_blocks);
+	sent += (sizeof (__u16) * 2 + sizeof (__u32) * 2);
+	if (pi->mask & WITH_SD_FIRST_DIRECT_BYTE) {
+	    fwrite32 (&sd_v1->sd_first_direct_byte);
+	    sent += sizeof (__u32);
+	}
+    } else {
+	/* for new stat data
+	   mode - 16 bits
+	   nlink in either 16 or 32 bits
+	   size in either 32 or 64 bits
+	   blocks - 32 bits
+	*/
+	struct stat_data * sd;
+	__u16 nlink16;
+	__u32 nlink32, size32;
+	__u64 size64;
+
+	sd = (struct stat_data *)B_I_PITEM (bh, ih);
+	if (sd->sd_nlink > 0xffff) {
+	    pi->mask |= NLINK_BITS_32;
+	    nlink32 = sd->sd_nlink;
+	} else {
+	    nlink16 = sd->sd_nlink;
+	}
+	if (sd->sd_size > 0xffffffff) {
+	    pi->mask |= SIZE_BITS_64;
+	    size64 = sd->sd_size;
+	} else {
+	    size32 = sd->sd_size;
+	}
+
+	/* we are done with packed_item send packed it to stdout */
+	fwrite (pi, sizeof (*pi), 1, stdout);
+	sent += sizeof (*pi);
+
+	/* send key components which are to be sent */
+	pack_key (pi, ih);
+
+	fwrite16 (&sd->sd_mode);
+	sent += sizeof (__u16);
+	if (pi->mask & NLINK_BITS_32) {
+	    fwrite32 (&nlink32);
+	    sent += sizeof (__u32);
+	} else {
+	    fwrite16 (&nlink16);	
+	    sent += sizeof (__u16);
+	}
+
+	if (pi->mask & SIZE_BITS_64) {
+	    fwrite64 (&size64);
+	    sent += sizeof (__u64);
+	} else {
+	    fwrite32 (&size32);
+	    sent += sizeof (__u32);
+	}
+    
+	fwrite32 (&sd->sd_blocks);
+	sent += sizeof (__u32);
+    }
+}
+
+
+static void pack_full_block (reiserfs_filsys_t fs, struct buffer_head * bh)
+{
+    __u16 magic;
+    __u32 block;
+
+    magic = FULL_BLOCK_START_MAGIC;
+    fwrite16 (&magic);
+
+    block = bh->b_blocknr;
+    fwrite32 (&block);
+    
+    fwrite (bh->b_data, 4096, 1, stdout);
+    sent += 4096;
+    had_to_be_sent += 4096;
+
+    full_blocks ++;
+    
+    if (who_is_this (bh->b_data, bh->b_size) == THE_JDESC)
+	descs ++;
+    if (who_is_this (bh->b_data, bh->b_size) == THE_INTERNAL)
+	internals ++;
+    if (block_of_journal (fs, bh->b_blocknr))
+	full_of_journal ++;
+}
+
+
+/* unformatted node pointer is considered bad when it points either to blocks
+   of journal, bitmap blocks, super block or is transparently out of range of
+   disk block numbers */
+static int check_unfm_ptr (reiserfs_filsys_t fs, __u32 block)
+{
+    if (block >= SB_BLOCK_COUNT (fs))
+        return 1;
+
+    if (not_data_block (fs, block))
+        return 1;
+
+    return 0;
+}
+
+
+/* we only pack leaves which do not have any corruptions */
+static int can_pack_leaf (reiserfs_filsys_t fs, struct buffer_head * bh)
+{
+    int i;
+    struct item_head * ih;
+
+    ih = B_N_PITEM_HEAD (bh, 0);
+    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
+	if (is_it_bad_item (fs, ih, B_I_PITEM (bh, ih), check_unfm_ptr, 1/*bad dir*/))
+	    return 0;
+    }
+    return 1;
+}
+
+
+/* pack leaf only if all its items are correct: keys are correct,
+   direntries are hashed properly and hash function is defined,
+   indirect items are correct, stat data ?, */
+static void pack_leaf (reiserfs_filsys_t fs, struct buffer_head * bh)
+{
+    int i;
+    struct item_head * ih;
+    struct packed_item pi;
+    __u16 v16;
+
+    if (!can_pack_leaf (fs, bh)) {
+	/* if something looks suspicious in this leaf - pack whole block */
+	pack_full_block (fs, bh);
+	fprintf (stderr, "leaf %lu is bad\n", bh->b_blocknr);
+	bad_leaves ++;
+	return;
+    }
+
+    /* start magic in low 8 bits, hash code in high 8 bits */
+    v16 = (LEAF_START_MAGIC | (func2code (fs->s_hash_function) << 8));
+    fwrite16 (&v16);
+    
+    /* block number */
+    fwrite32 (&bh->b_blocknr);
+
+    /* item number */
+    v16 = node_item_number (bh);
+    fwrite16 (&v16);
+
+    ih = B_N_PITEM_HEAD (bh, 0);
+
+    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
+#if 0
+	v32 = ITEM_START_MAGIC;
+	fwrite32 (&v32);
+#endif
+
+	pi.mask = 0;
+	pi.item_len = ih_item_len (ih);
+
+	// format
+	if (ih_key_format (ih) == KEY_FORMAT_2)
+	    pi.mask |= NEW_FORMAT;
+
+	// k_dir_id
+	if (!i || (i && ih->ih_key.k_dir_id != (ih - 1)->ih_key.k_dir_id)) {
+	    /* if item is first in the leaf or if previous item has different
+               k_dir_id - store it */
+	    pi.mask |= DIR_ID;
+	}
+	// k_object_id
+	if (!i || (i && ih->ih_key.k_objectid != (ih - 1)->ih_key.k_objectid)) {
+	    /* if item is first in the leaf or if previous item has different
+               k_objectid - store it */
+	    pi.mask |= OBJECT_ID;
+	}
+
+	/* store offset if it is != 0 in 32 or 64 bits */
+	if (get_offset (&ih->ih_key)) {
+	    if (get_offset (&ih->ih_key) > 0xffffffffULL)
+		pi.mask |= OFFSET_BITS_64;
+	    else
+		pi.mask |= OFFSET_BITS_32;
+	}
+
+	if (is_direct_ih (ih)) {
+	    pack_direct (&pi, bh, ih);
+	} else if (is_indirect_ih (ih))
+	    pack_indirect (&pi, bh, ih);
+	else if (is_direntry_ih (ih))
+	    pack_direntry (fs, &pi, bh, ih);
+	else if (is_stat_data_ih (ih))
+	    pack_stat_data (&pi, bh, ih);
+	else
+	    die ("pack_leaf: unknown item found");
+#if 0
+	v32 = ITEM_END_MAGIC;
+	fwrite32 (&v32);
+#endif
+    }
+
+    v16 = LEAF_END_MAGIC;
+    fwrite16 (&v16);
+
+    packed_leaves ++;
+    had_to_be_sent += 4096;
+
+    return;
+}
+
+
+static int can_pack_internal (reiserfs_filsys_t fs, struct buffer_head * bh)
+{
+    return 0;
+}
+
+
+/* pack internal node as a full block */
+static void pack_internal (reiserfs_filsys_t fs, struct buffer_head * bh)
+{
+    if (!can_pack_internal (fs, bh)) {
+	pack_full_block (fs, bh);
+	return;
+    }
+
+    reiserfs_panic ("pack_internal: packing code is not ready");
+}
+
+
+static int how_many_to_pack (reiserfs_filsys_t fs, unsigned long first, int count)
+{
+    int i;
+    int used;
+
+    used = 0;
+    for (i = 0; i < count; i ++) {
+	if ((SB_BLOCK_COUNT (fs) > (first + i)) &&
+	    reiserfs_bitmap_test_bit (what_to_pack, first + i))
+	    used ++;
+    }
+    return used;
+}
+
+
+/* packed blocks are marked free in the bitmap*/
+static void send_block (reiserfs_filsys_t fs, struct buffer_head * bh)
+{
+    int type;
+
+
+    if ((type = who_is_this (bh->b_data, bh->b_size)) != THE_LEAF) {
+	if (type == THE_INTERNAL) {
+	    pack_internal (fs, bh);
+	} else if (!not_data_block (fs, bh->b_blocknr)) {
+	    /* unformatted */
+	    return;
+	} else
+	    /* bitmaps, super block, blocks of journal - not leaves */
+	    pack_full_block (fs, bh);
+    } else
+	pack_leaf (fs, bh);
+
+    reiserfs_bitmap_set_bit (what_packed, bh->b_blocknr);
+    reiserfs_bitmap_clear_bit (what_to_pack, bh->b_blocknr);
+}
+
+
+/* super block, journal, bitmaps */
+static void pack_frozen_data (reiserfs_filsys_t fs)
+{
+    int i;
+    struct buffer_head * bh;
+
+    /* super block */
+    reiserfs_warning (stderr, "super block..");fflush (stderr);
+    send_block (fs, fs->s_sbh);
+    reiserfs_warning (stderr, "ok\nbitmaps..(%d).. ", SB_BMAP_NR (fs));
+    fflush (stderr);
+
+    /* bitmaps */ 
+    for (i = 0; i < SB_BMAP_NR (fs); i ++) {
+	send_block (fs, SB_AP_BITMAP (fs)[i]);
+    }
+
+    reiserfs_warning (stderr, "ok\njournal (from %lu to %lu)..",
+		      rs_journal_start (fs->s_rs),
+		      rs_journal_start (fs->s_rs) + rs_journal_size (fs->s_rs));
+    fflush (stderr);
+    /* journal */
+    for (i = rs_journal_start (fs->s_rs); 
+	 i <= rs_journal_start (fs->s_rs) + rs_journal_size (fs->s_rs);
+	 i ++) {
+	bh = bread (fs->s_dev, i, fs->s_blocksize);
+	send_block (fs, bh);
+	brelse (bh);
+    }
+    reiserfs_warning (stderr, "ok\n");fflush (stderr);
+}
+
+
+/* pack all "not data blocks" and correct leaf */
+void pack_partition (reiserfs_filsys_t fs)
+{
+    int i, j;
+    struct buffer_head tmp, * bh;
+    int nr_to_read = BLOCKS_PER_READ;
+    __u32 magic32;
+    __u16 blocksize;
+    __u16 magic16;
+    unsigned long done = 0, total;
+    
+
+    magic32 = REISERFS_SUPER_MAGIC;
+    fwrite32 (&magic32);
+    
+    blocksize = fs->s_blocksize;
+    fwrite16 (&blocksize);
+
+    tmp.b_size = blocksize;
+    
+    /* will save information about what packed here */
+    what_packed = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
+
+    /* will get information about what is to be packed */
+    what_to_pack = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
+    if (!what_to_pack)
+	die ("pack_partition: could not create bitmap");
+    if (mode == DO_PACK) {
+	/* read blocks marked used and pack them */
+	reiserfs_fetch_disk_bitmap (what_to_pack, fs);
+	reiserfs_warning (stderr, "Packing blocks marked used on the device %d\n",
+			  reiserfs_bitmap_ones (what_to_pack));
+    } else {
+	reiserfs_bitmap_fill (what_to_pack);
+	reiserfs_warning (stderr, "Packing all blocks of the device %d\n",
+			  reiserfs_bitmap_ones (what_to_pack));	    
+    }
+
+
+    /* super block, journal, bitmaps */
+    pack_frozen_data (fs);
+
+    reiserfs_warning (stderr, 
+		      "Super block, bitmaps, journal - %d blocks - done, %d blocks left\n",
+		      reiserfs_bitmap_ones (what_packed), reiserfs_bitmap_ones (what_to_pack));
+    total = reiserfs_bitmap_ones (what_to_pack);
+
+    for (i = 0; i < SB_BLOCK_COUNT (fs); i += nr_to_read) {
+	int to_pack;
+
+	to_pack = how_many_to_pack (fs, i, nr_to_read);
+	if (to_pack) {
+	    print_how_far (&done, total, to_pack, opt_quiet);
+
+	    bh = bread (fs->s_dev, i / nr_to_read, blocksize * nr_to_read);
+	    if (bh) {
+		for (j = 0; j < nr_to_read; j ++) {
+		    if (reiserfs_bitmap_test_bit (what_to_pack, i + j)) {
+			tmp.b_data = bh->b_data + j * tmp.b_size;
+			tmp.b_blocknr = i + j;
+			send_block (fs, &tmp);
+		    }
+		}
+		brelse (bh);
+	    } else {
+		/* 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 */
+		    reiserfs_warning (stderr, "could not read block %lu\n", i);
+		}
+	    }
+
+	}
+    }
+    
+    magic16 = END_MAGIC;
+    fwrite16 (&magic16);
+    
+    fprintf (stderr, "Packed\n\tleaves %d\n"
+	     "\tfull blocks %d\n"
+	     "\t\tof journal %d\n"
+	     "\t\tcorrupted leaves %d\n"
+	     "\t\tinternals %d\n"
+	     "\t\tdescriptors %d\n",
+	     packed_leaves, full_blocks, full_of_journal, bad_leaves, internals, descs);
+    fprintf (stderr, "data packed with ratio %.2f\n", (double)sent / had_to_be_sent);
+
+    if (where_to_save)
+	reiserfs_bitmap_save (where_to_save, what_packed);
+}
+
+
+
+    
+void pack_one_block (reiserfs_filsys_t fs, unsigned long block)
+{
+    __u32 magic32;
+    __u16 magic16;
+    struct buffer_head * bh;
+
+    // reiserfs magic
+    magic32 = REISERFS_SUPER_MAGIC;
+    fwrite32 (&magic32);
+
+    // blocksize
+    fwrite16 (&fs->s_blocksize);
+    
+    bh = bread (fs->s_dev, block, fs->s_blocksize);
+
+    if (who_is_this (bh->b_data, bh->b_size) == THE_LEAF)
+	pack_leaf (fs, bh);
+    else
+	pack_full_block (fs, bh);
+
+    brelse (bh);
+
+    // end magic
+    magic16 = END_MAGIC;
+    fwrite16 (&magic16);
+
+    fprintf (stderr, "Packed\n\tleaves %d\n\tfull block %d\n\tcorrupted leaves %d\n",
+	     packed_leaves, full_blocks, bad_leaves);
+}
+
+
+#if 0
+//
+// this test program has two modes: 'pack file blocknr'
+// and 'unpack file'
+// in the first mode blocknr-th 4k block of the 'file' will be packed out to stdout
+// the the second mode standart input will be converted to the reiserfs leaf on 'file'
+//
+static int do_unpack (char * file)
+{
+    char * buf;
+    int fd;
+
+    fd = open (file, O_RDONLY);
+    if (fd == -1) {
+	perror ("open failed");
+	return 0;
+    }
+    
+    buf = malloc (4096);
+    if (!buf) {
+	perror ("malloc failed");
+	return 0;
+    }
+
+    fread (buf, 4096, 1, stdin);
+    if (!feof (stdin)) {
+	printf ("fread returned not eof\n");
+	return 0;
+    }
+
+    unpack_leaf (buf, fd);
+
+    free (buf);
+    close (fd);
+    return 0;
+}
+
+static int do_pack (char * file, int block)
+{
+    int fd;
+    struct buffer_head * bh;
+    char * buf;
+    int len;
+
+    fprintf (stderr, "dumping block %d of the \"%s\"\n", block, file);
+
+    fd = open (file, O_RDONLY);
+    if (fd == -1) {
+	perror ("open failed");
+	return 0;
+    }
+    
+    bh = bread (fd, block, 4096);
+    if (!bh) {
+	fprintf (stderr, "bread failed\n");
+	return 0;
+    }
+
+    if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF) {
+	fprintf (stderr, "block %d is not a leaf\n", block);
+	return 0;
+    }
+
+    len = pack_leaf (bh, buf);
+    fwrite (buf, len, 1, stdout);
+
+    free (buf);
+    close (fd);
+    return 0;
+}
+
+
+int main (int argc, char ** argv)
+{
+    if (argc == 3 && !strcmp (argv[1], "unpack"))
+	return do_unpack (argv[2]);
+
+    if (argc == 4 && !strcmp (argv[1], "pack"))
+	return do_pack (argv[2], atoi (argv[3]));
+
+    fprintf (stderr, "Usage: \n\t%s pack filename block\nor\n"
+	     "\t%s unpack filename\n", argv[0], argv[0]);
+    return 0;
+}
+
+#endif
diff --git a/debugreiserfs/unpack.c b/debugreiserfs/unpack.c
new file mode 100644
index 0000000..c83bae6
--- /dev/null
+++ b/debugreiserfs/unpack.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+  
+#include "debugreiserfs.h"
+#include <sys/resource.h>
+
+
+#define print_usage_and_exit() die ("Usage: %s [-v] [-b filename] device\n\
+-v		prints blocks number of every block unpacked\n\
+-b filename	makes unpack to save bitmap of blocks unpacked\n", argv[0]);
+
+
+
+/* when super block gets unpacked for the first time - create a bitmap
+   and mark in it what have been unpacked. Save that bitmap at the end */
+reiserfs_bitmap_t what_unpacked = 0;
+
+
+int unpacked, data_blocks_unpacked;
+
+int verbose = 0;
+
+
+
+static void unpack_offset (struct packed_item * pi, struct item_head * ih)
+{
+    if (pi->mask & OFFSET_BITS_64) {
+	__u64 v64;
+
+	if (ih_key_format (ih) != KEY_FORMAT_2)
+	    die ("unpack_offset: key format is not set or wrong");
+	fread64 (&v64);
+	set_offset (KEY_FORMAT_2, &ih->ih_key, v64);
+	return;
+    }
+
+    if (pi->mask & OFFSET_BITS_32) {
+	__u32 v32;
+
+	fread32 (&v32);
+	set_offset (ih_key_format (ih), &ih->ih_key, v32);
+	return;
+    }
+
+    // offset is 0
+    return;
+}
+
+
+static void unpack_type (struct packed_item * pi, struct item_head * ih)
+{
+    if (pi->mask & DIRECT_ITEM)
+	set_type (ih_key_format (ih), &ih->ih_key, TYPE_DIRECT);
+    else if (pi->mask & STAT_DATA_ITEM)
+	set_type (ih_key_format (ih), &ih->ih_key, TYPE_STAT_DATA);
+    else if (pi->mask & INDIRECT_ITEM)
+	set_type (ih_key_format (ih), &ih->ih_key, TYPE_INDIRECT);
+    else if (pi->mask & DIRENTRY_ITEM)
+	set_type (ih_key_format (ih), &ih->ih_key, TYPE_DIRENTRY);
+    else
+	reiserfs_panic (0, "%h, mask 0%o\n", ih, pi->mask);
+}
+
+
+/* direntry item comes in the following format: 
+   entry count - 16 bits
+   for each entry
+      mask - 8 bits
+      entry length - 16 bits
+      entry itself
+      deh_objectid - 32 bits
+      	maybe deh_dir_id (32 bits)
+	maybe gencounter (16)
+	maybe deh_state (16)
+*/
+static void unpack_direntry (struct packed_item * pi, struct buffer_head * bh,
+			     struct item_head * ih, hashf_t hash_func)
+{
+    __u16 entry_count, namelen, gen_counter, entry_len;
+    __u8 mask;
+    int i;
+    struct reiserfs_de_head * deh;
+    int location;
+    char * item;
+
+    if (!hash_func)
+	die ("unpack_direntry: hash function is not set");
+
+    fread16 (&entry_count);
+    set_entry_count (ih, entry_count);
+
+    item = bh->b_data + ih_location (ih);
+    deh = (struct reiserfs_de_head *)item;
+    location = pi->item_len;
+    for (i = 0; i < entry_count; i ++, deh ++) {
+	fread8 (&mask);
+	fread16 (&entry_len);
+	location -= entry_len;
+	deh->deh_location = location;
+	fread (item + location, entry_len, 1, stdin);
+
+	/* find name length */
+	if (*(item + location + entry_len - 1))
+	    namelen = entry_len;
+	else
+	    namelen = strlen (item + location);
+
+	fread32 (&deh->deh_objectid);
+	if (mask & HAS_DIR_ID)
+	    fread32 (&deh->deh_dir_id);
+	else
+	    deh->deh_dir_id = ih->ih_key.k_objectid;
+	if (*(item + location) == '.' && namelen == 1)
+	    /* old or new "." */
+	    deh->deh_offset = DOT_OFFSET;
+	else if (*(item + location) == '.' && *(item + location + 1) == '.' && namelen == 2)
+	    /* old or new ".." */
+	    deh->deh_offset = DOT_DOT_OFFSET;
+	else
+	    deh->deh_offset = GET_HASH_VALUE (hash_func (item + location,
+							 namelen));
+	if (mask & HAS_GEN_COUNTER) {
+	    fread16 (&gen_counter);
+	    deh->deh_offset |= gen_counter;
+	}
+
+	if (mask & HAS_STATE)
+	    fread16 (&deh->deh_state);
+	else
+	    deh->deh_state = (1 << DEH_Visible);
+    }
+
+    return;
+}
+
+
+/* struct packed_item is already unpacked */
+static void unpack_stat_data (struct packed_item * pi, struct buffer_head * bh,
+			      struct item_head * ih)
+{
+    set_entry_count (ih, 0xffff);
+
+    if (ih_key_format (ih) == KEY_FORMAT_1) {
+	/* stat data comes in the following format:
+	   if this is old stat data:
+	   mode - 16 bits
+	   nlink - 16 bits
+	   size - 32 bits
+	   blocks/rdev - 32 bits
+	   maybe first_direct byte 32 bits
+	*/
+	struct stat_data_v1 * sd;
+
+	sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
+	memset (sd, 0, sizeof (sd));
+
+	fread16 (&sd->sd_mode);
+	fread16 (&sd->sd_nlink);
+	fread32 (&sd->sd_size);
+	fread32 (&sd->u.sd_blocks);
+	
+	if (pi->mask & WITH_SD_FIRST_DIRECT_BYTE) {
+	    fread32 (&sd->sd_first_direct_byte);
+	} else {
+	    sd->sd_first_direct_byte = 0xffffffff;
+	}
+    } else {
+	/* for new stat data
+	   mode - 16 bits
+	   nlink in either 16 or 32 bits
+	   size in either 32 or 64 bits
+	   blocks - 32 bits
+	*/
+	struct stat_data * sd;
+
+	sd = (struct stat_data *)B_I_PITEM (bh, ih);
+	memset (sd, 0, sizeof (sd));
+	
+	fread16 (&sd->sd_mode);
+
+	if (pi->mask & NLINK_BITS_32) {
+	    fread32 (&sd->sd_nlink);
+	} else {
+	    __u16 nlink16;
+
+	    fread16 (&nlink16);
+	    sd->sd_nlink = nlink16;
+	}
+
+	if (pi->mask & SIZE_BITS_64) {
+	    fread64 (&sd->sd_size);
+	} else {
+	    __u32 size32;
+
+	    fread32 (&size32);
+	    sd->sd_size = size32;
+	}
+
+	fread32 (&sd->sd_blocks);
+    }
+
+    return;
+}
+
+
+/* indirect item comes either in packed form or as is. ih_free_space
+   can go first */
+static void unpack_indirect (struct packed_item * pi, struct buffer_head * bh,
+			     struct item_head * ih)
+{
+    __u32 * ind_item, * end;
+    int i;
+    __u16 v16;
+
+    v16 = 0;
+    if (pi->mask & ENTRY_COUNT)
+	fread16 (&v16);
+
+    set_entry_count (ih, v16);
+
+    ind_item = (__u32 *)B_I_PITEM (bh, ih);
+    if (pi->mask & WHOLE_INDIRECT) {
+	fread (ind_item, pi->item_len, 1, stdin);
+	return;
+    }
+
+    end = ind_item + I_UNFM_NUM (ih);
+    while (ind_item < end) {
+	fread32 (ind_item);
+	fread16 (&v16);
+	for (i = 1; i < v16; i ++) {
+	    if (ind_item[0])
+		ind_item [i] = ind_item[0] + i;
+	    else
+		ind_item [i] = 0;
+	}
+	ind_item += i;
+    }
+    return;
+}
+
+
+// FIXME: we have no way to preserve symlinks
+static void unpack_direct (struct packed_item * pi, struct buffer_head * bh,
+			   struct item_head * ih)
+{
+    set_entry_count (ih, 0xffff);
+    memset (bh->b_data + ih_location (ih), 'a', pi->item_len);
+    return;
+}
+
+
+static void unpack_leaf (int dev, hashf_t hash_func)
+{
+    static int unpacked_leaves = 0;
+    struct buffer_head * bh;
+    struct packed_item pi;
+    struct item_head * ih;
+    int i;
+    __u16 v16;
+    __u32 v32;
+    
+    /* block number */
+    fread32 (&v32);
+
+
+    /* item number */
+    fread16 (&v16);
+
+    if (verbose)
+	fprintf (stderr, "leaf %d\n", v32);
+
+    
+ 
+    bh = getblk (dev, v32, 4096);
+    if (!bh)
+	die ("unpack_leaf: getblk failed");
+
+    set_node_item_number (bh, v16);
+    set_node_level (bh, DISK_LEAF_NODE_LEVEL);
+    set_node_free_space (bh, bh->b_size - BLKH_SIZE);
+    
+
+    ih = B_N_PITEM_HEAD (bh, 0);
+    for (i = 0; i < v16; i ++, ih ++) {
+#if 0
+	fread32 (&v32);
+	if (v32 != ITEM_START_MAGIC)
+	    die ("unpack_leaf: no start item magic found: block %lu, item %i",
+		 bh->b_blocknr, i);
+#endif	
+
+	fread (&pi, sizeof (struct packed_item), 1, stdin);
+	
+	/* dir_id - if it is there */
+	if (pi.mask & DIR_ID) {
+	    fread32 (&v32);
+	    ih->ih_key.k_dir_id = v32;
+	} else {
+	    if (!i)
+		die ("unpack_leaf: dir_id is not set");
+	    ih->ih_key.k_dir_id = (ih - 1)->ih_key.k_dir_id;
+	}
+
+	/* object_id - if it is there */
+	if (pi.mask & OBJECT_ID) {
+	    fread32 (&v32);
+	    ih->ih_key.k_objectid = v32;
+	} else {
+	    if (!i)
+		die ("unpack_leaf: object_id is not set");
+	    ih->ih_key.k_objectid = (ih - 1)->ih_key.k_objectid;
+	}
+
+	// we need to set item format before offset unpacking
+	set_key_format (ih, (pi.mask & NEW_FORMAT) ? KEY_FORMAT_2 : KEY_FORMAT_1);
+
+	// offset
+	unpack_offset (&pi, ih);
+
+	/* type */
+	unpack_type (&pi, ih);
+
+	/* item length and item location */
+	set_ih_item_len (ih, pi.item_len);
+	set_ih_location (ih, (i ? ih_location (ih - 1) : bh->b_size) - pi.item_len);
+
+	// item itself
+	if (is_direct_ih (ih)) {
+	    unpack_direct (&pi, bh, ih);
+	} else if (is_indirect_ih (ih)) {
+	    unpack_indirect (&pi, bh, ih);
+	} else if (is_direntry_ih (ih)) {
+	    unpack_direntry (&pi, bh, ih, hash_func);
+	} else if (is_stat_data_ih (ih)) {
+	    unpack_stat_data (&pi, bh, ih);
+	}
+	set_node_free_space (bh, node_free_space (bh) - (IH_SIZE + ih_item_len (ih)));
+#if 0
+	fread32 (&v32);
+	if (v32 != ITEM_END_MAGIC)
+	    die ("unpack_leaf: no end item magic found: block %lu, item %i",
+		 bh->b_blocknr, i);
+#endif
+    }
+
+    fread16 (&v16);
+    if (v16 != LEAF_END_MAGIC)
+	die ("unpack_leaf: wrong end signature found - %x, block %lu", 
+	     v16, bh->b_blocknr);
+
+    mark_buffer_uptodate (bh, 1);
+    mark_buffer_dirty (bh);
+    bwrite (bh);
+    /*
+    if (!not_data_block (bh->b_blocknr))
+	data_blocks_unpacked ++;
+    */
+    brelse (bh);
+
+    if (what_unpacked)
+	reiserfs_bitmap_set_bit (what_unpacked, bh->b_blocknr);
+    unpacked ++;
+
+    if (!(++ unpacked_leaves % 10))
+	fprintf (stderr, "#");
+}
+
+
+static void unpack_full_block (int dev, int blocksize)
+{
+    static int full_blocks_unpacked = 0;
+    __u32 block;
+    struct buffer_head * bh;
+
+    fread32 (&block);
+
+    if (verbose)
+	fprintf (stderr, "full #%d\n", block);
+
+    bh = getblk (dev, block, blocksize);
+    if (!bh)
+	die ("unpack_full_block: getblk failed");
+
+    fread (bh->b_data, bh->b_size, 1, stdin);
+
+    if (who_is_this (bh->b_data, bh->b_size) == THE_SUPER && !what_unpacked) {
+	unsigned long blocks;
+	
+	blocks = rs_block_count ((struct reiserfs_super_block *)(bh->b_data));
+	fprintf (stderr, "There were %lu blocks on the device\n", blocks);
+	what_unpacked = reiserfs_create_bitmap (blocks);
+    }
+
+    mark_buffer_uptodate (bh, 1);
+    mark_buffer_dirty (bh);
+    bwrite (bh);
+/*
+    if (!not_data_block (bh->b_blocknr))
+	data_blocks_unpacked ++;
+*/
+    brelse (bh);
+
+    if (what_unpacked)
+	reiserfs_bitmap_set_bit (what_unpacked, block);
+    unpacked ++;
+
+    if (!(++ full_blocks_unpacked % 50))
+	fprintf (stderr, ".");
+}
+
+
+/* just skip bitmaps of unformatted nodes */
+static void unpack_unformatted_bitmap (int dev, int blocksize)
+{
+    __u16 bmap_num;
+    __u32 block_count;
+    int i;
+    char * buf;
+ 
+    fread16 (&bmap_num);
+    fread32 (&block_count);
+    
+    buf = malloc (blocksize);
+    if (!buf)
+	reiserfs_panic ("unpack_unformatted_bitmap: malloc failed: %m");
+
+    for (i = 0; i < bmap_num; i ++) {
+	if (fread (buf, blocksize, 1, stdin) != 1)
+	    reiserfs_panic ("unpack_unformatted_bitmap: "
+			    "could not read bitmap #%d: %m", i);
+    }
+    free (buf);
+}
+
+
+// read packed reiserfs partition metadata from stdin
+void unpack_partition (int dev)
+{
+    __u32 magic32;
+    __u16 magic16;
+    __u16 blocksize;
+    
+    fread32 (&magic32);
+    if (magic32 != REISERFS_SUPER_MAGIC)
+	die ("unpack_partition: reiserfs magic number not found");
+    
+    fread16 (&blocksize);
+    
+    if (verbose)
+	fprintf (stderr, "Blocksize %d\n", blocksize);
+    
+    while (!feof (stdin)) {
+	char c[2];
+
+	fread (c, 1, 1, stdin);
+	switch (c[0]) {
+	case '.':
+	    if (verbose)
+		fprintf (stderr, "\".\" skipped\n");
+	    continue;
+
+	case '1':
+	    fread (c, 1, 1, stdin); /* that was 100%, read in first 0 */
+	case '2':
+	case '4':
+	case '6':
+	case '8':
+	    fread (c, 1, 1, stdin);
+	case '0':
+	    fread (c + 1, 1, 1, stdin); /* read % */
+		
+	    if (c[0] != '0' || c[1] != '%')
+		die ("0%% expected\n");
+
+	    if (verbose)
+		fprintf (stderr, "0%% skipped\n");
+	    continue;
+	}
+
+	fread (c + 1, 1, 1, stdin);
+	magic16 = *(__u16 *)c;
+	/*fread16 (&magic16);*/
+	
+	switch (magic16 & 0xff) {
+	case LEAF_START_MAGIC:
+	    unpack_leaf (dev, code2func (magic16 >> 8));
+	    break;
+	    
+	case FULL_BLOCK_START_MAGIC:
+	    unpack_full_block (dev, blocksize);
+	    break;
+
+	case UNFORMATTED_BITMAP_START_MAGIC:
+	    fprintf (stderr, "\nBitmap of unformatted - ignored\n");
+	    unpack_unformatted_bitmap (dev, blocksize);
+	    break;
+	    
+	case END_MAGIC:
+	    break;
+
+	default:
+	    die ("unpack_partition: bad magic found - %x", magic16 & 0xff);
+	}
+    }
+
+    fprintf (stderr, "Unpacked %d (%d) blocks\n", unpacked, what_unpacked ? reiserfs_bitmap_ones (what_unpacked) : 0);
+
+
+    /*    fclose (block_list);*/
+}
+
+
+int main (int argc, char ** argv)
+{
+    int fd;
+    int c;
+    char * filename = ".bitmap";
+    struct rlimit lim = {0xffffffff, 0xffffffff};
+
+    print_banner ("unpack");
+
+    /* with this 2.4.0-test9's file_write does not send SIGXFSZ */
+    if (setrlimit (RLIMIT_FSIZE, &lim)) {
+	fprintf  (stderr, "sertlimit failed: %m\n");
+    }
+
+    while ((c = getopt (argc, argv, "vb:")) != EOF) {
+	switch (c) {
+	case 'v':
+	    verbose = 1;
+	case 'b':
+	    asprintf (&filename, "%s", optarg);
+	    break;
+	}
+    }
+    if (optind != argc - 1)
+	/* only one non-option argument is permitted */
+	print_usage_and_exit();
+
+    if (is_mounted (argv[optind]))
+	reiserfs_panic ("%s seems mounted, umount it first\n", argv[optind]);
+  
+    fd = open (argv[optind], O_RDWR | O_LARGEFILE);
+    if (fd == -1) {
+	perror ("open failed");
+	return 0;
+    }
+
+    unpack_partition (fd);
+
+    if (what_unpacked && filename)
+	reiserfs_bitmap_save (filename, what_unpacked);
+
+    close (fd);
+    return 0;
+}
diff --git a/fsck/Makefile.am b/fsck/Makefile.am
new file mode 100644
index 0000000..a64e913
--- /dev/null
+++ b/fsck/Makefile.am
@@ -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.
diff --git a/fsck/Makefile.in b/fsck/Makefile.in
new file mode 100644
index 0000000..1d26e75
--- /dev/null
+++ b/fsck/Makefile.in
@@ -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:
diff --git a/fsck/check.c b/fsck/check.c
new file mode 100644
index 0000000..37dacdd
--- /dev/null
+++ b/fsck/check.c
@@ -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;
+}
+
+
+
+
+
+
+
diff --git a/fsck/check_tree.c b/fsck/check_tree.c
new file mode 100644
index 0000000..6615409
--- /dev/null
+++ b/fsck/check_tree.c
@@ -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;
+}
+
+
diff --git a/fsck/fsck.h b/fsck/fsck.h
new file mode 100644
index 0000000..ac0c7ce
--- /dev/null
+++ b/fsck/fsck.h
@@ -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);\
+}
diff --git a/fsck/info.c b/fsck/info.c
new file mode 100644
index 0000000..cd591d8
--- /dev/null
+++ b/fsck/info.c
@@ -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);
+    }
+}
+
+
diff --git a/fsck/journal.c b/fsck/journal.c
new file mode 100644
index 0000000..656dc4d
--- /dev/null
+++ b/fsck/journal.c
@@ -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;
+}
diff --git a/fsck/lost+found.c b/fsck/lost+found.c
new file mode 100644
index 0000000..83e77e7
--- /dev/null
+++ b/fsck/lost+found.c
@@ -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);
+}
+
diff --git a/fsck/main.c b/fsck/main.c
new file mode 100644
index 0000000..9f9575e
--- /dev/null
+++ b/fsck/main.c
@@ -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;
+
+}
diff --git a/fsck/pass0.c b/fsck/pass0.c
new file mode 100644
index 0000000..8b7b065
--- /dev/null
+++ b/fsck/pass0.c
@@ -0,0 +1,1502 @@
+/*
+ * Copyright 1996-2001 Hans Reiser
+ */
+
+#include "fsck.h"
+
+
+
+static unsigned long tmp_zeroed;
+
+/* pass 0 scans the partition (used part). It creates two maps which will be
+   used on the pass 1. These are a map of nodes looking like leaves and a map
+   of "bad" unformatted nodes. */
+
+
+/* leaves */
+reiserfs_bitmap_t leaves_bitmap;
+#define pass0_is_leaf(block) __is_marked (leaves, block)
+#define pass0_mark_leaf(block) __mark (leaves, block)
+
+/* nodes which are referred to from only one indirect item */
+reiserfs_bitmap_t good_unfm_bitmap;
+#define pass0_is_good_unfm(block) __is_marked (good_unfm, block)
+#define pass0_mark_good_unfm(block) __mark (good_unfm, block)
+#define pass0_unmark_good_unfm(block) __unmark (good_unfm, block)
+
+/* nodes which are referred to from more than one indirect item */
+reiserfs_bitmap_t bad_unfm_bitmap;
+#define pass0_is_bad_unfm(block) __is_marked (bad_unfm, block)
+#define pass0_mark_bad_unfm(block) __mark (bad_unfm, block)
+#define pass0_unmark_bad_unfm(block) __unmark (bad_unfm, block)
+
+
+
+/* there are three way to say of which blocks the tree should be built off:
+ default - */
+static void make_aux_bitmaps (reiserfs_filsys_t fs)
+{
+
+    /* bitmap of leaves found on the device. It will be saved if -c specified */
+    leaves_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
+
+    good_unfm_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
+
+    bad_unfm_bitmap = reiserfs_create_bitmap (SB_BLOCK_COUNT (fs));
+
+}
+
+
+/* register block some indirect item points to */
+static void register_unfm (unsigned long block)
+{
+    if (!pass0_is_good_unfm (block) && !pass0_is_bad_unfm (block)) {
+	/* this block was not pointed by other indirect items yet */
+	pass0_mark_good_unfm (block);
+	return;
+    }
+
+    if (pass0_is_good_unfm (block)) {
+	/* block was pointed once already, unmark it in bitmap of good
+           unformatted nodes and mark in bitmap of bad pointers */
+	pass0_unmark_good_unfm (block);
+	pass0_mark_bad_unfm (block);
+	return;
+    }
+
+    assert (pass0_is_bad_unfm (block));
+}
+
+
+/* 'upper' item is correct if 'upper + 2' exists and its key is greater than
+   key of 'upper' */
+static int upper_correct (struct buffer_head * bh, struct item_head * upper,
+			  int upper_item_num)
+{
+    if (upper_item_num + 2 < B_NR_ITEMS (bh)) {
+	if (comp_keys (&upper->ih_key, &(upper + 2)->ih_key) != -1)
+	    /* item-num's item is out of order of order */
+	    return 0;
+	return 1;
+    }
+    
+    /* there is no item above the "bad pair" */
+    return 2;
+}
+
+
+/* 'lower' item is correct if 'lower - 2' exists and its key is smaller than
+   key of 'lower' */
+static int lower_correct (struct buffer_head * bh, struct item_head * lower,
+			  int lower_item_num)
+{
+    if (lower_item_num - 2 >= 0) {
+	if (comp_keys (&(lower - 2)->ih_key, &lower->ih_key) != -1)
+	    return 0;
+	return 1;
+    }
+    return 2;
+}
+
+
+/* return 1 if something was changed */
+static int correct_key_format (struct item_head * ih)
+{
+    int dirty = 0;
+
+    if (is_stat_data_ih (ih)) {
+	/* for stat data we have no way to check whether key format in item
+	   head matches to the key format found from the key directly */
+	if (ih_item_len (ih) == SD_V1_SIZE) {
+	    if (ih_key_format (ih) != KEY_FORMAT_1) {
+		fsck_log ("correct_key_format: ih_key_format of (%H) is set to format 1\n",
+			  ih);
+		set_key_format (ih, KEY_FORMAT_1);
+		return 1;
+	}
+	    return 0;
+	}
+	if (ih_item_len (ih) == SD_SIZE) {
+	    if (ih_key_format (ih) != KEY_FORMAT_2) {
+		fsck_log ("correct_key_format: ih_key_format of (%H) is set to format 2\n",
+			  ih);
+		set_key_format (ih, KEY_FORMAT_2);
+		return 1;
+	    }
+	    return 0;
+	}
+	
+	die ("stat data of wrong length");
+    }
+    
+    if (key_format (&ih->ih_key) != ih_key_format (ih)) {
+	fsck_log ("correct_key_format: ih_key_format of (%H) is set to format found in the key\n",
+		  ih);
+	set_key_format (ih, key_format (&ih->ih_key));
+	dirty = 1;
+    }
+    
+    if (type_unknown (&ih->ih_key)) {
+	/* FIXME: */
+	set_type (key_format (&ih->ih_key), &ih->ih_key, TYPE_DIRECT);
+	dirty = 1;	
+    }
+    
+    return dirty;
+}
+
+#if 0
+/* fixme: we might try all available hashes */
+static int prob_name (reiserfs_filsys_t fs,
+		      char ** name, int max_len, __u32 deh_offset)
+{
+    int start; /* */
+    int len;
+
+    for (start = 0; start < max_len; start ++) {
+	for (len = 0; len < max_len - start; len ++) {
+	    if (is_properly_hashed (fs, *name + start, len + 1, deh_offset)) {
+		*name = *name + start;
+		return len + 1;
+	    }
+	}
+    }
+    return 0;
+}
+#endif
+
+
+static void hash_hits_init (reiserfs_filsys_t fs)
+{
+    stats (fs)->hash_amount = known_hashes ();
+    stats (fs)->hash_hits = getmem (sizeof (unsigned long) * stats (fs)->hash_amount);
+    return;
+}
+
+
+static void add_hash_hit (reiserfs_filsys_t fs, int hash_code)
+{
+    stats (fs)->hash_hits [hash_code] ++;
+}
+
+
+/* deh_location look reasonable, try to find name length. return 0 if
+   we failed */
+static int try_to_get_name_length (struct item_head * ih, struct reiserfs_de_head * deh,
+				int i)
+{
+    int len;
+
+    len = name_length (ih, deh, i);
+    if (i == 0 || !de_bad_location (deh - 1))
+	return (len > 0) ? len : 0;
+
+    /* previous entry had bad location so we had no way to find
+       name length */
+    return 0;
+}
+
+
+
+/* define this if you are using -t to debug recovering of corrupted directory
+   item */
+#define DEBUG_VERIFY_DENTRY
+#undef DEBUG_VERIFY_DENTRY
+
+
+/* check directory item and try to recover something */
+static int verify_directory_item (reiserfs_filsys_t fs, struct buffer_head * bh,
+				  int item_num)
+{
+    struct item_head * ih;
+    struct item_head tmp;
+    char * item;
+    struct reiserfs_de_head * deh;
+    char * name;
+    int name_len;
+    int bad;
+    int i, j;
+#if 0
+    int bad_entries; /* how many bad neighboring entries */
+    int total_entry_len;
+    char * entries, * end;
+#endif
+    int dirty;
+    int entry_count;
+    int hash_code;
+    int bad_locations;
+
+#ifdef DEBUG_VERIFY_DENTRY
+    char * direntries;
+#endif
+
+
+    ih = B_N_PITEM_HEAD (bh, item_num);
+    item = B_I_PITEM (bh,ih);
+    deh = (struct reiserfs_de_head *)item;
+
+    dirty = 0;
+    bad_locations = 0;
+    entry_count = ih_entry_count (ih);
+
+
+    /* check deh_location */
+    for (i = 0; i < ih_entry_count (ih); i ++) {
+	/* silently fix deh_state */
+	if (deh [i].deh_state != (1 << DEH_Visible)) {
+	    deh [i].deh_state = cpu_to_le16 (1 << DEH_Visible);
+	    mark_buffer_dirty (bh);
+	}
+	if (dir_entry_bad_location (deh + i, ih, !i))
+	    mark_de_bad_location (deh + i);
+    }
+
+#ifdef DEBUG_VERIFY_DENTRY
+    direntries = getmem (ih_entry_count (ih) * sizeof (int));
+
+    printf ("entries with bad locations: ");
+    for (i = 0; i < ih_entry_count (ih); i ++) {
+	if (de_bad_location (deh + i))
+	    printf ("%d ", i);
+    }
+    printf ("\n");
+#endif /* DEBUG_VERIFY_DENTRY */
+
+
+    /* find entries names in which have mismatching deh_offset */
+    for (i = ih_entry_count (ih) - 1; i >= 0; i --) {
+	if (de_bad (deh + i))
+	    /* bad location */
+	    continue;
+
+	if (i) {
+	    if (deh_location (deh + i - 1) < deh_location (deh + i))
+		mark_de_bad_location (deh + i - 1);
+	}
+
+	name = name_in_entry (deh + i, i);
+	/* we found a name, but we not always we can get its length as
+           it depends on deh_location of previous entry */
+	name_len = try_to_get_name_length (ih, deh + i, i);
+
+#ifdef DEBUG_VERIFY_DENTRY
+	if (name_len == 0)
+	    printf ("trying to find name length for %d-th entry\n", i);
+#endif /* DEBUG_VERIFY_DENTRY */
+	if (is_dot (name, name_len)) {
+	    if (i != 0)
+		fsck_log ("block %lu: item %d: \".\" is %d-th entry\n",
+			  bh->b_blocknr, item_num, i);
+	    /* check and fix "." */
+	    
+	    if (deh_offset (deh + i) != DOT_OFFSET) {
+		deh[i].deh_offset = cpu_to_le32 (DOT_OFFSET);
+		mark_buffer_dirty (bh);
+	    }
+	    /* "." must point to the directory it is in */
+	    if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) {
+		fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
+			  "pointing to (%K) instead of (%K)\n", 
+			  bh->b_blocknr, ih,
+			  &(deh[i].deh_dir_id), &(ih->ih_key));
+		deh[i].deh_dir_id = key_dir_id (&ih->ih_key);
+		deh[i].deh_objectid = key_objectid (&ih->ih_key);
+		mark_buffer_dirty (bh);
+	    }
+	} else if (is_dot_dot (name, name_len)) {
+	    if (i != 1)
+		fsck_log ("block %lu: item %d: \"..\" is %d-th entry\n",
+			  bh->b_blocknr, item_num, i);
+	    
+	    /* check and fix ".." */
+	    if (deh_offset (deh + i) != DOT_DOT_OFFSET)
+		deh[i].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
+	} else {
+	    int min_length, max_length;
+
+	    /* check other name */
+
+	    if (name_len == 0) {
+		/* we do not know the length of name - we will try to find it */
+		min_length = 1;
+		max_length = item + ih_item_len (ih) - name;
+	    } else
+		/* we kow name length, so we will try only one name length */
+		min_length = max_length = name_len;
+
+	    for (j = min_length; j <= max_length; j ++) {
+		hash_code = find_hash_in_use (name, j,
+					      GET_HASH_VALUE (deh_offset (deh + i)),
+					      rs_hash (fs->s_rs));
+		add_hash_hit (fs, hash_code);
+		if (code2func (hash_code) != 0) {
+		    /* deh_offset matches to some hash of the name */
+		    if (!name_len) {
+			fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" "
+				  "matching to deh_offset %u. FIXME: should set deh_location "
+				  "of previous entry (not ready)\n",
+				  bh->b_blocknr, ih, i, j, name, deh_offset (deh + i));
+			/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
+			if (i) {
+			    deh[i - 1].deh_location = cpu_to_le16 (deh_location (deh + i) +
+								   ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j)));
+			    mark_de_good_location (deh + i - 1);
+			    mark_buffer_dirty (bh);
+			}
+		    }
+		    break;
+		}
+	    }
+	    if (j == max_length + 1) {
+		/* deh_offset does not match to anything. it will be
+		   deleted for now, but maybe we could just fix a
+		   deh_offset if it is in ordeer */
+		mark_de_bad_offset (deh + i);
+	    }
+	}
+    } /* for */
+
+
+
+#if 0
+    /* find entries names in which have mismatching deh_offset */
+    for (i = 0; i < ih_entry_count (ih); i ++) {
+	if (de_bad (deh + i))
+	    /* bad location */
+	    continue;
+
+	name = name_in_entry (deh + i, i);
+	/* we found a name, but we not always we can get its length as
+           it depends on deh_location of previous entry */
+	name_len = try_to_get_name_length (ih, deh + i, i);
+
+	if (i == 0 && is_dot (name, name_len)) {
+	    
+	    /* check and fix "." */
+	    
+	    if (deh_offset (deh + i) != DOT_OFFSET) {
+		deh[i].deh_offset = cpu_to_le32 (DOT_OFFSET);
+		mark_buffer_dirty (bh);
+	    }
+	    /* "." must point to the directory it is in */
+	    if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) {
+		fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
+			  "pointing to (%K) instead of (%K)\n", 
+			  bh->b_blocknr, ih,
+			  &(deh[i].deh_dir_id), &(ih->ih_key));
+		deh[i].deh_dir_id = key_dir_id (&ih->ih_key);
+		deh[i].deh_objectid = key_objectid (&ih->ih_key);
+		mark_buffer_dirty (bh);
+	    }
+	} else if (i == 1 && is_dot_dot (name, name_len)) {
+	    
+	    /* check and fix ".." */
+
+	    if (deh_offset (deh + i) != DOT_DOT_OFFSET)
+		deh[i].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
+	} else {
+	    int min_length, max_length;
+
+	    /* check other name */
+
+	    if (name_len == 0) {
+		/* we do not know the length of name - we will try to find it */
+		min_length = 1;
+		max_length = item + ih_item_len (ih) - name;
+	    } else
+		/* we kow name length, so we will try only one name length */
+		min_length = max_length = name_len;
+
+	    for (j = min_length; j <= max_length; j ++) {
+		hash_code = find_hash_in_use (name, j,
+					      GET_HASH_VALUE (deh_offset (deh + i)),
+					      rs_hash (fs->s_rs));
+		add_hash_hit (fs, hash_code);
+		if (code2func (hash_code) != 0) {
+		    /* deh_offset matches to some hash of the name */
+		    if (!name_len) {
+			fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" "
+				  "matching to deh_offset %u. FIXME: should set deh_location "
+				  "of previous entry (not ready)\n",
+				  bh->b_blocknr, ih, i, j, name, deh_offset (deh + i));
+			/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
+			deh[i - 1].deh_location = cpu_to_le16 (deh_location (deh + i) +
+							       ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j)));
+		    }
+		    break;
+		}
+	    }
+	    if (j == max_length + 1) {
+		/* deh_offset does not match to anything. it will be
+		   deleted for now, but maybe we could just fix a
+		   deh_offset if it is in ordeer */
+		mark_de_bad_offset (deh + i);
+	    }
+	}
+    }
+#endif
+
+#ifdef DEBUG_VERIFY_DENTRY
+    printf ("entries with mismatching deh_offsets: ");
+    for (i = 0; i < ih_entry_count (ih); i ++) {
+	if (de_bad_offset (deh + i))
+	    printf ("%d ", i);
+    }
+    printf ("\n");
+#endif /* DEBUG_VERIFY_DENTRY */
+
+
+    /* correct deh_locations such that code cutting entries will not get
+       screwed up */
+    {
+	int prev_loc;
+	int loc_fixed;
+
+
+	prev_loc = ih_item_len (ih);
+	for (i = 0; i < ih_entry_count (ih); i ++) {
+	    loc_fixed = 0;
+	    if (de_bad_location (deh + i)) {
+		deh[i].deh_location = cpu_to_le16 (prev_loc/* - 1*/);
+		mark_buffer_dirty (bh);
+		loc_fixed = 1;
+	    } else {
+		if (deh_location (deh + i) >= prev_loc) {
+		    deh[i].deh_location = cpu_to_le16 (prev_loc/* - 1*/);
+		    mark_buffer_dirty (bh);
+		    loc_fixed = 1;
+		}
+	    }
+
+	    prev_loc = deh_location (deh + i);
+	    
+	    if (i == ih_entry_count (ih) - 1) {
+		/* last entry starts right after an array of dir entry headers */
+		if (!de_bad (deh + i) &&
+		    deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) {
+		    /* free space in the directory item */
+		    fsck_log ("verify_direntry: block %lu, item %H has free space\n",
+			      bh->b_blocknr, ih);
+		    cut_entry (fs, bh, item_num, ih_entry_count (ih), 0);
+		}
+		if (deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) {
+		    deh[i].deh_location = cpu_to_le16 (DEH_SIZE * ih_entry_count (ih));
+		    loc_fixed = 1;
+		    mark_buffer_dirty (bh);
+		}
+	    }
+
+#ifdef DEBUG_VERIFY_DENTRY
+	    if (loc_fixed)
+		direntries [i] = 1;
+#endif
+	} /* for */
+
+#ifdef DEBUG_VERIFY_DENTRY
+	printf ("entries with fixed deh_locations: ");
+	for (i = 0; i < ih_entry_count (ih); i ++) {
+	    if (direntries [i])
+		printf ("%d ", i);
+	}
+	printf ("\n");
+#endif /* DEBUG_VERIFY_DENTRY */
+
+    }
+
+#ifdef DEBUG_VERIFY_DENTRY
+    printf (" N  location name\n");
+    for (i = 0; i < ih_entry_count (ih); i ++) {
+	if (de_bad (deh + i) ||
+	    (i && de_bad (deh + i - 1)) || /* previous entry marked bad */
+	    (i < ih_entry_count (ih) - 1 && de_bad (deh + i + 1))) { /* next entry is marked bad */
+	    /* print only entries to be deleted and their nearest neighbors */
+	    printf ("%3d: %8d ", i, deh_location (deh + i));
+	    if (de_bad (deh + i))
+		printf ("will be deleted\n");
+	    else
+		printf ("\"%.*s\"\n", name_length (ih, deh + i, i),
+			name_in_entry (deh + i, i));
+	}
+    }
+#endif
+
+    bad = 0;
+    tmp = *ih;
+
+    /* delete entries which are marked bad */
+    for (i = 0; i < ih_entry_count (ih); i ++) {
+	deh = B_I_DEH (bh, ih) + i;
+	if (de_bad (deh)) {
+	    bad ++;
+	    if (ih_entry_count (ih) == 1) {
+		delete_item (fs, bh, item_num);
+		break;
+	    } else {
+		cut_entry (fs, bh, item_num, i, 1);
+	    }
+	    i --;
+	}
+    }
+    
+    if (bad == ih_entry_count (&tmp)) {
+	fsck_log ("pass0: block %lu, item %H - all entries were deleted\n", bh->b_blocknr, &tmp);
+	return 0;
+    }
+
+    deh = B_I_DEH (bh, ih);
+    if (get_offset (&ih->ih_key) != deh_offset (deh)) {
+	fsck_log ("verify_direntry: block %lu, item %H:  k_offset and deh_offset %u mismatched\n",
+		  bh->b_blocknr, ih, deh_offset (deh));
+	set_offset (KEY_FORMAT_1, &ih->ih_key, deh_offset (deh));
+	mark_buffer_dirty (bh);
+    }
+    
+    if (bad)
+	fsck_log ("pass0: block %lu, item %H: %d entries were deleted of \n",
+		  bh->b_blocknr, &tmp, bad);
+	
+    return 0;
+
+#if 0
+
+    /* FIXME: temporary */
+    if (bad_locations > ih_entry_count (ih) / 2) {
+	fsck_log ("pass0: block %u: item %d (%H) had too bad directory - deleted\n",
+		  bh->b_blocknr, item_num, ih);
+	delete_item (fs, bh, item_num);
+	return 0;
+    }
+
+    if (!dirty)
+	return 0;
+    
+    /* something is broken */
+
+    fsck_log ("pass0: block %lu: %d-th item (%H) has %d bad entries..",
+	      bh->b_blocknr, item_num, ih, dirty);
+
+    if (get_offset (&ih->ih_key) == DOT_OFFSET) {
+	/* first item of directory - make sure that "." and ".." are in place */
+	if (deh_offset (deh) != DOT_OFFSET || name_in_entry (deh, 0)[0] != '.') {
+	    deh->deh_offset = cpu_to_le32 (DOT_OFFSET);
+	    name_in_entry (deh, 0)[0] = '.';
+	}
+	if (deh_offset (deh + 1) != DOT_DOT_OFFSET ||
+	    name_in_entry (deh + 1, 1)[0] != '.' || name_in_entry (deh + 1, 1)[1] != '.') {
+	    (deh + 1)->deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
+	    name_in_entry (deh + 1, 1)[0] = '.';
+	    name_in_entry (deh + 1, 1)[1] = '.';
+	}
+    }
+
+    end = item + ih_item_len (ih);
+    deh += ih_entry_count (ih);
+    entries = (char *)deh;
+    total_entry_len = ih_item_len (ih) - DEH_SIZE * ih_entry_count (ih);
+    i = ih_entry_count (ih);
+
+    bad_entries = 0;
+    do {
+	i --;
+	deh --;
+	name_len = prob_name (fs, &entries, total_entry_len, deh_offset (deh));
+	if (!name_len) {
+	    if (!bad_entries) {
+		deh->deh_location = cpu_to_le16 (entries - item);
+	    } else {
+		deh->deh_location = cpu_to_le16 (deh_location (deh + 1) + 1);
+	    }
+	    bad_entries ++;
+	    
+	    /*fsck_log ("verify_directory_item: entry %d: in string \'%s\' there is no substring matching hash %ld\n",
+	      i, bad_name (entries, total_entry_len), masked_offset);*/
+	    mark_de_bad (deh);
+	    continue;
+	}
+	bad_entries = 0;
+	/*fsck_log ("verify_directory_item: entry %d: found \"%s\" name matching hash %ld\n",
+	  i, bad_name (entries, name_len), masked_offset);*/
+	
+	/* 'entries' points now to the name which match given offset -
+           so, set deh_location */
+	deh->deh_location = cpu_to_le16 (entries - item);
+	deh->deh_state = 0;
+	mark_de_visible (deh);
+	
+	entries += name_len;
+	total_entry_len = end - entries;
+	/* skip padding zeros */
+	while (!*entries) {
+	    entries ++;
+	    total_entry_len --;
+	}
+	/* 'entries' points now at the place where next (previous)
+           entry should start */
+    } while ((char *)deh != item);
+    
+    
+    /* fixme: this will not work if all entries are to be deleted */
+    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
+	deh = (struct reiserfs_de_head *)B_I_PITEM (bh, ih) + i;
+	if (de_bad (deh)) {
+	    if (ih_entry_count (ih) == 1) {
+		delete_item (fs, bh, i);
+		break;
+	    } else {
+		cut_entry (fs, bh, item_num, i);
+	    }
+	    i --;
+	}
+/*
+  fsck_log ("verify_directory_item: %d-th entry is to be deleted: "
+  "\"%s\" does not match to hash %lu\n", 
+  i, bad_name (name_in_entry (deh, i), name_length (ih, deh, i)),
+  deh_offset (deh));
+*/
+    }
+    
+    fsck_log ("%d entries were deleted\n", entry_count - ih_entry_count (ih));
+    mark_buffer_dirty (bh);
+
+    
+    return 0;
+
+#endif
+}
+
+
+/* do this on pass 0 with every leaf marked used */
+
+/* FIXME: we can improve fixing of broken keys: we can ssfe direct items which
+   go after stat data and have broken keys */
+static void pass0_correct_leaf (reiserfs_filsys_t fs,
+				struct buffer_head * bh)
+{
+    int i, j;
+    struct item_head * ih;
+    __u32 * ind_item;
+    unsigned long unfm_ptr;
+    int dirty = 0;
+
+ start_again:
+
+    ih = B_N_PITEM_HEAD (bh, 0);
+    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
+	if (ih->ih_key.k_dir_id == 0 || ih->ih_key.k_objectid == 0) {
+	    /* sometimes stat datas get k_objectid==0 or k_dir_id==0 */
+	    if (i == (node_item_number (bh) - 1)) {
+		/* */
+		if (i == 0) {
+		    fsck_log ("block %lu: item %d: (%H) is alone in the block\n",
+			      bh->b_blocknr, i, ih);
+		    return;
+		}
+		/* delete last item */
+		delete_item (fs, bh, i - 1);
+		return;
+	    }
+
+	    /* there is next item: if it is not stat data - take its k_dir_id
+               and k_objectid. if key order will be still wrong - the changed
+               item will be deleted */
+	    if (!is_stat_data_ih (ih + 1)) {
+		fsck_log ("block %lu: item %d: (%H) fixed to ", bh->b_blocknr, i, ih);
+		ih->ih_key.k_dir_id = (ih + 1)->ih_key.k_dir_id;
+		ih->ih_key.k_objectid = (ih + 1)->ih_key.k_objectid;
+		set_offset (KEY_FORMAT_1, &ih->ih_key, 0);
+		set_type (KEY_FORMAT_1, &ih->ih_key, TYPE_STAT_DATA);
+		fsck_log ("(%H)\n", ih);
+		dirty = 1;
+	    } else if (i == 0) {
+		delete_item (fs, bh, i);
+		goto start_again;
+	    }
+	}
+
+	/* this recovers corruptions like the below: 
+	   1774 1732 0 0
+	   116262638 1732 1 3
+	   1774 1736 0 0 */
+	if (i && is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
+	    if (ih->ih_key.k_objectid != (ih - 1)->ih_key.k_objectid ||
+		ih->ih_key.k_dir_id != (ih - 1)->ih_key.k_dir_id ||
+		get_offset (&ih->ih_key) != 1) {
+		if (is_direntry_ih (ih)) {
+		    fsck_log ("block %lu: item %d: no \".\" entry found in "
+			      "the first item of a directory\n", bh->b_blocknr, i);
+		} else {
+		    fsck_log ("block %lu: item %d: (%H) fixed to ", 
+			  bh->b_blocknr, i, ih);
+		    ih->ih_key.k_dir_id = (ih - 1)->ih_key.k_dir_id;
+		    ih->ih_key.k_objectid = (ih - 1)->ih_key.k_objectid;
+		    
+		    if (ih_item_len (ih - 1) == SD_SIZE) {
+			/* stat data is new, therefore this item is new too */
+			set_offset (KEY_FORMAT_2, &(ih->ih_key), 1);
+			if (ih_entry_count (ih) != 0xffff)
+			    set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_INDIRECT);
+			else
+			    set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_DIRECT);
+			set_key_format (ih, KEY_FORMAT_2);
+		    } else {
+			/* stat data is old, therefore this item is old too */
+			set_offset (KEY_FORMAT_1, &(ih->ih_key), 1);
+			if (ih_entry_count (ih) != 0xffff)
+			    set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_INDIRECT);
+			else
+			    set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_DIRECT);
+			set_key_format (ih, KEY_FORMAT_1);
+		    }
+		    fsck_log ("%H\n", ih);
+		    dirty = 1;
+		}
+	    }
+	}
+
+	/* FIXME: corruptions like:
+	   56702 66802 1 2
+	   56702 65536 0 0
+	   56702 66803 1 2
+	   do not get recovered (both last items will be deleted) */
+	/* delete item if it is not in correct order of object items */
+	if (i && not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key) &&
+	    !is_stat_data_ih (ih)) {
+	    fsck_log ("block %lu: item %d: %H follows non stat item %H - deleted\n",
+		      bh->b_blocknr, i, ih, ih - 1);
+	    delete_item (fs, bh, i);
+	    goto start_again;
+	}
+
+	if (i &&  comp_keys (&(ih - 1)->ih_key, &ih->ih_key) != -1) {
+	    /* previous item has key not smaller than the key of currect item */
+	    if (is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
+		/* fix key of stat data such as if it was stat data of that item */
+		fsck_log ("pass0: block %lu: %d-th item %k is out of order, made a stat data of %d-th (%k)\n",
+			  bh->b_blocknr, i - 1, &(ih - 1)->ih_key, i, &ih->ih_key);
+		(ih - 1)->ih_key.k_dir_id = ih->ih_key.k_dir_id;
+		(ih - 1)->ih_key.k_objectid = ih->ih_key.k_objectid;
+		set_offset (KEY_FORMAT_1, &(ih - 1)->ih_key, 0);
+		set_type (KEY_FORMAT_1, &(ih - 1)->ih_key, TYPE_STAT_DATA);
+		dirty = 1;
+	    } else {
+		/* ok, we have to delete one of these two - decide which one */
+		int retval;
+
+		/* something will be deleted */
+		dirty = 1;
+		retval = upper_correct (bh, ih - 1, i - 1);
+		switch (retval) {
+		case 0:
+		    /* delete upper item */
+		    fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n",
+			      bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
+		    delete_item (fs, bh, i - 1);
+		    goto start_again;
+
+		case 1:
+		    /* delete lower item */
+		    fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n",
+			      bh->b_blocknr, i, &ih->ih_key);
+		    delete_item (fs, bh, i);
+		    goto start_again;
+
+		default:
+		    /* upper item was the first item of a node */
+		}
+
+		retval = lower_correct (bh, ih, i);
+		switch (retval) {
+		case 0:
+		    /* delete lower item */
+		    fsck_log ("pass0: block %lu: %d-th (lower) item (%k) is out of order, deleted\n",
+			      bh->b_blocknr, i, &ih->ih_key);
+		    delete_item (fs, bh, i);
+		    goto start_again;
+
+		case 1:
+		    /* delete upper item */
+		    fsck_log ("pass0: block %lu: %d-th (upper) item (%k) is out of order, deleted\n",
+			      bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
+		    delete_item (fs, bh, i - 1);
+		    goto start_again;
+
+		default:
+		    /* there wer only two items in a node, so we could not
+                       decide what to delete, go and ask user */
+		}
+		fsck_log ("pass0: which of these items looks better (other will be deleted)?\n"
+			  "%H\n%H\n", ih - 1, ih);
+		if (fsck_user_confirmed (fs, "1 or 2?", "1\n", 1))
+		    delete_item (fs, bh, i - 1);
+		else
+		    delete_item (fs, bh, i);
+		goto start_again;
+	    }
+	}
+
+	if (is_stat_data_ih (ih) && (ih_item_len (ih) != SD_SIZE &&
+				     ih_item_len (ih) != SD_V1_SIZE)) {
+	    fsck_log ("pass0: block %lu, stat data of wrong length %H - deleted\n",
+		      bh, ih);
+	    delete_item (fs, bh, i);
+	    goto start_again;
+	}
+
+	dirty += correct_key_format (ih);
+
+	if (is_stat_data_ih (ih)) {
+	    ;/*correct_stat_data (fs, bh, i);*/
+	}
+
+	if (is_direntry_ih (ih)) {
+	    verify_directory_item (fs, bh, i);
+	    continue;
+	}
+
+	if (!is_indirect_ih (ih))
+	    continue;
+	
+	ind_item = (__u32 *)B_I_PITEM (bh, ih);
+	for (j = 0; j < I_UNFM_NUM (ih); j ++) {
+	    unfm_ptr = le32_to_cpu (ind_item [j]);
+	    if (!unfm_ptr)
+		continue;
+	    
+	    if (fsck_mode (fs) == FSCK_ZERO_FILES) {
+		/* FIXME: this is temporary mode of fsck */
+		ind_item [j] = 0;
+		reiserfs_bitmap_clear_bit (fsck_new_bitmap(fs), unfm_ptr);
+		tmp_zeroed ++;
+		dirty = 1;
+		continue;
+	    }
+
+	    if (not_data_block (fs, unfm_ptr) || /* journal area or bitmap or super block */
+		unfm_ptr >= SB_BLOCK_COUNT (fs)) {/* garbage in pointer */
+
+		stats (fs)->wrong_pointers ++;
+		/*
+		fsck_log ("pass0: %d-th pointer (%lu) in item %k (leaf block %lu) is wrong\n",
+			  j, unfm_ptr, &ih->ih_key, bh->b_blocknr);
+		*/
+		ind_item [j] = 0;
+		dirty = 1;
+		continue;
+	    }
+#if 0
+	    if (!was_block_used (unfm_ptr)) {
+	      /* this will get to a pool of allocable blocks */
+	      ind_item [j] = 0;
+	      dirty = 1;
+	      stat_wrong_pointer_found (fs);
+	      continue;
+	    }
+#endif
+	    /* mark block in bitmaps of unformatted nodes */
+	    register_unfm (unfm_ptr);
+	}
+    }
+
+    /* mark all objectids in use */
+    ih = B_N_PITEM_HEAD (bh, 0);
+    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
+	mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_dir_id));
+	mark_objectid_really_used (proper_id_map (fs), le32_to_cpu (ih->ih_key.k_objectid));
+    }
+
+    if (node_item_number (bh) < 1) {
+	/* pass 1 will skip this */
+	stats(fs)->all_contents_removed ++;
+	fsck_log ("pass0: block %lu got all items deleted\n",
+		  bh->b_blocknr);
+    } else {
+	/* pass1 will use this bitmap */
+	pass0_mark_leaf (bh->b_blocknr);
+
+    }
+    if (dirty) {
+	stats(fs)->leaves_corrected ++;
+	mark_buffer_dirty (bh);
+    }
+}
+
+
+static int is_bad_sd (struct item_head * ih, char * item)
+{
+    struct stat_data * sd = (struct stat_data *)item;
+
+    if (ih->ih_key.u.k_offset_v1.k_offset || ih->ih_key.u.k_offset_v1.k_uniqueness) {
+	reiserfs_warning (stderr, "Bad SD? %H\n", ih);
+	return 1;
+    }
+
+    if (ih_item_len (ih) == SD_V1_SIZE) {
+	/* looks like old stat data */
+	if (ih_key_format (ih) != KEY_FORMAT_1)
+	    fsck_log ("item %H has wrong format\n", ih);
+	return 0;
+    }
+
+    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;
+}
+
+
+int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize)
+{
+    int i;
+    char * name;
+    int namelen, entrylen;
+    struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item;
+    __u32 prev_offset = 0;
+    __u16 prev_location = ih_item_len (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 */
+
+    if (ih_item_len (ih) / (DEH_SIZE + min_entry_size) < ih_entry_count (ih))
+	/* entry count is too big */
+	return 1;
+
+    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
+	entrylen = entry_length(ih, deh, i);
+	if (entrylen > REISERFS_MAX_NAME_LEN (blocksize)) {
+	    return 1;
+	}
+	if (deh_offset (deh) <= prev_offset) {
+	    return 1;
+	}
+	prev_offset = deh_offset (deh);
+
+	if (deh_location(deh) + entrylen != prev_location) {
+	    return 1;
+	}
+	prev_location = deh_location (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;
+	}
+    }
+    return 0;
+}
+
+
+/* change incorrect block adresses by 0. Do not consider such item as incorrect */
+static int is_bad_indirect (struct item_head * ih, char * item, int dev, int blocksize)
+{
+    int i;
+    int bad = 0;
+    int blocks;
+
+    if (ih_item_len(ih) % UNFM_P_SIZE) {
+	fsck_log ("is_bad_indirect: indirect item of %H of invalid length\n", ih);
+	return 1;
+    }
+
+    blocks = SB_BLOCK_COUNT (fs);
+  
+    for (i = 0; i < I_UNFM_NUM (ih); i ++) {
+	__u32 * ind = (__u32 *)item;
+
+	if (le32_to_cpu (ind[i]) >= blocks) {
+	    bad ++;
+	    fsck_log ("is_bad_indirect: %d-th pointer of item %H looks bad (%lu)\n",
+		      i, ih, le32_to_cpu (ind [i]));
+	    continue;
+	}
+    }
+    return bad;
+}
+
+
+/* this is used by pass1.c:save_item and check.c:is_leaf_bad */
+int is_bad_item (struct buffer_head * bh, struct item_head * ih, char * item)
+{
+    int blocksize, dev;
+
+    blocksize = bh->b_size;
+    dev = bh->b_dev;
+
+    // FIXME: refuse transparently bad items
+    if (ih->ih_key.k_dir_id == ih->ih_key.k_objectid)
+	return 1;
+    if (!ih->ih_key.k_dir_id || !ih->ih_key.k_objectid)
+	return 1;
+
+    if (is_stat_data_ih(ih))
+	return is_bad_sd (ih, item);
+
+    if (is_direntry_ih (ih))
+	return is_bad_directory (ih, item, dev, blocksize);
+
+    if (is_indirect_ih (ih))
+	return is_bad_indirect (ih, item, dev, blocksize);
+
+    if (is_direct_ih (ih))
+	return 0;
+
+    return 1;
+}
+
+
+int is_leaf_bad (struct buffer_head * bh)
+{
+    int i;
+    struct item_head * ih;
+    int bad = 0;
+
+    assert (is_leaf_node (bh));
+
+    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))) {
+	    fsck_log ("is_leaf_bad: block %lu: %d-th item (%H) is bad\n",
+		      bh->b_blocknr, i, ih);
+	    bad = 1;
+	    continue;
+	}
+
+	if (i && bad_pair (fs, bh, i)) {
+	    fsck_log ("is_leaf_bad: block %luL %d-th item (%H) and "
+		      "the next one (%H) are in wrong order\n",
+		     bh->b_blocknr, i - 1, ih - 1, ih);
+	    bad = 1;
+	}
+    }
+
+    return bad;
+}
+
+
+static void go_through (reiserfs_filsys_t fs)
+{
+    struct buffer_head * bh;
+    int i;
+    int what_node;
+    unsigned long done = 0, total;
+
+    if (fsck_mode (fs) == DO_TEST) {
+	/* just to test pass0_correct_leaf */
+	bh = bread (fs->s_dev, stats(fs)->test, fs->s_blocksize);
+
+	/*
+	if (is_leaf_bad (bh)) {
+	    fsck_progress ("###############  bad #################\n");
+	}
+	*/
+	pass0_correct_leaf (fs, bh);
+	
+	print_block (stdout, fs, bh, 3, -1, -1);
+
+	if (is_leaf_bad (bh)) {
+	    fsck_progress ("############### still bad #################\n");
+	}
+	brelse (bh);
+	reiserfs_free (fs);
+	exit(4);
+    }
+
+
+    total = reiserfs_bitmap_ones (fsck_disk_bitmap (fs));
+    fsck_progress ("\nPass 0 (%lu (of %lu) blocks will be read):\n",
+		   total, SB_BLOCK_COUNT (fs));
+
+
+    for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) {
+	if (!is_to_be_read (fs, i))
+	    continue;
+
+	print_how_far (&done, total, 1, fsck_quiet (fs));
+
+	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 ("pass0: reading block %lu failed\n", i);
+	    continue;
+	}
+
+	if (not_data_block (fs, i))
+	    reiserfs_panic ("not data block found");
+	
+	stats (fs)->analyzed ++;
+	what_node = who_is_this (bh->b_data, fs->s_blocksize);
+	if ( what_node != THE_LEAF ) {
+	    brelse (bh);
+	    continue;
+	}
+	pass0_correct_leaf (fs, bh);
+	brelse (bh);
+    }
+
+
+#if 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_to_be_read (fs, i + j))
+			continue;
+
+		    if (not_data_block (fs, i + j))
+			reiserfs_panic ("not data block found");
+
+		    stats (fs)->analyzed ++;
+
+		    data = bbh->b_data + j * fs->s_blocksize;
+		    what_node = who_is_this (data, fs->s_blocksize);
+		    if ( what_node != THE_LEAF ) {
+			continue;
+		    }
+
+		    /* the node looks like a leaf, but it still can be
+		       not perfect */
+		    bh = make_buffer (fs->s_dev, i + j, fs->s_blocksize, data);
+
+		    /*printf ("block %lu .. ", bh->b_blocknr);fflush(stdout);*/
+		    pass0_correct_leaf (fs, bh);
+		    /*printf ("ok\n");fflush(stdout);*/
+
+		    brelse (bh);
+		}
+
+		if (buffer_dirty (bbh))
+		    bwrite (bbh);
+		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
+
+
+    /* just in case */
+    mark_objectid_really_used (proper_id_map (fs), REISERFS_ROOT_OBJECTID);
+
+    fsck_progress ("\n");
+
+    if (fsck_save_leaf_bitmap (fs)) {
+	reiserfs_bitmap_save (stats (fs)->new_bitmap_file_name, leaves_bitmap);
+    }
+}
+
+
+/* this makes a map of blocks which can be allocated when fsck will continue: */
+static void find_allocable_blocks (reiserfs_filsys_t fs)
+{
+    int i;
+ 
+
+    fsck_progress ("Looking for allocable blocks .. ");
+    stats (fs)->all_blocks = SB_BLOCK_COUNT (fs);
+
+    /* find how many leaves are not pointed by any indirect items */
+    for (i = 0; i < SB_BLOCK_COUNT (fs); i ++) {
+	if (not_data_block (fs, i))
+	    continue;
+
+#if 0
+	if (!was_block_used (i)) {
+	    /* marked free in the on-disk bitmap - so it is allocable */
+	    make_allocable (i);
+	    stat_allocable_found (fs);
+	    continue;
+	}
+#endif
+
+	if (pass0_is_leaf (i)) {
+	    /* block looks like a reiserfs leaf */
+	    stats(fs)->leaves ++;
+	    if (pass0_is_good_unfm (i) || pass0_is_bad_unfm (i))
+		/* leaf to which one or more indirect items point to */
+		stats(fs)->pointed_leaves ++;
+	}
+
+	if (pass0_is_good_unfm (i) && pass0_is_bad_unfm (i))
+	    die ("find_allocable_blocks: bad and good unformatted");
+
+	if (pass0_is_good_unfm (i)) {
+	    /* blocks which were pointed only once */
+	    stats(fs)->pointed ++;
+	    stats(fs)->pointed_once ++;
+	    continue;
+	}
+	if (pass0_is_bad_unfm (i)) {
+	    /* blocks pointed more than once */
+	    stats(fs)->pointed ++;
+	    stats(fs)->pointed_more_than_once ++;
+	    continue;
+	}
+
+	/* blocks which marked used but are not leaves and are not
+	   pointed (internals in short) get into bitmap of allocable
+	   blocks */
+	if (!pass0_is_leaf (i)) {
+	    make_allocable (i);
+	    stats(fs)->allocable ++;
+	}
+    }
+    fsck_progress ("ok\n");
+}
+
+#if 0
+int are_there_used_leaves (unsigned long from, int count)
+{
+    int i;
+    int used;
+
+    used = 0;
+    for (i = 0; i < count; i ++) {
+	if ((SB_BLOCK_COUNT (fs) > from + i) &&
+	    pass0_is_leaf (from + i))
+	    used ++;
+    }
+    return used;
+}
+#endif
+
+int is_used_leaf (unsigned long block)
+{
+    return pass0_is_leaf (block);
+}
+
+
+int how_many_leaves_were_there (void)
+{
+    return stats (fs)->leaves;
+}
+
+/* these are used to correct uformatted node pointers */
+int is_bad_unformatted (unsigned long block)
+{
+    return pass0_is_bad_unfm (block);
+}
+
+
+/* this is for check only. With this we make sure that all pointers we
+   put into tree on pass 1 do not point to leaves (FIXME), do not
+   point to journal, bitmap, etc, do not point out of fs boundary and
+   are marked used in on-disk bitmap */
+int still_bad_unfm_ptr_1 (unsigned long block)
+{
+    if (!block)
+	return 0;
+    if (pass0_is_leaf (block))
+	return 1;
+    if (pass0_is_bad_unfm (block) && !is_bad_unfm_in_tree_once (block))
+	return 1;
+    if (not_data_block (fs, block))
+	return 1;
+    /*
+    if (!was_block_used (block))
+	return 1;
+    */
+    if (block >= stats (fs)->all_blocks)
+	return 1;
+    return 0;
+    
+}
+
+
+/* pointers to data block which get into tree are checked with this */
+int still_bad_unfm_ptr_2 (unsigned long block)
+{
+    if (!block)
+	return 0;
+    if (is_block_used (block))
+	return 1;
+    if (block >= stats (fs)->all_blocks)
+	return 1;
+    return 0;
+}
+
+
+/* these are used to allocate blocks for tree building */
+int are_there_allocable_blocks (int amout_needed)
+{
+    if (reiserfs_bitmap_zeros (fsck_allocable_bitmap (fs)) < amout_needed) {
+	int zeros = 0, i;
+	
+	fsck_progress ("Hmm, there are not enough allocable blocks, checking bitmap...");fflush (stdout);
+	for (i = 0; i < fsck_allocable_bitmap (fs)->bm_bit_size; i ++)
+	    if (!reiserfs_bitmap_test_bit (fsck_allocable_bitmap (fs), i))
+		zeros ++;
+	fsck_progress ("there are %d zeros, btw\n", zeros);
+	return 0;
+    }
+    return 1;
+}
+
+
+unsigned long alloc_block (void)
+{
+    unsigned long block = 0; /* FIXME: start point could be used */
+
+    if (reiserfs_bitmap_find_zero_bit (fsck_allocable_bitmap (fs), &block)) {
+	die ("alloc_block: allocable blocks counter is wrong");
+	return 0;
+    }
+    reiserfs_bitmap_set_bit (fsck_allocable_bitmap (fs), block);
+    return block;
+}
+
+
+void make_allocable (unsigned long block)
+{
+    reiserfs_bitmap_clear_bit (fsck_allocable_bitmap (fs), block);
+}
+
+
+unsigned long how_many_uninsertables_were_there (void)
+{
+    return stats (fs)->uninsertable_leaves;
+}
+
+
+unsigned long how_many_items_were_saved (void)
+{
+    return stats (fs)->saved_on_pass1;
+}
+
+
+static void choose_hash_function (reiserfs_filsys_t fs)
+{
+    unsigned long max;
+    int hash_code;
+    int i;
+
+    max = 0;
+    hash_code = func2code (0);
+
+    for (i = 0; i < stats (fs)->hash_amount; i ++) {
+	/* remember hash whihc got more hits */
+	if (stats (fs)->hash_hits [i] > max) {
+	    hash_code = i;
+	    max = stats (fs)->hash_hits [i];
+	}
+
+	if (stats (fs)->hash_hits [i])
+	    fsck_log ("%s got %lu hits\n", code2name (i),
+		      stats (fs)->hash_hits [i]);
+    }
+    if (max == 0) {
+	/* no names were found. take either super block value or
+           default */
+	reiserfs_hash (fs) = code2func (rs_hash (fs->s_rs));
+	if (!reiserfs_hash (fs))
+	    reiserfs_hash (fs) = code2func (DEFAULT_HASH);
+	return;
+    }
+
+    /* compare the most appropriate hash with the hash set in super block */
+    if (hash_code != rs_hash (fs->s_rs)) {
+	fsck_progress ("Selected hash (%s) does not match to one set in super block (%s).\n",
+		       code2name (hash_code), code2name (rs_hash (fs->s_rs)));
+	/*
+	if (!fsck_user_confirmed (fs, "Overwrite?(Yes)", "Yes", 1)) {
+	    fsck_progress ("Not confirmed\n");
+	    exit (4);
+	}
+	*/
+	set_hash (fs->s_rs, hash_code);
+    } else {
+	fsck_progress ("\t%s hash is selected\n", code2name (hash_code));
+    }
+
+    reiserfs_hash (fs) = code2func (hash_code);
+}
+
+
+int pass_0 (reiserfs_filsys_t fs)
+{
+    if (fsck_log_file (fs) != stderr)
+	/* this is just to separate warnings in the log file */
+	fsck_log ("####### Pass 0 #######\n");
+
+    if (fsck_mode (fs) == FSCK_ZERO_FILES) {
+	reiserfs_bitmap_fill (fsck_new_bitmap (fs));
+	fsck_progress ("Zeroing existing files - all blocks marked used\n");
+    }
+
+    make_aux_bitmaps (fs);
+
+    /* pass0 gathers statistics about hash hits */
+    hash_hits_init (fs);
+    
+    /* scan the partition */
+    go_through (fs);
+
+    /* find blocks which can be allocated */
+    find_allocable_blocks (fs);
+
+    if (fsck_mode (fs) == FSCK_ZERO_FILES) {
+	/* flush bitmaps and exit */
+	fsck_progress ("Zeroing existing files - zeroed %lu blocks\n", tmp_zeroed);
+	reiserfs_flush_bitmap (fsck_new_bitmap (fs), fs);
+	reiserfs_close (fs);
+	exit (0);
+    }
+
+
+    choose_hash_function (fs);
+
+    stage_report (0, fs);
+    return 0;
+}
+
+
+#if 0
+
+/* node looks like a leaf (block head and ih_item_length & ih_location
+   of item_head array are correct. This function recovers (tries to) node's key
+   table and directory items. */
+static void recover_leaf (reiserfs_filsys_t fs, struct buffer_head * bh)
+{
+    int i;
+    struct item_head * ih;
+
+    /* mark transparently corrupted items - bad */
+    ih = B_N_PITEM_HEAD (bh, 0);
+    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
+	if (type_unknown (&ih->ih_key) ||
+	    ih->ih_key.k_dir_id == 0 ||
+	    ih->ih_key.k_objectid) {
+	    mark_ih_bad (ih);
+	    continue;
+	}
+    }
+}
+
+#endif
+
diff --git a/fsck/pass1.c b/fsck/pass1.c
new file mode 100644
index 0000000..d6b29e9
--- /dev/null
+++ b/fsck/pass1.c
@@ -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
+*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fsck/pass2.c b/fsck/pass2.c
new file mode 100644
index 0000000..c598a9f
--- /dev/null
+++ b/fsck/pass2.c
@@ -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);
+
+}
diff --git a/fsck/pass4.c b/fsck/pass4.c
new file mode 100644
index 0000000..acbdffe
--- /dev/null
+++ b/fsck/pass4.c
@@ -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;
+}
diff --git a/fsck/reiserfsck.8 b/fsck/reiserfsck.8
new file mode 100644
index 0000000..bec3c9a
--- /dev/null
+++ b/fsck/reiserfsck.8
@@ -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)
diff --git a/fsck/segments.c b/fsck/segments.c
new file mode 100644
index 0000000..73a2173
--- /dev/null
+++ b/fsck/segments.c
@@ -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);
+}
+
+
+
+
diff --git a/fsck/semantic.c b/fsck/semantic.c
new file mode 100644
index 0000000..a541e3b
--- /dev/null
+++ b/fsck/semantic.c
@@ -0,0 +1,1346 @@
+/*
+ * Copyright 1996-1999 Hans Reiser
+ */
+#include "fsck.h"
+
+
+struct key root_dir_key = {REISERFS_ROOT_PARENT_OBJECTID,
+			   REISERFS_ROOT_OBJECTID, {{0, 0},}};
+struct key parent_root_dir_key = {0, REISERFS_ROOT_PARENT_OBJECTID, {{0, 0},}};
+struct key lost_found_dir_key = {REISERFS_ROOT_OBJECTID, 0, {{0, 0}, }};
+
+
+struct path_key
+{
+    struct short_key
+    {
+        __u32 k_dir_id;
+        __u32 k_objectid;
+    } key;
+    struct path_key * next, * prev;
+};
+
+struct path_key * head_key = NULL;
+struct path_key * tail_key = NULL;
+
+void check_path_key(struct key * key)
+{
+    struct path_key * cur = head_key;
+
+    while(cur != NULL)
+    {
+        if (!comp_short_keys(&cur->key, key))
+            die("\nsemantic check: loop found %k", key);
+        cur = cur->next;
+    }
+}
+
+void add_path_key(struct key * key)
+{
+    check_path_key(key);
+
+    if (tail_key == NULL)
+    {
+        tail_key = getmem(sizeof(struct path_key));
+        head_key = tail_key;
+        tail_key->prev = NULL;
+    }else{
+        tail_key->next = getmem(sizeof(struct path_key));
+        tail_key->next->prev = tail_key;
+        tail_key = tail_key->next;
+    }
+    copy_short_key (&tail_key->key, key);
+    tail_key->next = NULL;
+}
+
+void del_path_key()
+{
+    if (tail_key == NULL)
+        die("wrong path_key structure");
+
+    if (tail_key->prev == NULL)
+    {
+        freemem(tail_key);
+        tail_key = head_key = NULL;
+    }else{
+        tail_key = tail_key->prev;
+        freemem(tail_key->next);
+        tail_key->next = NULL;
+    }
+}
+
+/* semantic pass progress */
+static void print_name (char * dir_name, int len)
+{
+    int i;
+
+    if (fsck_quiet (fs))
+	return;
+    printf("/");
+    for (i = 0; i<len; i++, dir_name++)
+        printf ("%c", *dir_name);
+    fflush (stdout);
+}
+
+static void erase_name (int len)
+{
+    int i;
+
+    if (fsck_quiet (fs))
+	return;
+    for (i = 0; i<=len; i++)
+        printf("\b");
+    for (i = 0; i<=len; i++)
+        printf(" ");
+    for (i = 0; i<=len; i++)
+        printf("\b");
+    fflush (stdout);
+}
+
+
+void get_set_sd_field (int field, struct item_head * ih, void * sd,
+		       void * value, int set)
+{
+    if (ih_key_format (ih) == KEY_FORMAT_1) {
+	struct stat_data_v1 * sd_v1 = sd;
+
+	switch (field) {
+	case GET_SD_MODE:
+	    if (set)
+		sd_v1->sd_mode = cpu_to_le16 (*(__u16 *)value);
+	    else
+		*(__u16 *)value = le16_to_cpu (sd_v1->sd_mode);
+	    break;
+
+	case GET_SD_SIZE:
+	    /* value must point to 64 bit int */
+	    if (set)
+		sd_v1->sd_size = cpu_to_le32 (*(__u64 *)value);
+	    else
+		*(__u64 *)value = le32_to_cpu (sd_v1->sd_size);
+	    break;
+
+	case GET_SD_BLOCKS:
+	    if (set)
+		sd_v1->u.sd_blocks = cpu_to_le32 (*(__u32 *)value);
+	    else
+		*(__u32 *)value = le32_to_cpu (sd_v1->u.sd_blocks);
+	    break;
+
+	case GET_SD_NLINK:
+	    /* value must point to 32 bit int */
+	    if (set)
+		sd_v1->sd_nlink = cpu_to_le16 (*(__u32 *)value);
+	    else
+		*(__u32 *)value = le16_to_cpu (sd_v1->sd_nlink);
+	    break;
+
+	case GET_SD_FIRST_DIRECT_BYTE:
+	    if (set)
+		sd_v1->sd_first_direct_byte = cpu_to_le32 (*(__u32 *)value);
+	    else
+		*(__u32 *)value = le32_to_cpu (sd_v1->sd_first_direct_byte);
+	    break;
+	    
+	default:
+	    reiserfs_panic ("get_set_sd_field: unknown field of old stat data");
+	}
+    } else {
+	struct stat_data * sd_v2 = sd;
+
+	switch (field) {
+	case GET_SD_MODE:
+	    if (set)
+		sd_v2->sd_mode = cpu_to_le16 (*(__u16 *)value);
+	    else
+		*(__u16 *)value = le16_to_cpu (sd_v2->sd_mode);
+	    break;
+
+	case GET_SD_SIZE:
+	    if (set)
+		sd_v2->sd_size = cpu_to_le64 (*(__u64 *)value);
+	    else
+		*(__u64 *)value = le64_to_cpu (sd_v2->sd_size);
+	    break;
+
+	case GET_SD_BLOCKS:
+	    if (set)
+		sd_v2->sd_blocks = cpu_to_le32 (*(__u32 *)value);
+	    else
+		*(__u32 *)value = le32_to_cpu (sd_v2->sd_blocks);
+	    break;
+
+	case GET_SD_NLINK:
+	    if (set)
+		sd_v2->sd_nlink = cpu_to_le32 (*(__u32 *)value);
+	    else
+		*(__u32 *)value = le32_to_cpu (sd_v2->sd_nlink);
+	    break;
+
+	case GET_SD_FIRST_DIRECT_BYTE:
+	default:
+	    reiserfs_panic ("get_set_sd_field: unknown field of new stat data");
+	}
+    }
+}
+
+
+
+/* *size is "real" file size, sd_size - size from stat data */
+static int wrong_st_size (struct key * key, loff_t max_file_size, int blocksize,
+			  __u64 * size, __u64 sd_size, int is_dir)
+{
+    if (sd_size <= max_file_size) {
+	if (sd_size == *size)
+	    return 0;
+
+	if (is_dir) {
+	    /* directory size must match to the sum of length of its entries */
+	    fsck_log ("dir %K has wrong sd_size %Ld, has to be %Ld\n",
+		      key, sd_size, *size);
+	    return 1;
+	}
+
+	if (sd_size > *size) {
+	    /* size in stat data can be bigger than size calculated by items */
+	    if (fsck_fix_non_critical (fs)) {
+		/* but it -o is given - fix that */
+		fsck_log ("file %K has too big file size sd_size %Ld - fixed to %Ld\n",
+			  key, sd_size, *size);
+		stats(fs)->fixed_sizes ++;
+		return 1;
+	    }
+	    *size = sd_size;
+	    return 0;
+	}
+	
+	if (!(*size % blocksize)) {
+	    /* last item is indirect */
+	    if (((sd_size & ~(blocksize - 1)) == (*size - blocksize)) && sd_size % blocksize) {
+		/* size in stat data is correct */
+		*size = sd_size;
+		return 0;
+	    }
+	} else {
+	    /* last item is a direct one */
+	    if (!(*size % 8)) {
+		if (((sd_size & ~7) == (*size - 8)) && sd_size % 8) {
+		    /* size in stat data is correct */
+		    *size = sd_size;
+		    return 0;
+		}
+	    }
+	}
+    }
+
+    fsck_log ("file %K has wrong sd_size %Ld, has to be %Ld\n",
+	      key, sd_size, *size);
+    stats(fs)->fixed_sizes ++;
+    return 1;
+}
+
+
+/* sd_blocks is 32 bit only */
+static int wrong_st_blocks (struct key * key, __u32 blocks, __u32 sd_blocks, int is_dir)
+{
+    if (blocks == sd_blocks)
+	return 0;
+
+    if (!is_dir || blocks != _ROUND_UP (sd_blocks, fs->s_blocksize / 512)) {
+	/*fsck_log ("%s %K has wrong sd_blocks %d, has to be %d\n",
+	  is_dir ? "dir" : "file", key, sd_blocks, blocks);*/
+	return 1;
+    } else
+	return 0;
+}
+
+
+/* only regular files and symlinks may have items but stat
+   data. Symlink shold have body */
+static int wrong_mode (struct key * key, mode_t * mode, __u64 real_size)
+{
+    if (!fsck_fix_non_critical (fs))
+	return 0;
+
+    if (ftypelet (*mode) != '?') {
+	/* mode looks reasonable */
+	if (S_ISREG (*mode) || S_ISLNK (*mode))
+	    return 0;
+	
+	/* device, pipe, socket have no items */
+	if (!real_size)
+	    return 0 ;
+    }
+    /* there are items, so change file mode to regular file. Otherwise
+       - file bodies do not get deleted */
+    fsck_log ("file %K (%M) has body, mode fixed to %M\n",
+	      key, *mode, (S_IFREG | 0600));
+    *mode = (S_IFREG | 0600);
+    return 1;
+}
+
+
+/* key is a key of last file item */
+static int wrong_first_direct_byte (struct key * key, int blocksize, 
+				    __u32 * first_direct_byte,
+				    __u32 sd_first_direct_byte, __u32 size)
+{
+    if (!size || is_indirect_key (key)) {
+	/* there is no direct item */
+	*first_direct_byte = NO_BYTES_IN_DIRECT_ITEM;
+	if (sd_first_direct_byte != NO_BYTES_IN_DIRECT_ITEM) {
+	    return 1;
+	}
+	return 0;
+    }
+
+    /* there is direct item */
+    *first_direct_byte = (get_offset (key) & ~(blocksize - 1)) + 1;
+    if (*first_direct_byte != sd_first_direct_byte) {
+	fsck_log ("file %k has wrong first direct byte %d, has to be %d\n",
+		  key, sd_first_direct_byte, *first_direct_byte);
+	return 1;
+    }
+    return 0;
+}
+
+
+/* return values for check_regular_file and check_semantic_tree */
+#define OK 0
+#define STAT_DATA_NOT_FOUND -1
+#define DIRECTORY_HAS_NO_ITEMS -2
+#define RELOCATED -3
+
+
+
+/* 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_dir (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 of a directory */
+	    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_direct_ih (path_ih) || is_indirect_ih (path_ih)) {
+	    /* item of not a directory found. Leave it in the
+               tree. FIXME: should not happen */
+	    key = path_ih->ih_key;
+	    set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1);
+	    pathrelse (&path);
+	    continue;
+	}
+
+	/* directory stat data ro directory item */
+	si = save_and_delete_file_item (si, &path);
+    }
+
+
+    if (!si) {
+	fsck_progress ("relocate_dir: no directory %K items found\n", &key);
+	return;
+    }
+
+
+    /* get new objectid for relocation or get objectid with which file
+       was relocated already */
+    new_objectid = objectid_for_relocation (&ih->ih_key);
+    ih->ih_key.k_objectid = new_objectid;
+
+    /* put all items removed back into tree */
+    while (si) {
+	fsck_log ("relocate_dir: move %H to ", &si->si_ih);
+	si->si_ih.ih_key.k_objectid = new_objectid;
+	fsck_log ("%H\n", &si->si_ih);
+	if (get_offset (&(si->si_ih.ih_key)) == DOT_OFFSET) {
+	    /* fix "." entry to point to a directtory properly */
+	    struct reiserfs_de_head * deh;
+
+	    deh = (struct reiserfs_de_head *)si->si_dnm_data;
+	    deh->deh_objectid = new_objectid;
+	}
+	insert_item_separately (&(si->si_ih), si->si_dnm_data, 1/*was in tree*/);
+	si = remove_saved_item (si);
+    }
+}
+
+
+
+/* path is path to stat data. If file will be relocated - new_ih will contain
+   a key file was relocated with */
+int rebuild_check_regular_file (struct path * path, void * sd,
+				struct item_head * new_ih)
+{
+    int is_new_file;
+    struct key key, sd_key;
+    mode_t mode;
+    __u32 nlink;
+    __u64 real_size, saved_size;
+    __u32 blocks, saved_blocks;	/* proper values and value in stat data */
+    __u32 first_direct_byte, saved_first_direct_byte;
+
+    struct buffer_head * bh;
+    struct item_head * ih;
+    int fix_sd;
+    int symlnk = 0;
+    int retval;
+
+    retval = OK;
+
+    /* stat data of a file */
+    ih = get_ih (path);
+    bh = get_bh (path);
+
+    if (new_ih) {
+	/* this objectid is used already */
+	*new_ih = *ih;
+	pathrelse (path);
+	relocate_file (new_ih, 1);
+	stats(fs)->oid_sharing_files_relocated ++;
+	retval = RELOCATED;
+	if (usearch_by_key (fs, &(new_ih->ih_key), path) == ITEM_NOT_FOUND)
+	    reiserfs_panic ("rebuild_check_regular_file: could not find stat data of relocated file");
+	/* stat data is marked unreachable again due to relocation, fix that */
+	ih = get_ih (path);
+	bh = get_bh (path);
+	mark_item_reachable (ih, bh);
+	sd = get_item (path);
+    }
+
+    /* check and set nlink first */
+    get_sd_nlink (ih, sd, &nlink);
+    nlink ++;
+    set_sd_nlink (ih, sd, &nlink);
+    mark_buffer_dirty (bh);
+
+    if (nlink > 1)
+	return OK;
+
+    /* firts name of a file found */
+    if (ih_item_len (ih) == SD_SIZE)
+	is_new_file = 1;
+    else
+	is_new_file = 0;
+
+    get_sd_mode (ih, sd, &mode);
+    get_sd_size (ih, sd, &saved_size);
+    get_sd_blocks (ih, sd, &saved_blocks);
+    if (!is_new_file)
+	get_sd_first_direct_byte (ih, sd, &saved_first_direct_byte);
+    
+    /* we met this file first time */
+    if (S_ISREG (mode)) {
+	stats(fs)->regular_files ++;
+    } else if (S_ISLNK (mode)) {
+	symlnk = 1;
+	stats(fs)->symlinks ++;
+    } else {
+	stats(fs)->others ++;
+    }
+
+
+    key = ih->ih_key; /*??*/
+    sd_key = key; /*??*/
+    pathrelse (path);
+    
+    if (are_file_items_correct (&key, is_new_file ? KEY_FORMAT_2 : KEY_FORMAT_1, 
+				&real_size, &blocks, 1/*mark items reachable*/,
+				symlnk, saved_size) != 1) {
+	/* unpassed items will be deleted in pass 4 as they left unaccessed */
+	stats(fs)->broken_files ++;
+    }
+    
+    fix_sd = 0;
+    
+    fix_sd += wrong_mode (&sd_key, &mode, real_size);
+    if (!is_new_file)
+	fix_sd += wrong_first_direct_byte (&key, fs->s_blocksize,
+					   &first_direct_byte, saved_first_direct_byte, real_size);
+    fix_sd += wrong_st_size (&sd_key, is_new_file ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1, 
+			     fs->s_blocksize, &real_size, saved_size, 0/*not dir*/);
+    if (!is_new_file && (S_ISREG (mode) || S_ISLNK (mode)))
+	/* old stat data shares sd_block and sd_dev. We do not want to wipe
+	   put sd_dev for device files */
+	fix_sd += wrong_st_blocks (&sd_key, blocks, saved_blocks, 0/*not dir*/);
+    
+    if (fix_sd) {
+	/* find stat data and correct it */
+	if (usearch_by_key (fs, &sd_key, path) != ITEM_FOUND)
+	    die ("check_regular_file: stat data not found");
+	
+	bh = get_bh (path);
+	ih = get_ih (path);
+	sd = get_item (path);
+	set_sd_size (ih, sd, &real_size);
+	set_sd_blocks (ih, sd, &blocks);
+	set_sd_mode (ih, sd, &mode);
+	if (!is_new_file)
+	    set_sd_first_direct_byte (ih, sd, &first_direct_byte);
+	mark_buffer_dirty (bh);
+    }
+
+    return retval;
+}
+
+
+static int is_rootdir_key (struct key * key)
+{
+    if (comp_keys (key, &root_dir_key))
+	return 0;
+    return 1;
+}
+
+
+/* returns buffer, containing found directory item.*/
+static char * get_next_directory_item (struct key * key, /* on return this
+                                                            will contain key
+                                                            of next item in
+                                                            the tree */
+				       struct key * parent,
+				       struct item_head * ih,/*not in tree*/
+				       int * pos_in_item)
+{
+    INITIALIZE_PATH (path);
+    char * dir_item;
+    struct key * rdkey;
+    struct buffer_head * bh;
+    struct reiserfs_de_head * deh;
+    int i;
+    int retval;
+
+
+    if ((retval = usearch_by_entry_key (fs, key, &path)) != POSITION_FOUND) {
+      die ("get_next_directory_item: %k is not found", key);
+    }
+#if 0
+	if (get_offset (key) != DOT_OFFSET)
+	    /* we always search for existing key, but "." */
+	    die ("get_next_directory_item: %k is not found", key);
+	
+	pathrelse (&path);
+
+	if (fsck_mode (fs) == FSCK_CHECK) {
+	    fsck_log ("get_next_directory_item: directory has no \".\" entry %k\n",
+		      key);
+	    pathrelse (&path);
+	    return 0;
+	}
+
+ 	fsck_log ("making \".\" and/or \"..\" for %K\n", key);
+	reiserfs_add_entry (fs, key, ".", key, 1 << IH_Unreachable);
+	reiserfs_add_entry (fs, key, "..", parent, 1 << IH_Unreachable);
+
+
+	/* we have fixed a directory, search its first item again */
+	usearch_by_entry_key (fs, key, &path);
+    }
+#endif
+
+    /* leaf containing directory item */
+    bh = PATH_PLAST_BUFFER (&path);
+    *pos_in_item = path.pos_in_item;
+    *ih = *get_ih (&path);
+    deh = B_I_DEH (bh, ih);
+
+    /* make sure, that ".." exists as well */
+    if (get_offset (key) == DOT_OFFSET) {
+	if (ih_entry_count (ih) < 2) {
+	    fsck_progress ("1. Does this ever happen?\n");
+	    pathrelse (&path);
+	    return 0;
+	}
+	if (name_length (ih, deh + 1, 1) != 2 ||
+	    strncmp (name_in_entry (deh + 1, 1), "..", 2)) {
+	    fsck_progress ("2. Does this ever happen?\n");
+	    fsck_log ("get_next_directory_item: \"..\" not found in %H\n", ih);
+	    pathrelse (&path);
+	    return 0;
+	}
+    }
+
+    /* mark hidden entries as visible, set "." and ".." correctly */
+    deh += *pos_in_item; 
+    for (i = *pos_in_item; i < ih_entry_count (ih); i ++, deh ++) {
+	int namelen;
+	char * name;
+
+	name = name_in_entry (deh, i);
+	namelen = name_length (ih, deh, i);
+	if (de_hidden (deh))
+	    reiserfs_panic ("get_next_directory_item: item %k: hidden entry %d \'%.*s\'\n",
+			    key, i, namelen, name);
+
+	if (deh->deh_offset == DOT_OFFSET) {
+	    if (not_of_one_file (&(deh->deh_dir_id), key))
+		//deh->deh_objectid != REISERFS_ROOT_PARENT_OBJECTID)/*????*/ {
+		reiserfs_panic ("get_next_directory_item: wrong \".\" found %k\n", key);
+	}
+
+	if (deh->deh_offset == DOT_DOT_OFFSET) {
+	    /* set ".." so that it points to the correct parent directory */
+	    if (comp_short_keys (&(deh->deh_dir_id), parent) &&
+		deh->deh_objectid != REISERFS_ROOT_PARENT_OBJECTID)/*???*/ {
+		/* FIXME */
+		fsck_log ("get_next_directory_item: %k: \"..\" pointes to [%K], "
+			      "should point to [%K]",
+			      key, (struct key *)(&(deh->deh_dir_id)), parent);
+		if (fsck_mode (fs) == FSCK_REBUILD) {
+		    deh->deh_dir_id = parent->k_dir_id;
+		    deh->deh_objectid = parent->k_objectid;
+		    mark_buffer_dirty (bh);
+		    fsck_log (" - fixed\n");
+		} else
+		    fsck_log ("\n");
+		
+	    }
+	}
+    }
+
+    /* copy directory item to the temporary buffer */
+    dir_item = getmem (ih_item_len (ih)); 
+    memcpy (dir_item, B_I_PITEM (bh, ih), ih_item_len (ih));
+
+
+    /* next item key */
+    if (PATH_LAST_POSITION (&path) == (B_NR_ITEMS (bh) - 1) &&
+	(rdkey = uget_rkey (&path)))
+	copy_key (key, rdkey);
+    else {
+	key->k_dir_id = 0;
+	key->k_objectid = 0;
+    }
+
+    if (fsck_mode (fs) != FSCK_CHECK)
+        mark_item_reachable (get_ih (&path), bh);
+    pathrelse (&path);
+
+    return dir_item;
+}
+
+
+// get key of an object pointed by direntry and the key of the entry itself
+static void get_object_key (struct reiserfs_de_head * deh, struct key * key, 
+			    struct key * entry_key, struct item_head * ih)
+{
+    key->k_dir_id = deh->deh_dir_id;
+    key->k_objectid = deh->deh_objectid;
+    key->u.k_offset_v1.k_offset = SD_OFFSET;
+    key->u.k_offset_v1.k_uniqueness = V1_SD_UNIQUENESS;
+
+    entry_key->k_dir_id = ih->ih_key.k_dir_id;
+    entry_key->k_objectid = ih->ih_key.k_objectid;
+    entry_key->u.k_offset_v1.k_offset = deh->deh_offset;
+    entry_key->u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS;
+}
+
+
+/* check recursively the semantic tree. Returns OK if entry points to good
+   object, STAT_DATA_NOT_FOUND if stat data was not found or RELOCATED when
+   file was relocated because its objectid was already marked as used by
+   another file */
+int rebuild_semantic_pass (struct key * key, struct key * parent, int dot_dot,
+			   struct item_head * new_ih)
+{
+    struct path path;
+    void * sd;
+    int is_new_dir;
+    __u32 nlink;
+    struct buffer_head * bh;
+    struct item_head * ih;
+    int retval, retval1;
+    char * dir_item;
+    int pos_in_item;
+    struct item_head tmp_ih;
+    struct key item_key, entry_key, object_key;
+    __u64 dir_size;
+    __u32 blocks;
+    __u64 saved_size;
+    __u32 saved_blocks;
+    int fix_sd;
+    int relocate;
+    
+
+    retval = OK;
+
+ start_again: /* when directory was relocated */
+
+    if (!KEY_IS_STAT_DATA_KEY (key))
+	reiserfs_panic ("rebuild_semantic_pass: key %k must be key of a stat data",
+			key);
+
+    /* look for stat data of an object */
+    if (usearch_by_key (fs, key, &path) == ITEM_NOT_FOUND) {
+	pathrelse (&path);
+	if (is_rootdir_key (key))
+	    /* root directory has to exist at this point */
+	    reiserfs_panic ("rebuild_semantic_pass: root directory not found");
+
+	return STAT_DATA_NOT_FOUND;
+    }
+
+
+    /* stat data has been found */
+    bh = get_bh (&path);
+    ih = get_ih (&path);
+    sd = get_item(&path);
+
+    /* */
+    get_sd_nlink (ih, sd, &nlink);
+
+    relocate = 0;
+    if (!nlink) {
+	/* we reached the stat data for the first time */
+	if (is_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid, &pos_in_item)) {
+	    /* calculate number of found files/dirs who are using objectid
+	       which is used by another file */
+	    stats(fs)->oid_sharing ++;
+	    if (fsck_fix_non_critical (fs))
+		/* this works for files only */
+		relocate = 1;
+	} else
+	    mark_objectid_really_used (semantic_id_map (fs), ih->ih_key.k_objectid);
+
+	mark_item_reachable (ih, bh);
+    }
+
+
+    if (not_a_directory (sd)) {
+	retval = rebuild_check_regular_file (&path, sd, relocate ? new_ih : 0);
+	pathrelse (&path);
+	return retval;
+    }
+
+    if (relocate) {
+	if (!new_ih)
+	    reiserfs_panic ("rebuild_semantic_pass: can not relocate %K",
+			    &ih->ih_key);
+	*new_ih = *ih;
+	pathrelse (&path);
+	stats(fs)->oid_sharing_dirs_relocated ++;
+	relocate_dir (new_ih, 1);
+	*key = new_ih->ih_key;
+	retval = RELOCATED;
+	goto start_again;
+    }
+
+    /* stat data of a directory found */
+    if (nlink) {
+	/* we saw this directory already */
+	if (!dot_dot) {
+	    /* this name is not ".."  - and hard links are not allowed on
+               directories */
+	    pathrelse (&path);
+	    return STAT_DATA_NOT_FOUND;
+	} else {
+	    /* ".." found */
+	    nlink ++;
+	    set_sd_nlink (ih, sd, &nlink);
+	    mark_buffer_dirty (bh);
+	    pathrelse (&path);
+	    return OK;
+	}
+    }
+
+
+    /* we see the directory first time */
+    stats(fs)->directories ++;
+    nlink = 2;
+    if (key->k_objectid == REISERFS_ROOT_OBJECTID)
+	nlink ++;
+    set_sd_nlink (ih, sd, &nlink);
+    mark_buffer_dirty (bh);
+    
+    if (ih_item_len (ih) == SD_SIZE)
+	is_new_dir = 1;
+    else
+	is_new_dir = 0;
+
+    /* release path pointing to stat data */
+    pathrelse (&path);
+
+
+    /* make sure that "." and ".." exist */
+    reiserfs_add_entry (fs, key, ".", key, 1 << IH_Unreachable);
+    reiserfs_add_entry (fs, key, "..", parent, 1 << IH_Unreachable);
+
+    item_key = *key;
+    item_key.u.k_offset_v1.k_offset = DOT_OFFSET;
+    item_key.u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS;
+
+    /* save stat data's size and st_blocks */
+    get_sd_size (ih, sd, &saved_size);
+    get_sd_blocks (ih, sd, &saved_blocks);	
+    
+    dir_size = 0;
+    while ((dir_item = get_next_directory_item (&item_key, parent, &tmp_ih, &pos_in_item)) != 0) {
+	/* dir_item is copy of the item in separately allocated memory,
+	   item_key is a key of next item in the tree */
+	int i;
+	struct reiserfs_de_head * deh = (struct reiserfs_de_head *)dir_item + pos_in_item;
+	
+	
+	for (i = pos_in_item; i < ih_entry_count (&tmp_ih); i ++, deh ++) {
+	    char * name;
+	    int namelen;
+	    struct item_head relocated_ih;
+	    
+	    name = name_in_entry (deh, i);
+	    namelen = name_length (&tmp_ih, deh, i);
+	    
+	    if (is_dot (name, namelen)) {
+		dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i);
+		continue;
+	    }
+
+	    print_name (name, namelen);
+	    
+	    if (!is_properly_hashed (fs, name, namelen, deh_offset (deh)))
+		reiserfs_panic ("rebuild_semantic_pass: name has to be hashed properly");
+	    
+	    get_object_key (deh, &object_key, &entry_key, &tmp_ih);
+	    
+	    retval1 = rebuild_semantic_pass (&object_key, key, is_dot_dot (name, namelen), &relocated_ih);
+    
+	    erase_name (namelen);
+	    
+	    switch (retval1) {
+	    case OK:
+		dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i);
+		break;
+
+	    case STAT_DATA_NOT_FOUND:
+	    case DIRECTORY_HAS_NO_ITEMS:
+		if (get_offset (&entry_key) == DOT_DOT_OFFSET && object_key.k_objectid == REISERFS_ROOT_PARENT_OBJECTID) {
+		    /* ".." of root directory can not be found */
+		    dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i);
+		    continue;
+		}
+		fsck_log ("name \"%.*s\" in directory %K points to nowhere %K - removed\n",
+			  namelen, name, &tmp_ih.ih_key, (struct key *)&(deh->deh_dir_id));
+		reiserfs_remove_entry (fs, &entry_key);
+		stats(fs)->deleted_entries ++;
+		break;
+		
+	    case RELOCATED:
+		/* file was relocated, update key in corresponding directory entry */
+		if (_search_by_entry_key (fs, &entry_key, &path) != POSITION_FOUND) {
+		    fsck_progress ("could not find name of relocated file\n");
+		} else {
+		    /* update key dir entry points to */
+		    struct reiserfs_de_head * tmp_deh;
+		    
+		    tmp_deh = B_I_DEH (get_bh (&path), get_ih (&path)) + path.pos_in_item;
+		    fsck_log ("name \"%.*s\" of dir %K pointing to %K updated to point to ",
+			      namelen, name, &tmp_ih.ih_key, &tmp_deh->deh_dir_id);
+		    tmp_deh->deh_dir_id = cpu_to_le32 (relocated_ih.ih_key.k_dir_id);
+		    tmp_deh->deh_objectid = cpu_to_le32 (relocated_ih.ih_key.k_objectid);
+		    fsck_log ("%K\n",  &tmp_deh->deh_dir_id);
+		    mark_buffer_dirty (get_bh (&path));
+		}
+		dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i);
+		pathrelse (&path);
+		break;
+	    }
+	} /* for */
+	
+	freemem (dir_item);
+	
+	if (not_of_one_file (&item_key, key))
+	    /* next key is not of this directory */
+	    break;
+	
+    } /* while (dir_item) */
+    
+    
+    if (dir_size == 0)
+	/* FIXME: is it possible? */
+	return DIRECTORY_HAS_NO_ITEMS;
+    
+    /* calc correct value of sd_blocks field of stat data */
+    blocks = dir_size2st_blocks (fs->s_blocksize, dir_size);
+    
+    fix_sd = 0;
+    fix_sd += wrong_st_blocks (key, blocks, saved_blocks, 1/*dir*/);
+    fix_sd += wrong_st_size (key, is_new_dir ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1,
+			     fs->s_blocksize, &dir_size, saved_size, 1/*dir*/);
+    
+    if (fix_sd) {
+	/* we have to fix either sd_size or sd_blocks, so look for stat data again */
+	if (usearch_by_key (fs, key, &path) != ITEM_FOUND)
+	    die ("rebuild_semantic_pass: stat data not found");
+	    
+	bh = get_bh (&path);
+	ih = get_ih (&path);
+	sd = get_item (&path);
+	
+	set_sd_size (ih, sd, &dir_size);
+	set_sd_blocks (ih, sd, &blocks);
+	mark_buffer_dirty (bh);
+	pathrelse (&path);
+    }
+    
+    return retval;
+}
+
+
+int is_dot (char * name, int namelen)
+{
+    return (namelen == 1 && name[0] == '.') ? 1 : 0;
+}
+
+
+int is_dot_dot (char * name, int namelen)
+{
+    return (namelen == 2 && name[0] == '.' && name[1] == '.') ? 1 : 0;
+}
+
+
+int not_a_directory (void * sd)
+{
+    /* mode is at the same place and of the same size in both stat
+       datas (v1 and v2) */
+    struct stat_data_v1 * sd_v1 = sd;
+
+    return !(S_ISDIR (le16_to_cpu (sd_v1->sd_mode)));
+}
+
+
+
+
+void zero_nlink (struct item_head * ih, void * sd)
+{
+    int zero = 0;
+
+    if (ih_item_len (ih) == SD_V1_SIZE && ih_key_format (ih) != KEY_FORMAT_1) {
+	fsck_log ("zero_nlink: %H had wrong keys format %d, fixed to %d",
+		  ih, ih_key_format (ih), KEY_FORMAT_1);
+	set_key_format (ih, KEY_FORMAT_1);
+    }
+    if (ih_item_len (ih) == SD_SIZE && ih_key_format (ih) != KEY_FORMAT_2) {
+	fsck_log ("zero_nlink: %H had wrong keys format %d, fixed to %d",
+		  ih, ih_key_format (ih), KEY_FORMAT_2);
+	set_key_format (ih, KEY_FORMAT_2);
+    }
+
+    set_sd_nlink (ih, sd, &zero);
+}
+
+
+/* inserts new or old stat data of a directory (unreachable, nlinks == 0) */
+void create_dir_sd (reiserfs_filsys_t fs, 
+		    struct path * path, struct key * key)
+{
+    struct item_head ih;
+    struct stat_data sd;
+    int key_format;
+
+    if (SB_VERSION(fs) == REISERFS_VERSION_2)
+	key_format = KEY_FORMAT_2;
+    else
+	key_format = KEY_FORMAT_1;
+
+    make_dir_stat_data (fs->s_blocksize, key_format, key->k_dir_id,
+			key->k_objectid, &ih, &sd);
+
+    /* set nlink count to 0 and make the item unreachable */
+    zero_nlink (&ih, &sd);
+    mark_item_unreachable (&ih);
+
+    reiserfs_insert_item (fs, path, &ih, &sd);
+}
+
+
+static void make_sure_root_dir_exists (reiserfs_filsys_t fs)
+{
+    INITIALIZE_PATH (path);
+
+    /* is there root's stat data */
+    if (usearch_by_key (fs, &root_dir_key, &path) == ITEM_NOT_FOUND) {	
+	create_dir_sd (fs, &path, &root_dir_key);
+	mark_objectid_really_used (proper_id_map (fs), REISERFS_ROOT_OBJECTID);
+    } else
+	pathrelse (&path);
+
+    /* add "." and ".." if any of them do not exist. Last two
+       parameters say: 0 - entry is not added on lost_found pass and 1
+       - mark item unreachable */
+    reiserfs_add_entry (fs, &root_dir_key, ".", &root_dir_key, 
+			1 << IH_Unreachable);
+    reiserfs_add_entry (fs, &root_dir_key, "..", &parent_root_dir_key, 
+			1 << IH_Unreachable);
+}
+
+
+/* mkreiserfs should have created this */
+static void make_sure_lost_found_exists (reiserfs_filsys_t fs)
+{
+    int retval;
+    INITIALIZE_PATH (path);
+    int gen_counter;
+
+    /* look for "lost+found" in the root directory */
+    lost_found_dir_key.k_objectid = reiserfs_find_entry (fs, &root_dir_key,
+							 "lost+found", &gen_counter);
+    if (!lost_found_dir_key.k_objectid) {
+	lost_found_dir_key.k_objectid = get_unused_objectid (fs);
+	if (!lost_found_dir_key.k_objectid) {
+	    fsck_progress ("make_sure_lost_found_exists: could not get objectid"
+			   " for \"/lost+found\", will not link lost files\n");
+	    return;
+	}
+    }
+
+    /* look for stat data of "lost+found" */
+    retval = usearch_by_key (fs, &lost_found_dir_key, &path);
+    if (retval == ITEM_NOT_FOUND)
+	create_dir_sd (fs, &path, &lost_found_dir_key);
+    else {
+	if (not_a_directory (get_item (&path))) {
+	    fsck_progress ("make_sure_lost_found_exists: \"/lost+found\" is "
+			   "not a directory, will not link lost files\n");
+	    lost_found_dir_key.k_objectid = 0;
+	    pathrelse (&path);
+	    return;
+	}
+	pathrelse (&path);
+    }
+
+    /* add "." and ".." if any of them do not exist */
+    reiserfs_add_entry (fs, &lost_found_dir_key, ".", &lost_found_dir_key,
+			1 << IH_Unreachable);
+    reiserfs_add_entry (fs, &lost_found_dir_key, "..", &root_dir_key, 
+			1 << IH_Unreachable);
+
+    reiserfs_add_entry (fs, &root_dir_key, "lost+found", &lost_found_dir_key, 
+			1 << IH_Unreachable);
+
+    return;
+}
+
+
+/* this is part of rebuild tree */
+void pass_3_semantic (void)
+{
+    fsck_progress ("Pass 3 (semantic):\n");
+
+    /* when warnings go not to stderr - separate then in the log */
+    if (fsck_log_file (fs) != stderr)
+	fsck_log ("####### Pass 3 #########\n");
+    
+    if (!fs->s_hash_function)
+	reiserfs_panic ("Hash function should be selected already");
+
+    make_sure_root_dir_exists (fs);
+    make_sure_lost_found_exists (fs);
+
+    /* link all relocated files into root directory */
+    link_relocated_files ();
+
+    rebuild_semantic_pass (&root_dir_key, &parent_root_dir_key, 0/*!dot_dot*/, 0/*reloc_ih*/);
+    stage_report (3, fs);
+
+}
+
+
+/* path is path to stat data. If file will be relocated - new_ih will contain
+   a key file was relocated with */
+static int check_check_regular_file (struct path * path, void * sd)
+{
+    int is_new_file;
+    struct key key, sd_key;
+    mode_t mode;
+    __u32 nlink;
+    __u64 real_size, saved_size;
+    __u32 blocks, saved_blocks;	/* proper values and value in stat data */
+    __u32 first_direct_byte, saved_first_direct_byte;
+
+    struct buffer_head * bh;
+    struct item_head * ih;
+    int fix_sd;
+    int symlnk = 0;
+
+
+    ih = get_ih (path);
+    bh = get_bh (path);
+
+    if (ih_item_len (ih) == SD_SIZE)
+	is_new_file = 1;
+    else
+	is_new_file = 0;
+
+
+    get_sd_nlink (ih, sd, &nlink);
+    get_sd_mode (ih, sd, &mode);
+    get_sd_size (ih, sd, &saved_size);
+    get_sd_blocks (ih, sd, &saved_blocks);
+    if (!is_new_file)
+	get_sd_first_direct_byte (ih, sd, &saved_first_direct_byte);
+
+    if (S_ISREG (mode)) {
+	/* fixme: this could be wrong due to hard links */
+	stats(fs)->regular_files ++;
+    } else if (S_ISLNK (mode)) {
+	symlnk = 1;
+	stats(fs)->symlinks ++;
+    } else {
+	stats(fs)->others ++;
+    }
+
+
+    key = ih->ih_key; /*??*/
+    sd_key = key; /*??*/
+    pathrelse (path);
+
+    if (are_file_items_correct (&key, is_new_file ? KEY_FORMAT_2 : KEY_FORMAT_1, 
+				&real_size, &blocks, 0/*do not mark items reachable*/,
+				symlnk, saved_size) != 1) {
+	fsck_log ("check_regular_file: broken file found %K\n", key);
+    } else {
+	fix_sd = 0;
+    
+	fix_sd += wrong_mode (&sd_key, &mode, real_size);
+	if (!is_new_file)
+	    fix_sd += wrong_first_direct_byte (&key, fs->s_blocksize,
+					       &first_direct_byte, saved_first_direct_byte, real_size);
+	fix_sd += wrong_st_size (&sd_key, is_new_file ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1, 
+				 fs->s_blocksize, &real_size, saved_size, 0/*not dir*/);
+	if (!is_new_file && (S_ISREG (mode) || S_ISLNK (mode)))
+	    /* old stat data shares sd_block and sd_dev. We do not want to wipe
+	       put sd_dev for device files */
+	    fix_sd += wrong_st_blocks (&sd_key, blocks, saved_blocks, 0/*not dir*/);
+	
+	if (fix_sd && fsck_fix_fixable (fs)) {
+	    /* find stat data and correct it */
+	    if (usearch_by_key (fs, &sd_key, path) != ITEM_FOUND)
+		die ("check_regular_file: stat data not found");
+	    
+	    bh = get_bh (path);
+	    ih = get_ih (path);
+	    sd = get_item (path);
+	    set_sd_size (ih, sd, &real_size);
+	    set_sd_blocks (ih, sd, &blocks);
+	    set_sd_mode (ih, sd, &mode);
+	    if (!is_new_file)
+		set_sd_first_direct_byte (ih, sd, &first_direct_byte);
+	    mark_buffer_dirty (bh);
+	}
+    }
+    return OK;
+}
+
+
+/* semantic pass of --check */
+static int check_semantic_pass (struct key * key, struct key * parent)
+{
+    struct path path;
+    void * sd;
+    int is_new_dir;
+    struct buffer_head * bh;
+    struct item_head * ih;
+    int retval;
+    char * dir_item;
+    int pos_in_item;
+    struct item_head tmp_ih;
+    struct key next_item_key, entry_key, object_key;
+    __u64 dir_size = 0;
+    __u32 blocks;
+    __u64 saved_size;
+    __u32 saved_blocks;
+    int fix_sd;
+	
+
+    if (!KEY_IS_STAT_DATA_KEY (key))
+	die ("check_semantic_pass: key must be key of a stat data");
+
+    /* look for stat data of an object */
+    if (usearch_by_key (fs, key, &path) == ITEM_NOT_FOUND) {
+	pathrelse (&path);
+	return STAT_DATA_NOT_FOUND;
+    }
+
+    /* stat data has been found */
+    sd = get_item(&path);
+
+    if (not_a_directory (sd)) {
+	retval = check_check_regular_file (&path, sd);
+	pathrelse (&path);
+	return retval;
+    }
+
+    ih = get_ih (&path);
+    /* directory stat data found */
+    if (ih_item_len (ih) == SD_SIZE)
+	is_new_dir = 1;
+    else
+	is_new_dir = 0;
+
+    /* save stat data's size and st_blocks */
+    get_sd_size (ih, sd, &saved_size);
+    get_sd_blocks (ih, sd, &saved_blocks);
+
+    /* release path pointing to stat data */
+    pathrelse (&path);
+
+    stats(fs)->directories ++;
+    next_item_key = *key;
+    next_item_key.u.k_offset_v1.k_offset = DOT_OFFSET;
+    next_item_key.u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS;
+
+
+    dir_size = 0;
+    while ((dir_item = get_next_directory_item (&next_item_key, parent, &tmp_ih, &pos_in_item)) != 0) {
+	/* dir_item is copy of the item in separately allocated memory,
+	   item_key is a key of next item in the tree */
+	int i;
+	struct reiserfs_de_head * deh = (struct reiserfs_de_head *)dir_item + pos_in_item;
+	
+	
+	for (i = pos_in_item; i < ih_entry_count (&tmp_ih); i ++, deh ++) {
+	    char * name;
+	    int namelen;
+	    
+	    name = name_in_entry (deh, i);
+	    namelen = name_length (&tmp_ih, deh, i);
+	    
+	    print_name (name, namelen);
+	    
+	    if (!is_properly_hashed (fs, name, namelen, deh_offset (deh))) {
+		fsck_log ("check_semantic_pass: hash mismatch detected (%.*s)\n", namelen, name);
+	    }
+	    get_object_key (deh, &object_key, &entry_key, &tmp_ih);
+	    
+	    if (is_dot (name, namelen) || is_dot_dot (name, namelen)) {
+		/* do not go through "." and ".." */
+		retval = OK;
+	    } else {
+		add_path_key (&object_key);
+		retval = check_semantic_pass (&object_key, key);
+		del_path_key ();
+	    }
+	    
+	    erase_name (namelen);
+	    
+	    /* check what check_semantic_tree returned */
+	    switch (retval) {
+	    case OK:
+		dir_size += DEH_SIZE + entry_length (&tmp_ih, deh, i);
+		break;
+		
+	    case STAT_DATA_NOT_FOUND:
+		fsck_log ("check_semantic_pass: name \"%.*s\" in directory %K points to nowhere",
+			  namelen, name, &tmp_ih.ih_key);
+		if (fsck_fix_fixable (fs)) {
+		    reiserfs_remove_entry (fs, &entry_key);
+		    stats(fs)->deleted_entries ++;
+		    fsck_log (" - removed");
+		}
+		fsck_log ("\n");
+		    break;
+		    
+	    case DIRECTORY_HAS_NO_ITEMS:
+		fsck_log ("check_semantic_pass: name \"%.*s\" in directory %K points dir without body\n",
+			  namelen, name, &tmp_ih.ih_key);
+		/* fixme: stat data should be deleted as well */
+		/*
+		  if (fsck_fix_fixable (fs)) {
+		  reiserfs_remove_entry (fs, &entry_key);
+		  stats(fs)->deleted_entries ++;
+		  fsck_log (" - removed");
+		  }
+		  fsck_log ("\n");*/
+		break;
+		
+	    case RELOCATED:
+		/* fixme: we could also relocate file */
+		reiserfs_panic ("check_semantic_pass: relocation in check mode is not ready");
+	    }
+	} /* for */
+	
+	freemem (dir_item);
+	
+	if (not_of_one_file (&next_item_key, key))
+	    /* next key is not of this directory */
+	    break;
+	
+    } /* while (dir_item) */
+    
+    
+    if (dir_size == 0)
+	/* FIXME: is it possible? */
+	return DIRECTORY_HAS_NO_ITEMS;
+    
+    /* calc correct value of sd_blocks field of stat data */
+    blocks = dir_size2st_blocks (fs->s_blocksize, dir_size);
+    
+    fix_sd = 0;
+    fix_sd += wrong_st_blocks (key, blocks, saved_blocks, 1/*dir*/);
+    fix_sd += wrong_st_size (key, is_new_dir ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1,
+			     fs->s_blocksize, &dir_size, saved_size, 1/*dir*/);
+    
+    if (fix_sd && fsck_fix_fixable (fs)) {
+	/* we have to fix either sd_size or sd_blocks, so look for stat data again */
+	if (usearch_by_key (fs, key, &path) != ITEM_FOUND)
+	    die ("check_semantic_tree: stat data not found");
+	
+	bh = get_bh (&path);
+	ih = get_ih (&path);
+	sd = get_item (&path);
+	
+	set_sd_size (ih, sd, &dir_size);
+	set_sd_blocks (ih, sd, &blocks);
+	mark_buffer_dirty (bh);
+	pathrelse (&path);
+    }
+    
+    return OK;
+}
+
+
+/* called when --check is given */
+void semantic_check (void)
+{
+    fsck_progress ("Checking Semantic tree...");
+
+    if (check_semantic_pass (&root_dir_key, &parent_root_dir_key) != OK)
+        die ("check_semantic_tree: no root directory found");
+
+    fsck_progress ("ok\n");
+
+}
+
+
+
diff --git a/fsck/ubitmap.c b/fsck/ubitmap.c
new file mode 100644
index 0000000..76e5b78
--- /dev/null
+++ b/fsck/ubitmap.c
@@ -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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fsck/ufile.c b/fsck/ufile.c
new file mode 100644
index 0000000..7037c5a
--- /dev/null
+++ b/fsck/ufile.c
@@ -0,0 +1,1069 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser
+ */
+#include "fsck.h"
+
+
+
+
+static int do_items_have_the_same_type (struct item_head * ih, struct key * key)
+{
+    return (get_type (&ih->ih_key) == get_type (key)) ? 1 : 0;
+}
+
+static int are_items_in_the_same_node (struct path * path)
+{
+  return (PATH_LAST_POSITION (path) < B_NR_ITEMS (PATH_PLAST_BUFFER (path)) - 1) ? 1 : 0;
+}
+
+
+/* FIXME: there is get_next_key in pass4.c */
+static struct key * get_next_key_2 (struct path * path)
+{
+    if (PATH_LAST_POSITION (path) < B_NR_ITEMS (get_bh (path)) - 1)
+	return B_N_PKEY (get_bh (path), PATH_LAST_POSITION (path) + 1);
+    return uget_rkey (path);
+}
+
+
+int do_make_tails ()
+{
+    return 1;/*SB_MAKE_TAIL_FLAG (&g_sb) == MAKE_TAILS ? YES : NO;*/
+}
+
+
+static void cut_last_unfm_pointer (struct path * path, struct item_head * ih)
+{
+    set_free_space(ih, 0);
+    if (I_UNFM_NUM (ih) == 1)
+	reiserfsck_delete_item (path, 0);
+    else
+	reiserfsck_cut_from_item (path, -UNFM_P_SIZE);
+}
+
+
+// we use this to convert symlinks back to direct items if they were
+// direct2indirect converted on tree building
+static unsigned long indirect_to_direct (struct path * path, __u64 *symlink_size)
+{
+    struct buffer_head * bh = PATH_PLAST_BUFFER (path);
+    struct item_head * ih = PATH_PITEM_HEAD (path);
+    unsigned long unfm_ptr;
+    struct buffer_head * unfm_bh = 0;
+    struct item_head ins_ih;
+    char * buf;
+    int len;
+    __u32 * indirect;
+    char bad_link[] = "broken_link";
+
+/*    add_event (INDIRECT_TO_DIRECT);*/
+
+
+    /* direct item to insert */
+    set_key_format (&ins_ih, ih_key_format (ih));
+    ins_ih.ih_key.k_dir_id = ih->ih_key.k_dir_id;
+    ins_ih.ih_key.k_objectid = ih->ih_key.k_objectid;
+    set_type_and_offset (ih_key_format (ih), &ins_ih.ih_key,
+			 get_offset (&ih->ih_key) + (I_UNFM_NUM (ih) - 1) * bh->b_size, TYPE_DIRECT);
+
+    // we do not know what length this item should be
+    indirect = get_item (path);
+    unfm_ptr = le32_to_cpu (indirect [I_UNFM_NUM (ih) - 1]);
+    if (unfm_ptr && (unfm_bh = bread (bh->b_dev, unfm_ptr, bh->b_size))) {
+	buf = unfm_bh->b_data;
+	// get length of direct item
+	for (len = 0; buf[len] && len < bh->b_size; len ++);
+    } else {
+	fsck_log ("indirect_to_direct: could not read block %lu, "
+		  "making (%K) bad link instead\n", unfm_ptr, &ih->ih_key);
+	buf = bad_link;
+	len = strlen (bad_link);
+    }
+
+    if (len > MAX_DIRECT_ITEM_LEN (fs->s_blocksize)) {
+	fsck_log ("indirect_to_direct: symlink %K seems too long %d, "
+		  "Cutting it down to %d byte\n",
+			  &ih->ih_key, len, MAX_DIRECT_ITEM_LEN (fs->s_blocksize) - 8);
+	len = MAX_DIRECT_ITEM_LEN (fs->s_blocksize) - 8;
+    }
+
+    if (!len) {
+	buf = bad_link;
+	len = strlen (bad_link);
+    }
+
+    *symlink_size = len;
+    
+    ins_ih.ih_item_len = cpu_to_le16 ((ih_key_format (ih) == KEY_FORMAT_2) ? ROUND_UP(len) : len);
+    set_free_space (&ins_ih, MAX_US_INT);
+
+
+    // last last unformatted node pointer
+    path->pos_in_item = I_UNFM_NUM (ih) - 1;
+    cut_last_unfm_pointer (path, ih);
+
+    /* insert direct item */
+    if (usearch_by_key (fs, &(ins_ih.ih_key), path) == ITEM_FOUND)
+	die ("indirect_to_direct: key must be not found");
+    reiserfsck_insert_item (path, &ins_ih, (const char *)(buf));
+
+    brelse (unfm_bh);
+
+    /* put to stat data offset of first byte in direct item */
+    return get_offset (&ins_ih.ih_key); //offset;
+}
+
+
+extern inline __u64 get_min_bytes_number (struct item_head * ih, int blocksize)
+{
+    switch (get_type (&ih->ih_key)) {
+    case TYPE_DIRECT:
+	if (SB_VERSION(fs) == REISERFS_VERSION_2)
+	    return ROUND_UP(ih_item_len (ih) - 8);
+        else
+	    return ih_item_len (ih);
+    case TYPE_INDIRECT:
+	return (I_UNFM_NUM(ih) - 1) * blocksize;
+    }
+    fsck_log ("get_min_bytes_number: called for wrong type of item %H\n", ih);
+    return 0;
+}
+
+
+/* returns 1 when file looks correct, -1 if directory items appeared
+   there, 0 - only holes in the file found */
+/* when it returns, key->k_offset is offset of the last item of file */
+int are_file_items_correct (struct key * key, int key_version, __u64 * size,
+			    /*__u64 * min_size,*/ __u32 * blocks,
+			    int mark_passed_items, int symlink, __u64 symlink_size)
+{
+    struct path path;
+    int retval, i;
+    struct item_head * ih;
+    struct key * next_key;
+    int had_direct = 0;
+
+    set_offset (key_version, key, 1);
+    set_type (key_version, key, TYPE_DIRECT);
+
+    *size = 0;
+    /*    *min_size = 0;*/
+    *blocks = 0;
+
+    path.path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+
+    do {
+	retval = usearch_by_position (fs, key, key_version, &path);
+	if (retval == POSITION_FOUND && path.pos_in_item != 0)
+	    die ("are_file_items_correct: all bytes we look for must be found at position 0");
+
+	switch (retval) {
+	case POSITION_FOUND:/**/
+
+	    ih = PATH_PITEM_HEAD (&path);
+
+	    set_type (ih_key_format (ih), key, get_type (&ih->ih_key));
+
+	    if (mark_passed_items == 1) {
+		mark_item_reachable (ih, PATH_PLAST_BUFFER (&path));
+	    }
+	    // does not change path
+	    next_key = get_next_key_2 (&path);
+
+    	    if (get_type (&ih->ih_key) == TYPE_INDIRECT)
+	    {
+                if (symlink)
+                    *blocks = 1;
+                else
+                    for (i = 0; i < I_UNFM_NUM (ih); i ++)
+                    {
+                        __u32 * ind = (__u32 *)get_item(&path);
+
+                        if (ind[i] != 0)
+                             *blocks += (fs->s_blocksize >> 9);
+                    }
+
+	    }else if ((get_type (&ih->ih_key) == TYPE_DIRECT) && !(had_direct))
+            {
+                if (symlink)
+                    *blocks = (fs->s_blocksize >> 9);
+                else
+                    *blocks += (fs->s_blocksize >> 9);
+	        had_direct++;
+	    }
+	
+	    if (next_key == 0 || not_of_one_file (key, next_key) ||
+  		(!is_indirect_key (next_key) && !is_direct_key(next_key) ) )
+            {
+		/* next item does not exists or is of another object,
+                   therefore all items of file are correct */
+	
+	      /*		*min_size = get_offset (key) + get_min_bytes_number (ih, fs->s_blocksize);*/
+		*size = get_offset (key) + get_bytes_number (ih, fs->s_blocksize) - 1;
+		
+		
+		/* here is a problem: if file system being repaired was full
+                   enough, then we should avoid indirect_to_direct
+                   conversions. This is because unformatted node we have to
+                   free will not get into pool of free blocks, but new direct
+                   item is very likely of big size, therefore it may require
+                   allocation of new blocks. So, skip it for now */
+		if (symlink && is_indirect_ih (ih)) {
+//		    struct key sd_key;
+		    unsigned long first_direct_byte;
+
+		    if (fsck_mode (fs) == FSCK_CHECK) {
+			fsck_log ("are_file_items_correct: symlink found in indirect item %K\n", &ih->ih_key);
+		    } else {
+			first_direct_byte = indirect_to_direct (&path, &symlink_size);
+			
+			/* last item of the file is direct item */		
+			set_offset (key_version, key, first_direct_byte);
+			set_type (key_version, key, TYPE_DIRECT);
+			*size = symlink_size;
+		    }
+		} else
+		    pathrelse (&path);
+		return 1;
+	    }
+
+	    /* next item is item of this file */
+	    if ((is_indirect_ih (ih) &&
+                 (get_offset (&ih->ih_key) + fs->s_blocksize * I_UNFM_NUM (ih) != get_offset (next_key))) ||
+		(is_direct_ih (ih) &&
+		 (get_offset (&ih->ih_key) + ih_item_len (ih) != get_offset (next_key))))
+	    {
+		/* next item has incorrect offset (hole or overlapping) */
+		*size = get_offset (&ih->ih_key) + get_bytes_number (ih, fs->s_blocksize) - 1;
+		/**min_size = *size;*/
+		pathrelse (&path);
+		return 0;
+	    }
+	    if (do_items_have_the_same_type (ih, next_key) == 1 && are_items_in_the_same_node (&path) == 1) 
+	    {
+		/* two indirect items or two direct items in the same leaf. FIXME: Second will be deleted */
+		*size = get_offset (&ih->ih_key) + get_bytes_number (ih, fs->s_blocksize) - 1;
+		/**min_size = *size;*/
+		pathrelse (&path);
+		return 0;
+	    }
+
+	    /* items are of different types or are in different nodes */
+	    if (get_offset (&ih->ih_key) + get_bytes_number (ih, fs->s_blocksize) != get_offset (next_key))
+            {
+		/* indirect item free space is not set properly */
+		if (!is_indirect_ih (ih) ) //|| get_ih_free_space(ih) == 0)
+		    fsck_log ("are_file_items_correct: "
+			      "item must be indirect and must have invalid free space (%H)", ih);
+	
+                if (fsck_mode (fs) != FSCK_CHECK)
+                {		
+                    set_free_space(ih, 0);
+                    mark_buffer_dirty (PATH_PLAST_BUFFER (&path));
+        	}
+	    }
+
+	    /* next item exists */
+	    set_type_and_offset(key_version, key, get_offset (next_key), get_type(next_key));
+	
+	    if (comp_keys (key, next_key))
+		die ("are_file_items_correct: keys do not match %k and %k", key, next_key);
+	    pathrelse (&path);
+	    break;
+
+	case POSITION_NOT_FOUND:
+	    // we always must have next key found. Exception is first
+	    // byte. It does not have to exist
+	
+	    if (get_offset (key) != 1)
+		die ("are_file_items_correct: key not found %byte can be not found only when it is first byte of file");
+	    pathrelse (&path);
+	    return 0;
+      
+	case FILE_NOT_FOUND:
+	    if (get_offset (key) != 1)
+		die ("are_file_items_correct: there is no items of this file, byte 0 found though");
+	    pathrelse (&path);
+	    return 1;
+
+	case DIRECTORY_FOUND:
+	    pathrelse (&path);
+	    return -1;
+	}
+    } while (1);
+
+    die ("are_file_items_correct: code can not reach here");
+    return 0;
+}
+
+
+/* delete all items and put them back (after that file should have
+   correct sequence of items.It is very similar to
+   pass2.c:relocate_file () and should_relocate () */
+static void rewrite_file (struct item_head * ih)
+{
+    struct key key;
+    struct key * rkey;
+    struct path path;
+    struct item_head * path_ih;
+    struct si * si;
+
+    /* starting with the leftmost one - look for all items of file,
+       store and delete and  */
+    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 */
+		copy_key (&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)))
+	    reiserfs_panic ("rewrite_file: no directory items of %K are expected",
+			    &key);
+
+	si = save_and_delete_file_item (si, &path);
+    }
+
+    /* put all items back into tree */
+    while (si) {
+	insert_item_separately (&(si->si_ih), si->si_dnm_data, 1/*was in tree*/);
+	si = remove_saved_item (si);
+    }
+}
+
+
+/* file must have correct sequence of items and tail must be stored in
+   unformatted pointer */
+static int make_file_writeable (struct item_head * ih)
+{
+    struct key key;
+    __u64 size;/*, min_size;*/
+    __u32 blocks;
+    int retval;
+
+    copy_key (&key, &(ih->ih_key));
+
+    retval = are_file_items_correct (&key, ih_key_format (ih), &size,/* &min_size, */
+				     &blocks, 0/*do not mark accessed*/, 0, 0);
+    if (retval == 1)
+	/* file looks correct */
+	return 1;
+
+    rewrite_file (ih);
+    stats(fs)->rewritten ++;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+    copy_key (&key, &(ih->ih_key));
+    size = 0;
+    if (are_file_items_correct (&key, ih_key_format (ih), &size, &blocks,
+				0/*do not mark accessed*/, 0, 0) == 0) {
+	fsck_progress ("file still incorrect %K\n", &key);
+    }
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+    return 1;
+}
+
+
+/* this inserts __first__ indirect item (having k_offset == 1 and only
+   one unfm pointer) into tree */
+static int create_first_item_of_file (struct item_head * ih, char * item, struct path * path,
+				      int *pos_in_coming_item, int was_in_tree)
+{
+    __u32 unfm_ptr;
+    struct buffer_head * unbh;
+    struct item_head indih;
+    int retval;
+    __u32 free_sp = 0;
+
+    if (get_offset (&ih->ih_key) > fs->s_blocksize) {
+	/* insert indirect item containing 0 unfm pointer */
+	unfm_ptr = 0;
+	set_free_space (&indih, 0);
+	free_sp = 0;
+	retval = 0;
+    } else {
+	if (is_direct_ih (ih)) {
+	    /* copy direct item to new unformatted node. Save information about it */
+	    //__u64 len = get_bytes_number(0, ih, item, CHECK_FREE_BYTES);
+	    __u64 len = get_bytes_number (ih, fs->s_blocksize);
+
+	    unbh = reiserfsck_get_new_buffer (PATH_PLAST_BUFFER (path)->b_blocknr);
+	    memset (unbh->b_data, 0, unbh->b_size);
+	    unfm_ptr = cpu_to_le32 (unbh->b_blocknr);
+/* this is for check only */
+	    /*mark_block_unformatted (le32_to_cpu (unfm_ptr));*/
+	    memcpy (unbh->b_data + get_offset (&ih->ih_key) - 1, item, len);
+
+	    save_unfm_overwriting (le32_to_cpu (unfm_ptr), ih);
+
+	    set_free_space (&indih, fs->s_blocksize - len - (get_offset (&ih->ih_key) - 1));
+	    free_sp = fs->s_blocksize - len - (get_offset (&ih->ih_key) - 1);
+	    mark_buffer_dirty (unbh);
+//      mark_buffer_uptodate (unbh, 0);
+	    mark_buffer_uptodate (unbh, 1);
+	    brelse (unbh);
+
+	    retval = len;
+	} else {
+	    /* take first unformatted pointer from an indirect item */
+	    unfm_ptr = cpu_to_le32 (*(__u32 *)item);/*B_I_POS_UNFM_POINTER (bh, ih, 0);*/
+	    if (!was_in_tree) {
+		if (still_bad_unfm_ptr_2 (unfm_ptr))
+		    die ("create_first_item_of_file: bad unfm pointer %d", unfm_ptr);
+		mark_block_used (unfm_ptr);
+	    }
+
+	    //free_sp = ih_get_free_space(0, ih, item);
+	    free_sp = ih_free_space (ih);
+	    set_free_space (&indih, ((ih_item_len(ih) == UNFM_P_SIZE) ? free_sp /*get_ih_free_space(ih)*/ : 0));
+	    if (ih_item_len (ih) != UNFM_P_SIZE)
+		free_sp = 0;
+//      free_sp = ((ih->ih_item_len == UNFM_P_SIZE) ? ih->u.ih_free_space : 0);
+	    retval = fs->s_blocksize - free_sp;
+	    (*pos_in_coming_item) ++;
+	}
+    }
+    set_key_format (&indih, ih_key_format (ih));
+    //ih_version(&indih) = ih_version(ih);
+    copy_key (&(indih.ih_key), &(ih->ih_key));
+    set_offset (key_format (&(ih->ih_key)), &indih.ih_key, 1);
+    set_type (key_format (&(ih->ih_key)), &indih.ih_key, TYPE_INDIRECT);
+
+    indih.ih_item_len = cpu_to_le16 (UNFM_P_SIZE);
+    mark_item_unreachable (&indih);
+    reiserfsck_insert_item (path, &indih, (const char *)&unfm_ptr);
+
+    return retval;
+}
+
+
+/* path points to first part of tail. Function copies file tail into unformatted node and returns
+   its block number. If we are going to overwrite direct item then keep free space (keep_free_space
+   == YES). Else (we will append file) set free space to 0 */
+/* we convert direct item that is on the path to indirect. we need a number of free block for
+   unformatted node. reiserfs_new_blocknrs will start from block number returned by this function */
+static unsigned long block_to_start (struct path * path)
+{
+  struct buffer_head * bh;
+  struct item_head * ih;
+
+  bh = PATH_PLAST_BUFFER (path);
+  ih = PATH_PITEM_HEAD (path);
+  if (get_offset(&ih->ih_key) == 1 || PATH_LAST_POSITION (path) == 0)
+    return bh->b_blocknr;
+
+  ih --;
+  return (B_I_POS_UNFM_POINTER (bh, ih, I_UNFM_NUM (ih) - 1)) ?: bh->b_blocknr;
+}
+
+
+static void direct2indirect2 (unsigned long unfm, struct path * path, int keep_free_space)
+{
+    struct item_head * ih;
+    struct key key;
+    struct buffer_head * unbh;
+    struct unfm_nodeinfo ni;
+    int copied = 0;
+
+    ih = PATH_PITEM_HEAD (path);
+    copy_key (&key, &(ih->ih_key));
+
+    if (get_offset (&key) % fs->s_blocksize != 1) {
+	/* look for first part of tail */
+	pathrelse (path);
+	set_offset (key_format (&key), &key, (get_offset (&key) & ~(fs->s_blocksize - 1)) + 1);	
+	if (usearch_by_key (fs, &key, path) != ITEM_FOUND)
+	    die ("direct2indirect: can not find first part of tail");
+    }
+
+    unbh = reiserfsck_get_new_buffer (unfm ?: block_to_start (path));
+    memset (unbh->b_data, 0, unbh->b_size);
+
+    /* delete parts of tail coping their contents to new buffer */
+    do {
+	//__u64 len = get_bytes_number(PATH_PLAST_BUFFER(path), ih, 0, CHECK_FREE_BYTES);
+	__u64 len;
+
+	ih = PATH_PITEM_HEAD (path);
+	
+	len = get_bytes_number(ih, fs->s_blocksize);
+	
+	memcpy (unbh->b_data + copied, B_I_PITEM (PATH_PLAST_BUFFER (path), ih), len);
+
+	save_unfm_overwriting (unbh->b_blocknr, ih);
+	copied += len;	
+	set_offset (key_format (&key), &key, get_offset (&key) +  len);
+//	set_offset (ih_key_format (ih), &key, get_offset (&key) +  len);
+
+	reiserfsck_delete_item (path, 0);
+	
+    } while (usearch_by_key (fs, &key, path) == ITEM_FOUND);
+	ih = PATH_PITEM_HEAD (path);
+
+    pathrelse (path);
+
+    /* paste or insert pointer to the unformatted node */
+    set_offset (key_format (&key), &key, get_offset (&key) - copied);
+//    set_offset (ih_key_format (ih), &key, get_offset (&key) - copied);
+//  key.k_offset -= copied;
+    ni.unfm_nodenum = cpu_to_le32 (unbh->b_blocknr);
+    ni.unfm_freespace = (keep_free_space == 1) ? (fs->s_blocksize - copied) : 0;
+
+/* this is for check only */
+    /*mark_block_unformatted (ni.unfm_nodenum);*/
+
+    if (usearch_by_position (fs, &key, key_format (&key), path) == FILE_NOT_FOUND) {
+	struct item_head insih;
+
+	copy_key (&(insih.ih_key), &key);
+	set_key_format (&insih, key_format (&key));
+	set_type (ih_key_format (&insih), &insih.ih_key, TYPE_INDIRECT);
+	set_free_space (&insih, ni.unfm_freespace);
+//    insih.u.ih_free_space = ni.unfm_freespace;
+	mark_item_unreachable (&insih);
+	insih.ih_item_len = cpu_to_le16 (UNFM_P_SIZE);
+	reiserfsck_insert_item (path, &insih, (const char *)&(ni.unfm_nodenum));
+    } else {
+	ih = PATH_PITEM_HEAD (path);
+
+	if (!is_indirect_ih (ih) || get_offset (&key) != get_bytes_number (ih, fs->s_blocksize) + 1)
+	    die ("direct2indirect: incorrect item found");
+	reiserfsck_paste_into_item (path, (const char *)&ni, UNFM_P_SIZE);
+    }
+
+    mark_buffer_dirty (unbh);
+//  mark_buffer_uptodate (unbh, 0);
+    mark_buffer_uptodate (unbh, 1);
+    brelse (unbh);
+
+    if (usearch_by_position (fs, &key, ih_key_format (ih), path) != POSITION_FOUND || !is_indirect_ih (PATH_PITEM_HEAD (path)))
+	die ("direct2indirect: position not found");
+    return;
+}
+
+
+
+
+static int append_to_unformatted_node (struct item_head * comingih, struct item_head * ih, char * item,
+                                        struct path * path, __u16 * free_sp, __u64 coming_len)
+{
+    struct buffer_head * bh, * unbh;
+    __u64 end_of_data; //ih->u.ih_free_space;
+    __u64 offset = get_offset (&comingih->ih_key) % fs->s_blocksize - 1;
+    int zero_number;
+    __u32 unfm_ptr;
+    
+    /* append to free space of the last unformatted node of indirect item ih */
+    if (*free_sp /*ih->u.ih_free_space*/ < coming_len)
+    {
+
+	*free_sp = get_offset (&ih->ih_key) + fs->s_blocksize * I_UNFM_NUM (ih) - get_offset (&comingih->ih_key);
+	if (*free_sp < coming_len)
+	        die ("reiserfsck_append_file: there is no enough free space in unformatted node");
+    }
+
+    end_of_data = fs->s_blocksize - *free_sp;
+    zero_number = offset - end_of_data;
+
+    bh = PATH_PLAST_BUFFER (path);
+    
+    unfm_ptr = B_I_POS_UNFM_POINTER (bh, ih, I_UNFM_NUM (ih) - 1);
+
+    /*if (unfm_ptr != 0 && unfm_ptr < SB_BLOCK_COUNT (fs))*/
+    if (unfm_ptr && !not_data_block (fs, unfm_ptr))
+    {
+	unbh = bread (fs->s_dev, unfm_ptr, fs->s_blocksize);
+	if (!is_block_used (unfm_ptr))
+	    die ("append_to_unformatted_node:  unused block %d", unfm_ptr);
+	if (unbh == 0)
+	    unfm_ptr = 0;
+    } else {
+	/* indirect item points to block which can not be pointed or to 0, in
+           any case we have to allocate new node */
+	/*if (unfm_ptr == 0 || unfm_ptr >= SB_BLOCK_COUNT (fs)) {*/
+	unbh = reiserfsck_get_new_buffer (bh->b_blocknr);
+	memset (unbh->b_data, 0, unbh->b_size);
+	B_I_POS_UNFM_POINTER (bh, ih, I_UNFM_NUM (ih) - 1) = unbh->b_blocknr;
+	/*mark_block_unformatted (unbh->b_blocknr);*/
+	mark_buffer_dirty (bh);
+    }
+    memset (unbh->b_data + end_of_data, 0, zero_number);
+    memcpy (unbh->b_data + offset, item, coming_len);
+
+    save_unfm_overwriting (unbh->b_blocknr, comingih);
+
+    *free_sp /*ih->u.ih_free_space*/ -= (zero_number + coming_len);
+    set_free_space(ih, ih_free_space(ih) - (zero_number + coming_len));
+    memset (unbh->b_data + offset + coming_len, 0, *free_sp);
+//  mark_buffer_uptodate (unbh, 0);
+    mark_buffer_uptodate (unbh, 1);
+    mark_buffer_dirty (unbh);
+    brelse (unbh);
+    pathrelse (path);
+    return coming_len;
+}
+
+
+static void adjust_free_space (struct buffer_head * bh, struct item_head * ih, struct item_head * comingih, __u16 *free_sp)
+{
+  //    printf ("adjust_free_space does nothing\n");
+    return;
+    if (is_indirect_ih (comingih)) {
+	set_free_space(ih, 0);//??
+	*free_sp = (__u16)0;
+    } else {
+	if (get_offset (&comingih->ih_key) < get_offset (&ih->ih_key) + fs->s_blocksize * I_UNFM_NUM (ih))
+	{
+	    /* append to the last unformatted node */
+	    set_free_space (ih, fs->s_blocksize - get_offset(&ih->ih_key) % fs->s_blocksize + 1);//??
+	    *free_sp = (__u16)fs->s_blocksize - get_offset(&ih->ih_key) % fs->s_blocksize + 1;
+	}
+	else
+	{
+	    set_free_space(ih,0);//??
+	    *free_sp =0;
+	}
+    }
+    mark_buffer_dirty (bh);
+}
+
+
+/* this appends file with one unformatted node pointer (since balancing
+   algorithm limitation). This pointer can be 0, or new allocated block or
+   pointer from indirect item that is being inserted into tree */
+int reiserfsck_append_file (struct item_head * comingih, char * item, int pos, struct path * path,
+			    int was_in_tree)
+{
+    struct unfm_nodeinfo ni;
+    struct buffer_head * unbh;
+    int retval;
+    struct item_head * ih = PATH_PITEM_HEAD (path);
+    __u16 keep_free_space;
+    __u32 bytes_number;
+
+    if (!is_indirect_ih (ih))
+	die ("reiserfsck_append_file: can not append to non-indirect item");
+
+    //keep_free_space = ih_get_free_space(PATH_PLAST_BUFFER (path), PATH_PITEM_HEAD(path), 0);
+    keep_free_space = ih_free_space (ih);
+
+    if (get_offset (&ih->ih_key) + get_bytes_number (ih, fs->s_blocksize)
+	//get_bytes_number (PATH_PLAST_BUFFER (path), PATH_PITEM_HEAD(path), 0, CHECK_FREE_BYTES)
+	!= get_offset (&comingih->ih_key)){
+	adjust_free_space (PATH_PLAST_BUFFER (path), ih, comingih, &keep_free_space);
+    }
+
+    if (is_direct_ih (comingih)) {
+	//__u64 coming_len = get_bytes_number (0,comingih, item, CHECK_FREE_BYTES);
+	__u64 coming_len = get_bytes_number (comingih, fs->s_blocksize);
+
+	if (get_offset (&comingih->ih_key) < get_offset (&ih->ih_key) + fs->s_blocksize * I_UNFM_NUM (ih)) {
+	    /* direct item fits to free space of indirect item */
+	    return append_to_unformatted_node (comingih, ih, item, path, &keep_free_space, coming_len);
+	}
+
+	unbh = reiserfsck_get_new_buffer (PATH_PLAST_BUFFER (path)->b_blocknr);
+	memset (unbh->b_data, 0, unbh->b_size);
+	/* this is for check only */
+	/*mark_block_unformatted (unbh->b_blocknr);*/
+	memcpy (unbh->b_data + get_offset (&comingih->ih_key) % unbh->b_size - 1, item, coming_len);
+
+	save_unfm_overwriting (unbh->b_blocknr, comingih);
+
+	mark_buffer_dirty (unbh);
+//    mark_buffer_uptodate (unbh, 0);
+	mark_buffer_uptodate (unbh, 1);
+
+	ni.unfm_nodenum = unbh->b_blocknr;
+	ni.unfm_freespace = fs->s_blocksize - coming_len - (get_offset (&comingih->ih_key) % unbh->b_size - 1);
+	brelse (unbh);
+	retval = coming_len;
+    } else {
+	/* coming item is indirect item */
+	//bytes_number = get_bytes_number (PATH_PLAST_BUFFER (path), PATH_PITEM_HEAD(path), 0, CHECK_FREE_BYTES);
+	bytes_number = get_bytes_number (ih, fs->s_blocksize);
+	if (get_offset (&comingih->ih_key) + pos * fs->s_blocksize != get_offset (&ih->ih_key) + bytes_number)
+	    fsck_progress ("reiserfsck_append_file: can not append indirect item (%H) to the %H",
+			   comingih, ih);
+
+	/* take unformatted pointer from an indirect item */
+	ni.unfm_nodenum = *(__u32 *)(item + pos * UNFM_P_SIZE);/*B_I_POS_UNFM_POINTER (bh, ih, pos);*/
+	    
+	if (!was_in_tree) {
+	    if (still_bad_unfm_ptr_2 (ni.unfm_nodenum))
+		die ("reiserfsck_append_file: bad unfm pointer");
+	    mark_block_used (ni.unfm_nodenum);
+	}
+
+	ni.unfm_freespace = ((pos == (I_UNFM_NUM (comingih) - 1)) ?
+			     //ih_get_free_space(0, comingih, item) /*comingih->u.ih_free_space*/ : 0);
+			     ih_free_space (comingih) /*comingih->u.ih_free_space*/ : 0);
+	retval = fs->s_blocksize - ni.unfm_freespace;
+    }
+
+    reiserfsck_paste_into_item (path, (const char *)&ni, UNFM_P_SIZE);
+    return retval;
+}
+
+
+int must_there_be_a_hole (struct item_head * comingih, struct path * path)
+{
+    struct item_head * ih = PATH_PITEM_HEAD (path);
+    int keep_free_space;
+
+    if (is_direct_ih (ih)) {
+	direct2indirect2 (0, path, keep_free_space = 1);
+	ih = PATH_PITEM_HEAD (path);
+    }
+
+    path->pos_in_item = I_UNFM_NUM (ih);
+    if (get_offset (&ih->ih_key) + (I_UNFM_NUM (ih) + 1) * fs->s_blocksize <= get_offset (&comingih->ih_key))
+	return 1;
+
+    return 0;
+}
+
+
+int reiserfs_append_zero_unfm_ptr (struct path * path)
+{
+    struct unfm_nodeinfo ni;
+    int keep_free_space;
+
+    ni.unfm_nodenum = 0;
+    ni.unfm_freespace = 0;
+
+    if (is_direct_ih (PATH_PITEM_HEAD (path)))
+	/* convert direct item to indirect */
+	direct2indirect2 (0, path, keep_free_space = 0);
+	
+    reiserfsck_paste_into_item (path, (const char *)&ni, UNFM_P_SIZE);
+    return 0;
+}
+
+
+/* write direct item to unformatted node */
+/* coming item is direct */
+static int overwrite_by_direct_item (struct item_head * comingih, char * item, struct path * path)
+{
+    __u32 unfm_ptr;
+    struct buffer_head * unbh, * bh;
+    struct item_head * ih;
+    int offset;
+    __u64 coming_len = get_bytes_number (comingih, fs->s_blocksize);
+
+
+    bh = PATH_PLAST_BUFFER (path);
+    ih = PATH_PITEM_HEAD (path);
+
+    unfm_ptr = le32_to_cpu (B_I_POS_UNFM_POINTER (bh, ih, path->pos_in_item));
+    unbh = 0;
+
+    if (unfm_ptr != 0 && unfm_ptr < SB_BLOCK_COUNT (fs)) {
+	/**/
+	unbh = bread (fs->s_dev, unfm_ptr, bh->b_size);
+	if (!is_block_used (unfm_ptr))
+	    die ("overwrite_by_direct_item: unused block %d", unfm_ptr);
+	if (unbh == 0)
+	    unfm_ptr = 0;
+    }
+    if (unfm_ptr == 0 || unfm_ptr >= SB_BLOCK_COUNT (fs))
+    {
+	unbh = reiserfsck_get_new_buffer (bh->b_blocknr);
+	memset (unbh->b_data, 0, unbh->b_size);
+	B_I_POS_UNFM_POINTER (bh, ih, path->pos_in_item) = cpu_to_le32 (unbh->b_blocknr);
+	mark_buffer_dirty (bh);
+    }
+
+    if (!unbh) {
+	die ("overwrite_by_direct_item: could not put direct item in");
+    }
+      
+    offset = (get_offset (&comingih->ih_key) % bh->b_size) - 1;
+    if (offset + coming_len > MAX_DIRECT_ITEM_LEN (bh->b_size))
+    	die ("overwrite_by_direct_item: direct item too long (offset=%lu, length=%u)",
+	         get_offset (&comingih->ih_key), coming_len);
+
+    memcpy (unbh->b_data + offset, item, coming_len);
+
+    save_unfm_overwriting (unbh->b_blocknr, comingih);
+
+    if ((path->pos_in_item == (I_UNFM_NUM (ih) - 1)) && 
+	(bh->b_size - ih_free_space (ih)) < (offset + coming_len)) {
+	set_free_space (ih, bh->b_size - (offset + coming_len)) ;
+	mark_buffer_dirty (bh);
+    }
+    mark_buffer_dirty (unbh);
+//  mark_buffer_uptodate (unbh, 0);
+    mark_buffer_uptodate (unbh, 1);
+    brelse (unbh);
+    return coming_len;
+}
+
+
+
+void overwrite_unfm_by_unfm (unsigned long unfm_in_tree, unsigned long coming_unfm, int bytes_in_unfm)
+{
+  struct overwritten_unfm_segment * unfm_os_list;/* list of overwritten segments of the unformatted node */
+  struct overwritten_unfm_segment unoverwritten_segment;
+  struct buffer_head * bh_in_tree, * coming_bh;
+
+  if (!test_bit (coming_unfm % (fs->s_blocksize * 8), SB_AP_BITMAP (fs)[coming_unfm / (fs->s_blocksize * 8)]->b_data))
+    /* block (pointed by indirect item) is free, we do not have to keep its contents */
+    return;
+
+  /* coming block is marked as used in disk bitmap. Put its contents to block in tree preserving
+     everything, what has been overwritten there by direct items */
+  unfm_os_list = find_overwritten_unfm (unfm_in_tree, bytes_in_unfm, &unoverwritten_segment);
+  if (unfm_os_list) {
+    /*    add_event (UNFM_OVERWRITING_UNFM);*/
+    bh_in_tree = bread (fs->s_dev, unfm_in_tree, fs->s_blocksize);
+    coming_bh = bread (fs->s_dev, coming_unfm, fs->s_blocksize);
+    if (bh_in_tree == 0 || coming_bh == 0)
+        return;
+
+    while (get_unoverwritten_segment (unfm_os_list, &unoverwritten_segment)) {
+      if (unoverwritten_segment.ous_begin < 0 || unoverwritten_segment.ous_end > bytes_in_unfm - 1 ||
+	  unoverwritten_segment.ous_begin > unoverwritten_segment.ous_end)
+	die ("overwrite_unfm_by_unfm: invalid segment found (%d %d)", unoverwritten_segment.ous_begin, unoverwritten_segment.ous_end);
+
+      memcpy (bh_in_tree->b_data + unoverwritten_segment.ous_begin, coming_bh->b_data + unoverwritten_segment.ous_begin,
+	      unoverwritten_segment.ous_end - unoverwritten_segment.ous_begin + 1);
+      mark_buffer_dirty (bh_in_tree);
+    }
+
+    brelse (bh_in_tree);
+    brelse (coming_bh);
+  }
+}
+
+
+/* put unformatted node pointers from incoming item over the in-tree ones */
+static int overwrite_by_indirect_item (struct item_head * comingih, __u32 * coming_item, struct path * path, int * pos_in_coming_item)
+{
+    struct buffer_head * bh = PATH_PLAST_BUFFER (path);
+    struct item_head * ih = PATH_PITEM_HEAD (path);
+    int written;
+    __u32 * item_in_tree;
+    int src_unfm_ptrs, dest_unfm_ptrs, to_copy;
+    int i;
+    __u16 free_sp;
+
+
+    item_in_tree = (__u32 *)B_I_PITEM (bh, ih) + path->pos_in_item;
+    coming_item += *pos_in_coming_item;
+
+    dest_unfm_ptrs = I_UNFM_NUM (ih) - path->pos_in_item;
+    src_unfm_ptrs = I_UNFM_NUM (comingih) - *pos_in_coming_item;
+  
+    if (dest_unfm_ptrs >= src_unfm_ptrs) {
+	/* whole coming item (comingih) fits into item in tree (ih) starting with path->pos_in_item */
+
+	//free_sp = ih_get_free_space(0, comingih, (char *)coming_item);
+	free_sp = ih_free_space (comingih);
+
+	written = get_bytes_number (comingih, fs->s_blocksize) -
+	    free_sp - *pos_in_coming_item * fs->s_blocksize;
+	*pos_in_coming_item = I_UNFM_NUM (comingih);
+	to_copy = src_unfm_ptrs;
+	if (dest_unfm_ptrs == src_unfm_ptrs)
+	    set_free_space(ih, free_sp); //comingih->u.ih_free_space;
+    } else {
+	/* only part of coming item overlaps item in the tree */
+	*pos_in_coming_item += dest_unfm_ptrs;
+	written = dest_unfm_ptrs * fs->s_blocksize;
+	to_copy = dest_unfm_ptrs;
+	set_free_space(ih, 0);
+    }
+  
+    for (i = 0; i < to_copy; i ++) {
+	if (!is_block_used (coming_item[i]) && !is_block_uninsertable (coming_item[i])) {
+	    if (item_in_tree[i]) {
+		/* do not overwrite unformatted pointer. We must save everything what is there already from
+		   direct items */
+		overwrite_unfm_by_unfm (item_in_tree[i], coming_item[i], fs->s_blocksize);
+	    } else {
+		item_in_tree[i] = coming_item[i];
+		mark_block_used (coming_item[i]);
+	    }
+	}
+    }
+    mark_buffer_dirty (bh);
+    return written;
+}
+
+
+static int reiserfsck_overwrite_file (struct item_head * comingih, char * item,
+				      struct path * path, int * pos_in_coming_item,
+				      int was_in_tree)
+{
+    __u32 unfm_ptr;
+    int written = 0;
+    int keep_free_space;
+    struct item_head * ih = PATH_PITEM_HEAD (path);
+
+
+    if (not_of_one_file (ih, &(comingih->ih_key)))
+	die ("reiserfsck_overwrite_file: found [%lu %lu], new item [%lu %lu]",
+	     ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
+	     comingih->ih_key.k_dir_id, comingih->ih_key.k_objectid);
+
+    if (is_direct_ih (ih)) {
+	unfm_ptr = 0;
+	if (is_indirect_ih (comingih)) {
+	    if (get_offset (&ih->ih_key) % fs->s_blocksize != 1)
+		die ("reiserfsck_overwrite_file: second part of tail can not be overwritten by indirect item");
+	    /* use pointer from coming indirect item */
+	    unfm_ptr = le32_to_cpu (*(__u32 *)(item + *pos_in_coming_item * UNFM_P_SIZE));
+	    if (!was_in_tree) {
+		if (still_bad_unfm_ptr_2 (unfm_ptr))
+		    die ("reiserfsck_overwrite_file: still bad ");
+	    }
+	}
+	/* */
+	direct2indirect2 (le32_to_cpu (unfm_ptr), path, keep_free_space = 1);
+    }
+    if (is_direct_ih (comingih))
+    {
+	written = overwrite_by_direct_item (comingih, item, path);
+    } else {
+	if (was_in_tree)
+	    die ("reiserfsck_overwrite_file: item we are going to overwrite with could not be in the tree yet");
+	written = overwrite_by_indirect_item (comingih, (__u32 *)item, path, pos_in_coming_item);
+    }
+
+    return written;
+}
+
+
+/*
+ */
+int reiserfsck_file_write (struct item_head * ih, char * item, int was_in_tree)
+{
+    struct path path;
+    struct item_head * path_ih;
+    int count, pos_in_coming_item;
+    int retval;
+    struct key key;
+    int written;
+
+
+    if (make_file_writeable (ih) == -1) {
+	/* write was not completed. Skip that item. Maybe it should be
+	   saved to lost_found */
+	fsck_progress ("reiserfsck_file_write: skip writing %H\n", ih);
+	return 0;
+    }
+
+    count = get_bytes_number (ih, fs->s_blocksize);
+    pos_in_coming_item = 0;
+
+    copy_key (&key, &(ih->ih_key));
+
+    while (count) {
+
+	retval = usearch_by_position (fs, &key, key_format (&key), &path);
+	
+	if (retval == DIRECTORY_FOUND)
+	    reiserfs_panic ("directory found %k", key);
+
+
+	if (retval == POSITION_FOUND) {
+	    written = reiserfsck_overwrite_file (ih, item, &path, &pos_in_coming_item, was_in_tree);
+            count -= written;
+	    set_offset (key_format (&key), &key, get_offset (&key) + written);
+	}
+	if (retval == FILE_NOT_FOUND) {
+	    written = create_first_item_of_file (ih, item, &path, &pos_in_coming_item, was_in_tree);
+	    count -= written;
+
+	    set_offset (key_format (&key), &key, get_offset (&key) + written );
+	}
+	if (retval == POSITION_NOT_FOUND) {
+	
+	    path_ih = PATH_PITEM_HEAD (&path);
+	
+	    if (must_there_be_a_hole (ih, &path) == 1)
+	    {
+		reiserfs_append_zero_unfm_ptr (&path);
+	    }else {
+		count -= reiserfsck_append_file (ih, item, pos_in_coming_item, &path, was_in_tree);
+		set_offset (key_format (&key), &key, get_offset (&key) + fs->s_blocksize);
+		pos_in_coming_item ++;
+	    }
+	}
+	if (count < 0)
+	    die ("reiserfsck_file_write: count < 0 (%d)", count);
+	pathrelse (&path);
+    }
+
+    return get_bytes_number (ih, fs->s_blocksize);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fsck/uobjectid.c b/fsck/uobjectid.c
new file mode 100644
index 0000000..ee9a07f
--- /dev/null
+++ b/fsck/uobjectid.c
@@ -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);
+}
diff --git a/fsck/ustree.c b/fsck/ustree.c
new file mode 100644
index 0000000..68e7f48
--- /dev/null
+++ b/fsck/ustree.c
@@ -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 ++;
+    }
+}
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..0de55ab
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1 @@
+noinst_HEADERS = io.h  misc.h  reiserfs_fs.h  reiserfs_lib.h
diff --git a/include/Makefile.in b/include/Makefile.in
new file mode 100644
index 0000000..813e729
--- /dev/null
+++ b/include/Makefile.in
@@ -0,0 +1,197 @@
+# 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@
+
+noinst_HEADERS = io.h  misc.h  reiserfs_fs.h  reiserfs_lib.h
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+HEADERS =  $(noinst_HEADERS)
+
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+all: all-redirect
+.SUFFIXES:
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps include/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+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 = include
+
+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
+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-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(HEADERS)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+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-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-tags clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  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: 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:
diff --git a/include/io.h b/include/io.h
new file mode 100644
index 0000000..3ffbbfe
--- /dev/null
+++ b/include/io.h
@@ -0,0 +1,57 @@
+struct buffer_head {
+  unsigned long b_blocknr;
+  unsigned short b_dev;
+  unsigned long b_size;
+  char * b_data;
+  unsigned long b_state;
+  unsigned int b_count;
+  unsigned int b_list ;
+  void (*b_end_io)(struct buffer_head *bh, int uptodate);
+
+  struct buffer_head * b_next;
+  struct buffer_head * b_prev;
+  struct buffer_head * b_hash_next;
+  struct buffer_head * b_hash_prev;
+};
+
+#define BH_Uptodate	0
+#define BH_Dirty	1
+#define BH_Lock		2
+
+
+#define buffer_uptodate(bh) test_bit(BH_Uptodate, &(bh)->b_state)
+#define buffer_dirty(bh) test_bit(BH_Dirty, &(bh)->b_state)
+#define buffer_locked(bh) test_bit(BH_Lock, &(bh)->b_state)
+#define buffer_clean(bh) !test_bit(BH_Dirty, &(bh)->b_state)
+#define mark_buffer_dirty(bh) set_bit(BH_Dirty, &(bh)->b_state)
+/*
+printf ("%s:%s:%u %p %p %p\n", 
+__FILE__, __FUNCTION__, __LINE__,
+	__builtin_return_address (0),
+	__builtin_return_address (1),
+	__builtin_return_address (2));
+*/
+
+#define mark_buffer_uptodate(bh,i) set_bit(BH_Uptodate, &(bh)->b_state)
+#define mark_buffer_clean(bh) clear_bit(BH_Dirty, &(bh)->b_state)
+
+
+void __wait_on_buffer (struct buffer_head * bh);
+struct buffer_head * getblk (int dev, int block, int size);
+struct buffer_head * reiserfs_getblk (int dev, int block, int size, int *repeat);
+
+struct buffer_head * find_buffer (int dev, int block, int size);
+struct buffer_head * get_hash_table(dev_t dev, int block, int size);
+struct buffer_head * bread (int dev, unsigned long block, size_t size);
+struct buffer_head * reiserfs_bread (int dev, int block, int size, int *repeat);
+int valid_offset (int fd, loff_t offset);
+int bwrite (struct buffer_head * bh);
+void brelse (struct buffer_head * bh);
+void bforget (struct buffer_head * bh);
+void check_and_free_buffer_mem (void);
+
+void flush_buffers (void);
+void free_buffers (void);
+
+loff_t reiserfs_llseek (unsigned int fd, loff_t offset, unsigned int origin);
+
diff --git a/include/misc.h b/include/misc.h
new file mode 100644
index 0000000..91df4db
--- /dev/null
+++ b/include/misc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 1996-2000 Hans Reiser
+ */
+
+/* nothing abount reiserfs here */
+
+void die (char * fmt, ...);
+void * getmem (int size);
+void freemem (void * p);
+void checkmem (char * p, int size);
+void * expandmem (void * p, int size, int by);
+int is_mounted (char * device_name);
+int is_mounted_read_only (char * device_name);
+void check_and_free_mem (void);
+char * kdevname (int dev);
+
+
+int set_bit (int nr, void * addr);
+int clear_bit (int nr, void * addr);
+int test_bit(int nr, const void * addr);
+int find_first_zero_bit (const void *vaddr, unsigned size);
+int find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset);
+
+void print_how_far (unsigned long * passed, unsigned long total, int inc, int quiet);
+void print_how_fast (unsigned long total, 
+		     unsigned long passed, int cursor_pos);
+int user_confirmed (char * q, char * yes);
+
+
+/*
+int test_and_set_bit (int nr, void * addr);
+int test_and_clear_bit (int nr, void * addr);
+*/
+inline __u32 cpu_to_le32 (__u32 val);
+inline __u32 le32_to_cpu (__u32 val);
+inline __u16 cpu_to_le16 (__u16 val);
+inline __u16 le16_to_cpu (__u16 val);
+inline __u64 cpu_to_le64 (__u64 val);
+inline __u64 le64_to_cpu (__u64 val);
+
+unsigned long count_blocks (char * filename, int blocksize, int fd);
+
diff --git a/include/reiserfs_fs.h b/include/reiserfs_fs.h
new file mode 100644
index 0000000..101a151
--- /dev/null
+++ b/include/reiserfs_fs.h
@@ -0,0 +1,1392 @@
+/*
+ * Copyright 1996-2001 by Hans Reiser, licensing governed by reiserfs/README
+ */
+  
+/*
+ *  include/linux/reiser_fs.h
+ *
+ *  Reiser File System constants and structures
+ *
+ */
+
+/* in reading the #defines, it may help to understand that they employ
+ the following abbreviations:
+
+B = Buffer
+I = Item header
+H = Height within the tree (should be changed to LEV)
+N = Number of the item in the node
+STAT = stat data
+DEH = Directory Entry Header
+EC = Entry Count
+E = Entry number
+UL = Unsigned Long
+BLKH = BLocK Header
+UNFM = UNForMatted node
+DC = Disk Child
+P = Path
+
+These #defines are named by concatenating these abbreviations, where
+first comes the arguments, and last comes the return value, of the
+macro.
+
+*/
+
+#include <limits.h>
+
+/* NEW_GET_NEW_BUFFER will try to allocate new blocks better */
+/*#define NEW_GET_NEW_BUFFER*/
+#define OLD_GET_NEW_BUFFER
+
+/* n must be power of 2 */
+#define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u))
+
+// to be ok for alpha and others we have to align structures to 8 byte
+// boundary.
+// FIXME: do not change 4 by anything else: there is code which relies on that
+#define ROUND_UP(x) _ROUND_UP(x,8LL)
+
+
+
+
+/***************************************************************************/
+/*                             SUPER BLOCK                                 */
+/***************************************************************************/
+
+#define UNSET_HASH 0 // read_super will guess about, what hash names
+                     // in directories were sorted with
+#define TEA_HASH  1
+#define YURA_HASH 2
+#define R5_HASH   3
+#define DEFAULT_HASH R5_HASH
+
+
+// can be used only to complete indirect to direct convertion and for
+// nothing else
+#define RESERVED_SPACE 20
+
+
+/* super block of prejournalled version */
+struct reiserfs_super_block_v0
+{
+    __u32 s_block_count;
+    __u32 s_free_blocks;
+    __u32 s_root_block;
+    __u16 s_blocksize;
+    __u16 s_oid_maxsize;
+    __u16 s_oid_cursize;
+    __u16 s_state;
+    char s_magic[16];
+    __u16 s_tree_height;
+    __u16 s_bmap_nr;
+    __u16 s_reserved;
+};
+
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1
+{
+    __u32 s_block_count;	/* blocks count         */
+    __u32 s_free_blocks;        /* free blocks count    */
+    __u32 s_root_block;         /* root block number    */
+    __u32 s_journal_block;      /* journal block number    */
+    __u32 s_journal_dev;        /* journal device number  */
+    __u32 s_orig_journal_size; 	/* size of the journal on FS creation.  used to make sure they don't overflow it */
+    __u32 s_journal_trans_max ; /* max number of blocks in a transaction.  */
+    __u32 s_journal_block_count ; /* total size of the journal. can change over time  */
+    __u32 s_journal_max_batch ;   /* max number of blocks to batch into a trans */
+    __u32 s_journal_max_commit_age ; /* in seconds, how old can an async commit be */
+    __u32 s_journal_max_trans_age ;  /* in seconds, how old can a transaction be */
+    __u16 s_blocksize;               /* block size           */
+    __u16 s_oid_maxsize;	/* max size of object id array, see get_objectid() commentary  */
+    __u16 s_oid_cursize;	/* current size of object id array */
+    __u16 s_state;              /* valid or error       */
+    char s_magic[10];           /* reiserfs magic string indicates that file system is reiserfs */
+    __u16 s_fsck_state;		/* when fsck managed to build the tree - it puts */
+    __u32 s_hash_function_code;	/* indicate, what hash fuction is being use to sort names in a directory*/
+    __u16 s_tree_height;        /* height of disk tree */
+    __u16 s_bmap_nr;            /* amount of bitmap blocks needed to address each block of file system */
+    __u16 s_version;
+};
+
+#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1)) /* 76 bytes */
+
+
+/* Structure of super block on disk, a version of which in RAM is often
+   accessed as s->u.reiserfs_sb.s_rs the version in RAM is part of a larger
+   structure containing fields never written to disk.  */
+struct reiserfs_super_block
+{
+    struct reiserfs_super_block_v1 s_v1;
+    char s_unused[128] ;			/* zero filled by mkreiserfs */
+};
+
+#define SB_SIZE (sizeof(struct reiserfs_super_block)) /* 204 bytes */
+
+
+typedef __u32 (*hashf_t) (const char *, int);
+
+
+
+
+
+
+#define SB_BUFFER_WITH_SB(s) ((s)->s_sbh)
+#define SB_AP_BITMAP(s) ((s)->s_ap_bitmap)
+
+#define SB_DISK_SUPER_BLOCK(s) (&((s)->s_rs->s_v1))
+#define SB_JOURNAL_BLOCK(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_journal_block))
+#define SB_JOURNAL_SIZE(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_orig_journal_size))
+#define SB_BLOCK_COUNT(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_block_count))
+#define SB_FREE_BLOCKS(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_free_blocks))
+#define SB_REISERFS_MAGIC(s) (SB_DISK_SUPER_BLOCK(s)->s_magic)
+#define SB_ROOT_BLOCK(s) le32_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_root_block))
+#define SB_TREE_HEIGHT(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_tree_height))
+#define SB_REISERFS_STATE(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_state))
+#define SB_VERSION(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_version))
+#define SB_BMAP_NR(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_bmap_nr))
+#define SB_OBJECTID_MAP_SIZE(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_oid_cursize))
+#define SB_OBJECTID_MAP_MAXSIZE(s) le16_to_cpu ((SB_DISK_SUPER_BLOCK(s)->s_oid_maxsize))
+
+#define rs_blocksize(rs) le16_to_cpu ((rs)->s_v1.s_blocksize)
+#define set_blocksize(rs,n) ((rs)->s_v1.s_blocksize = cpu_to_le16 (n))
+
+#define rs_block_count(rs) le32_to_cpu ((rs)->s_v1.s_block_count)
+#define set_block_count(rs,n) ((rs)->s_v1.s_block_count = cpu_to_le32 (n))
+
+#define rs_journal_dev(rs) le32_to_cpu ((rs)->s_v1.s_journal_dev)
+#define set_journal_dev(rs,n) ((rs)->s_v1.s_journal_dev = cpu_to_le32 (n))
+
+#define rs_journal_start(rs) le32_to_cpu ((rs)->s_v1.s_journal_block)
+#define set_journal_start(rs,n) ((rs)->s_v1.s_journal_block = cpu_to_le32 (n))
+
+#define rs_journal_size(rs) le32_to_cpu((rs)->s_v1.s_orig_journal_size)
+#define set_journal_size(rs,n) ((rs)->s_v1.s_orig_journal_size = cpu_to_le32(n))
+
+#define rs_root_block(rs) le32_to_cpu ((rs)->s_v1.s_root_block)
+#define set_root_block(rs,n) ((rs)->s_v1.s_root_block = cpu_to_le32 (n))
+
+#define rs_tree_height(rs) le16_to_cpu ((rs)->s_v1.s_tree_height)
+#define set_tree_height(rs,n) ((rs)->s_v1.s_tree_height = cpu_to_le16 (n))
+
+#define rs_free_blocks(rs) le32_to_cpu ((rs)->s_v1.s_free_blocks)
+#define set_free_blocks(rs,n) ((rs)->s_v1.s_free_blocks = cpu_to_le32 (n))
+
+#define rs_bmap_nr(rs) le16_to_cpu ((rs)->s_v1.s_bmap_nr)
+#define set_bmap_nr(rs,n) ((rs)->s_v1.s_bmap_nr = cpu_to_le16 (n))
+
+#define rs_state(rs) le16_to_cpu ((rs)->s_v1.s_state)
+#define set_state(rs,n) ((rs)->s_v1.s_state = cpu_to_le16 (n))
+
+#define rs_objectid_map_size(rs) (le16_to_cpu ((rs)->s_v1.s_oid_cursize))
+#define set_objectid_map_size(rs,n) ((rs)->s_v1.s_oid_cursize = cpu_to_le16 (n))
+
+#define rs_objectid_map_max_size(rs) (le16_to_cpu ((rs)->s_v1.s_oid_maxsize))
+#define set_objectid_map_max_size(rs,n) ((rs)->s_v1.s_oid_maxsize = cpu_to_le16 (n))
+
+#define rs_hash(rs) (le32_to_cpu ((rs)->s_v1.s_hash_function_code))
+#define set_hash(rs,n) ((rs)->s_v1.s_hash_function_code = cpu_to_le32 (n))
+
+#define rs_version(rs) (le16_to_cpu ((rs)->s_v1.s_version))
+#define set_version(rs,n) ((rs)->s_v1.s_version = cpu_to_le16 (n))
+
+#define TREE_IS_BUILT 0xfaaf
+#define fsck_state(rs) le16_to_cpu (((rs)->s_v1.s_fsck_state))
+#define set_fsck_state(rs,n) ((rs)->s_v1.s_fsck_state = cpu_to_le16 (n))
+
+
+#define sb_size(fs) (fs->s_version == REISERFS_VERSION_2) ? SB_SIZE : SB_SIZE_V1
+
+/* struct stat_data* access macros */
+/* v1 */
+#define sd_v1_mode(sd)                 (le16_to_cpu((sd)->sd_mode))
+#define set_sd_v1_mode(sd,n)           ((sd)->sd_mode = cpu_to_le16((n)))
+#define sd_v1_nlink(sd)                (le16_to_cpu((sd)->sd_nlink))
+#define set_sd_v1_nlink(sd,n)          ((sd)->sd_nlink = cpu_to_le16((n))) 
+#define sd_v1_uid(sd)                  (le16_to_cpu((sd)->sd_uid))
+#define set_sd_v1_uid(sd,n)            ((sd)->sd_uid = cpu_to_le16((n)))
+#define sd_v1_gid(sd)                  (le16_to_cpu((sd)->sd_gid))
+#define set_sd_v1_gid(sd,n)            ((sd)->sd_gid = cpu_to_le16((n)))
+#define sd_v1_size(sd)                 (le32_to_cpu((sd)->sd_size))
+#define set_sd_v1_size(sd,n)           ((sd)->sd_size = cpu_to_le32((n)))
+#define sd_v1_atime(sd)                (le32_to_cpu((sd)->sd_atime))
+#define set_sd_v1_atime(sd,n)          ((sd)->sd_atime = cpu_to_le32((n)))
+#define sd_v1_mtime(sd)                (le32_to_cpu((sd)->sd_mtime))
+#define set_sd_v1_mtime(sd,n)          ((sd)->sd_mtime = cpu_to_le32((n)))
+#define sd_v1_ctime(sd)                (le32_to_cpu((sd)->sd_ctime))
+#define set_sd_v1_ctime(sd,n)          ((sd)->sd_ctime = cpu_to_le32((n)))
+#define sd_v1_blocks(sd)               (le32_to_cpu((sd)->u.sd_blocks))
+#define set_sd_v1_blocks(sd,n)         ((sd)->u.sd_blocks = cpu_to_le32((n)))
+#define sd_v1_rdev(sd)                 (le32_to_cpu((sd)->u.sd_rdev))
+#define set_sd_v1_rdev(sd,n)           ((sd)->u.sd_rdev = cpu_to_le32((n)))
+#define sd_v1_first_direct_byte(sd)    (le32_to_cpu((sd)->sd_first_direct_byte))
+#define set_sd_v1_first_direct_byte(sd,n) \
+                                 ((sd)->sd_first_direct_byte = cpu_to_le32((n)))
+/* v2 */
+#define sd_v2_mode(sd)                 (le16_to_cpu((sd)->sd_mode))
+#define set_sd_v2_mode(sd,n)           ((sd)->sd_mode = cpu_to_le16((n)))
+#define sd_v2_reserved(sd)             (le16_to_cpu((sd)->sd_reserved))
+#define set_sd_v2_reserved(sd,n)       ((sd)->sd_reserved = cpu_to_le16((n)))
+#define sd_v2_nlink(sd)                (le32_to_cpu((sd)->sd_nlink))
+#define set_sd_v2_nlink(sd,n)          ((sd)->sd_nlink = cpu_to_le32((n))) 
+#define sd_v2_size(sd)                 (le64_to_cpu((sd)->sd_size))
+#define set_sd_v2_size(sd,n)           ((sd)->sd_size = cpu_to_le64((n)))
+#define sd_v2_uid(sd)                  (le32_to_cpu((sd)->sd_uid))
+#define set_sd_v2_uid(sd,n)            ((sd)->sd_uid = cpu_to_le32((n)))
+#define sd_v2_gid(sd)                  (le32_to_cpu((sd)->sd_gid))
+#define set_sd_v2_gid(sd,n)            ((sd)->sd_gid = cpu_to_le32((n)))
+#define sd_v2_atime(sd)                (le32_to_cpu((sd)->sd_atime))
+#define set_sd_v2_atime(sd,n)          ((sd)->sd_atime = cpu_to_le32((n)))
+#define sd_v2_mtime(sd)                (le32_to_cpu((sd)->sd_mtime))
+#define set_sd_v2_mtime(sd,n)          ((sd)->sd_mtime = cpu_to_le32((n)))
+#define sd_v2_ctime(sd)                (le32_to_cpu((sd)->sd_ctime))
+#define set_sd_v2_ctime(sd,n)          ((sd)->sd_ctime = cpu_to_le32((n)))
+#define sd_v2_blocks(sd)               (le32_to_cpu((sd)->sd_blocks))
+#define set_sd_v2_blocks(sd,n)         ((sd)->sd_blocks = cpu_to_le32((n)))
+#define sd_v2_rdev(sd)                 (le32_to_cpu((sd)->u.sd_rdev))
+#define set_sd_v2_rdev(sd,n)           ((sd)->u.sd_rdev = cpu_to_le32((n)))
+
+
+/* ReiserFS leaves the first 64k unused, so that partition labels have enough
+   space.  If someone wants to write a fancy bootloader that needs more than
+   64k, let us know, and this will be increased in size.  This number must be
+   larger than than the largest block size on any platform, or code will
+   break.  -Hans */
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+
+/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+
+/* prejournalled reiserfs had signature in the other place in super block */
+#define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20
+
+/* f_type of struct statfs will be set at this value by statfs(2) */
+#define REISERFS_SUPER_MAGIC 0x52654973
+
+/* various reiserfs signatures. We have 2 so far. ReIsErFs for the system
+   which is not able to deal with long files and ReIsEr2Fs for another. Those
+   signature should be looked for at the 64-th and at the 8-th 1k block of the
+   device */
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+
+
+
+/* values for s_version field of struct reiserfs_super_block */
+#define REISERFS_VERSION_1 0 /* old (short) super block, all keys in old
+                                format */
+#define REISERFS_VERSION_2 2 /* new super block, keys may be in new format */
+
+/*
+ * values for s_state field
+ */
+#define REISERFS_VALID_FS    1
+#define REISERFS_ERROR_FS    2
+
+
+
+/***************************************************************************/
+/*                             JOURNAL                                     */
+/***************************************************************************/
+
+#define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick.  magic string to find desc blocks in the journal */
+#define JOURNAL_TRANS_MAX 1024   /* biggest possible single transaction, don't change for now (8/3/99) */
+
+/* journal.c see journal.c for all the comments here */
+
+#define JOURNAL_TRANS_HALF 1018   /* must be correct to keep the desc and commit structs at 4k */
+
+/* first block written in a commit.  BUG, not 64bit safe */
+struct reiserfs_journal_desc {
+    __u32 j_trans_id ;			/* id of commit */
+    __u32 j_len ;			/* length of commit. len +1 is the commit block */
+    __u32 j_mount_id ;				/* mount id of this trans*/
+    __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */
+    char j_magic[12] ;
+} ;
+
+/* last block written in a commit BUG, not 64bit safe */
+struct reiserfs_journal_commit {
+    __u32 j_trans_id ;			/* must match j_trans_id from the desc block */
+    __u32 j_len ;			/* ditto */
+    __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */
+    char j_digest[16] ;			/* md5 sum of all the blocks involved, including desc and commit. not used, kill it */
+} ;
+
+/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
+** last fully flushed transaction.  fully flushed means all the log blocks and all the real blocks are on disk,
+** and this transaction does not need to be replayed.
+*/
+struct reiserfs_journal_header {
+    __u32 j_last_flush_trans_id ;		/* id of last fully flushed transaction */
+    __u32 j_first_unflushed_offset ;      /* offset in the log of where to start replay after a crash */
+    __u32 j_mount_id ;
+} ;
+
+
+#define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */
+
+
+
+#define bh_desc(bh) ((struct reiserfs_journal_desc *)((bh)->b_data))
+#define bh_commit(bh) ((struct reiserfs_journal_commit *)((bh)->b_data))
+
+
+/***************************************************************************/
+/*                       KEY & ITEM HEAD                                   */
+/***************************************************************************/
+
+struct offset_v1 {
+    __u32 k_offset;
+    __u32 k_uniqueness;
+} __attribute__ ((__packed__));
+
+struct offset_v2 {
+    __u64 k_offset:60;
+    __u64 k_type: 4; // TYPE_STAT_DATA | TYPE_INDIRECT | TYPE_DIRECT | TYPE_DIRENTRY
+} __attribute__ ((__packed__));
+
+
+/* Key of the object drop determines its location in the S+tree, and is
+   composed of 4 components */
+struct key {
+    __u32 k_dir_id;    /* packing locality: by default parent directory object
+                          id */
+    __u32 k_objectid;  /* object identifier */
+    union {
+	struct offset_v1 k_offset_v1;
+	struct offset_v2 k_offset_v2;
+    } u;
+} __attribute__ ((__packed__));
+
+#define key_dir_id(key)                 (le32_to_cpu((key)->k_dir_id))
+#define set_key_dir_id(key,n)           ((key)->k_dir_id = cpu_to_le32((n)))
+#define key_objectid(key)               (le32_to_cpu((key)->k_objectid))
+#define set_key_objectid(key,n)         ((key)->k_objectid = cpu_to_le32((n)))
+
+
+#define KEY_SIZE (sizeof(struct key))
+#define SHORT_KEY_SIZE 8
+
+
+// values for k_uniqueness field of the struct key
+#define V1_SD_UNIQUENESS 0
+#define V1_DIRENTRY_UNIQUENESS 500
+#define DIRENTRY_UNIQUENESS 500
+#define V1_DIRECT_UNIQUENESS 0xffffffff
+#define V1_INDIRECT_UNIQUENESS 0xfffffffe
+#define V1_UNKNOWN_UNIQUENESS 555
+
+// values for k_type field of the struct key
+#define TYPE_STAT_DATA 0
+#define TYPE_INDIRECT 1
+#define TYPE_DIRECT 2
+#define TYPE_DIRENTRY 3 
+
+#define TYPE_UNKNOWN 15
+
+
+#define KEY_FORMAT_1 0
+#define KEY_FORMAT_2 1
+
+
+
+
+
+
+ /* Our function for comparing keys can compare keys of different
+    lengths.  It takes as a parameter the length of the keys it is to
+    compare.  These defines are used in determining what is to be
+    passed to it as that parameter. */
+#define REISERFS_FULL_KEY_LEN     4
+
+#define REISERFS_SHORT_KEY_LEN    2
+
+
+/* Everything in the filesystem is stored as a set of items.  The item head
+   contains the key of the item, its free space (for indirect items) and
+   specifies the location of the item itself within the block.  */
+
+struct item_head
+{
+    struct key ih_key; 	/* Everything in the tree is found by searching for it based on its key.*/
+
+    union {
+	__u16 ih_free_space1; /* The free space in the last unformatted node of
+				an indirect item if this is an indirect item.
+				This equals 0xFFFF iff this is a direct item
+				or stat data item. Note that the key, not this
+				field, is used to determine the item type, and
+				thus which field this union contains. */
+	__u16 ih_entry_count; /* Iff this is a directory item, this field
+				 equals the number of directory entries in the
+				 directory item. */
+    } u;
+    __u16 ih_item_len;           /* total size of the item body */
+    __u16 ih_item_location;      /* an offset to the item body within the
+                                    block */
+    struct {
+	__u16 key_format : 12; /* KEY_FORMAT_1 or KEY_FORMAT_2. This is not
+				     necessary, but we have space, let use it */
+	__u16 fsck_need : 4;   /* fsck set here its flag (reachable/unreachable) */
+    } ih_format;
+} __attribute__ ((__packed__));
+
+
+/* size of item header     */
+#define IH_SIZE (sizeof(struct item_head))
+
+
+#define ih_item_len(ih) (le16_to_cpu((ih)->ih_item_len))
+#define set_ih_item_len(ih,x) ((ih)->ih_item_len = cpu_to_le16 (x))
+
+#define ih_location(ih) (le16_to_cpu ((ih)->ih_item_location))
+#define set_ih_location(ih,x) ((ih)->ih_item_location = cpu_to_le16 (x))
+
+#define ih_key_format(ih) (le16_to_cpu ((ih)->ih_format.key_format))
+#define set_key_format(ih,x) ((ih)->ih_format.key_format = cpu_to_le16 (x))
+
+
+// FIXME: ih_free_space does not appear to be very important, but we
+// have to make sure that earlier version have no trouble when
+// ih_free_space is 0
+#define ih_free_space(ih) 0 // le16_to_cpu (ih->u.ih_free_space)
+#define set_free_space(ih,val) ((ih)->u.ih_free_space1 = 0)//val)
+
+//#define get_ih_free_space(ih) 0 //(ih_key_format (ih) == KEY_FORMAT ? 0 : ih_free_space (ih))
+//#define set_ih_free_space(ih,val) // (ih_free_space (ih) = (ih_version (ih) == ITEM_VERSION_2 ? 0 : val))
+
+#define ih_entry_count(ih) (le16_to_cpu ((ih)->u.ih_entry_count))
+//#define set_ih_free_space(ih,x) ((ih)->u.ih_free_space = cpu_to_le16(x))
+#define set_entry_count(ih,x) ((ih)->u.ih_entry_count = cpu_to_le16(x))
+
+#define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \
+    ( ! not_of_one_file(p_s_ih, p_s_key) && \
+          I_OFF_BYTE_IN_ITEM(p_s_ih, get_offset (p_s_key), n_blocksize) )
+
+#define IH_Bad 0
+#define IH_Unreachable 1
+
+/* Bad item flag is set temporary by recover_leaf */
+#define mark_ih_bad(ih) ((ih)->ih_format.fsck_need |= IH_Bad)
+#define ih_bad(ih) test_bit (IH_Bad, &((ih)->ih_format.fsck_need))
+#define unmark_item_bad(ih) clear_bit (IH_Bad,  &((ih)->ih_format.fsck_need))
+
+/* Unreachable bit is set on tree rebuilding and is cleared in semantic pass */
+#define mark_ih_ok(ih) ((ih)->ih_format.fsck_need = 0)
+#define ih_reachable(ih) (!(ih)->ih_format.fsck_need & IH_Unreachable)
+#define mark_ih_unreachable(ih) ((ih)->ih_format.fsck_need |= IH_Unreachable)
+
+
+
+/* maximal length of item */ 
+#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
+#define MIN_ITEM_LEN 1
+
+
+/* object identifier for root dir */
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+/*extern struct key root_key;*/
+
+
+/* 
+ * Picture represents a leaf of the S+tree
+ *  ______________________________________________________
+ * |      |  Array of     |                   |           |
+ * |Block |  Object-Item  |      F r e e      |  Objects- |
+ * | head |  Headers      |     S p a c e     |   Items   |
+ * |______|_______________|___________________|___________|
+ */
+
+/* Header of a disk block.  More precisely, header of a formatted leaf
+   or internal node, and not the header of an unformatted node. */
+struct block_head {       
+    __u16 blk_level;        /* Level of a block in the tree. */
+    __u16 blk_nr_item;      /* Number of keys/items in a block. */
+    __u16 blk_free_space;   /* Block free space in bytes. */
+	__u16 blk_reserved;
+    struct key not_used; /* Right delimiting key for this block
+			    (supported for leaf level nodes only) */
+};
+
+#define BLKH_SIZE (sizeof(struct block_head))
+
+/*
+ * values for blk_type field
+ */
+
+#define FREE_LEVEL        0 /* Node of this level is out of the tree. */
+
+#define DISK_LEAF_NODE_LEVEL  1 /* Leaf node level.                       */
+
+
+#define is_leaf_block_head(buf) (le16_to_cpu (((struct block_head *)(buf))->blk_level) == DISK_LEAF_NODE_LEVEL)
+#define is_internal_block_head(buf) \
+((le16_to_cpu (((struct block_head *)(buf))->blk_level) > DISK_LEAF_NODE_LEVEL) &&\
+ (le16_to_cpu (((struct block_head *)(buf))->blk_level) <= MAX_HEIGHT))
+
+
+/* Given the buffer head of a formatted node, resolve to the block head of that node. */
+#define B_BLK_HEAD(p_s_bh)  ((struct block_head *)((p_s_bh)->b_data))
+
+/* Number of items that are in buffer. */
+#define node_item_number(bh)	(le16_to_cpu ( B_BLK_HEAD(bh)->blk_nr_item ))
+#define node_pointer_number(bh) (node_item_number(bh) + 1)
+#define node_level(bh)		(le16_to_cpu ( B_BLK_HEAD(bh)->blk_level ))
+#define node_free_space(bh)	(le16_to_cpu ( B_BLK_HEAD(bh)->blk_free_space ))
+
+#define set_node_item_number(bh,n) (B_BLK_HEAD(bh)->blk_nr_item = cpu_to_le16 (n))
+#define set_node_free_space(bh,n) (B_BLK_HEAD(bh)->blk_free_space = cpu_to_le16 (n))
+#define set_node_level(bh,n) (B_BLK_HEAD(bh)->blk_level = cpu_to_le16 (n))
+#define set_leaf_node_level(bh) set_node_level (bh, DISK_LEAF_NODE_LEVEL)
+
+#define B_NR_ITEMS(bh)		node_item_number(bh)
+#define B_LEVEL(bh)		node_level(bh)
+#define B_FREE_SPACE(bh)	node_free_space(bh)
+
+
+#define is_leaf_node(bh) is_leaf_block_head ((bh)->b_data)
+#define is_internal_node(bh) is_internal_block_head ((bh)->b_data)
+
+
+
+
+
+
+/***************************************************************************/
+/*                             STAT DATA                                   */
+/***************************************************************************/
+
+/* Stat Data on disk (reiserfs version of UFS disk inode minus the address blocks) */
+
+/* The sense of adding union to stat data is to keep a value of real number of
+   blocks used by file.  The necessity of adding such information is caused by
+   existing of files with holes.  Reiserfs should keep number of used blocks
+   for file, but not calculate it from file size (that is not correct for
+   holed files). Thus we have to add additional information to stat data.
+   When we have a device special file, there is no need to get number of used
+   blocks for them, and, accordingly, we doesn't need to keep major and minor
+   numbers for regular files, which might have holes. So this field is being
+   overloaded.  */
+
+struct stat_data_v1 {
+    __u16 sd_mode;	/* file type, permissions */
+    __u16 sd_nlink;	/* number of hard links */
+    __u16 sd_uid;		/* owner */
+    __u16 sd_gid;		/* group */
+    __u32 sd_size;	/* file size */
+    __u32 sd_atime;	/* time of last access */
+    __u32 sd_mtime;	/* time file was last modified  */
+    __u32 sd_ctime;	/* time inode (stat data) was last changed (except
+                           changes to sd_atime and sd_mtime) */
+    union {
+	__u32 sd_rdev;
+	__u32 sd_blocks;	/* number of blocks file uses */
+    } u;
+    __u32 sd_first_direct_byte; /* first byte of file which is stored
+				   in a direct item: except that if it
+				   equals 1 it is a symlink and if it
+				   equals MAX_KEY_OFFSET there is no
+				   direct item.  The existence of this
+				   field really grates on me. Let's
+				   replace it with a macro based on
+				   sd_size and our tail suppression
+				   policy.  Someday.  -Hans */
+} __attribute__ ((__packed__));
+#define SD_V1_SIZE (sizeof(struct stat_data_v1))
+
+
+/* this is used to check sd_size of stat data v1 */
+#define MAX_FILE_SIZE_V1 0x7fffffff
+
+
+// sd_first_direct_byte is set to this when there are no direct items in a
+// file
+#define NO_BYTES_IN_DIRECT_ITEM 0xffffffff
+
+
+/* Stat Data on disk (reiserfs version of UFS disk inode minus the
+   address blocks) */
+struct stat_data {
+    __u16 sd_mode;	/* file type, permissions */
+    __u16 sd_reserved;
+    __u32 sd_nlink;	/* 32 bit nlink! */
+    __u64 sd_size;	/* 64 bit size!*/
+    __u32 sd_uid;	/* 32 bit uid! */
+    __u32 sd_gid;	/* 32 bit gid! */
+    __u32 sd_atime;	/* time of last access */
+    __u32 sd_mtime;	/* time file was last modified  */
+    __u32 sd_ctime;	/* time inode (stat data) was last changed (except
+                           changes to sd_atime and sd_mtime) */
+    __u32 sd_blocks;
+    union {
+	__u32 sd_rdev;
+      //__u32 sd_first_direct_byte; 
+      /* first byte of file which is stored in a direct item: except that if
+	 it equals 1 it is a symlink and if it equals ~(__u32)0 there is no
+	 direct item.  The existence of this field really grates on me. Let's
+	 replace it with a macro based on sd_size and our tail suppression
+	 policy? */
+  } u;
+} __attribute__ ((__packed__));
+//
+// this is 44 bytes long
+//
+#define SD_SIZE (sizeof(struct stat_data))
+
+// there are two ways: to check length of item or ih_version field
+// (for old stat data it is set to 0 (KEY_FORMAT_1))
+#define stat_data_v1(ih) (ih_key_format (ih) == KEY_FORMAT_1)
+
+/* this is used to check sd_size of stat data v2: max offset which can
+   be reached with a key of format 2 is 60 bits */
+#define MAX_FILE_SIZE_V2 0xfffffffffffffffLL
+
+
+/***************************************************************************/
+/*                      DIRECTORY STRUCTURE                                */
+/***************************************************************************/
+/* 
+   Picture represents the structure of directory items
+   ________________________________________________
+   |  Array of     |   |     |        |       |   |
+   | directory     |N-1| N-2 | ....   |   1st |0th|
+   | entry headers |   |     |        |       |   |
+   |_______________|___|_____|________|_______|___|
+                    <----   directory entries         ------>
+
+ First directory item has k_offset component 1. We store "." and ".."
+ in one item, always, we never split "." and ".." into differing
+ items.  This makes, among other things, the code for removing
+ directories simpler. */
+#define SD_OFFSET  0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+
+/* */
+#define FIRST_ITEM_OFFSET 1
+
+/*
+   Q: How to get key of object pointed to by entry from entry?  
+
+   A: Each directory entry has its header. This header has deh_dir_id
+   and deh_objectid fields, those are key of object, entry points to */
+
+/* NOT IMPLEMENTED:   
+   Directory will someday contain stat data of object */
+
+
+
+struct reiserfs_de_head
+{
+  __u32 deh_offset;  /* third component of the directory entry key */
+  __u32 deh_dir_id;  /* objectid of the parent directory of the
+			object, that is referenced by directory entry */
+  __u32 deh_objectid;/* objectid of the object, that is referenced by
+                        directory entry */
+  __u16 deh_location;/* offset of name in the whole item */
+  __u16 deh_state;   /* whether 1) entry contains stat data (for
+			future), and 2) whether entry is hidden
+			(unlinked) */
+} __attribute__ ((__packed__));
+#define DEH_SIZE sizeof(struct reiserfs_de_head)
+
+
+#define deh_offset(deh) (le32_to_cpu ((deh)->deh_offset))
+#define deh_dir_id(deh) (le32_to_cpu ((deh)->deh_dir_id))
+#define deh_objectid(deh) (le32_to_cpu ((deh)->deh_objectid))
+#define deh_location(deh) (le16_to_cpu ((deh)->deh_location))
+#define deh_state(deh) (le16_to_cpu ((deh)->deh_state))
+
+/* empty directory contains two entries "." and ".." and their headers */
+#define EMPTY_DIR_SIZE \
+(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen ("..")))
+
+/* old format directories have this size when empty */
+#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
+
+#define DEH_Statdata 0			/* not used now */
+#define DEH_Visible 2
+
+#define DEH_Bad_offset 4 /* fsck marks entries to be deleted with this flag */
+#define DEH_Bad_location 5
+
+#define mark_de_with_sd(deh)        set_bit (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_without_sd(deh)     clear_bit (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_visible(deh)	    set_bit (DEH_Visible, &((deh)->deh_state))
+#define mark_de_hidden(deh)	    clear_bit (DEH_Visible, &((deh)->deh_state))
+#define mark_de_lost_found(deh)	    set_bit (DEH_Lost_Found, &((deh)->deh_state))
+#define unmark_de_lost_found(deh)   clear_bit (DEH_Lost_Found, &((deh)->deh_state))
+
+#define de_with_sd(deh)		    test_bit (DEH_Statdata, &((deh)->deh_state))
+#define de_visible(deh)	    	    test_bit (DEH_Visible, &((deh)->deh_state))
+#define de_hidden(deh)	    	    !test_bit (DEH_Visible, &((deh)->deh_state))
+
+/* Bad means "hashed unproperly or/and invalid location" */
+#define de_bad_location(deh) test_bit (DEH_Bad_location, &((deh)->deh_state))
+#define mark_de_bad_location(deh) set_bit (DEH_Bad_location, &((deh)->deh_state))
+#define mark_de_good_location(deh) clear_bit (DEH_Bad_location, &((deh)->deh_state))
+
+#define de_bad_offset(deh) test_bit (DEH_Bad_offset, &((deh)->deh_state))
+#define mark_de_bad_offset(deh) set_bit (DEH_Bad_offset, &((deh)->deh_state))
+
+#define de_bad(deh) (de_bad_location(deh) || de_bad_offset(deh))
+
+
+/* for directories st_blocks is number of 512 byte units which fit into dir
+   size round up to blocksize */
+#define dir_size2st_blocks(blocksize,size) \
+((((size) + (blocksize) - 1) / (blocksize)) * ((blocksize) / 512))
+
+
+/* array of the entry headers */
+#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
+
+#define REISERFS_MAX_NAME_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE - DEH_SIZE)	/* -SD_SIZE when entry will contain stat data */
+
+/* this structure is used for operations on directory entries. It is
+   not a disk structure. */
+/* When reiserfs_find_entry or search_by_entry_key find directory
+   entry, they return filled reiserfs_dir_entry structure */
+struct reiserfs_dir_entry
+{
+    struct buffer_head * de_bh;
+    int de_item_num;
+    struct item_head * de_ih;
+    int de_entry_num;
+    struct reiserfs_de_head * de_deh;
+    int de_entrylen;
+    int de_namelen;
+    char * de_name;
+    char * de_gen_number_bit_string;
+
+    __u32 de_dir_id;
+    __u32 de_objectid;
+
+    struct key de_entry_key;
+};
+
+
+/* hash value occupies 24 bits starting from 7 up to 30 */
+#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80)
+/* generation number occupies 7 bits starting from 0 up to 6 */
+#define GET_GENERATION_NUMBER(offset) ((offset) & 0x0000007f)
+
+
+/*
+ * Picture represents an internal node of the reiserfs tree
+ *  ______________________________________________________
+ * |      |  Array of     |  Array of         |  Free     |
+ * |block |    keys       |  pointers         | space     |
+ * | head |      N        |      N+1          |           |
+ * |______|_______________|___________________|___________|
+ */
+
+/***************************************************************************/
+/*                      DISK CHILD                                         */
+/***************************************************************************/
+/* Disk child pointer: The pointer from an internal node of the tree
+   to a node that is on disk. */
+struct disk_child {
+    __u32 dc_block_number;              /* Disk child's block number. */
+    __u16 dc_size;		            /* Disk child's used space.   */
+    __u16 dc_reserved;
+};
+
+#define DC_SIZE (sizeof(struct disk_child))
+
+/* Get disk child by buffer header and position in the tree node. */
+#define B_N_CHILD(p_s_bh,n_pos)  ((struct disk_child *)\
+            ((p_s_bh)->b_data + BLKH_SIZE + B_NR_ITEMS(p_s_bh) \
+            * KEY_SIZE + DC_SIZE * (n_pos)))
+
+/* Get disk child number by buffer header and position in the tree node. */
+#define B_N_CHILD_NUM(p_s_bh,n_pos) (B_N_CHILD(p_s_bh,n_pos)->dc_block_number)
+#define child_block_number(bh,pos) le32_to_cpu (B_N_CHILD(bh,pos)->dc_block_number)
+#define child_block_size(bh,pos) le16_to_cpu (B_N_CHILD(bh,pos)->dc_size)
+
+#define set_dc_block_number(bh,pos,block) (B_N_CHILD (bh, pos)->dc_block_number = cpu_to_le32 (block))
+
+ /* maximal value of field child_size in structure disk_child */ 
+ /* child size is the combined size of all items and their headers */
+#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
+
+/* amount of used space in buffer (not including block head) */
+#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur)))
+
+/* max and min number of keys in internal node */
+#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) )
+#define MIN_NR_KEY(bh)    (MAX_NR_KEY(bh)/2)
+
+
+/***************************************************************************/
+/*                      PATH STRUCTURES AND DEFINES                        */
+/***************************************************************************/
+
+/* Search_by_key fills up the path from the root to the leaf as it
+   descends the tree looking for the key.  It uses reiserfs_bread to
+   try to find buffers in the cache given their block number.  If it
+   does not find them in the cache it reads them from disk.  For each
+   node search_by_key finds using reiserfs_bread it then uses
+   bin_search to look through that node.  bin_search will find the
+   position of the block_number of the next node if it is looking
+   through an internal node.  If it is looking through a leaf node
+   bin_search will find the position of the item which has key either
+   equal to given key, or which is the maximal key less than the given
+   key. */
+
+struct path_element  {
+    struct buffer_head * pe_buffer; /* Pointer to the buffer at the path in
+				       the tree. */
+    int pe_position;  /* Position in the tree node which is placed in the
+			 buffer above. */
+};
+
+
+#define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
+#define EXTENDED_MAX_HEIGHT         7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
+#define FIRST_PATH_ELEMENT_OFFSET   2 /* Must be equal to at least 2. */
+
+#define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
+#define MAX_FEB_SIZE 6   /* this MUST be MAX_HEIGHT + 1. See about FEB below */
+
+
+
+/* We need to keep track of who the ancestors of nodes are.  When we
+   perform a search we record which nodes were visited while
+   descending the tree looking for the node we searched for. This list
+   of nodes is called the path.  This information is used while
+   performing balancing.  Note that this path information may become
+   invalid, and this means we must check it when using it to see if it
+   is still valid. You'll need to read search_by_key and the comments
+   in it, especially about decrement_counters_in_path(), to understand
+   this structure. */
+struct path {
+  int                   path_length;                      	/* Length of the array above.   */
+  struct  path_element  path_elements[EXTENDED_MAX_HEIGHT];	/* Array of the path elements.  */
+  int			pos_in_item;
+};
+
+#define INITIALIZE_PATH(var) \
+struct path var = {ILLEGAL_PATH_ELEMENT_OFFSET, }
+
+/* Get path element by path and path position. */
+#define PATH_OFFSET_PELEMENT(p_s_path,n_offset)  ((p_s_path)->path_elements +(n_offset))
+
+/* Get buffer header at the path by path and path position. */
+#define PATH_OFFSET_PBUFFER(p_s_path,n_offset)   (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_buffer)
+
+/* Get position in the element at the path by path and path position. */
+#define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position)
+
+
+#define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length))
+#define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length))
+
+
+#define PATH_PITEM_HEAD(p_s_path)    B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path))
+
+/* in do_balance leaf has h == 0 in contrast with path structure,
+   where root has level == 0. That is why we need these defines */
+#define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h))	/* tb->S[h] */
+#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1)			/* tb->F[h] or tb->S[0]->b_parent */
+#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))	
+#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1)		/* tb->S[h]->b_item_order */
+
+#define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h))
+
+#define get_bh(path) PATH_PLAST_BUFFER(path)
+#define get_ih(path) PATH_PITEM_HEAD(path)
+#define get_item_pos(path) PATH_LAST_POSITION(path)
+#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path)))
+#define item_moved(ih,path) comp_items(ih, path)
+#define path_changed(ih,path) comp_items (ih, path)
+
+
+/***************************************************************************/
+/*                       MISC                                              */
+/***************************************************************************/
+
+
+// search_by_key (and clones) and fix_nodes error code
+#define CARRY_ON          	0
+#define SCHEDULE_OCCURRED  	1
+#define PATH_INCORRECT    	2
+#define IO_ERROR		3
+
+#define NO_DISK_SPACE           4
+#define NO_BALANCING_NEEDED     5
+#define ITEM_FOUND              6
+#define ITEM_NOT_FOUND          7
+#define POSITION_FOUND          8
+#define POSITION_NOT_FOUND      9
+#define GOTO_PREVIOUS_ITEM      10
+#define POSITION_FOUND_INVISIBLE 11
+#define FILE_NOT_FOUND          12
+
+// used by fsck
+#define DIRECTORY_NOT_FOUND     13 
+#define REGULAR_FILE_FOUND     14
+#define DIRECTORY_FOUND        15
+
+
+
+typedef unsigned long b_blocknr_t;
+typedef __u32 unp_t;
+
+struct unfm_nodeinfo {
+  __u32	 unfm_nodenum;
+  unsigned short unfm_freespace;
+};
+
+/* when reiserfs_file_write is called with a byte count >= MIN_PACK_ON_CLOSE,
+** it sets the inode to pack on close, and when extending the file, will only
+** use unformatted nodes.
+**
+** This is a big speed up for the journal, which is badly hurt by direct->indirect
+** conversions (they must be logged).
+*/
+#define MIN_PACK_ON_CLOSE		512
+
+
+  /* This is an aggressive tail suppression policy, I am hoping it
+     improves our benchmarks. The principle behind it is that
+     percentage space saving is what matters, not absolute space
+     saving.  This is non-intuitive, but it helps to understand it if
+     you consider that the cost to access 4 blocks is not much more
+     than the cost to access 1 block, if you have to do a seek and
+     rotate.  A tail risks a non-linear disk access that is
+     significant as a percentage of total time cost for a 4 block file
+     and saves an amount of space that is less significant as a
+     percentage of space, or so goes the hypothesis.  -Hans */
+#define STORE_TAIL_IN_UNFM(n_file_size,n_tail_size,n_block_size) \
+\
+( ((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
+  ( (n_file_size) >= (n_block_size) * 4 ) || \
+   ( ( (n_file_size) >= (n_block_size) * 3 ) && \
+   ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \
+   ( ( (n_file_size) >= (n_block_size) * 2 ) && \
+   ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \
+   ( ( (n_file_size) >= (n_block_size) ) && \
+   ( (n_tail_size) >=   (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) )
+
+
+#define first_direct_byte(inode) ((inode)->u.reiserfs_i.i_first_direct_byte)
+
+#define has_tail(inode) (first_direct_byte(inode) != NO_BYTES_IN_DIRECT_ITEM)
+
+#define tail_offset(inode) (first_direct_byte(inode) - 1)
+
+// mark file as not having tail stored in direct item
+#define file_has_no_tail(inode) (first_direct_byte (inode) = NO_BYTES_IN_DIRECT_ITEM)
+
+#define block_size(inode) ((inode)->i_sb->s_blocksize)
+#define file_size(inode) ((inode)->i_size)
+#define tail_size(inode) (file_size (inode) & (block_size (inode) - 1))
+
+#define tail_has_to_be_packed(inode) (!dont_have_tails ((inode)->i_sb) &&\
+!STORE_TAIL_IN_UNFM(file_size (inode), tail_size(inode), block_size (inode)))
+
+
+/* Size of pointer to the unformatted node. */
+#define UNFM_P_SIZE (sizeof(__u32))
+
+#define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
+#define inode_key_format(inode) ((inode)->u.reiserfs_i.i_key_format) 
+
+//#define MAX_UL_INT ULONG_MAX
+//#define MAX_INT    INT_MAX
+//#define MAX_US_INT  USHRT_MAX
+
+#define MAX_KEY1_OFFSET	 INT_MAX
+#define MAX_KEY2_OFFSET  0xfffffffffffffffLL
+
+
+
+#define MAX_KEY_UNIQUENESS	UINT_MAX
+#define MAX_KEY_OBJECTID	UINT_MAX
+
+#define MAX_B_NUM  UINT_MAX
+#define MAX_FC_NUM USHRT_MAX
+
+
+/* the purpose is to detect overflow of an unsigned short */
+#define REISERFS_LINK_MAX (USHRT_MAX - 1000)
+
+
+/* The following defines are used in reiserfs_insert_item and reiserfs_append_item  */
+#define REISERFS_KERNEL_MEM		0	/* reiserfs kernel memory mode	*/
+#define REISERFS_USER_MEM		1	/* reiserfs user memory mode		*/
+
+
+/***************************************************************************/
+/*                  FIXATE NODES                                           */
+/***************************************************************************/
+
+#define VI_TYPE_STAT_DATA 1
+#define VI_TYPE_DIRECT 2
+#define VI_TYPE_INDIRECT 4
+#define VI_TYPE_DIRECTORY 8
+#define VI_TYPE_FIRST_DIRECTORY_ITEM 16
+#define VI_TYPE_INSERTED_DIRECTORY_ITEM 32
+
+#define VI_TYPE_LEFT_MERGEABLE 64
+#define VI_TYPE_RIGHT_MERGEABLE 128
+
+/* To make any changes in the tree we always first find node, that contains
+   item to be changed/deleted or place to insert a new item. We call this node
+   S. To do balancing we need to decide what we will shift to left/right
+   neighbor, or to a new node, where new item will be etc. To make this
+   analysis simpler we build virtual node. Virtual node is an array of items,
+   that will replace items of node S. (For instance if we are going to delete
+   an item, virtual node does not contain it). Virtual node keeps information
+   about item sizes and types, mergeability of first and last items, sizes of
+   all entries in directory item. We use this array of items when calculating
+   what we can shift to neighbors and how many nodes we have to have if we do
+   not any shiftings, if we shift to left/right neighbor or to both. */
+struct virtual_item
+{
+    unsigned short vi_type;	/* item type, mergeability */
+    unsigned short vi_item_len; /* length of item that it will have after balancing */
+  
+    short vi_entry_count;	/* number of entries in directory item
+				   (including the new one if any, or excluding
+				   entry if it must be cut) */
+    unsigned short * vi_entry_sizes; /* array of entry lengths for directory item */
+};
+
+struct virtual_node
+{
+    char * vn_free_ptr;		/* this is a pointer to the free space in the buffer */
+    unsigned short vn_nr_item;	/* number of items in virtual node */
+    short vn_size;        	/* size of node , that node would have if it has unlimited size and no balancing is performed */
+    short vn_mode;		/* mode of balancing (paste, insert, delete, cut) */
+    short vn_affected_item_num; 
+    short vn_pos_in_item;
+    struct item_head * vn_ins_ih;	/* item header of inserted item, 0 for other modes */
+    struct virtual_item * vn_vi;	/* array of items (including a new one, excluding item to be deleted) */
+};
+
+
+/***************************************************************************/
+/*                  TREE BALANCE                                           */
+/***************************************************************************/
+
+/* This temporary structure is used in tree balance algorithms, and
+   constructed as we go to the extent that its various parts are needed.  It
+   contains arrays of nodes that can potentially be involved in the balancing
+   of node S, and parameters that define how each of the nodes must be
+   balanced.  Note that in these algorithms for balancing the worst case is to
+   need to balance the current node S and the left and right neighbors and all
+   of their parents plus create a new node.  We implement S1 balancing for the
+   leaf nodes and S0 balancing for the internal nodes (S1 and S0 are defined
+   in our papers.)*/
+
+#define MAX_FREE_BLOCK 7	/* size of the array of buffers to free at end of do_balance */
+
+/* maximum number of FEB blocknrs on a single level */
+#define MAX_AMOUNT_NEEDED 2
+
+/* someday somebody will prefix every field in this struct with tb_ */
+struct tree_balance
+{
+    struct reiserfs_transaction_handle *transaction_handle ;
+    struct super_block * tb_sb;
+    struct path * tb_path;
+    struct buffer_head * L[MAX_HEIGHT];        /* array of left neighbors of nodes in the path */
+    struct buffer_head * R[MAX_HEIGHT];        /* array of right neighbors of nodes in the path*/
+    struct buffer_head * FL[MAX_HEIGHT];       /* array of fathers of the left  neighbors      */
+    struct buffer_head * FR[MAX_HEIGHT];       /* array of fathers of the right neighbors      */
+    struct buffer_head * CFL[MAX_HEIGHT];      /* array of common parents of center node and its left neighbor  */
+    struct buffer_head * CFR[MAX_HEIGHT];      /* array of common parents of center node and its right neighbor */
+    
+    /* array of blocknr's that are free and are the nearest to the left node that are usable
+       for writing dirty formatted leaves, using the write_next_to algorithm. */
+    /*unsigned long free_and_near[MAX_DIRTIABLE];*/
+    
+    struct buffer_head * FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals
+					       cur_blknum. */
+    struct buffer_head * used[MAX_FEB_SIZE];
+    short int lnum[MAX_HEIGHT];	/* array of number of items which must be shifted to the left in
+				   order to balance the current node; for leaves includes item
+				   that will be partially shifted; for internal nodes, it is
+				   the number of child pointers rather than items. It includes
+				   the new item being created.  For preserve_shifted() purposes
+				   the code sometimes subtracts one from this number to get the
+				   number of currently existing items being shifted, and even
+				   more often for leaves it subtracts one to get the number of
+				   wholly shifted items for other purposes. */
+    short int rnum[MAX_HEIGHT];	/* substitute right for left in comment above */
+    short int lkey[MAX_HEIGHT];               /* array indexed by height h mapping the key delimiting L[h] and
+					       S[h] to its item number within the node CFL[h] */
+    short int rkey[MAX_HEIGHT];               /* substitute r for l in comment above */
+    short int insert_size[MAX_HEIGHT];        /* the number of bytes by we are trying to add or remove from
+						 S[h]. A negative value means removing.  */
+    short int blknum[MAX_HEIGHT];             /* number of nodes that will replace node S[h] after
+						 balancing on the level h of the tree.  If 0 then S is
+						 being deleted, if 1 then S is remaining and no new nodes
+						 are being created, if 2 or 3 then 1 or 2 new nodes is
+						 being created */
+    
+    /* fields that are used only for balancing leaves of the tree */
+    short int cur_blknum;	/* number of empty blocks having been already allocated			*/
+    short int s0num;             /* number of items that fall into left most  node when S[0] splits	*/
+    short int s1num;             /* number of items that fall into first  new node when S[0] splits	*/
+    short int s2num;             /* number of items that fall into second new node when S[0] splits	*/
+    short int lbytes;            /* number of bytes which can flow to the left neighbor from the	left	*/
+    /* most liquid item that cannot be shifted from S[0] entirely		*/
+    /* if -1 then nothing will be partially shifted */
+    short int rbytes;            /* number of bytes which will flow to the right neighbor from the right	*/
+    /* most liquid item that cannot be shifted from S[0] entirely		*/
+    /* if -1 then nothing will be partially shifted                           */
+    short int s1bytes;		/* number of bytes which flow to the first  new node when S[0] splits	*/
+            			/* note: if S[0] splits into 3 nodes, then items do not need to be cut	*/
+    short int s2bytes;
+    struct buffer_head * buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */
+    char * vn_buf;		/* kmalloced memory. Used to create
+				   virtual node and keep map of
+				   dirtied bitmap blocks */
+    int vn_buf_size;		/* size of the vn_buf */
+    struct virtual_node * tb_vn;	/* VN starts after bitmap of bitmap blocks */
+} ;
+
+
+
+/* These are modes of balancing */
+
+/* When inserting an item. */
+#define M_INSERT	'i'
+/* When inserting into (directories only) or appending onto an already
+   existant item. */
+#define M_PASTE		'p'
+/* When deleting an item. */
+#define M_DELETE	'd'
+/* When truncating an item or removing an entry from a (directory) item. */
+#define M_CUT 		'c'
+
+/* used when balancing on leaf level skipped (in reiserfsck) */
+#define M_INTERNAL	'n'
+
+/* When further balancing is not needed, then do_balance does not need
+   to be called. */
+#define M_SKIP_BALANCING 		's'
+#define M_CONVERT	'v'
+
+/* modes of leaf_move_items */
+#define LEAF_FROM_S_TO_L 0
+#define LEAF_FROM_S_TO_R 1
+#define LEAF_FROM_R_TO_L 2
+#define LEAF_FROM_L_TO_R 3
+#define LEAF_FROM_S_TO_SNEW 4
+
+#define FIRST_TO_LAST 0
+#define LAST_TO_FIRST 1
+
+/* used in do_balance for passing parent of node information that has been
+   gotten from tb struct */
+struct buffer_info {
+    struct buffer_head * bi_bh;
+    struct buffer_head * bi_parent;
+    int bi_position;
+};
+
+
+/* there are 4 types of items: stat data, directory item, indirect, direct.
+   FIXME: This table does not describe new key format
++-------------------+------------+--------------+------------+
+|	            |  k_offset  | k_uniqueness | mergeable? |
++-------------------+------------+--------------+------------+
+|     stat data     |	0        |      0       |   no       |
++-------------------+------------+--------------+------------+
+| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS|   no       | 
+| non 1st directory | hash value |              |   yes      |
+|     item          |            |              |            |
++-------------------+------------+--------------+------------+
+| indirect item     | offset + 1 |TYPE_INDIRECT |   if this is not the first indirect item of the object
++-------------------+------------+--------------+------------+
+| direct item       | offset + 1 |TYPE_DIRECT   | if not this is not the first direct item of the object
++-------------------+------------+--------------+------------+
+*/
+
+
+
+#define KEY_IS_STAT_DATA_KEY(p_s_key) 	( get_type (p_s_key) == TYPE_STAT_DATA )
+#define KEY_IS_DIRECTORY_KEY(p_s_key)	( get_type (p_s_key) == TYPE_DIRENTRY )
+#define KEY_IS_DIRECT_KEY(p_s_key) 	( get_type (p_s_key) == TYPE_DIRECT )
+#define KEY_IS_INDIRECT_KEY(p_s_key)	( get_type (p_s_key) == TYPE_INDIRECT )
+
+#define I_IS_STAT_DATA_ITEM(p_s_ih) 	KEY_IS_STAT_DATA_KEY(&((p_s_ih)->ih_key))
+#define I_IS_DIRECTORY_ITEM(p_s_ih) 	KEY_IS_DIRECTORY_KEY(&((p_s_ih)->ih_key))
+#define I_IS_DIRECT_ITEM(p_s_ih) 	KEY_IS_DIRECT_KEY(&((p_s_ih)->ih_key))
+#define I_IS_INDIRECT_ITEM(p_s_ih) 	KEY_IS_INDIRECT_KEY(&((p_s_ih)->ih_key))
+
+#define is_indirect_ih(ih) I_IS_INDIRECT_ITEM(ih)
+#define is_direct_ih(ih) I_IS_DIRECT_ITEM(ih)
+#define is_direntry_ih(ih) I_IS_DIRECTORY_ITEM(ih)
+#define is_stat_data_ih(ih) I_IS_STAT_DATA_ITEM(ih)
+
+#define is_indirect_key(key) KEY_IS_INDIRECT_KEY(key)
+#define is_direct_key(key) KEY_IS_DIRECT_KEY(key)
+#define is_direntry_key(key) KEY_IS_DIRECTORY_KEY(key)
+#define is_stat_data_key(key) KEY_IS_STAT_DATA_KEY(key)
+
+#define COMP_KEYS comp_keys
+
+//#define COMP_SHORT_KEYS comp_short_keys
+#define not_of_one_file comp_short_keys
+
+/* number of blocks pointed to by the indirect item */
+#define I_UNFM_NUM(p_s_ih)	( (p_s_ih)->ih_item_len / UNFM_P_SIZE )
+
+/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
+#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space (ih) : (size))
+
+/* check whether byte number 'offset' is in this item */
+#define I_OFF_BYTE_IN_ITEM(p_s_ih, n_offset, n_blocksize) \
+                  ( get_offset(&(p_s_ih)->ih_key) <= (n_offset) && \
+                    get_offset(&(p_s_ih)->ih_key) + get_bytes_number(p_s_ih,n_blocksize) > (n_offset) )
+
+/* get the item header */ 
+#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get key */
+#define B_N_PDELIM_KEY(bh,item_num) ( (struct key * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get the key */
+#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
+
+/* get item body */
+#define B_N_PITEM(bh,item_num) ( (bh)->b_data + B_N_PITEM_HEAD((bh),(item_num))->ih_item_location)
+
+/* get the stat data by the buffer header and the item order */
+#define B_N_STAT_DATA(bh,nr) \
+( (struct stat_data *)((bh)->b_data+B_N_PITEM_HEAD((bh),(nr))->ih_item_location ) )
+
+ /* following defines use reiserfs buffer header and item header */
+ /* get item body */
+#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih))
+
+/* get stat-data */
+#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )B_I_PITEM(bh,ih) )
+
+#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
+
+/* indirect items consist of entries which contain blocknrs, pos
+   indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
+   blocknr contained by the entry pos points to */
+#define B_I_POS_UNFM_POINTER(bh,ih,pos) (*(((__u32 *)B_I_PITEM(bh,ih)) + (pos)))
+
+
+
+/***************************************************************************/
+/*                    FUNCTION DECLARATIONS                                */
+/***************************************************************************/
+
+
+
+
+/* objectid.c */
+__u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th);
+void reiserfs_release_objectid (struct reiserfs_transaction_handle *th, __u32 objectid_to_release);
+int reiserfs_convert_objectid_map_v1(struct super_block *s);
+
+
+/* stree.c */
+void padd_item (char * item, int total_length, int length);
+int B_IS_IN_TREE(struct buffer_head *);
+struct key * get_rkey (struct path * p_s_chk_path, struct super_block  * p_s_sb);
+int bin_search (void * p_v_key, void * p_v_base, int p_n_num, int p_n_width, int * p_n_pos);
+int search_by_key (struct super_block *, struct key *, struct path *, int * , int);
+int search_by_entry_key (struct super_block * sb, struct key * key, struct path * path);
+int search_for_position_by_key (struct super_block * p_s_sb, struct key * p_s_key, 
+				struct path * p_s_search_path);
+int search_by_objectid (struct super_block *, struct key *, struct path *, int *);
+void decrement_counters_in_path (struct path * p_s_search_path);
+void pathrelse (struct path * p_s_search_path);
+
+
+int is_left_mergeable (struct super_block * s, struct path * path);
+int is_right_mergeable (struct super_block * s, struct path * path);
+int are_items_mergeable (struct item_head * left, struct item_head * right, int bsize);
+
+
+/* fix_nodes.c */
+void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s);
+void reiserfs_kfree (/*const*/ void * vp, size_t size, struct super_block * s);
+int fix_nodes (/*struct reiserfs_transaction_handle *th,*/ int n_op_mode, struct tree_balance * p_s_tb, 
+               /*int n_pos_in_item,*/ struct item_head * p_s_ins_ih);
+void unfix_nodes (/*struct reiserfs_transaction_handle *th,*/ struct tree_balance *);
+void free_buffers_in_tb (struct tree_balance * p_s_tb);
+void init_path (struct path *);
+
+/* prints.c */
+#define PRINT_LEAF_ITEMS 1   /* print all items */
+#define PRINT_ITEM_DETAILS 2 /* print contents of directory items and stat
+                                data items and indirect items */
+#define PRINT_DIRECT_ITEMS 4 /* print contents of direct items */
+void print_tb (int mode, int item_pos, int pos_in_item, struct tree_balance * tb, char * mes);
+
+
+void print_bmap (FILE * fp, reiserfs_filsys_t fs, int silent);
+void print_objectid_map (FILE * fp, reiserfs_filsys_t fs);
+
+
+
+/* lbalance.c */
+int leaf_move_items (int shift_mode, struct tree_balance * tb, 
+                     int mov_num, int mov_bytes, struct buffer_head * Snew);
+int leaf_shift_left (struct tree_balance * tb, int shift_num, int shift_bytes);
+int leaf_shift_right (struct tree_balance * tb, int shift_num, int shift_bytes);
+void leaf_delete_items (reiserfs_filsys_t, struct buffer_info * cur_bi, 
+                        int last_first, int first, int del_num, int del_bytes);
+void leaf_insert_into_buf (reiserfs_filsys_t, struct buffer_info * bi, 
+			   int before, struct item_head * inserted_item_ih, const char * inserted_item_body, 
+			   int zeros_number);
+void leaf_paste_in_buffer (reiserfs_filsys_t, struct buffer_info * bi, int pasted_item_num, 
+			   int pos_in_item, int paste_size, const char * body, int zeros_number);
+void leaf_cut_from_buffer (reiserfs_filsys_t, struct buffer_info * bi, int cut_item_num, 
+                           int pos_in_item, int cut_size);
+void leaf_paste_entries (struct buffer_head * bh, int item_num, int before, int new_entry_count,
+			 struct reiserfs_de_head * new_dehs, const char * records,
+			 int paste_size);
+void delete_item (reiserfs_filsys_t fs, struct buffer_head * bh, int item_num);
+void cut_entry (reiserfs_filsys_t fs, struct buffer_head * bh,
+		int item_num, int entry_num, int del_count);
+
+
+/* ibalance.c */
+int balance_internal (struct tree_balance * , int, int, struct item_head * , 
+                      struct buffer_head **);
+
+/* do_balance.c */
+void do_balance (struct tree_balance * tb,
+                 struct item_head * ih, const char * body, int flag, int zeros_num);
+void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head * bh, int);
+int get_left_neighbor_position (struct tree_balance * tb, int h);
+int get_right_neighbor_position (struct tree_balance * tb, int h);
+void replace_key (reiserfs_filsys_t, struct buffer_head *, int, struct buffer_head *, int);
+void replace_lkey (struct tree_balance *, int, struct item_head *);
+void replace_rkey (struct tree_balance *, int, struct item_head *);
+void make_empty_node (struct buffer_info *);
+struct buffer_head * get_FEB (struct tree_balance *);
+
+
+__u64 get_bytes_number (struct item_head * ih, int blocksize);
+
+
+
+
+/* hashes.c */
+__u32 keyed_hash (const char *msg, int len);
+__u32 yura_hash (const char *msg, int len);
+__u32 r5_hash (const char *msg, int len);
+
+
+
+/* node_format.c */
+int get_journal_old_start_must (struct reiserfs_super_block * rs);
+int get_journal_start_must (int blocksize);
+/*extern hashf_t hashes [];*/
+
+
diff --git a/include/reiserfs_lib.h b/include/reiserfs_lib.h
new file mode 100644
index 0000000..b23893e
--- /dev/null
+++ b/include/reiserfs_lib.h
@@ -0,0 +1,199 @@
+/*
+ *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+
+#ifndef REISERFS_LIB_H
+#define REISERFS_LIB_H
+
+typedef struct super_block * reiserfs_filsys_t;
+
+#include "reiserfs_fs.h"
+
+struct _bitmap {
+    unsigned long bm_byte_size;
+    unsigned long bm_bit_size;
+    char * bm_map;
+    unsigned long bm_set_bits;
+};
+
+typedef struct _bitmap * reiserfs_bitmap_t;
+
+struct super_block {
+    int s_version;		/* on-disk format version */
+    reiserfs_bitmap_t bitmap;	/* copy of reiserfs on-disk bitmap */
+    
+    int s_dev; /* descriptor of opened block device file */
+    int s_blocksize;
+    struct buffer_head ** s_ap_bitmap; /* array of buffers containing bitmap
+                                          blocks */
+    struct buffer_head * s_sbh;  /* buffer containing super block */
+    struct reiserfs_super_block * s_rs; /* pointer to its b_data */
+    int s_dirt;
+    hashf_t s_hash_function; /* pointer to function which is used to sort
+				names in directory. It is set by reiserfs_open
+				if it is set in the super block, otherwise it
+				is set by first is_properly_hashed */
+    char * file_name;	/* file name of underlying device */
+    int s_flags;
+    void * s_vp;
+    int (*block_allocator) (reiserfs_filsys_t fs, 
+			    unsigned long * free_blocknrs,
+			    unsigned long start, int amount_needed);
+    int (*block_deallocator) (reiserfs_filsys_t fs, unsigned long block);
+};
+
+
+/* reiserfslib.c */
+
+reiserfs_filsys_t reiserfs_open (char * filename, int flags, int * error, void * vp);
+void reiserfs_read_bitmap_blocks (reiserfs_filsys_t);
+void reiserfs_free_bitmap_blocks (reiserfs_filsys_t);
+int no_reiserfs_found (reiserfs_filsys_t fs);
+void reiserfs_reopen (reiserfs_filsys_t fs, int flags);
+void reiserfs_flush (reiserfs_filsys_t fs);
+void reiserfs_free (reiserfs_filsys_t fs);
+void reiserfs_close (reiserfs_filsys_t fs);
+int reiserfs_new_blocknrs (reiserfs_filsys_t fs, 
+			   unsigned long * free_blocknrs, unsigned long start,
+			   int amount_needed);
+int reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block);
+int spread_bitmaps (reiserfs_filsys_t fs);
+int filesystem_dirty (reiserfs_filsys_t fs);
+void mark_filesystem_dirty (reiserfs_filsys_t fs);
+
+void reiserfs_paste_into_item (reiserfs_filsys_t fs, struct path * path,
+			       const void * body, int size);
+void reiserfs_insert_item (reiserfs_filsys_t fs, struct path * path,
+			   struct item_head * ih, const void * body);
+
+int reiserfs_find_entry (reiserfs_filsys_t fs, struct key * dir, char * name,
+			 int * min_gen_counter);
+int reiserfs_add_entry (reiserfs_filsys_t fs, struct key * dir, char * name,
+			struct key * key, int fsck_need);
+
+int _search_by_entry_key (reiserfs_filsys_t fs, struct key * key, 
+			  struct path * path);
+void copy_key (void * to, void * from);
+void copy_short_key (void * to, void * from);
+void copy_item_head(void * p_v_to, void * p_v_from);
+int comp_keys (void * k1, void * k2);
+int  comp_short_keys (void * p_s_key1, void * p_s_key2);
+int comp_items (struct item_head  * p_s_ih, struct path * p_s_path);
+
+
+/* bitmap.c */
+
+reiserfs_bitmap_t reiserfs_create_bitmap (unsigned int bit_count);
+int reiserfs_expand_bitmap (reiserfs_bitmap_t bm, unsigned int bit_count);
+void reiserfs_delete_bitmap (reiserfs_bitmap_t bm);
+void reiserfs_bitmap_copy (reiserfs_bitmap_t to, reiserfs_bitmap_t from);
+int reiserfs_bitmap_compare (reiserfs_bitmap_t bm1, reiserfs_bitmap_t bm2);
+void reiserfs_bitmap_set_bit (reiserfs_bitmap_t bm, unsigned int bit_number);
+void reiserfs_bitmap_clear_bit (reiserfs_bitmap_t bm, unsigned int bit_number);
+
+int reiserfs_bitmap_test_bit (reiserfs_bitmap_t bm, unsigned int bit_number);
+int reiserfs_bitmap_find_zero_bit (reiserfs_bitmap_t bm, unsigned long * start);
+int reiserfs_fetch_disk_bitmap (reiserfs_bitmap_t bm, reiserfs_filsys_t fs);
+int reiserfs_flush_bitmap (reiserfs_bitmap_t bm, reiserfs_filsys_t fs);
+void reiserfs_bitmap_zero (reiserfs_bitmap_t bm);
+void reiserfs_bitmap_fill (reiserfs_bitmap_t bm);
+int reiserfs_bitmap_ones (reiserfs_bitmap_t bm);
+int reiserfs_bitmap_zeros (reiserfs_bitmap_t bm);
+
+void reiserfs_bitmap_save (char * filename, reiserfs_bitmap_t bm);
+reiserfs_bitmap_t reiserfs_bitmap_load (char * filename);
+void reiserfs_bitmap_invert (reiserfs_bitmap_t bm);
+
+
+int reiserfs_remove_entry (reiserfs_filsys_t fs, struct key * key);
+
+
+
+/* node_formats.c */
+
+#define THE_LEAF 1
+#define THE_INTERNAL 2
+#define THE_SUPER 3
+#define THE_JDESC 4
+#define THE_UNKNOWN 5
+
+int is_reiserfs_magic_string (struct reiserfs_super_block * rs);
+int is_reiser2fs_magic_string (struct reiserfs_super_block * rs);
+int is_prejournaled_reiserfs (struct reiserfs_super_block * rs);
+int does_desc_match_commit (struct reiserfs_journal_desc *desc, 
+			    struct reiserfs_journal_commit *commit);
+int who_is_this (char * buf, int blocksize);
+int journal_size (struct super_block * s);
+int not_data_block (struct super_block * s, unsigned long block);
+int not_journalable (reiserfs_filsys_t fs, unsigned long block);
+int block_of_bitmap (reiserfs_filsys_t fs, unsigned long block);
+int block_of_journal (reiserfs_filsys_t fs, unsigned long block);
+int is_tree_node (struct buffer_head * bh, int level);
+int is_properly_hashed (reiserfs_filsys_t fs,
+			char * name, int namelen, __u32 offset);
+int dir_entry_bad_location (struct reiserfs_de_head * deh, 
+			    struct item_head * ih, int first);
+void make_dir_stat_data (int blocksize, int key_format, 
+			 __u32 dirid, __u32 objectid, 
+			 struct item_head * ih, void * sd);
+void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
+			     __u32 par_dirid, __u32 par_objid);
+void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
+			  __u32 par_dirid, __u32 par_objid);
+
+
+typedef void (*item_action_t) (struct buffer_head * bh, struct item_head * ih);
+typedef void (*item_head_action_t) (struct item_head * ih);
+
+void for_every_item (struct buffer_head * bh, item_head_action_t action,
+		     item_action_t * actions);
+int key_format (const struct key * key);
+loff_t get_offset (const struct key * key);
+int uniqueness2type (__u32 uniqueness);
+__u32 type2uniqueness (int type);
+int get_type (const struct key * key);
+char * key_of_what (const struct key * key);
+int type_unknown (struct key * key);
+void set_type (int format, struct key * key, int type);
+void set_offset (int format, struct key * key, loff_t offset);
+void set_type_and_offset (int format, struct key * key, loff_t offset, int type);
+
+
+typedef int (*check_unfm_func_t) (reiserfs_filsys_t fs, __u32);
+int is_it_bad_item (reiserfs_filsys_t, struct item_head *, char *,
+		    check_unfm_func_t, int bad_dir);
+
+
+#define hash_func_is_unknown(fs) ((fs)->s_hash_function == 0)
+#define reiserfs_hash(fs) ((fs)->s_hash_function)
+
+int known_hashes (void);
+char * code2name (int code);
+int func2code (hashf_t func);
+hashf_t code2func (int code);
+int find_hash_in_use (char * name, int namelen, __u32 hash_value_masked, int code_to_try_first);
+
+int entry_length (struct item_head * ih, struct reiserfs_de_head * deh,
+		  int pos_in_item);
+char * name_in_entry (struct reiserfs_de_head * deh, int pos_in_item);
+int name_length (struct item_head * ih,
+		 struct reiserfs_de_head * deh, int pos_in_item);
+
+
+
+
+/* prints.c */
+void print_indirect_item (FILE * fp, struct buffer_head * bh, int item_num);
+void print_block (FILE * fp, reiserfs_filsys_t, struct buffer_head * bh, ...);//int print_mode, int first, int last);
+void reiserfs_warning (FILE * fp, const char * fmt, ...);
+char ftypelet (mode_t mode);
+
+#define reiserfs_panic(fmt, list...) \
+{\
+	fprintf (stderr, "%s %d %s\n", __FILE__, __LINE__, __FUNCTION__);\
+	reiserfs_warning (stderr, fmt, ## list);\
+	exit(4);\
+}
+
+#endif /* REISERFS_LIB_H */
+
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission.  M.I.T. makes no representations about the
+# suitability of this software for any purpose.  It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-d) dir_arg=true
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
+	    shift
+	    continue;;
+
+	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		# this colon is to work around a 386BSD /bin/sh bug
+		:
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:	no input file specified"
+	exit 1
+else
+	true
+fi
+
+if [ x"$dir_arg" != x ]; then
+	dst=$src
+	src=""
+	
+	if [ -d $dst ]; then
+		instcmd=:
+		chmodcmd=""
+	else
+		instcmd=mkdir
+	fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad 
+# if $src (and thus $dsttmp) contains '*'.
+
+	if [ -f $src -o -d $src ]
+	then
+		true
+	else
+		echo "install:  $src does not exist"
+		exit 1
+	fi
+	
+	if [ x"$dst" = x ]
+	then
+		echo "install:	no destination specified"
+		exit 1
+	else
+		true
+	fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+	if [ -d $dst ]
+	then
+		dst="$dst"/`basename $src`
+	else
+		true
+	fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+#  this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='	
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+	pathcomp="${pathcomp}${1}"
+	shift
+
+	if [ ! -d "${pathcomp}" ] ;
+        then
+		$mkdirprog "${pathcomp}"
+	else
+		true
+	fi
+
+	pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+	$doit $instcmd $dst &&
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+	if [ x"$transformarg" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		dstfile=`basename $dst $transformbasename | 
+			sed $transformarg`$transformbasename
+	fi
+
+# don't allow the sed command to completely eliminate the filename
+
+	if [ x"$dstfile" = x ] 
+	then
+		dstfile=`basename $dst`
+	else
+		true
+	fi
+
+# Make a temp file name in the proper directory.
+
+	dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+	$doit $instcmd $src $dsttmp &&
+
+	trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing.  If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+	$doit $rmcmd -f $dstdir/$dstfile &&
+	$doit $mvcmd $dsttmp $dstdir/$dstfile 
+
+fi &&
+
+
+exit 0
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..270515e
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,23 @@
+noinst_LIBRARIES = libmisc.a
+
+libmisc_a_SOURCES = io.c misc.c 
+##reiserfs.c
+
+INCLUDES = -I$(top_srcdir)/include
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..309dda3
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,260 @@
+# 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@
+
+noinst_LIBRARIES = libmisc.a
+
+libmisc_a_SOURCES = io.c misc.c 
+
+INCLUDES = -I$(top_srcdir)/include
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libmisc_a_LIBADD = 
+libmisc_a_OBJECTS =  io.o misc.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+SOURCES = $(libmisc_a_SOURCES)
+OBJECTS = $(libmisc_a_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 lib/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.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:
+
+libmisc.a: $(libmisc_a_OBJECTS) $(libmisc_a_DEPENDENCIES)
+	-rm -f libmisc.a
+	$(AR) cru libmisc.a $(libmisc_a_OBJECTS) $(libmisc_a_LIBADD)
+	$(RANLIB) libmisc.a
+
+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 = lib
+
+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
+io.o: io.c ../include/io.h ../include/misc.h
+misc.o: misc.c ../include/io.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-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+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-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		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-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile 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:
diff --git a/lib/io.c b/lib/io.c
new file mode 100644
index 0000000..fe94334
--- /dev/null
+++ b/lib/io.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright 1996, 1997 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <asm/types.h>
+
+#include <sys/types.h>
+/*#include <linux/unistd.h>*/
+
+
+#include "io.h"
+#include "misc.h"
+
+
+
+/* All buffers are in double linked cycled list. Buffers of tree are
+   hashed by their block number.  If getblk found buffer with wanted
+   block number in hash queue it moves buffer to the end of list */
+
+#define BLOCK_SIZE 1024
+#define MAX_NR_BUFFERS 16384
+static int g_nr_buffers;
+
+#define NR_HASH_QUEUES 4096
+static struct buffer_head * g_a_hash_queues [NR_HASH_QUEUES];
+static struct buffer_head * g_buffer_list_head;
+static struct buffer_head * g_buffer_heads;
+
+
+
+static void show_buffers (int dev, int size)
+{
+    int all = 0;
+    int dirty = 0;
+    int in_use = 0; /* count != 0 */
+    int free = 0;
+    struct buffer_head * next = g_buffer_list_head;
+
+    for (;;) {
+	if (!next)
+	    die ("show_buffers: buffer list is corrupted");
+	if (next->b_dev == dev && next->b_size == size) {
+	    all ++;
+	    if (next->b_count != 0) {
+		in_use ++;
+	    }
+	    if (buffer_dirty (next)) {
+		dirty ++;
+	    }
+	    if (buffer_clean (next) && next->b_count == 0) {
+		free ++;
+	    }
+	}
+	next = next->b_next;
+	if (next == g_buffer_list_head)
+	    break;
+    }
+
+    printf ("show_buffers (dev %d, size %d): free %d, count != 0 %d, dirty %d, all %d\n", dev, size, free, in_use, dirty, all);
+}
+
+
+static void insert_into_hash_queue (struct buffer_head * bh)
+{
+    int index = bh->b_blocknr % NR_HASH_QUEUES;
+
+    if (bh->b_hash_prev || bh->b_hash_next)
+	die ("insert_into_hash_queue: hash queue corrupted");
+
+    if (g_a_hash_queues[index]) {
+	g_a_hash_queues[index]->b_hash_prev = bh;
+	bh->b_hash_next = g_a_hash_queues[index];
+    }
+    g_a_hash_queues[index] = bh;
+}
+
+
+static void remove_from_hash_queue (struct buffer_head * bh)
+{
+    if (bh->b_hash_next == 0 && bh->b_hash_prev == 0 && bh != g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES])
+	/* (b_dev == 0) ? */
+	return;
+
+    if (bh == g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES]) {
+	if (bh->b_hash_prev != 0)
+	    die ("remove_from_hash_queue: hash queue corrupted");
+	g_a_hash_queues[bh->b_blocknr % NR_HASH_QUEUES] = bh->b_hash_next;
+    }
+    if (bh->b_hash_next)
+	bh->b_hash_next->b_hash_prev = bh->b_hash_prev;
+
+    if (bh->b_hash_prev)
+	bh->b_hash_prev->b_hash_next = bh->b_hash_next;
+
+    bh->b_hash_prev = bh->b_hash_next = 0;
+}
+
+
+static void put_buffer_list_end (struct buffer_head * bh)
+{
+    struct buffer_head * last = 0;
+
+    if (bh->b_prev || bh->b_next)
+	die ("put_buffer_list_end: buffer list corrupted");
+
+    if (g_buffer_list_head == 0) {
+	bh->b_next = bh;
+	bh->b_prev = bh;
+	g_buffer_list_head = bh;
+    } else {
+	last = g_buffer_list_head->b_prev;
+    
+	bh->b_next = last->b_next;
+	bh->b_prev = last;
+	last->b_next->b_prev = bh;
+	last->b_next = bh;
+    }
+}
+
+
+static void remove_from_buffer_list (struct buffer_head * bh)
+{
+    if (bh == bh->b_next) {
+	g_buffer_list_head = 0;
+    } else {
+	bh->b_prev->b_next = bh->b_next;
+	bh->b_next->b_prev = bh->b_prev;
+	if (bh == g_buffer_list_head)
+	    g_buffer_list_head = bh->b_next;
+    }
+
+    bh->b_next = bh->b_prev = 0;
+}
+
+
+static void put_buffer_list_head (struct buffer_head * bh)
+{
+    put_buffer_list_end (bh);
+    g_buffer_list_head = bh;
+}
+
+
+#define GROW_BUFFERS__NEW_BUFERS_PER_CALL 10
+/* creates number of new buffers and insert them into head of buffer list 
+ */
+static int grow_buffers (int size)
+{
+    int i;
+    struct buffer_head * bh, * tmp;
+
+    if (g_nr_buffers + GROW_BUFFERS__NEW_BUFERS_PER_CALL > MAX_NR_BUFFERS)
+	return 0;
+
+    /* get memory for array of buffer heads */
+    bh = (struct buffer_head *)getmem (GROW_BUFFERS__NEW_BUFERS_PER_CALL * sizeof (struct buffer_head) + sizeof (struct buffer_head *));
+    if (g_buffer_heads == 0)
+	g_buffer_heads = bh;
+    else {
+	/* link new array to the end of array list */
+	tmp = g_buffer_heads;
+	while (*(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL) != 0)
+	    tmp = *(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL);
+	*(struct buffer_head **)(tmp + GROW_BUFFERS__NEW_BUFERS_PER_CALL) = bh;
+    }
+
+    for (i = 0; i < GROW_BUFFERS__NEW_BUFERS_PER_CALL; i ++) {
+
+	tmp = bh + i;
+	memset (tmp, 0, sizeof (struct buffer_head));
+	tmp->b_data = getmem (size);
+	if (tmp->b_data == 0)
+	    die ("grow_buffers: no memory for new buffer data");
+	tmp->b_dev = 0;
+	tmp->b_size = size;
+	put_buffer_list_head (tmp);
+
+	g_nr_buffers ++;
+    }
+    return GROW_BUFFERS__NEW_BUFERS_PER_CALL;
+}
+
+
+struct buffer_head * find_buffer (int dev, int block, int size)
+{		
+    struct buffer_head * next;
+
+    next = g_a_hash_queues[block % NR_HASH_QUEUES];
+    for (;;) {
+	struct buffer_head *tmp = next;
+	if (!next)
+	    break;
+	next = tmp->b_hash_next;
+	if (tmp->b_blocknr != block || tmp->b_size != size || tmp->b_dev != dev)
+	    continue;
+	next = tmp;
+	break;
+    }
+    return next;
+}
+
+void __wait_on_buffer (struct buffer_head * bh)
+{
+}
+
+struct buffer_head * get_hash_table(dev_t dev, int block, int size)
+{
+    struct buffer_head * bh;
+
+    bh = find_buffer (dev, block, size);
+    if (bh) {
+	bh->b_count ++;
+    }
+    return bh;
+}
+
+
+static struct buffer_head * get_free_buffer (int size)
+{
+    struct buffer_head * next = g_buffer_list_head;
+
+    if (!next)
+	return 0;
+    for (;;) {
+	if (!next)
+	    die ("get_free_buffer: buffer list is corrupted");
+	if (next->b_count == 0 && buffer_clean (next) && next->b_size == size) {
+	    remove_from_hash_queue (next);
+	    remove_from_buffer_list (next);
+	    put_buffer_list_end (next);
+	    return next;
+	}
+	next = next->b_next;
+	if (next == g_buffer_list_head)
+	    break;
+    }
+    return 0;
+}
+
+
+static void sync_buffers (int size, int to_write)
+{
+    struct buffer_head * next = g_buffer_list_head;
+    int written = 0;
+
+    for (;;) {
+	if (!next)
+	    die ("flush_buffer: buffer list is corrupted");
+    
+	if ((!size || next->b_size == size) && buffer_dirty (next) && buffer_uptodate (next)) {
+	    written ++;
+	    bwrite (next);
+	    if (written == to_write)
+		return;
+	}
+    
+	next = next->b_next;
+	if (next == g_buffer_list_head)
+	    break;
+    }
+}
+
+void flush_buffers (void)
+{
+    sync_buffers (0, 0);
+}
+
+
+struct buffer_head * getblk (int dev, int block, int size)
+{
+    struct buffer_head * bh;
+
+    bh = find_buffer (dev, block, size);
+    if (bh) {
+	if (0 && !buffer_uptodate (bh))
+	    die ("getblk: buffer must be uptodate");
+	// move the buffer to the end of list
+
+	/*checkmem (bh->b_data, bh->b_size);*/
+
+	remove_from_buffer_list (bh);
+	put_buffer_list_end (bh);
+	bh->b_count ++;
+	return bh;
+    }
+
+    bh = get_free_buffer (size);
+    if (bh == 0) {
+	if (grow_buffers (size) == 0) {
+	    sync_buffers (size, 10);
+	}
+	bh = get_free_buffer (size);
+	if (bh == 0) {
+	    show_buffers (dev, size);
+	    die ("getblk: no free buffers after grow_buffers and refill (%d)", g_nr_buffers);
+	}
+    }
+
+    bh->b_count = 1;
+    bh->b_dev = dev;
+    bh->b_size = size;
+    bh->b_blocknr = block;
+    bh->b_end_io = NULL ;
+    memset (bh->b_data, 0, size);
+    clear_bit(BH_Dirty, &bh->b_state);
+    clear_bit(BH_Uptodate, &bh->b_state);
+
+    insert_into_hash_queue (bh);
+    /*checkmem (bh->b_data, bh->b_size);*/
+
+    return bh;
+}
+
+struct buffer_head * reiserfs_getblk (int dev, int block, int size, int *repeat)
+{
+    return getblk (dev, block, size);
+}
+
+
+void brelse (struct buffer_head * bh)
+{
+    if (bh == 0)
+	return;
+    if (bh->b_count == 0) {
+	die ("brelse: can not free a free buffer %lu", bh->b_blocknr);
+    }
+    /*checkmem (bh->b_data, bh->b_size);*/
+    bh->b_count --;
+}
+
+
+void bforget (struct buffer_head * bh)
+{
+    if (bh) {
+	brelse (bh);
+	remove_from_hash_queue (bh);
+	remove_from_buffer_list (bh);
+	put_buffer_list_head (bh);
+    }
+}
+
+#if 0
+#if ! ( defined __USE_LARGEFILE64 || defined __USE_FILE_OFFSET64 )
+_syscall5 (int,  _llseek,  uint,  fd, ulong, hi, ulong, lo,
+           loff_t *, res, uint, wh);
+#endif
+
+loff_t reiserfs_llseek (unsigned int fd, loff_t offset, unsigned int origin)
+{
+#if defined __USE_FILE_OFFSET64
+    return lseek(fd, offset, origin);
+#elif defined __USE_LARGEFILE64
+    return lseek64(fd, offset, origin);
+#else
+    loff_t retval, result;
+    retval = _llseek (fd, ((unsigned long long) offset) >> 32,
+		      ((unsigned long long) offset) & 0xffffffff,
+		      &result, origin);
+    return (retval != 0 ? (loff_t)-1 : result);
+#endif
+}
+#endif
+
+static int f_read(struct buffer_head * bh)
+{
+    loff_t offset;
+    ssize_t bytes;
+
+    offset = (loff_t)bh->b_size * (loff_t)bh->b_blocknr;
+    /*if (reiserfs_llseek (bh->b_dev, offset, SEEK_SET) == (loff_t)-1)*/
+    if (lseek64 (bh->b_dev, offset, SEEK_SET) == (loff_t)-1)
+        return 0;
+
+    bytes = read (bh->b_dev, bh->b_data, bh->b_size);
+    if (bytes != (ssize_t)bh->b_size)
+        return 0;
+
+    return 1;
+}
+
+struct buffer_head * bread (int dev, unsigned long block, size_t size)
+{
+    struct buffer_head * bh;
+
+    /*
+    if ((size == 32768 && (block == 16 || 1026)) ||
+	(size == 4096 && (block == 128 || block == 8211))) {
+	size = 10;
+	return 0;
+    }
+    */
+
+    bh = getblk (dev, block, size);
+    if (buffer_uptodate (bh))
+	return bh;
+
+    if (f_read(bh) == 0)
+    {
+        brelse(bh);
+        return 0;
+    }
+
+    mark_buffer_uptodate (bh, 0);
+    return bh;
+}
+
+
+int valid_offset( int fd, loff_t offset)
+{
+    char ch;
+    loff_t res;
+
+    /*res = reiserfs_llseek (fd, offset, 0);*/
+    res = lseek64 (fd, offset, 0);
+    if (res < 0)
+	return 0;
+
+    if (read (fd, &ch, 1) < 1)
+	return 0;
+
+    return 1;
+}
+
+
+struct buffer_head * reiserfs_bread (int dev, int block, int size, int *repeat)
+{
+    return bread (dev, block, size);
+}
+
+
+int bwrite (struct buffer_head * bh)
+{
+    loff_t offset;
+    ssize_t bytes;
+    size_t size;
+
+    if (!buffer_dirty (bh) || !buffer_uptodate (bh))
+	return 0;
+
+    size = bh->b_size;
+    offset = (loff_t)size * (loff_t)bh->b_blocknr;
+
+    if (lseek64 (bh->b_dev, offset, SEEK_SET) == (loff_t)-1){
+	fprintf (stderr, "bwrite: lseek to position %Ld (block=%lu, dev=%d): %s\n",
+		 offset, bh->b_blocknr, bh->b_dev, strerror (errno));
+	exit (4); /* File system errors left uncorrected */
+    }
+
+    bytes = write (bh->b_dev, bh->b_data, size);
+    if (bytes != (ssize_t)size) {
+	fprintf (stderr, "bwrite: write %d bytes returned %d (block=%ld, dev=%d): %s\n",
+		size, bytes, bh->b_blocknr, bh->b_dev, strerror (errno));
+	exit (4);
+    }
+
+    mark_buffer_clean (bh);
+    if (bh->b_end_io) {
+	bh->b_end_io(bh, 1) ;
+    }
+    return 0;
+}
+
+
+void check_and_free_buffer_mem (void)
+{
+    int i = 0;
+    struct buffer_head * next = g_buffer_list_head;
+
+    //sync_buffers (0, 0);
+    for (;;) {
+	if (!next)
+	    die ("check_and_free_buffer_mem: buffer list is corrupted");
+	if (next->b_count != 0)
+	    fprintf (stderr, "check_and_free_buffer_mem: not free buffer (%ld, %ld, %d)",
+		     next->b_blocknr, next->b_size, next->b_count);
+
+	if (buffer_dirty (next) && buffer_uptodate (next))
+	    fprintf (stderr, "check_and_free_buffer_mem: dirty buffer %lu found\n",
+		    next->b_blocknr);
+
+	freemem (next->b_data);
+	i ++;
+	next = next->b_next;
+	if (next == g_buffer_list_head)
+	    break;
+    }
+    if (i != g_nr_buffers)
+	die ("check_and_free_buffer_mem: found %d buffers, must be %d", i, g_nr_buffers);
+
+    /* free buffer heads */
+    while ((next = g_buffer_heads)) {
+	g_buffer_heads = *(struct buffer_head **)(next + GROW_BUFFERS__NEW_BUFERS_PER_CALL);
+	freemem (next);
+    }
+  
+    return;
+}
+
+
+/* */
+void free_buffers (void)
+{
+    check_and_free_buffer_mem ();
+}
diff --git a/lib/misc.c b/lib/misc.c
new file mode 100644
index 0000000..f14fa6a
--- /dev/null
+++ b/lib/misc.c
@@ -0,0 +1,613 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser
+ */
+/*#define _GNU_SOURCE*/
+/*#define _FILE_OFFSET_BITS 64*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <asm/types.h>
+#include <stdlib.h>
+#include <mntent.h>
+#include <sys/vfs.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "io.h"
+
+/*
+ * These have been stolen somewhere from linux
+ */
+int set_bit (int nr, void * addr)
+{
+    __u8 * p, mask;
+    int retval;
+
+    p = (__u8 *)addr;
+    p += nr >> 3;
+    mask = 1 << (nr & 0x7);
+    /*cli();*/
+    retval = (mask & *p) != 0;
+    *p |= mask;
+    /*sti();*/
+    return retval;
+}
+
+
+int clear_bit (int nr, void * addr)
+{
+    __u8 * p, mask;
+    int retval;
+
+    p = (__u8 *)addr;
+    p += nr >> 3;
+    mask = 1 << (nr & 0x7);
+    /*cli();*/
+    retval = (mask & *p) != 0;
+    *p &= ~mask;
+    /*sti();*/
+    return retval;
+}
+
+int test_bit(int nr, const void * addr)
+{
+    __u8 * p, mask;
+  
+    p = (__u8 *)addr;
+    p += nr >> 3;
+    mask = 1 << (nr & 0x7);
+    return ((mask & *p) != 0);
+}
+
+int find_first_zero_bit (const void *vaddr, unsigned size)
+{
+    const __u8 *p = vaddr, *addr = vaddr;
+    int res;
+
+    if (!size)
+	return 0;
+
+    size = (size >> 3) + ((size & 0x7) > 0);
+    while (*p++ == 255) {
+	if (--size == 0)
+	    return (p - addr) << 3;
+    }
+  
+    --p;
+    for (res = 0; res < 8; res++)
+	if (!test_bit (res, p))
+	    break;
+    return (p - addr) * 8 + res;
+}
+
+
+int find_next_zero_bit (const void *vaddr, unsigned size, unsigned offset)
+{
+    const __u8 *addr = vaddr;
+    const __u8 *p = addr + (offset >> 3);
+    int bit = offset & 7, res;
+  
+    if (offset >= size)
+	return size;
+  
+    if (bit) {
+	/* Look for zero in first char */
+	for (res = bit; res < 8; res++)
+	    if (!test_bit (res, p))
+		return (p - addr) * 8 + res;
+	p++;
+    }
+    /* No zero yet, search remaining full bytes for a zero */
+    res = find_first_zero_bit (p, size - 8 * (p - addr));
+    return (p - addr) * 8 + res;
+}
+
+
+/*int test_and_set_bit (int nr, void * addr)
+{
+  int oldbit = test_bit (nr, addr);
+  set_bit (nr, addr);
+  return oldbit;
+}
+
+
+int test_and_clear_bit (int nr, void * addr)
+{
+  int oldbit = test_bit (nr, addr);
+  clear_bit (nr, addr);
+  return oldbit;
+}*/
+
+
+void die (char * fmt, ...)
+{
+    static char buf[1024];
+    va_list args;
+
+    va_start (args, fmt);
+    vsprintf (buf, fmt, args);
+    va_end (args);
+
+    fprintf (stderr, "\n%s\n\n\n", buf);
+    exit (-1);
+}
+
+
+
+#define MEM_BEGIN "_mem_begin_"
+#define MEM_END "mem_end"
+#define MEM_FREED "__free_"
+#define CONTROL_SIZE (strlen (MEM_BEGIN) + 1 + sizeof (int) + strlen (MEM_END) + 1)
+
+
+static int get_mem_size (char * p)
+{
+    char * begin;
+
+    begin = p - strlen (MEM_BEGIN) - 1 - sizeof (int);
+    return *(int *)(begin + strlen (MEM_BEGIN) + 1);
+}
+
+
+void checkmem (char * p, int size)
+{
+    char * begin;
+    char * end;
+  
+    begin = p - strlen (MEM_BEGIN) - 1 - sizeof (int);
+    if (strcmp (begin, MEM_BEGIN))
+	die ("checkmem: memory corrupted - invalid head sign");
+
+    if (*(int *)(begin + strlen (MEM_BEGIN) + 1) != size)
+	die ("checkmem: memory corrupted - invalid size");
+
+    end = begin + size + CONTROL_SIZE - strlen (MEM_END) - 1;
+    if (strcmp (end, MEM_END))
+	die ("checkmem: memory corrupted - invalid end sign");
+}
+
+
+void * getmem (int size)
+{
+    char * p;
+    char * mem;
+
+    p = (char *)malloc (CONTROL_SIZE + size);
+    if (!p)
+	die ("getmem: no more memory (%d)", size);
+
+    strcpy (p, MEM_BEGIN);
+    p += strlen (MEM_BEGIN) + 1;
+    *(int *)p = size;
+    p += sizeof (int);
+    mem = p;
+    memset (mem, 0, size);
+    p += size;
+    strcpy (p, MEM_END);
+
+    checkmem (mem, size);
+
+    return mem;
+}
+
+
+void * expandmem (void * vp, int size, int by)
+{
+    int allocated;
+    char * mem, * p = vp;
+    int expand_by = by;
+
+    if (p) {
+	checkmem (p, size);
+	allocated = CONTROL_SIZE + size;
+	p -= (strlen (MEM_BEGIN) + 1 + sizeof (int));
+    } else {
+	allocated = 0;
+	/* add control bytes to the new allocated area */
+	expand_by += CONTROL_SIZE;
+    }
+    p = realloc (p, allocated + expand_by);
+    if (!p)
+	die ("expandmem: no more memory (%d)", size);
+    if (!vp) {
+	strcpy (p, MEM_BEGIN);
+    }
+    mem = p + strlen (MEM_BEGIN) + 1 + sizeof (int);
+
+    *(int *)(p + strlen (MEM_BEGIN) + 1) = size + by;
+    /* fill new allocated area by 0s */
+    if(by > 0)
+        memset (mem + size, 0, by);
+    strcpy (mem + size + by, MEM_END);
+    checkmem (mem, size + by);
+
+    return mem;
+}
+
+
+void freemem (void * vp)
+{
+    char * p = vp;
+    int size;
+  
+    if (!p)
+	return;
+    size = get_mem_size (vp);
+    checkmem (p, size);
+
+    p -= (strlen (MEM_BEGIN) + 1 + sizeof (int));
+    strcpy (p, MEM_FREED);
+    strcpy (p + size + CONTROL_SIZE - strlen (MEM_END) - 1, MEM_FREED);
+    free (p);
+}
+
+
+
+typedef int (*func_t) (char *);
+
+static int is_readonly_dir (char * dir)
+{
+    char * name;
+    FILE * f;
+
+    name = tempnam (dir, 0);
+    if (!name) {	
+	fprintf (stderr, "is_readonly: tempnam failed, think fs is not readonly\n");
+	return 0;
+    }
+
+    f = fopen (name, "w");
+    if (f) {
+	unlink (name);
+	free (name);
+	return 0;
+    }
+    free (name);
+    return (errno == EROFS) ? 1 : 0;
+}
+
+int user_confirmed (char * q, char * yes)
+{
+    char * answer = 0;
+    size_t n = 0;
+
+    fprintf (stderr, "%s", q);
+    if (getline (&answer, &n, stdin) != strlen (yes) || strcmp (yes, answer))
+	return 0;
+
+    return 1;
+}
+
+
+#include <unistd.h>
+#include <linux/unistd.h>
+
+#define __NR_stat64 195
+_syscall2(long, stat64, char *, filename, struct stat *, statbuf);
+
+
+static int _is_mounted (char * device_name, func_t f)
+{
+    int retval;
+    FILE *fp;
+    struct mntent *mnt;
+    struct statfs stfs;
+    struct stat root_st;
+    struct stat device_st;
+    /*    struct stat64 device_st64;*/
+    int used_stat64 = 1;
+
+    if (stat ("/", &root_st) == -1)
+	die ("is_mounted: could not stat \"/\": %m\n");
+
+    if (stat64 (device_name, &device_st) == -1) {
+	used_stat64 = 0;
+	if (stat (device_name, &device_st) == -1)
+	    die ("is_mounted: could not stat file \"%s\": %m",
+		 device_name);
+    }
+
+    if ((used_stat64 && !S_ISBLK (device_st.st_mode)) || !S_ISBLK (device_st.st_mode))
+	/* not block device file could not be mounted */
+	return 0;
+
+    if ((used_stat64 && root_st.st_dev == device_st.st_rdev) ||
+	root_st.st_dev == device_st.st_rdev) {
+	/* device is mounted as root */
+	return (f ? f ("/") : 1);
+    }
+
+    /* if proc filesystem is mounted */
+    if (statfs ("/proc", &stfs) == -1 || stfs.f_type != 0x9fa0/*procfs magic*/ ||
+	(fp = setmntent ("/proc/mounts", "r")) == NULL) {
+	/* proc filesystem is not mounted, or /proc/mounts does not
+           exist */
+	if (f)
+	    return (user_confirmed (" (could not figure out) Is filesystem mounted read-only? (Yes)",
+				    "Yes\n"));
+	else
+	    return (user_confirmed (" (could not figure out) Is filesystem mounted? (Yes)",
+				    "Yes\n"));
+    }
+    
+    retval = 0;
+    while ((mnt = getmntent (fp)) != NULL)
+	if (strcmp (device_name, mnt->mnt_fsname) == 0) {
+	    retval = (f ? f (mnt->mnt_dir) : 1);
+	    break;
+	}
+    endmntent (fp);
+
+    return retval;
+}
+
+
+int is_mounted_read_only (char * device_name)
+{
+    return _is_mounted (device_name, is_readonly_dir);
+}
+
+
+int is_mounted (char * device_name)
+{
+    return _is_mounted (device_name, 0);
+}
+
+
+char buf1 [100];
+char buf2 [100];
+
+void print_how_fast (unsigned long passed, unsigned long total,
+		     int cursor_pos, int reset_time)
+{
+    static time_t t0, t1;
+    int speed;
+    int indent;
+
+    if (reset_time)
+	time (&t0);
+
+    time (&t1);
+    if (t1 != t0)
+	speed = passed / (t1 - t0);
+    else
+	speed = 0;
+
+    /* what has to be written */
+    if (total)
+      sprintf (buf1, "left %lu, %d /sec", total - passed, speed);
+    else {
+	/*(*passed) ++;*/
+	sprintf (buf1, "done %lu, %d /sec", passed, speed);
+    }
+    
+    /* make indent */
+    indent = 79 - cursor_pos - strlen (buf1);
+    memset (buf2, ' ', indent);
+    buf2[indent] = 0;
+    fprintf (stderr, "%s%s", buf2, buf1);
+
+    memset (buf2, '\b', indent + strlen (buf1));
+    buf2 [indent + strlen (buf1)] = 0;
+    fprintf (stderr, "%s", buf2);
+    fflush (stderr);
+}
+
+
+static char * strs[] =
+{"0%",".",".",".",".","20%",".",".",".",".","40%",".",".",".",".","60%",".",".",".",".","80%",".",".",".",".","100%"};
+
+static char progress_to_be[1024];
+static char current_progress[1024];
+
+static void str_to_be (char * buf, int prosents)
+{
+    int i;
+    prosents -= prosents % 4;
+    buf[0] = 0;
+    for (i = 0; i <= prosents / 4; i ++)
+	strcat (buf, strs[i]);
+}
+
+
+void print_how_far (unsigned long * passed, unsigned long total,
+		    int inc, int quiet)
+{
+    int percent;
+
+    if (*passed == 0)
+	current_progress[0] = 0;
+
+    (*passed) += inc;
+    if (*passed > total) {
+	fprintf (stderr, "\nprint_how_far: total %lu has been reached already. cur=%lu\n",
+		 total, *passed);
+	return;
+    }
+
+    percent = ((*passed) * 100) / total;
+
+    str_to_be (progress_to_be, percent);
+
+    if (strlen (current_progress) != strlen (progress_to_be)) {
+	fprintf (stderr, "%s", progress_to_be + strlen (current_progress));
+    }
+
+    strcat (current_progress, progress_to_be + strlen (current_progress));
+
+    if (!quiet)
+	print_how_fast (*passed/* - inc*/, total, strlen (progress_to_be),
+			(*passed == inc) ? 1 : 0);
+
+    fflush (stderr);
+}
+
+
+
+#define ENDIANESS_NOT_DEFINED 0
+#define LITTLE_ENDIAN_ARCH 1
+#define BIG_ENDIAN_ARCH 2
+
+static int endianess = ENDIANESS_NOT_DEFINED;
+
+
+static void find_endianess (void)
+{
+    __u32 x = 0x0f0d0b09;
+    char * s;
+
+    s = (char *)&x;
+
+    // little-endian is 1234
+    if (s[0] == '\11' && s[1] == '\13' && s[2] == '\15' && s[3] == '\17')
+	endianess = LITTLE_ENDIAN_ARCH;
+
+    // big-endian is 4321
+    if (s[0] == '\17' && s[1] == '\15' && s[2] == '\13' && s[3] == '\11')
+	die ("big-endian archs are not supported");
+
+    // nuxi/pdp-endian is 3412
+    if (s[0] == '\15' && s[1] == '\17' && s[2] == '\11' && s[3] == '\13')
+	die ("nuxi/pdp-endian archs are not supported");
+}
+
+
+// we used to use such function in the kernel stuff of reiserfs. Lets
+// have them in utils as well
+inline __u32 cpu_to_le32 (__u32 val)
+{
+    if (endianess == ENDIANESS_NOT_DEFINED)
+	find_endianess ();
+
+    if (endianess == LITTLE_ENDIAN_ARCH)
+	return val;
+
+    die ("neither big- nor any other endian archs are supported yet ");
+
+    return ((val>>24) | ((val>>8)&0xFF00) |
+	    ((val<<8)&0xFF0000) | (val<<24));
+}
+
+
+inline __u32 le32_to_cpu (__u32 val)
+{
+    return cpu_to_le32 (val);
+}
+
+
+inline __u16 cpu_to_le16 (__u16 val)
+{
+    return val;
+
+    if (endianess == ENDIANESS_NOT_DEFINED)
+	find_endianess ();
+
+    if (endianess == LITTLE_ENDIAN_ARCH)
+	return val;
+    die ("neither big- nor pdp- endian arch are supported yet ");
+
+    return (val >> 8) | (val << 8);
+}
+
+
+inline __u16 le16_to_cpu (__u16 val)
+{
+    /*printf ("%s:%u %p %p %p\n", __FILE__, __LINE__,
+	    __builtin_return_address (0),
+	    __builtin_return_address (1),
+	    __builtin_return_address (2));*/
+    return val;
+    return cpu_to_le16 (val);
+}
+
+
+inline __u64 cpu_to_le64 (__u64 val)
+{
+    if (endianess == ENDIANESS_NOT_DEFINED)
+	find_endianess ();
+
+    if (endianess == LITTLE_ENDIAN_ARCH)
+	return val;
+    die ("neither big- nor pdp- endian arch are supported yet ");
+
+    return 0;
+}
+
+
+inline __u64 le64_to_cpu (__u64 val)
+{
+    return cpu_to_le64 (val);
+}
+
+
+/* Given a file descriptor and an offset, check whether the offset is
+   a valid offset for the file - return 0 if it isn't valid or 1 if it
+   is */
+loff_t reiserfs_llseek (unsigned int fd, loff_t offset, unsigned int origin);
+#if 0
+static int valid_offset( int fd, loff_t offset )
+{
+    char ch;
+    loff_t res;
+
+    /*res = reiserfs_llseek (fd, offset, 0);*/
+    res = lseek64 (fd, offset, 0);
+    if (res < 0)
+	return 0;
+
+    if (read (fd, &ch, 1) < 1)
+	return 0;
+
+    return 1;
+}
+#endif
+
+/* calculates number of blocks on device */
+unsigned long count_blocks (char * filename, int blocksize, int fd)
+{
+    loff_t high, low;
+    int opened_here = 0;
+
+    if (fd < 0) {
+	fd = open (filename, O_RDONLY);
+	opened_here = 1;
+    }
+    if (fd < 0)
+	die ("count_blocks: open failed (%s)", strerror (errno));
+
+#ifdef BLKGETSIZE
+    {
+	long size;
+
+	if (ioctl (fd, BLKGETSIZE, &size) >= 0) {
+	    if (opened_here)
+		close (fd);
+	    return  size / (blocksize / 512);
+	}
+    }
+#endif
+
+    low = 0;
+    for( high = 1; valid_offset (fd, high); high *= 2 )
+	low = high;
+    while (low < high - 1) {
+	const loff_t mid = ( low + high ) / 2;
+
+	if (valid_offset (fd, mid))
+	    low = mid;
+	else
+	    high = mid;
+    }
+    valid_offset (fd, 0);
+    if (opened_here)
+        close (fd);
+
+    return (low + 1) / (blocksize);
+}
+
+
+
diff --git a/missing b/missing
new file mode 100755
index 0000000..7789652
--- /dev/null
+++ b/missing
@@ -0,0 +1,190 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+case "$1" in
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]"
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing - GNU libit 0.0"
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+  aclocal)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acinclude.m4' or \`configure.in'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`configure.in'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`acconfig.h' or \`configure.in'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case "$f" in
+      *:*) touch_files="$touch_files "`echo "$f" |
+				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+	   sed 's/\.am$/.in/' |
+	   while read f; do touch "$f"; done
+    ;;
+
+  bison|yacc)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.y)
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.c
+	    fi
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" y.tab.h
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f y.tab.h ]; then
+	echo >y.tab.h
+    fi
+    if [ ! -f y.tab.c ]; then
+	echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex|flex)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if [ $# -ne 1 ]; then
+        eval LASTARG="\${$#}"
+	case "$LASTARG" in
+	*.l)
+	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+	    if [ -f "$SRCFILE" ]; then
+	         cp "$SRCFILE" lex.yy.c
+	    fi
+	  ;;
+	esac
+    fi
+    if [ ! -f lex.yy.c ]; then
+	echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  makeinfo)
+    echo 1>&2 "\
+WARNING: \`$1' is missing on your system.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+    if test -z "$file"; then
+      file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+    fi
+    touch $file
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+         system.  You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequirements for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 0000000..dd68e26
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1.1.1 2000/08/03 10:35:16 vs Exp $
+
+errstatus=0
+
+for file
+do
+   set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+   shift
+
+   pathcomp=
+   for d
+   do
+     pathcomp="$pathcomp$d"
+     case "$pathcomp" in
+       -* ) pathcomp=./$pathcomp ;;
+     esac
+
+     if test ! -d "$pathcomp"; then
+        echo "mkdir $pathcomp"
+
+        mkdir "$pathcomp" || lasterr=$?
+
+        if test ! -d "$pathcomp"; then
+  	  errstatus=$lasterr
+        fi
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/mkreiserfs/Makefile.am b/mkreiserfs/Makefile.am
new file mode 100644
index 0000000..54198db
--- /dev/null
+++ b/mkreiserfs/Makefile.am
@@ -0,0 +1,9 @@
+sbin_PROGRAMS = mkreiserfs
+
+mkreiserfs_SOURCES = mkreiserfs.c
+man_MANS = mkreiserfs.8
+EXTRA_DIST = $(man_MANS)
+
+LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
+
+INCLUDES = -I../include
diff --git a/mkreiserfs/Makefile.in b/mkreiserfs/Makefile.in
new file mode 100644
index 0000000..f73f030
--- /dev/null
+++ b/mkreiserfs/Makefile.in
@@ -0,0 +1,325 @@
+# 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 = mkreiserfs
+
+mkreiserfs_SOURCES = mkreiserfs.c
+man_MANS = mkreiserfs.8
+EXTRA_DIST = $(man_MANS)
+
+LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
+
+INCLUDES = -I../include
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(sbin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+mkreiserfs_OBJECTS =  mkreiserfs.o
+mkreiserfs_LDADD = $(LDADD)
+mkreiserfs_DEPENDENCIES =  ../lib/libmisc.a ../reiserfscore/libcore.a
+mkreiserfs_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 = $(mkreiserfs_SOURCES)
+OBJECTS = $(mkreiserfs_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 mkreiserfs/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:
+
+mkreiserfs: $(mkreiserfs_OBJECTS) $(mkreiserfs_DEPENDENCIES)
+	@rm -f mkreiserfs
+	$(LINK) $(mkreiserfs_LDFLAGS) $(mkreiserfs_OBJECTS) $(mkreiserfs_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 = mkreiserfs
+
+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
+mkreiserfs.o: mkreiserfs.c ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.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:
diff --git a/mkreiserfs/mkreiserfs.8 b/mkreiserfs/mkreiserfs.8
new file mode 100644
index 0000000..4509f42
--- /dev/null
+++ b/mkreiserfs/mkreiserfs.8
@@ -0,0 +1,62 @@
+.\" -*- nroff -*-
+.\" Copyright 1996-2001 Hans Reiser.
+.\" 
+.TH MKREISERFS 8 "March 2001" "Reiserfsprogs-3.x.0j"
+.SH NAME
+mkreiserfs \- create a Linux Reiserfs file system
+.SH SYNOPSIS
+.B mkreiserfs
+[
+.B -h
+.I r5 
+| 
+.I tea
+|
+.I rupasov
+] [
+.B \-v
+.I 1 
+|
+.I 2
+] [
+.B -q
+]
+.I device
+[
+.I size-in-blocks
+]
+.SH DESCRIPTION
+It creates a Linux Reiserfs file system on a device
+(usually a disk partition).
+.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).
+.TP
+.I block-count
+is the number of blocks on the device. If omitted, it will be
+determined by
+.B mkreiserfs
+automatically.
+.SH OPTIONS
+.TP
+\fB\-h \fIr5\fR |\fI tea\fR |\fI rupasov
+This specifies the name of hash function file names in directories
+will be sorted with. Choose one of the above. 'r5' is default.
+.TP
+\fB\-v \fI1\fR |\fI 2
+This specifies format new filsystem has to be of.
+.TP
+\fB\-q\fR
+This makes the progress bar much less verbose.  Useful when
+logged in via a slow link (e.g. serial console).
+.SH AUTHOR
+This version of
+.B mkreiserfs
+has been written by Hans Reiser <reiser@idiom.com>.
+.SH BUGS
+No other blocksizes but 4k are available.
+Please, report about other bugs to Hans Reiser <reiser@idiom.com>.
+.SH SEE ALSO
+.BR reiserfsck (8),
+.BR debugreiserfs (8)
diff --git a/mkreiserfs/mkreiserfs.c b/mkreiserfs/mkreiserfs.c
new file mode 100644
index 0000000..a907d19
--- /dev/null
+++ b/mkreiserfs/mkreiserfs.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright 1996, 1997, 1998, 1999 Hans Reiser
+ */
+
+/* mkreiserfs is very simple. It supports only 4 and 8K blocks. It skips
+   first 64k of device, and then writes the super
+   block, the needed amount of bitmap blocks (this amount is calculated
+   based on file system size), and root block. Bitmap policy is
+   primitive: it assumes, that device does not have unreadable blocks,
+   and it occupies first blocks for super, bitmap and root blocks.
+   bitmap blocks are interleaved across the disk, mainly to make
+   resizing faster. */
+
+//
+// FIXME: not 'not-i386' safe
+//
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/vfs.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <linux/major.h>
+#include <sys/stat.h>
+#include <linux/kdev_t.h>
+
+#include "io.h"
+#include "misc.h"
+#include "reiserfs_lib.h"
+#include "../version.h"
+
+
+#define print_usage_and_exit() die ("Usage: %s [ -f ] [ -h tea | rupasov | r5 ]"\
+				    " [ -v 1 | 2] [ -q ] device [block-count]\n\n", argv[0])
+
+
+#define DEFAULT_BLOCKSIZE 4096
+
+
+
+
+struct buffer_head * g_sb_bh;
+struct buffer_head * g_bitmap_bh;
+struct buffer_head * g_rb_bh;
+struct buffer_head * g_journal_bh ;
+
+
+int g_block_size = DEFAULT_BLOCKSIZE;
+unsigned long int g_block_number;
+int g_hash = DEFAULT_HASH;
+int g_3_6_format = 1; /* new format is default */
+
+int quiet = 0;
+
+/* reiserfs needs at least: enough blocks for journal, 64 k at the beginning,
+   one block for super block, bitmap block and root block */
+static unsigned long min_block_amount (int block_size, unsigned long journal_size)
+{
+    unsigned long blocks;
+
+    blocks = REISERFS_DISK_OFFSET_IN_BYTES / block_size + 
+	1 + 1 + 1 + journal_size;
+    if (blocks > block_size * 8)
+	die ("mkreiserfs: journal size specified incorrectly");
+
+    return blocks;
+}
+
+
+/* form super block (old one) */
+static void make_super_block (int dev)
+{
+    struct reiserfs_super_block * rs;
+    int sb_size = g_3_6_format ? SB_SIZE : SB_SIZE_V1;
+    __u32 * oids;
+
+
+    if (SB_SIZE > g_block_size)
+	die ("mkreiserfs: blocksize (%d) too small", g_block_size);
+
+    /* get buffer for super block */
+    g_sb_bh = getblk (dev, REISERFS_DISK_OFFSET_IN_BYTES / g_block_size, g_block_size);
+
+    rs = (struct reiserfs_super_block *)g_sb_bh->b_data;
+    set_blocksize (rs, g_block_size);
+    set_block_count (rs, g_block_number);
+    set_state (rs, REISERFS_VALID_FS);
+    set_tree_height (rs, 2);
+
+    set_bmap_nr (rs, (g_block_number + (g_block_size * 8 - 1)) / (g_block_size * 8));
+    set_version (rs, g_3_6_format ? REISERFS_VERSION_2 : REISERFS_VERSION_1);
+
+    set_hash (rs, g_hash);
+
+    // journal things
+    rs->s_v1.s_journal_dev = cpu_to_le32 (0) ;
+    rs->s_v1.s_orig_journal_size = cpu_to_le32 (JOURNAL_BLOCK_COUNT) ;
+    rs->s_v1.s_journal_trans_max = cpu_to_le32 (0) ;
+    rs->s_v1.s_journal_block_count = cpu_to_le32 (0) ;
+    rs->s_v1.s_journal_max_batch = cpu_to_le32 (0) ;
+    rs->s_v1.s_journal_max_commit_age = cpu_to_le32 (0) ;
+    rs->s_v1.s_journal_max_trans_age = cpu_to_le32 (0) ;
+
+    // the differences between sb V1 and sb V2 are: magic string
+    memcpy (rs->s_v1.s_magic, g_3_6_format ? REISER2FS_SUPER_MAGIC_STRING : REISERFS_SUPER_MAGIC_STRING,
+	    strlen (g_3_6_format ? REISER2FS_SUPER_MAGIC_STRING : REISERFS_SUPER_MAGIC_STRING));
+    // start of objectid map
+    oids = (__u32 *)((char *)rs + sb_size);
+    
+    // max size of objectid map
+    rs->s_v1.s_oid_maxsize = cpu_to_le16 ((g_block_size - sb_size) / sizeof(__u32) / 2 * 2);
+
+    oids[0] = cpu_to_le32 (1);
+    oids[1] = cpu_to_le32 (REISERFS_ROOT_OBJECTID + 1);
+    set_objectid_map_size (rs, 2);
+
+    mark_buffer_dirty (g_sb_bh);
+    mark_buffer_uptodate (g_sb_bh, 1);
+    return;
+
+}
+
+
+void zero_journal_blocks(int dev, int start, int len) {
+    int i ;
+    struct buffer_head *bh ;
+    unsigned long done = 0;
+
+    printf ("Initializing journal - "); fflush (stdout);
+
+    for (i = 0 ; i < len ; i++) {
+	print_how_far (&done, len, 1, quiet);
+
+	bh = getblk (dev, start + i, g_block_size) ;
+	memset(bh->b_data, 0, g_block_size) ;
+	mark_buffer_dirty(bh) ;
+	mark_buffer_uptodate(bh,0) ;
+	bwrite (bh);
+	brelse(bh) ;
+    }
+    printf ("\n"); fflush (stdout);
+}
+
+
+/* this only sets few first bits in bitmap block. Fills not initialized fields
+   of super block (root block and bitmap block numbers) */
+static void make_bitmap (void)
+{
+    struct reiserfs_super_block * rs = (struct reiserfs_super_block *)g_sb_bh->b_data;
+    int i, j;
+    
+    /* get buffer for bitmap block */
+    g_bitmap_bh = getblk (g_sb_bh->b_dev, g_sb_bh->b_blocknr + 1, g_sb_bh->b_size);
+  
+    /* mark, that first 8K of device is busy */
+    for (i = 0; i < REISERFS_DISK_OFFSET_IN_BYTES / g_block_size; i ++)
+	set_bit (i, g_bitmap_bh->b_data);
+    
+    /* mark that super block is busy */
+    set_bit (i++, g_bitmap_bh->b_data);
+
+    /* mark first bitmap block as busy */
+    set_bit (i ++, g_bitmap_bh->b_data);
+  
+    /* sb->s_journal_block = g_block_number - JOURNAL_BLOCK_COUNT ; */ /* journal goes at end of disk */
+    set_journal_start (rs, i);
+
+    /* mark journal blocks as busy BUG! we need to check to make sure journal
+       will fit in the first bitmap block */
+    for (j = 0 ; j < (JOURNAL_BLOCK_COUNT + 1); j++) /* the descriptor block goes after the journal */
+	set_bit (i ++, g_bitmap_bh->b_data);
+
+    /* and tree root is busy */
+    set_bit (i, g_bitmap_bh->b_data);
+
+    set_root_block (rs, i);
+    set_free_blocks (rs, rs_block_count (rs) - i - 1);
+
+    /* count bitmap blocks not resides in first s_blocksize blocks - ?? */
+    set_free_blocks (rs, rs_free_blocks (rs) - (rs_bmap_nr (rs) - 1));
+
+    mark_buffer_dirty (g_bitmap_bh);
+    mark_buffer_uptodate (g_bitmap_bh, 0);
+
+    mark_buffer_dirty (g_sb_bh);
+    return;
+}
+
+
+/* form the root block of the tree (the block head, the item head, the
+   root directory) */
+static void make_root_block (void)
+{
+    struct reiserfs_super_block * rs = (struct reiserfs_super_block *)g_sb_bh->b_data;
+    char * rb;
+    struct item_head * ih;
+
+    /* get memory for root block */
+    g_rb_bh = getblk (g_sb_bh->b_dev, rs_root_block (rs), rs_blocksize (rs));
+    rb = g_rb_bh->b_data;
+
+    /* block head */
+    set_leaf_node_level (g_rb_bh);
+    set_node_item_number (g_rb_bh, 0);
+    set_node_free_space (g_rb_bh, rs_blocksize (rs) - BLKH_SIZE);
+    
+    /* first item is stat data item of root directory */
+    ih = (struct item_head *)(g_rb_bh->b_data + BLKH_SIZE);
+
+    make_dir_stat_data (g_block_size, g_3_6_format ? KEY_FORMAT_2 : KEY_FORMAT_1,
+			REISERFS_ROOT_PARENT_OBJECTID, REISERFS_ROOT_OBJECTID,
+			ih, g_rb_bh->b_data + g_block_size - (g_3_6_format ? SD_SIZE : SD_V1_SIZE));
+    set_ih_location (ih, g_block_size - ih_item_len (ih));
+
+    // adjust block head
+    set_node_item_number (g_rb_bh, node_item_number (g_rb_bh) + 1);
+    set_node_free_space (g_rb_bh, node_free_space (g_rb_bh) - (IH_SIZE + ih_item_len (ih)));
+  
+
+    /* second item is root directory item, containing "." and ".." */
+    ih ++;
+    ih->ih_key.k_dir_id = cpu_to_le32 (REISERFS_ROOT_PARENT_OBJECTID);
+    ih->ih_key.k_objectid = cpu_to_le32 (REISERFS_ROOT_OBJECTID);
+    ih->ih_key.u.k_offset_v1.k_offset = cpu_to_le32 (DOT_OFFSET);
+    ih->ih_key.u.k_offset_v1.k_uniqueness = cpu_to_le32 (DIRENTRY_UNIQUENESS);
+    ih->ih_item_len = cpu_to_le16 (g_3_6_format ? EMPTY_DIR_SIZE : EMPTY_DIR_SIZE_V1);
+    ih->ih_item_location = cpu_to_le16 (ih_location (ih-1) - ih_item_len (ih));
+    ih->u.ih_entry_count = cpu_to_le16 (2);
+    set_key_format (ih, KEY_FORMAT_1);
+
+    if (g_3_6_format)
+	make_empty_dir_item (g_rb_bh->b_data + ih_location (ih),
+			     REISERFS_ROOT_PARENT_OBJECTID, REISERFS_ROOT_OBJECTID,
+			     0, REISERFS_ROOT_PARENT_OBJECTID);
+    else
+	make_empty_dir_item_v1 (g_rb_bh->b_data + ih_location (ih),
+				REISERFS_ROOT_PARENT_OBJECTID, REISERFS_ROOT_OBJECTID,
+				0, REISERFS_ROOT_PARENT_OBJECTID);
+
+    // adjust block head
+    set_node_item_number (g_rb_bh, node_item_number (g_rb_bh) + 1);
+    set_node_free_space (g_rb_bh, node_free_space (g_rb_bh) - (IH_SIZE + ih_item_len (ih)));
+
+
+    print_block (stdout, 0, g_rb_bh, 3, -1, -1);
+    
+    mark_buffer_dirty (g_rb_bh);
+    mark_buffer_uptodate (g_rb_bh, 0);
+    return;
+}
+
+
+/*
+ *  write the super block, the bitmap blocks and the root of the tree
+ */
+static void write_super_and_root_blocks (void)
+{
+    struct reiserfs_super_block * rs = (struct reiserfs_super_block *)g_sb_bh->b_data;
+    int i;
+
+    zero_journal_blocks(g_sb_bh->b_dev, rs_journal_start (rs), JOURNAL_BLOCK_COUNT + 1) ;
+
+    /* super block */
+    bwrite (g_sb_bh);
+
+    /* bitmap blocks */
+    for (i = 0; i < rs_bmap_nr (rs); i ++) {
+	if (i != 0) {
+	    g_bitmap_bh->b_blocknr = i * rs_blocksize (rs) * 8;
+	    memset (g_bitmap_bh->b_data, 0, g_bitmap_bh->b_size);
+	    set_bit (0, g_bitmap_bh->b_data);
+	}
+	if (i == rs_bmap_nr (rs) - 1) {
+	    int j;
+
+	    /* fill unused part of last bitmap block with 1s */
+	    if (rs_block_count (rs) % (rs_blocksize (rs) * 8))
+		for (j = rs_block_count (rs) % (rs_blocksize (rs) * 8); j < rs_blocksize (rs) * 8; j ++) {
+		    set_bit (j, g_bitmap_bh->b_data);
+		}
+	}
+	/* write bitmap */
+	mark_buffer_dirty (g_bitmap_bh);
+	bwrite (g_bitmap_bh);
+    }
+
+    /* root block */
+    bwrite (g_rb_bh);
+    brelse (g_rb_bh);
+    brelse (g_bitmap_bh);
+    brelse (g_sb_bh);
+}
+
+
+static void report (char * devname)
+{
+    struct reiserfs_super_block * rs = (struct reiserfs_super_block *)g_sb_bh->b_data;
+    unsigned int i;
+
+    printf ("Creating reiserfs of %s format\n", g_3_6_format ? "3.6" : "3.5");
+    printf ("Block size %d bytes\n", rs_blocksize (rs));
+    printf ("Block count %d\n", rs_block_count (rs));
+    printf ("Used blocks %d\n", rs_block_count (rs) - rs_free_blocks (rs));
+    printf ("Free blocks count %d\n", rs_free_blocks (rs));
+    printf ("First %ld blocks skipped\n", g_sb_bh->b_blocknr);
+    printf ("Super block is in %ld\n", g_sb_bh->b_blocknr);
+    printf ("Bitmap blocks (%d) are : \n\t%ld", rs_bmap_nr (rs), g_bitmap_bh->b_blocknr);
+    for (i = 1; i < rs_bmap_nr (rs); i ++) {
+	printf (", %d", i * rs_blocksize (rs) * 8);
+    }
+    printf ("\nJournal size %d (blocks %d-%d of file %s)\n",
+	    JOURNAL_BLOCK_COUNT, rs_journal_start (rs), 
+	    rs_journal_start (rs) + JOURNAL_BLOCK_COUNT, devname);
+    printf ("Root block %u\n", rs_root_block (rs));
+    printf ("Hash function \"%s\"\n", g_hash == TEA_HASH ? "tea" :
+	    ((g_hash == YURA_HASH) ? "rupasov" : "r5"));
+    fflush (stdout);
+}
+
+
+/* wipe out first 2 k of a device and both possible reiserfs super block */
+static void invalidate_other_formats (int dev)
+{
+    struct buffer_head * bh;
+    
+    bh = getblk (dev, 0, 2048);
+    mark_buffer_uptodate (bh, 1);
+    mark_buffer_dirty (bh);
+    bwrite (bh);
+    brelse (bh);
+
+    bh = getblk(dev, REISERFS_OLD_DISK_OFFSET_IN_BYTES / 1024, 1024) ;
+    mark_buffer_uptodate (bh, 1);
+    mark_buffer_dirty (bh);
+    bwrite (bh);
+    brelse (bh);
+
+    bh = getblk(dev, REISERFS_DISK_OFFSET_IN_BYTES / 1024, 1024) ;
+    mark_buffer_uptodate (bh, 1);
+    mark_buffer_dirty (bh);
+    bwrite (bh);
+    brelse (bh);
+}
+
+
+static void set_hash_function (char * str)
+{
+    if (!strcmp (str, "tea"))
+	g_hash = TEA_HASH;
+    else if (!strcmp (str, "rupasov"))
+	g_hash = YURA_HASH;
+    else if (!strcmp (str, "r5"))
+	g_hash = R5_HASH;
+    else
+	printf ("mkreiserfs: wrong hash type specified. Using default\n");
+}
+
+
+static void set_reiserfs_version (char * str)
+{
+    if (!strcmp (str, "1"))
+	g_3_6_format = 0;
+    else if (!strcmp (str, "2"))
+	g_3_6_format = 1;
+    else
+	printf ("mkreiserfs: wrong reiserfs version specified. Using default 3.5 format\n");
+}
+
+
+int main (int argc, char **argv)
+{
+    char *tmp;
+    int dev;
+    int force = 0;
+    struct stat st;
+    char * device_name;
+    char c;
+
+    print_banner ("mkreiserfs");
+
+    if (argc < 2)
+	print_usage_and_exit ();
+
+
+    while ( ( c = getopt( argc, argv, "fh:v:q" ) ) != EOF )
+	switch( c )
+	{
+	case 'f' : /* force if file is not a block device or fs is
+                      mounted. Confirm still required */
+	    force = 1;
+	    break;
+
+	case 'h':
+	    set_hash_function (optarg);
+	    break;
+
+	case 'v':
+	    set_reiserfs_version (optarg);
+	    break;
+
+	case 'q':
+	    quiet = 1;
+            break;
+
+	default :
+	    print_usage_and_exit ();
+	}
+    device_name = argv [optind];
+  
+
+    /* get block number for file system */
+    if (optind == argc - 2) {
+	g_block_number = strtol (argv[optind + 1], &tmp, 0);
+	if (*tmp == 0) {    /* The string is integer */
+	    if (g_block_number > count_blocks (device_name, g_block_size, -1))
+		die ("mkreiserfs: specified block number (%d) is too high", g_block_number);
+	} else {
+	    die ("mkreiserfs: bad block count : %s\n", argv[optind + 1]);
+	}	
+    } else 
+	if (optind == argc - 1) {
+	    /* number of blocks is not specified */
+	    g_block_number = count_blocks (device_name, g_block_size, -1);
+	    tmp = "";
+	} else
+	    print_usage_and_exit ();
+
+
+    /*g_block_number = g_block_number / 8 * 8;*/
+
+    if (g_block_number < min_block_amount (g_block_size, JOURNAL_BLOCK_COUNT + 1))
+	die ("mkreiserfs: can not create filesystem on that small device (%lu blocks).\n"
+	     "It should have at least %lu blocks",
+	     g_block_number, min_block_amount (g_block_size, JOURNAL_BLOCK_COUNT + 1));
+
+    if (is_mounted (device_name)) {
+	printf ("mkreiserfs: '%s' contains a mounted file system\n", device_name);
+	if (!force)
+	    exit (1);
+	if (!user_confirmed ("Forced to continue, but please confirm (y/n)", "y"))
+	    exit (1);
+    }
+
+    dev = open (device_name, O_RDWR);
+    if (dev == -1)
+	die ("mkreiserfs: can not open '%s': %s", device_name, strerror (errno));
+  
+    if (fstat (dev, &st) < 0)
+	die ("mkreiserfs: unable to stat %s", device_name);
+
+    if (!S_ISBLK (st.st_mode)) {
+	printf ("mkreiserfs: %s is not a block special device.\n", device_name);
+	if (!force) {
+	    exit (1);
+	}
+	if (!user_confirmed ("Forced to continue, but please confirm (y/n)", "y"))
+	    exit (1);
+    } else {
+	// from e2progs-1.18/misc/mke2fs.c
+	if ((MAJOR (st.st_rdev) == HD_MAJOR && MINOR (st.st_rdev)%64 == 0) ||
+	    (SCSI_BLK_MAJOR (MAJOR(st.st_rdev)) && MINOR (st.st_rdev) % 16 == 0)) {
+	    printf ("mkreiserfs: %s is entire device, not just one partition! Continue? (y/n) ", 
+		   device_name); 
+	    if (!user_confirmed ("Continue (y/n)", "y"))
+		exit (1);
+	}
+    }
+
+    /* these fill buffers (super block, first bitmap, root block) with
+       reiserfs structures */
+    make_super_block (dev);
+    make_bitmap ();
+    make_root_block ();
+  
+    report (device_name);
+
+    printf ("ATTENTION: YOU SHOULD REBOOT AFTER FDISK!\n\t    ALL DATA WILL BE LOST ON '%s'! ", device_name);
+    if (!user_confirmed ("(y/n)", "y\n"))
+	die ("mkreiserfs: Disk was not formatted");
+
+    invalidate_other_formats (dev);
+    write_super_and_root_blocks ();
+
+    check_and_free_buffer_mem ();
+
+    printf ("Syncing.."); fflush (stdout);
+
+    close(dev) ;
+    sync ();
+ 
+    printf ("\n\nReiserFS core development sponsored by SuSE Labs (suse.com)\n\n"
+	    "Journaling sponsored by MP3.com.\n\n"
+	    //"Item handlers sponsored by Ecila.com\n\n
+	    "To learn about the programmers and ReiserFS, please go to\n"
+	    "http://www.devlinux.com/namesys\n\nHave fun.\n\n"); 
+    fflush (stdout);
+    return 0;
+}
diff --git a/reiserfscore/Makefile.am b/reiserfscore/Makefile.am
new file mode 100644
index 0000000..3dc78bc
--- /dev/null
+++ b/reiserfscore/Makefile.am
@@ -0,0 +1,5 @@
+noinst_LIBRARIES = libcore.a
+
+libcore_a_SOURCES = do_balan.c fix_node.c hashes.c ibalance.c lbalance.c prints.c stree.c node_formats.c reiserfslib.c bitmap.c includes.h
+
+INCLUDES = -I../include
diff --git a/reiserfscore/Makefile.in b/reiserfscore/Makefile.in
new file mode 100644
index 0000000..967298f
--- /dev/null
+++ b/reiserfscore/Makefile.in
@@ -0,0 +1,280 @@
+# 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@
+
+noinst_LIBRARIES = libcore.a
+
+libcore_a_SOURCES = do_balan.c fix_node.c hashes.c ibalance.c lbalance.c prints.c stree.c node_formats.c reiserfslib.c bitmap.c includes.h
+
+INCLUDES = -I../include
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+LIBRARIES =  $(noinst_LIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libcore_a_LIBADD = 
+libcore_a_OBJECTS =  do_balan.o fix_node.o hashes.o ibalance.o \
+lbalance.o prints.o stree.o node_formats.o reiserfslib.o bitmap.o
+AR = ar
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON =  Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = tar
+GZIP_ENV = --best
+SOURCES = $(libcore_a_SOURCES)
+OBJECTS = $(libcore_a_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 reiserfscore/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) \
+	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-noinstLIBRARIES:
+
+clean-noinstLIBRARIES:
+	-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+
+distclean-noinstLIBRARIES:
+
+maintainer-clean-noinstLIBRARIES:
+
+.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:
+
+libcore.a: $(libcore_a_OBJECTS) $(libcore_a_DEPENDENCIES)
+	-rm -f libcore.a
+	$(AR) cru libcore.a $(libcore_a_OBJECTS) $(libcore_a_LIBADD)
+	$(RANLIB) libcore.a
+
+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 = reiserfscore
+
+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
+bitmap.o: bitmap.c includes.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h
+do_balan.o: do_balan.c includes.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h
+fix_node.o: fix_node.c includes.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h
+hashes.o: hashes.c
+ibalance.o: ibalance.c includes.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h
+lbalance.o: lbalance.c includes.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h
+node_formats.o: node_formats.c includes.h ../include/io.h \
+	../include/misc.h ../include/reiserfs_lib.h \
+	../include/reiserfs_fs.h
+prints.o: prints.c includes.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h
+reiserfslib.o: reiserfslib.c includes.h ../include/io.h \
+	../include/misc.h ../include/reiserfs_lib.h \
+	../include/reiserfs_fs.h
+stree.o: stree.c includes.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-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am:
+uninstall: uninstall-am
+all-am: Makefile $(LIBRARIES)
+all-redirect: all-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+
+
+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-noinstLIBRARIES mostlyclean-compile \
+		mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+		mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-noinstLIBRARIES distclean-compile \
+		distclean-tags distclean-generic clean-am
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-noinstLIBRARIES \
+		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-noinstLIBRARIES distclean-noinstLIBRARIES \
+clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile 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:
diff --git a/reiserfscore/bitmap.c b/reiserfscore/bitmap.c
new file mode 100644
index 0000000..4318c08
--- /dev/null
+++ b/reiserfscore/bitmap.c
@@ -0,0 +1,448 @@
+/* 
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+  
+/*
+ * 2000/10/26 - Initial version.
+ */
+
+#include <assert.h>
+#include "includes.h"
+
+
+/* create clean bitmap */
+reiserfs_bitmap_t reiserfs_create_bitmap (unsigned int bit_count)
+{
+    reiserfs_bitmap_t bm;
+
+    bm = getmem (sizeof (*bm));
+    if (!bm)
+	return 0;
+    bm->bm_bit_size = bit_count;
+    bm->bm_byte_size = (bit_count + 7) / 8;
+    bm->bm_set_bits = 0;
+    bm->bm_map = getmem (bm->bm_byte_size);
+    if (!bm->bm_map) {
+	freemem (bm);
+	return 0;
+    }
+
+    return bm;
+}
+
+/* Expand existing bitmap.  Return non-zero if can't. FIXME: it is
+   assumed that bit_count is new number of blocks to be addressed */
+int reiserfs_expand_bitmap (reiserfs_bitmap_t bm, unsigned int bit_count)
+{
+    unsigned int byte_count = ((bit_count + 7) / 8);
+    char * new_map;
+
+    new_map = expandmem (bm->bm_map, bm->bm_byte_size,
+			 byte_count - bm->bm_byte_size);
+
+    if (!new_map) {
+	return 1;
+    }
+    
+    bm->bm_map = new_map;
+    bm->bm_byte_size = byte_count;
+    bm->bm_bit_size = bit_count;
+    return 0;
+}
+
+/* bitmap destructor */
+void reiserfs_delete_bitmap (reiserfs_bitmap_t bm)
+{
+    freemem(bm->bm_map);
+    bm->bm_map = NULL;		/* to not reuse bitmap handle */
+    bm->bm_bit_size = 0;
+    bm->bm_byte_size = 0;
+    freemem(bm);
+}
+
+
+void reiserfs_bitmap_copy (reiserfs_bitmap_t to, reiserfs_bitmap_t from)
+{
+    assert (to->bm_byte_size == from->bm_byte_size);
+    memcpy (to->bm_map, from->bm_map, from->bm_byte_size);
+    to->bm_bit_size = from->bm_bit_size;
+    to->bm_set_bits = from->bm_set_bits;
+}
+
+
+int reiserfs_bitmap_compare (reiserfs_bitmap_t bm1, reiserfs_bitmap_t bm2)
+{
+    int bytes, bits;
+    int i, diff;
+
+    assert (bm1->bm_byte_size == bm2->bm_byte_size &&
+	    bm1->bm_bit_size == bm2->bm_bit_size);
+
+    diff = 0;
+
+    /* compare full bytes */
+    bytes = bm1->bm_bit_size / 8;
+    if (memcmp (bm1->bm_map, bm2->bm_map, bytes)) {
+	for (i = 0; i < bytes; i ++)
+	    if (bm1->bm_map [i] != bm2->bm_map[i]) {
+		printf ("byte %d: bm1: %x bm2 %x\n", i, bm1->bm_map[i], bm2->bm_map[i]);
+		diff ++;
+	    }
+    }
+
+    /* compare last byte of bitmap which can be used partially */
+    bits = bm1->bm_bit_size % 8;
+    if (bits) {
+	int mask;
+
+	mask = 255 >> (8 - bits);
+	if ((bm1->bm_map [bytes] & mask) != (bm2->bm_map [bytes] & mask)) {
+	    printf ("last byte %d: bm1: %x bm2 %x\n", bytes, bm1->bm_map[bytes], bm2->bm_map[bytes]);
+	    diff ++;
+	}
+    }
+    return diff;
+}
+
+
+void reiserfs_bitmap_set_bit (reiserfs_bitmap_t bm, unsigned int bit_number)
+{
+    assert(bit_number < bm->bm_bit_size);
+    if (test_bit (bit_number, bm->bm_map))
+	return;
+    set_bit(bit_number, bm->bm_map);
+    bm->bm_set_bits ++;
+}
+
+
+void reiserfs_bitmap_clear_bit (reiserfs_bitmap_t bm, unsigned int bit_number)
+{
+    assert(bit_number < bm->bm_bit_size);
+    if (!test_bit (bit_number, bm->bm_map))
+	return;
+    clear_bit (bit_number, bm->bm_map);
+    bm->bm_set_bits --;
+}
+
+
+int reiserfs_bitmap_test_bit (reiserfs_bitmap_t bm, unsigned int bit_number)
+{
+    if (bit_number >= bm->bm_bit_size)
+	printf ("bit %u, bitsize %lu\n", bit_number, bm->bm_bit_size);
+    assert(bit_number < bm->bm_bit_size);
+    return test_bit(bit_number, bm->bm_map);
+}
+
+
+int reiserfs_bitmap_zeros (reiserfs_bitmap_t bm)
+{
+    return bm->bm_bit_size - bm->bm_set_bits;
+}
+
+
+int reiserfs_bitmap_ones (reiserfs_bitmap_t bm)
+{
+    return bm->bm_set_bits;
+}
+
+
+int reiserfs_bitmap_find_zero_bit (reiserfs_bitmap_t bm, unsigned long * start)
+{
+    unsigned int  bit_nr = *start;
+    assert(*start < bm->bm_bit_size);
+
+    bit_nr = find_next_zero_bit(bm->bm_map, bm->bm_bit_size, *start);
+
+    if (bit_nr >= bm->bm_bit_size) { /* search failed */	
+	return 1;
+    }
+
+    *start = bit_nr;
+    return 0;
+}
+
+
+/* copy reiserfs filesystem bitmap into memory bitmap */
+int reiserfs_fetch_disk_bitmap (reiserfs_bitmap_t bm, reiserfs_filsys_t fs)
+{
+    int i;
+    int bytes;
+    char * p;
+    int unused_bits;
+
+    reiserfs_warning (stderr, "Fetching on-disk bitmap..");
+    assert (bm->bm_bit_size == SB_BLOCK_COUNT (fs));
+
+    bytes = fs->s_blocksize;
+    p = bm->bm_map;
+    for (i = 0; i < SB_BMAP_NR (fs); i ++) {
+	if ((i == (SB_BMAP_NR (fs) - 1)) && bm->bm_byte_size % fs->s_blocksize)
+	    bytes = bm->bm_byte_size % fs->s_blocksize;
+
+	memcpy (p, SB_AP_BITMAP (fs)[i]->b_data, bytes);
+	p += bytes;
+    }
+
+    /* on disk bitmap has bits out of SB_BLOCK_COUNT set to 1, where as
+       reiserfs_bitmap_t has those bits set to 0 */
+    unused_bits = bm->bm_byte_size * 8 - bm->bm_bit_size;
+    for (i = 0; i < unused_bits; i ++)
+	clear_bit (bm->bm_bit_size + i, bm->bm_map);
+
+    bm->bm_set_bits = 0;
+    /* FIXME: optimize that */
+    for (i = 0; i < bm->bm_bit_size; i ++)
+	if (reiserfs_bitmap_test_bit (bm, i))
+	    bm->bm_set_bits ++;
+
+    /* unused part of last bitmap block is filled with 0s */
+    if (bm->bm_bit_size % (fs->s_blocksize * 8))
+	for (i = SB_BLOCK_COUNT (fs) % (fs->s_blocksize * 8); i < fs->s_blocksize * 8; i ++)
+	    if (!test_bit (i, SB_AP_BITMAP (fs)[SB_BMAP_NR (fs) - 1]->b_data)) {
+		reiserfs_warning (stderr, "fetch_bitmap: on-disk bitmap is not padded properly\n");
+		break;
+	    }
+    
+    reiserfs_warning (stderr, "done\n");
+    return 0;
+}
+
+
+/* copy bitmap to buffers which hold on-disk bitmap */
+int reiserfs_flush_bitmap (reiserfs_bitmap_t bm, reiserfs_filsys_t fs)
+{
+    int i;
+    int bytes;
+    char * p;
+
+    bytes = fs->s_blocksize;
+    p = bm->bm_map;
+    for (i = 0; i < SB_BMAP_NR (fs); i ++) {
+	if ((i == (SB_BMAP_NR (fs) - 1)) && (bm->bm_byte_size % fs->s_blocksize))
+	    bytes = bm->bm_byte_size % fs->s_blocksize;
+
+	memcpy (SB_AP_BITMAP (fs)[i]->b_data, p, bytes);
+	mark_buffer_dirty (SB_AP_BITMAP (fs)[i]);
+	
+	p += bytes;
+    }
+
+    /* unused part of last bitmap block is filled with 0s */
+    if (bm->bm_bit_size % (fs->s_blocksize * 8))
+	for (i = bm->bm_bit_size % (fs->s_blocksize * 8); i < fs->s_blocksize * 8; i ++)
+	    set_bit (i, SB_AP_BITMAP (fs)[SB_BMAP_NR (fs) - 1]->b_data);
+
+    return 0;
+}
+
+
+void reiserfs_bitmap_zero (reiserfs_bitmap_t bm)
+{
+    memset (bm->bm_map, 0, bm->bm_byte_size);
+    bm->bm_set_bits = 0;
+}
+
+
+void reiserfs_bitmap_fill (reiserfs_bitmap_t bm)
+{
+    memset (bm->bm_map, 0xff, bm->bm_byte_size);
+    bm->bm_set_bits = bm->bm_bit_size;
+}
+
+
+/* format of bitmap saved in a file:
+   magic number (32 bits)
+   bm_bit_size (32 bits)
+   number of ranges of used and free blocks (32 bits)
+   number of contiguously used block, .. of free blocks, used, free, etc
+   magic number (32 bits) */
+
+#define BITMAP_START_MAGIC 374031
+#define BITMAP_END_MAGIC 7786472
+
+void reiserfs_bitmap_save (char * filename, reiserfs_bitmap_t bm)
+{
+    FILE * fp;
+    __u32 v;
+    int zeros;
+    int count;
+    int i;
+    int extents;
+    
+    fp = fopen (filename, "w+");
+    if (!fp) {
+	reiserfs_warning (stderr, "reiserfs_bitmap_save: could not save bitmap in %s: %m",
+			  filename);
+	return;
+    }
+
+    reiserfs_warning (stderr, "Saving bitmap in \"%s\" .. ", filename); fflush (stderr);
+
+    v = BITMAP_START_MAGIC;
+    fwrite (&v, 4, 1, fp);
+
+    v = bm->bm_bit_size;
+    fwrite (&v, 4, 1, fp);
+
+    /*printf ("SAVE: bit_size - %d\n", v);*/
+
+
+    if (fseek (fp, 4, SEEK_CUR)) {
+	reiserfs_warning (stderr, "reiserfs_bitmap_save: fseek failed: %m\n");
+	fclose (fp);
+	return;
+    }
+
+    zeros = 0;
+    count = 0;
+    extents = 0;
+    for (i = 0; i < v; i ++) {
+	if (reiserfs_bitmap_test_bit (bm, i)) {
+	    if (zeros) {
+		/* previous bit was not set, write amount of not set
+                   bits, switch to count set bits */
+		fwrite (&count, 4, 1, fp);
+		/*printf ("SAVE: Free %d\n", count);*/
+		extents ++;
+		count = 1;
+		zeros = 0;
+	    } else {
+		/* one more zero bit appeared */
+		count ++;
+	    }
+	} else {
+	    /* zero bit found */
+	    if (zeros) {
+		count ++;
+	    } else {
+		/* previous bit was set, write amount of set bits,
+                   switch to count not set bits */
+		fwrite (&count, 4, 1, fp);
+		/*printf ("SAVE: Used %d\n", count);*/
+		extents ++;
+		count = 1;
+		zeros = 1;
+	    }
+	}
+    }
+
+    fwrite (&count, 4, 1, fp);
+    extents ++;
+/*
+    if (zeros)
+	printf ("SAVE: Free %d\n", count);
+    else	
+	printf ("SAVE: Used %d\n", count);
+*/
+
+    v = BITMAP_END_MAGIC;
+    fwrite (&v, 4, 1, fp);
+
+    if (fseek (fp, 8, SEEK_SET)) {
+	reiserfs_warning (stderr, "reiserfs_bitmap_save: fseek failed: %m");
+	fclose (fp);
+	return;
+    }
+
+    fwrite (&extents, 4, 1, fp);
+    /*printf ("SAVE: extents %d\n", extents);*/
+		
+    fclose (fp);
+
+    reiserfs_warning (stderr, "done\n"); fflush (stderr);
+}
+
+
+reiserfs_bitmap_t reiserfs_bitmap_load (char * filename)
+{
+    FILE * fp;
+    __u32 v;
+    int count;
+    int i, j;
+    int extents;
+    int bit;
+    reiserfs_bitmap_t bm;
+    
+    fp = fopen (filename, "r");
+    if (!fp) {
+	reiserfs_warning (stderr, "reiserfs_bitmap_load: fseek failed: %m\n");
+	return 0;
+    }
+
+    fread (&v, 4, 1, fp);
+    if (v != BITMAP_START_MAGIC) {
+	reiserfs_warning (stderr, "reiserfs_bitmap_load: "
+			  "no bitmap start magic found");	
+	fclose (fp);
+	return 0;
+    }
+	
+    /* read bit size of bitmap */
+    fread (&v, 4, 1, fp);
+
+    bm = reiserfs_create_bitmap (v);
+    if (!bm) {
+	reiserfs_warning (stderr, "reiserfs_bitmap_load: creation failed");	
+	fclose (fp);
+	return 0;
+    }
+    
+    reiserfs_warning (stderr, "Loading bitmap from %s .. ", filename); fflush (stderr);
+
+    /*printf ("LOAD: bit_size - %d\n", v);*/
+
+    fread (&extents, 4, 1, fp);
+
+    /*printf ("LOAD: extents - %d\n", extents);*/
+
+    bit = 0;
+    for (i = 0; i < extents; i ++) {
+	fread (&count, 4, 1, fp);
+/*
+	if (i % 2)
+	    printf ("LOAD: Free %d\n", count);
+	else
+	    printf ("LOAD: Used %d\n", count);
+*/
+	for (j = 0; j < count; j ++, bit ++)
+	    if (i % 2 == 0) {
+		reiserfs_bitmap_set_bit (bm, bit);
+	    }
+    }
+
+    fread (&v, 4, 1, fp);
+
+    /*printf ("LOAD: Endmagic %d\n", v);*/
+
+    fclose (fp);
+    if (v != BITMAP_END_MAGIC) {
+	reiserfs_warning (stderr, "reiserfs_bitmap_load: "
+			  "no bitmap end magic found");
+	return 0;
+    }
+
+    reiserfs_warning (stderr, "%d bits set - done\n", reiserfs_bitmap_ones (bm));
+    fflush (stderr);
+    return bm;
+}
+
+
+void reiserfs_bitmap_invert (reiserfs_bitmap_t bm)
+{
+    int i;
+
+    reiserfs_warning (stderr, "Bitmap inverting..");fflush (stderr);
+    for (i = 0; i < bm->bm_bit_size; i ++) {
+	if (reiserfs_bitmap_test_bit (bm, i))
+	    reiserfs_bitmap_clear_bit (bm, i);
+	else
+	    reiserfs_bitmap_set_bit (bm, i);
+    }
+
+    reiserfs_warning (stderr, "done\n");
+}
+
+
+
+
+
diff --git a/reiserfscore/do_balan.c b/reiserfscore/do_balan.c
new file mode 100644
index 0000000..f81ff78
--- /dev/null
+++ b/reiserfscore/do_balan.c
@@ -0,0 +1,1720 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+
+/* Now we have all buffers that must be used in balancing of the tree 	*/
+/* Further calculations can not cause schedule(), and thus the buffer 	*/
+/* tree will be stable until the balancing will be finished 		*/
+/* balance the tree according to the analysis made before,		*/
+/* and using buffers obtained after all above.				*/
+
+
+/**
+ ** balance_leaf_when_delete
+ ** balance_leaf
+ ** do_balance
+ **
+ **/
+
+#include "includes.h"
+
+
+#ifdef CONFIG_REISERFS_CHECK
+
+struct tree_balance * cur_tb = NULL; /* detects whether more than one copy of tb exists as a means
+					of checking whether schedule is interrupting do_balance */
+struct tree_balance init_tb;	/* Sometimes used to store a snapshot of tb during debugging. */
+int init_item_pos, init_pos_in_item, init_mode;  /* Sometimes used to store a snapshot of tb during debugging. */
+
+
+#endif /* CONFIG_REISERFS_CHECK */
+
+
+
+/* summary: 
+ if deleting something ( tb->insert_size[0] < 0 )
+   return(balance_leaf_when_delete()); (flag d handled here)
+ else
+   if lnum is larger than 0 we put items into the left node
+   if rnum is larger than 0 we put items into the right node
+   if snum1 is larger than 0 we put items into the new node s1
+   if snum2 is larger than 0 we put items into the new node s2 
+Note that all *num* count new items being created.
+
+It would be easier to read balance_leaf() if each of these summary
+lines was a separate procedure rather than being inlined.  I think
+that there are many passages here and in balance_leaf_when_delete() in
+which two calls to one procedure can replace two passages, and it
+might save cache space and improve software maintenance costs to do so.  
+
+Vladimir made the perceptive comment that we should offload most of
+the decision making in this function into fix_nodes/check_balance, and
+then create some sort of structure in tb that says what actions should
+be performed by do_balance.
+
+-Hans */
+
+
+
+/* Balance leaf node in case of delete or cut: insert_size[0] < 0
+ *
+ * lnum, rnum can have values >= -1
+ *	-1 means that the neighbor must be joined with S
+ *	 0 means that nothing should be done with the neighbor
+ *	>0 means to shift entirely or partly the specified number of items to the neighbor
+ */
+static int balance_leaf_when_delete (/*struct reiserfs_transaction_handle *th,*/
+				     struct tree_balance * tb, 
+				     int flag)
+{
+    struct buffer_head * tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
+    int item_pos = PATH_LAST_POSITION (tb->tb_path);
+    int pos_in_item = tb->tb_path->pos_in_item;
+    struct buffer_info bi;
+    int n;
+    struct item_head * ih;
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( tb->FR[0] && B_BLK_HEAD(tb->FR[0])->blk_level <= DISK_LEAF_NODE_LEVEL )
+	reiserfs_panic (tb->tb_sb,
+			"balance_leaf_when_delete: 11999:level == %u\n", B_BLK_HEAD(tb->FR[0])->blk_level);
+    if ( tb->blknum[0] > 1 )
+	reiserfs_panic (tb->tb_sb,
+			"PAP-12005: balance_leaf_when_delete: tb->blknum == %d, can not be > 1", tb->blknum[0]);
+	
+    if ( ! tb->blknum[0] && ! PATH_H_PPARENT(tb->tb_path, 0))
+	reiserfs_panic (tb->tb_sb, "PAP-12010: balance_leaf_when_delete: tree can not be empty");
+#endif
+
+    ih = B_N_PITEM_HEAD (tbS0, item_pos);
+
+    /* Delete or truncate the item */
+
+    switch (flag) {
+    case M_DELETE:   /* delete item in S[0] */
+
+	bi.bi_bh = tbS0;
+	bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
+	bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
+	leaf_delete_items (tb->tb_sb, &bi, 0, item_pos, 1, -1);
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (! item_pos && !tb->CFL[0])
+	    reiserfs_panic (tb->tb_sb, "PAP-12020: balance_leaf_when_delete: "
+			    "tb->CFL[0]==0 when item_pos == 0");
+#endif
+
+	if ( ! item_pos ) {
+	    // we have removed first item in the node - update left delimiting key
+	    if ( B_NR_ITEMS(tbS0) ) {
+		replace_key(tb->tb_sb, tb->CFL[0],tb->lkey[0],tbS0,0);
+	    }
+	    else {
+		if ( ! PATH_H_POSITION (tb->tb_path, 1) )
+		    replace_key(tb->tb_sb, tb->CFL[0],tb->lkey[0],PATH_H_PPARENT(tb->tb_path, 0),0);
+	    }
+	} 
+    
+	break;
+
+    case M_CUT: {  /* cut item in S[0] */
+	bi.bi_bh = tbS0;
+	bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
+	bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
+	if (I_IS_DIRECTORY_ITEM (ih)) {
+	    /* UFS unlink semantics are such that you can only delete
+               one directory entry at a time. */
+	    /* when we cut a directory tb->insert_size[0] means number
+               of entries to be cut (always 1) */
+	    tb->insert_size[0] = -1;
+	    leaf_cut_from_buffer (tb->tb_sb, &bi, item_pos, pos_in_item, -tb->insert_size[0]);
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if (! item_pos && ! pos_in_item && ! tb->CFL[0])
+		reiserfs_panic (tb->tb_sb, "PAP-12030: balance_leaf_when_delete: can not change delimiting key. CFL[0]=%p", tb->CFL[0]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+	    if ( ! item_pos && ! pos_in_item ) {
+		replace_key(tb->tb_sb, tb->CFL[0],tb->lkey[0],tbS0,0);
+	    }
+	} else {
+	    leaf_cut_from_buffer (tb->tb_sb, &bi, item_pos, pos_in_item, -tb->insert_size[0]);
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if (! ih->ih_item_len)
+		reiserfs_panic (tb->tb_sb, "PAP-12035: balance_leaf_when_delete: cut must leave non-zero dynamic length of item");
+#endif /* CONFIG_REISERFS_CHECK */
+	}
+	break;
+    }
+
+    default:
+	print_tb(flag, item_pos, pos_in_item, tb,"when_del");
+	reiserfs_panic ("PAP-12040: balance_leaf_when_delete: unexpectable mode: %s(%d)",
+			(flag == M_PASTE) ? "PASTE" : ((flag == M_INSERT) ? "INSERT" : "UNKNOWN"), flag);
+    }
+
+    /* the rule is that no shifting occurs unless by shifting a node can be freed */
+    n = B_NR_ITEMS(tbS0);
+    if ( tb->lnum[0] )     /* L[0] takes part in balancing */
+    {
+	if ( tb->lnum[0] == -1 )    /* L[0] must be joined with S[0] */
+	{
+	    if ( tb->rnum[0] == -1 )    /* R[0] must be also joined with S[0] */
+	    {			
+		if ( tb->FR[0] == PATH_H_PPARENT(tb->tb_path, 0) )
+		{
+		    /* all contents of all the 3 buffers will be in L[0] */
+		    if ( PATH_H_POSITION (tb->tb_path, 1) == 0 && 1 < B_NR_ITEMS(tb->FR[0]) )
+			replace_key(tb->tb_sb, tb->CFL[0],tb->lkey[0],tb->FR[0],1);
+
+
+		    leaf_move_items (LEAF_FROM_S_TO_L, tb, n, -1, 0);
+		    leaf_move_items (LEAF_FROM_R_TO_L, tb, B_NR_ITEMS(tb->R[0]), -1, 0);
+
+		    reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/);
+		    reiserfs_invalidate_buffer (tb, tb->R[0], 1/*do_free_block*/);
+
+		    return 0;
+		}
+		/* all contents of all the 3 buffers will be in R[0] */
+		leaf_move_items(LEAF_FROM_S_TO_R, tb, n, -1, 0);
+		leaf_move_items(LEAF_FROM_L_TO_R, tb, B_NR_ITEMS(tb->L[0]), -1, 0);
+
+		/* right_delimiting_key is correct in R[0] */
+		replace_key(tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
+
+		reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/);
+		reiserfs_invalidate_buffer (tb, tb->L[0], 1/*do_free_block*/);
+
+		return -1;
+	    }
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if ( tb->rnum[0] != 0 )
+		reiserfs_panic (tb->tb_sb, "PAP-12045: balance_leaf_when_delete: rnum must be 0 (%d)", tb->rnum[0]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+	    /* all contents of L[0] and S[0] will be in L[0] */
+	    leaf_shift_left(tb, n, -1);
+
+	    reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/);
+
+	    return 0;
+	}
+	/* a part of contents of S[0] will be in L[0] and the rest part of S[0] will be in R[0] */
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (( tb->lnum[0] + tb->rnum[0] < n ) || ( tb->lnum[0] + tb->rnum[0] > n+1 ))
+	    reiserfs_panic (tb->tb_sb, "PAP-12050: balance_leaf_when_delete: rnum(%d) and lnum(%d) and item number in S[0] are not consistent",
+			    tb->rnum[0], tb->lnum[0], n);
+
+	if (( tb->lnum[0] + tb->rnum[0] == n ) && (tb->lbytes != -1 || tb->rbytes != -1))
+	    reiserfs_panic (tb->tb_sb, "PAP-12055: balance_leaf_when_delete: bad rbytes (%d)/lbytes (%d) parameters when items are not split", 
+			    tb->rbytes, tb->lbytes);
+	if (( tb->lnum[0] + tb->rnum[0] == n + 1 ) && (tb->lbytes < 1 || tb->rbytes != -1))
+	    reiserfs_panic (tb->tb_sb, "PAP-12060: balance_leaf_when_delete: bad rbytes (%d)/lbytes (%d) parameters when items are split", 
+			    tb->rbytes, tb->lbytes);
+#endif
+
+	leaf_shift_left (tb, tb->lnum[0], tb->lbytes);
+	leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
+
+	reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/);
+
+	return 0;
+    }
+
+    if ( tb->rnum[0] == -1 ) {
+	/* all contents of R[0] and S[0] will be in R[0] */
+	leaf_shift_right(tb, n, -1);
+	reiserfs_invalidate_buffer (tb, tbS0, 1/*do_free_block*/);
+	return 0;
+    }
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( tb->rnum[0] )
+	reiserfs_panic (tb->tb_sb, "PAP-12065: balance_leaf_when_delete: bad rnum parameter must be 0 (%d)", tb->rnum[0]);
+#endif
+
+    return 0;
+}
+
+
+static int balance_leaf(/*struct reiserfs_transaction_handle *th, */
+			struct tree_balance * tb, /* see reiserfs_fs.h */
+			struct item_head * ih, /* item header of inserted item */
+			const char * body,		/* body  of inserted item or bytes to paste */
+			int flag,			/* i - insert, d - delete, c - cut, p - paste
+							   (see comment to do_balance) */
+			int zeros_number,		/* will be commented later */
+				
+			struct item_head * insert_key,  /* in our processing of one level we sometimes determine what
+							   must be inserted into the next higher level.  This insertion
+							   consists of a key or two keys and their corresponding
+							   pointers */
+			struct buffer_head ** insert_ptr /* inserted node-ptrs for the next level */
+    )
+{
+    int pos_in_item = tb->tb_path->pos_in_item; /* position in item, in bytes for direct and
+						   indirect items, in entries for directories (for
+						   which it is an index into the array of directory
+						   entry headers.) */
+    struct buffer_head * tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
+/*  struct buffer_head * tbF0 = PATH_H_PPARENT (tb->tb_path, 0);
+    int S0_b_item_order = PATH_H_B_ITEM_ORDER (tb->tb_path, 0);*/
+    int item_pos = PATH_LAST_POSITION (tb->tb_path);	/*  index into the array of item headers in S[0] 
+							    of the affected item */
+    struct buffer_info bi;
+    struct buffer_head *S_new[2];  /* new nodes allocated to hold what could not fit into S */
+    int snum[2];			   /* number of items that will be placed into S_new (includes partially shifted items) */
+    int sbytes[2];                   /* if an item is partially shifted into S_new then 
+					if it is a directory item 
+					it is the number of entries from the item that are shifted into S_new
+					else
+					it is the number of bytes from the item that are shifted into S_new
+				     */
+    int n, i;
+    int ret_val;
+
+    /* Make balance in case insert_size[0] < 0 */
+    if ( tb->insert_size[0] < 0 )
+	return balance_leaf_when_delete (/*th,*/ tb, flag);
+  
+    /* for indirect item pos_in_item is measured in unformatted node
+       pointers. Recalculate to bytes */
+    if (flag != M_INSERT && I_IS_INDIRECT_ITEM (B_N_PITEM_HEAD (tbS0, item_pos)))
+	pos_in_item *= UNFM_P_SIZE;
+
+    if ( tb->lnum[0] > 0 ) {
+	/* Shift lnum[0] items from S[0] to the left neighbor L[0] */
+	if ( item_pos < tb->lnum[0] ) {
+	    /* new item or it part falls to L[0], shift it too */
+	    n = B_NR_ITEMS(tb->L[0]);
+
+	    switch (flag) {
+	    case M_INSERT:   /* insert item into L[0] */
+
+		if ( item_pos == tb->lnum[0] - 1 && tb->lbytes != -1 ) {
+		    /* part of new item falls into L[0] */
+		    int new_item_len;
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if (!I_IS_DIRECT_ITEM (ih))
+			reiserfs_panic (tb->tb_sb, "PAP-12075: balance_leaf: " 
+					"this item (%h) can not be split on insertion", ih);
+#endif
+		    ret_val = leaf_shift_left (/*th,*/ tb, tb->lnum[0]-1, -1);
+
+		    /* Calculate item length to insert to S[0] */
+		    new_item_len = ih->ih_item_len - tb->lbytes;
+		    /* Calculate and check item length to insert to L[0] */
+		    ih->ih_item_len -= new_item_len;
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( (int)(ih->ih_item_len) <= 0 )
+			reiserfs_panic(tb->tb_sb, "PAP-12080: balance_leaf: "
+				       "there is nothing to insert into L[0]: ih_item_len=%d",
+				       (int)ih->ih_item_len);
+#endif
+
+		    /* Insert new item into L[0] */
+		    bi.bi_bh = tb->L[0];
+		    bi.bi_parent = tb->FL[0];
+		    bi.bi_position = get_left_neighbor_position (tb, 0);
+		    leaf_insert_into_buf (tb->tb_sb, &bi, n + item_pos - ret_val, ih, body,
+					  zeros_number > ih->ih_item_len ? ih->ih_item_len : zeros_number);
+
+		    /* Calculate key component, item length and body to insert into S[0] */
+		    //ih->ih_key.k_offset += tb->lbytes;
+		    set_offset (key_format (&ih->ih_key), &ih->ih_key, get_offset (&ih->ih_key) + tb->lbytes);
+		    ih->ih_item_len = new_item_len;
+		    if ( tb->lbytes >  zeros_number ) {
+			body += (tb->lbytes - zeros_number);
+			zeros_number = 0;
+		    }
+		    else
+			zeros_number -= tb->lbytes;
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( (int)(ih->ih_item_len) <= 0 )
+			reiserfs_panic(tb->tb_sb, "PAP-12085: balance_leaf: "
+				       "there is nothing to insert into S[0]: ih_item_len=%d",
+				       (int)ih->ih_item_len);
+#endif
+		} else {
+		    /* new item in whole falls into L[0] */
+		    /* Shift lnum[0]-1 items to L[0] */
+		    ret_val = leaf_shift_left(tb, tb->lnum[0]-1, tb->lbytes);
+
+		    /* Insert new item into L[0] */
+		    bi.bi_bh = tb->L[0];
+		    bi.bi_parent = tb->FL[0];
+		    bi.bi_position = get_left_neighbor_position (tb, 0);
+		    leaf_insert_into_buf (tb->tb_sb, &bi, n + item_pos - ret_val, ih, body, zeros_number);
+
+		    tb->insert_size[0] = 0;
+		    zeros_number = 0;
+		}
+		break;
+
+	    case M_PASTE:   /* append item in L[0] */
+
+		if ( item_pos == tb->lnum[0] - 1 && tb->lbytes != -1 ) {
+		    /* we must shift the part of the appended item */
+		    if ( I_IS_DIRECTORY_ITEM (B_N_PITEM_HEAD (tbS0, item_pos))) {
+
+#ifdef CONFIG_REISERFS_CHECK
+			if ( zeros_number )
+			    reiserfs_panic(tb->tb_sb, "PAP-12090: balance_leaf: illegal parameter in case of a directory");
+#endif
+            
+			/* directory item */
+			if ( tb->lbytes > pos_in_item ) {
+			    /* new directory entry falls into L[0] */
+			    struct item_head * pasted;
+			    int l_pos_in_item = pos_in_item;
+							  
+			    /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
+			    ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes - 1);
+			    if ( ret_val && ! item_pos ) {
+				pasted =  B_N_PITEM_HEAD(tb->L[0],B_NR_ITEMS(tb->L[0])-1);
+				l_pos_in_item += ih_entry_count(pasted) - (tb->lbytes-1);
+			    }
+
+			    /* Append given directory entry to directory item */
+			    bi.bi_bh = tb->L[0];
+			    bi.bi_parent = tb->FL[0];
+			    bi.bi_position = get_left_neighbor_position (tb, 0);
+			    leaf_paste_in_buffer (tb->tb_sb, &bi, n + item_pos - ret_val, l_pos_in_item,
+						  tb->insert_size[0], body, zeros_number);
+
+			    /* previous string prepared space for pasting new entry, following string pastes this entry */
+
+			    /* when we have merge directory item, pos_in_item has been changed too */
+
+			    /* paste new directory entry. 1 is entry number */
+			    leaf_paste_entries (bi.bi_bh, n + item_pos - ret_val, l_pos_in_item, 1,
+						(struct reiserfs_de_head *)body, 
+						body + DEH_SIZE, tb->insert_size[0]
+				);
+			    tb->insert_size[0] = 0;
+			} else {
+			    /* new directory item doesn't fall into L[0] */
+			    /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */
+			    leaf_shift_left (tb, tb->lnum[0], tb->lbytes);
+			}
+			/* Calculate new position to append in item body */
+			pos_in_item -= tb->lbytes;
+		    }
+		    else {
+			/* regular object */
+
+#ifdef CONFIG_REISERFS_CHECK
+			if ( tb->lbytes  <= 0 )
+			    reiserfs_panic(tb->tb_sb, "PAP-12095: balance_leaf: " 
+					   "there is nothing to shift to L[0]. lbytes=%d",
+					   tb->lbytes);
+			if ( pos_in_item != B_N_PITEM_HEAD(tbS0, item_pos)->ih_item_len )
+			    reiserfs_panic(tb->tb_sb, "PAP-12100: balance_leaf: " 
+					   "incorrect position to paste: item_len=%d, pos_in_item=%d",
+					   B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len, pos_in_item);
+#endif
+
+			if ( tb->lbytes >= pos_in_item ) {
+			    /* appended item will be in L[0] in whole */
+			    int l_n;
+			    struct key * key;
+
+			    /* this bytes number must be appended to the last item of L[h] */
+			    l_n = tb->lbytes - pos_in_item;
+
+			    /* Calculate new insert_size[0] */
+			    tb->insert_size[0] -= l_n;
+
+#ifdef CONFIG_REISERFS_CHECK
+			    if ( tb->insert_size[0] <= 0 )
+				reiserfs_panic(tb->tb_sb, "PAP-12105: balance_leaf: " 
+					       "there is nothing to paste into L[0]. insert_size=%d",
+					       tb->insert_size[0]);
+#endif
+
+			    ret_val =  leaf_shift_left(tb, tb->lnum[0], 
+						       B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len);
+			    /* Append to body of item in L[0] */
+			    bi.bi_bh = tb->L[0];
+			    bi.bi_parent = tb->FL[0];
+			    bi.bi_position = get_left_neighbor_position (tb, 0);
+			    leaf_paste_in_buffer(tb->tb_sb, 
+						 &bi,n + item_pos - ret_val,
+						 B_N_PITEM_HEAD(tb->L[0],n+item_pos-ret_val)->ih_item_len,
+						 l_n,body, zeros_number > l_n ? l_n : zeros_number
+				);
+
+#ifdef CONFIG_REISERFS_CHECK
+			    if (l_n && I_IS_INDIRECT_ITEM(B_N_PITEM_HEAD(tb->L[0],
+									 n + item_pos - ret_val)))
+				reiserfs_panic(tb->tb_sb, "PAP-12110: balance_leaf: "
+					       "pasting more than 1 unformatted node pointer into indirect item");
+#endif
+
+			    /* 0-th item in S0 can be only of DIRECT type when l_n != 0*/
+			    //B_N_PKEY (tbS0, 0)->k_offset += l_n;
+			    key = B_N_PKEY (tbS0, 0);
+			    set_offset (key_format (key), key, get_offset (key) + l_n);
+
+			    //B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])->k_offset += l_n;
+			    key = B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]);
+			    set_offset (key_format (key), key, get_offset (key) + l_n);
+
+			    /* Calculate new body, position in item and insert_size[0] */
+			    if ( l_n > zeros_number ) {
+				body += (l_n - zeros_number);
+				zeros_number = 0;
+			    }
+			    else
+				zeros_number -= l_n;
+			    pos_in_item = 0;	
+
+#ifdef CONFIG_REISERFS_CHECK	
+			    if (not_of_one_file (B_N_PKEY(tbS0,0),
+						 B_N_PKEY(tb->L[0],B_NR_ITEMS(tb->L[0])-1)) ||
+				!is_left_mergeable (B_N_PITEM_HEAD (tbS0, 0), tbS0->b_size) ||
+				!is_left_mergeable((struct item_head *)B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]), tbS0->b_size))
+				reiserfs_panic (tb->tb_sb, "PAP-12120: balance_leaf: "
+						"item must be merge-able with left neighboring item");
+#endif
+
+			}
+			else {
+			    /* only part of the appended item will be in L[0] */
+
+			    /* Calculate position in item for append in S[0] */
+			    pos_in_item -= tb->lbytes;
+
+#ifdef CONFIG_REISERFS_CHECK
+			    if ( pos_in_item <= 0 )
+				reiserfs_panic(tb->tb_sb, "PAP-12125: balance_leaf: "
+					       "no place for paste. pos_in_item=%d", pos_in_item);
+#endif
+
+			    /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
+			    leaf_shift_left(tb,tb->lnum[0],tb->lbytes);
+			}
+		    }
+		} else {
+		    /* appended item will be in L[0] in whole */
+		    struct item_head * pasted;
+
+#ifndef FU//REISERFS_FSCK
+		    // this works
+		    if ( ! item_pos  && is_left_mergeable (tb->tb_sb, tb->tb_path) == 1 )
+#else
+			if ( ! item_pos  && is_left_mergeable (B_N_PITEM_HEAD (tbS0, 0), tbS0->b_size) )
+#endif
+			{ /* if we paste into first item of S[0] and it is left mergable */
+			    /* then increment pos_in_item by the size of the last item in L[0] */
+			    pasted = B_N_PITEM_HEAD(tb->L[0],n-1);
+			    if ( I_IS_DIRECTORY_ITEM(pasted) )
+				pos_in_item += ih_entry_count (pasted);
+			    else
+				pos_in_item += pasted->ih_item_len;
+			}
+
+		    /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
+		    ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
+		    /* Append to body of item in L[0] */
+		    bi.bi_bh = tb->L[0];
+		    bi.bi_parent = tb->FL[0];
+		    bi.bi_position = get_left_neighbor_position (tb, 0);
+		    leaf_paste_in_buffer (tb->tb_sb, &bi, n + item_pos - ret_val, pos_in_item, tb->insert_size[0],
+					  body, zeros_number);
+
+		    /* if appended item is directory, paste entry */
+		    pasted = B_N_PITEM_HEAD (tb->L[0], n + item_pos - ret_val);
+		    if (I_IS_DIRECTORY_ITEM (pasted))
+			leaf_paste_entries (bi.bi_bh, n + item_pos - ret_val, pos_in_item, 1, 
+					    (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]);
+
+		    /* if appended item is indirect item, put unformatted node into un list */
+		    if (I_IS_INDIRECT_ITEM (pasted))
+			set_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+		    //pasted->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace;
+
+		    tb->insert_size[0] = 0;
+		    zeros_number = 0;
+		}
+		break;
+	    default:    /* cases d and t */
+		reiserfs_panic ("PAP-12130: balance_leaf: lnum > 0: unexpectable mode: %s(%d)",
+				(flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
+	    }
+	} else { 
+	    /* new item doesn't fall into L[0] */
+	    leaf_shift_left (tb, tb->lnum[0], tb->lbytes);
+	}
+    }	/* tb->lnum[0] > 0 */
+
+    /* Calculate new item position */
+    item_pos -= ( tb->lnum[0] - (( tb->lbytes != -1 ) ? 1 : 0));
+
+    if ( tb->rnum[0] > 0 ) {
+	/* shift rnum[0] items from S[0] to the right neighbor R[0] */
+	n = B_NR_ITEMS(tbS0);
+	switch ( flag ) {
+
+	case M_INSERT:   /* insert item */
+	    if ( n - tb->rnum[0] < item_pos ) {
+		/* new item or its part falls to R[0] */
+		if ( item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1 ) {
+		    /* part of new item falls into R[0] */
+		    int old_key_comp, old_len, r_zeros_number;
+		    const char * r_body;
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( !I_IS_DIRECT_ITEM(ih) )
+			reiserfs_panic(tb->tb_sb, "PAP-12135: balance_leaf: "
+				       "this item (%h) can not be split", ih);
+#endif
+
+		    leaf_shift_right(tb, tb->rnum[0] - 1, -1);
+
+		    /* Remember key component and item length */
+		    old_key_comp = get_offset (&ih->ih_key);
+		    old_len = ih->ih_item_len;
+
+		    /* Calculate key component and item length to insert into R[0] */
+		    //ih->ih_key.k_offset += (old_len - tb->rbytes);
+		    set_offset (key_format (&ih->ih_key), &ih->ih_key, old_key_comp + old_len - tb->rbytes);
+
+		    ih->ih_item_len = tb->rbytes;
+		    /* Insert part of the item into R[0] */
+		    bi.bi_bh = tb->R[0];
+		    bi.bi_parent = tb->FR[0];
+		    bi.bi_position = get_right_neighbor_position (tb, 0);
+		    if ( get_offset (&ih->ih_key) - old_key_comp > zeros_number ) {
+			r_zeros_number = 0;
+			r_body = body + get_offset (&ih->ih_key) - old_key_comp - zeros_number;
+		    }
+		    else {
+			r_body = body;
+			r_zeros_number = zeros_number - (get_offset (&ih->ih_key) - old_key_comp);
+			zeros_number -= r_zeros_number;
+		    }
+
+		    leaf_insert_into_buf (tb->tb_sb, &bi, 0, ih, r_body, r_zeros_number);
+
+		    /* Replace right delimiting key by first key in R[0] */
+		    replace_key(tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
+
+		    /* Calculate key component and item length to insert into S[0] */
+		    //ih->ih_key.k_offset = old_key_comp;
+		    set_offset (key_format (&ih->ih_key), &ih->ih_key, old_key_comp);
+
+		    ih->ih_item_len = old_len - tb->rbytes;
+
+		    tb->insert_size[0] -= tb->rbytes;
+
+		} else {
+		    /* whole new item falls into R[0] */
+
+		    /* Shift rnum[0]-1 items to R[0] */
+		    ret_val = leaf_shift_right(tb, tb->rnum[0] - 1, tb->rbytes);
+
+		    /* Insert new item into R[0] */
+		    bi.bi_bh = tb->R[0];
+		    bi.bi_parent = tb->FR[0];
+		    bi.bi_position = get_right_neighbor_position (tb, 0);
+		    leaf_insert_into_buf (tb->tb_sb, &bi, item_pos - n + tb->rnum[0] - 1, ih, body, zeros_number);
+
+		    /* If we insert new item in the begin of R[0] change the right delimiting key */
+		    if ( item_pos - n + tb->rnum[0] - 1 == 0 ) {
+			replace_key (tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
+		    }
+		    zeros_number = tb->insert_size[0] = 0;
+		}
+	    } else {
+		/* new item or part of it doesn't fall into R[0] */
+		leaf_shift_right (tb, tb->rnum[0], tb->rbytes);
+	    }
+	    break;
+
+	case M_PASTE:   /* append item */
+
+	    if ( n - tb->rnum[0] <= item_pos ) { /* pasted item or part of it falls to R[0] */
+		if ( item_pos == n - tb->rnum[0] && tb->rbytes != -1 ) {
+		    /* we must shift the part of the appended item */
+		    if ( I_IS_DIRECTORY_ITEM (B_N_PITEM_HEAD(tbS0, item_pos))) {
+			/* we append to directory item */
+			int entry_count;
+
+#ifdef CONFIG_REISERFS_CHECK
+			if ( zeros_number )
+			    reiserfs_panic(tb->tb_sb, "PAP-12145: balance_leaf: "
+					   "illegal parameter in case of a directory");
+#endif
+
+			entry_count = ih_entry_count (B_N_PITEM_HEAD(tbS0, item_pos));
+			if ( entry_count - tb->rbytes < pos_in_item ) {
+			    /* new directory entry falls into R[0] */
+			    int paste_entry_position;
+
+#ifdef CONFIG_REISERFS_CHECK
+			    if ( tb->rbytes - 1 >= entry_count || ! tb->insert_size[0] )
+				reiserfs_panic(tb->tb_sb, "PAP-12150: balance_leaf: "
+					       "no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d",
+					       tb->rbytes, entry_count);
+#endif
+
+			    /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
+			    leaf_shift_right (tb, tb->rnum[0], tb->rbytes - 1);
+
+			    /* Paste given directory entry to directory item */
+			    paste_entry_position = pos_in_item - entry_count + tb->rbytes - 1;
+
+			    bi.bi_bh = tb->R[0];
+			    bi.bi_parent = tb->FR[0];
+			    bi.bi_position = get_right_neighbor_position (tb, 0);
+			    leaf_paste_in_buffer (tb->tb_sb, &bi, 0, paste_entry_position,
+						  tb->insert_size[0],body,zeros_number);
+			    /* paste entry */
+			    leaf_paste_entries (
+				bi.bi_bh, 0, paste_entry_position, 1, (struct reiserfs_de_head *)body, 
+				body + DEH_SIZE, tb->insert_size[0]
+				);								
+						
+			    if ( paste_entry_position == 0 ) {
+				/* change delimiting keys */
+				replace_key(tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
+			    }
+
+			    tb->insert_size[0] = 0;
+			    pos_in_item++;
+			} else {
+			    /* new directory entry doesn't fall into R[0] */
+			    leaf_shift_right (tb, tb->rnum[0],tb->rbytes);
+			}
+		    }
+		    else {
+			/* regular object */
+
+			int n_shift, n_rem, r_zeros_number;
+			const char * r_body;
+			struct key * key;
+
+			/* Calculate number of bytes which must be shifted from appended item */
+			if ( (n_shift = tb->rbytes - tb->insert_size[0]) < 0 )
+			    n_shift = 0;
+
+#ifdef CONFIG_REISERFS_CHECK
+			if (pos_in_item != B_N_PITEM_HEAD (tbS0, item_pos)->ih_item_len)
+			    reiserfs_panic(tb->tb_sb,"PAP-12155: balance_leaf: invalid position %d to paste item %h",
+					   pos_in_item, B_N_PITEM_HEAD(tbS0,item_pos));
+#endif
+
+			leaf_shift_right (tb, tb->rnum[0], n_shift);
+
+			/* Calculate number of bytes which must remain in body after appending to R[0] */
+			if ( (n_rem = tb->insert_size[0] - tb->rbytes) < 0 )
+			    n_rem = 0;
+
+			//B_N_PKEY(tb->R[0],0)->k_offset += n_rem;
+			key = B_N_PKEY(tb->R[0],0);
+			set_offset (key_format (key), key, get_offset (key) + n_rem);
+
+			//B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])->k_offset += n_rem;
+			key = B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0]);
+			set_offset (key_format (key), key, get_offset (key) + n_rem);
+
+			mark_buffer_dirty (tb->CFR[0]);
+
+			/* Append part of body into R[0] */
+			bi.bi_bh = tb->R[0];
+			bi.bi_parent = tb->FR[0];
+			bi.bi_position = get_right_neighbor_position (tb, 0);
+			if ( n_rem > zeros_number ) {
+			    r_zeros_number = 0;
+			    r_body = body + n_rem - zeros_number;
+			}
+			else {
+			    r_body = body;
+			    r_zeros_number = zeros_number - n_rem;
+			    zeros_number -= r_zeros_number;
+			}
+
+			leaf_paste_in_buffer(tb->tb_sb, &bi, 0, n_shift, tb->insert_size[0] - n_rem, r_body, r_zeros_number);
+
+			if (I_IS_INDIRECT_ITEM(B_N_PITEM_HEAD(tb->R[0],0))) {
+
+#ifdef CONFIG_REISERFS_CHECK
+			    if (n_rem)
+				reiserfs_panic(tb->tb_sb, "PAP-12160: balance_leaf: paste more than one unformatted node pointer");
+#endif
+
+			    set_free_space (B_N_PITEM_HEAD(tb->R[0],0), ((struct unfm_nodeinfo*)body)->unfm_freespace);
+			    //B_N_PITEM_HEAD(tb->R[0],0)->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace;
+			}
+
+			tb->insert_size[0] = n_rem;
+			if ( ! n_rem )
+			    pos_in_item ++;
+		    }
+		}
+		else { 
+		    /* pasted item falls into R[0] entirely */
+
+		    struct item_head * pasted;
+
+		    ret_val = leaf_shift_right (tb, tb->rnum[0], tb->rbytes);
+
+		    /* append item in R[0] */
+		    if ( pos_in_item >= 0 ) {
+			bi.bi_bh = tb->R[0];
+			bi.bi_parent = tb->FR[0];
+			bi.bi_position = get_right_neighbor_position (tb, 0);
+			leaf_paste_in_buffer(tb->tb_sb, &bi,item_pos - n + tb->rnum[0], pos_in_item,
+					     tb->insert_size[0],body, zeros_number);
+		    }
+
+		    /* paste new entry, if item is directory item */
+		    pasted = B_N_PITEM_HEAD(tb->R[0], item_pos - n + tb->rnum[0]);
+		    if (I_IS_DIRECTORY_ITEM (pasted) && pos_in_item >= 0 ) {
+			leaf_paste_entries (bi.bi_bh, item_pos - n + tb->rnum[0], pos_in_item, 1, 
+					    (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]);
+			if ( ! pos_in_item ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+			    if ( item_pos - n + tb->rnum[0] )
+				reiserfs_panic (tb->tb_sb, "PAP-12165: balance_leaf: " 
+						"directory item must be first item of node when pasting is in 0th position");
+#endif
+
+			    /* update delimiting keys */
+			    replace_key (tb->tb_sb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
+			}
+		    }
+
+		    if (I_IS_INDIRECT_ITEM (pasted))
+			//pasted->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace;
+			set_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+		    zeros_number = tb->insert_size[0] = 0;
+		}
+	    }
+	    else {
+		/* new item doesn't fall into R[0] */
+		leaf_shift_right (tb, tb->rnum[0], tb->rbytes);
+	    }
+	    break;
+
+	default:    /* cases d and t */
+	    reiserfs_panic ("PAP-12175: balance_leaf: rnum > 0: unexpectable mode: %s(%d)",
+			    (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
+	}
+    
+    }	/* tb->rnum[0] > 0 */
+
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( tb->blknum[0] > 3 )  
+	reiserfs_panic (tb->tb_sb, "PAP-12180: balance_leaf: "
+			"blknum can not be %d. It must be <= 3",  tb->blknum[0]);
+
+    if ( tb->blknum[0] < 0 )  
+	reiserfs_panic (tb->tb_sb, "PAP-12185: balance_leaf: "
+			"blknum can not be %d. It must be >= 0",  tb->blknum[0]);
+
+    if ( tb->blknum[0] == 0 && (! tb->lnum[0] || ! tb->rnum[0]) )
+	reiserfs_panic(tb->tb_sb, "PAP-12190: balance_leaf: lnum and rnum must not be zero");
+#endif
+
+    /* if while adding to a node we discover that it is possible to split
+       it in two, and merge the left part into the left neighbor and the
+       right part into the right neighbor, eliminating the node */
+    if ( tb->blknum[0] == 0 ) { /* node S[0] is empty now */
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (!tb->CFL[0] || !tb->CFR[0] || !tb->R[0] || !tb->R[0] ||
+	    COMP_KEYS (B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]),
+		       B_N_PKEY (tb->R[0], 0)))
+	    reiserfs_panic (tb->tb_sb, "vs-12195: balance_leaf: "
+			    "right delim key (%k) is not set properly (%k)",
+			    B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]), B_N_PKEY (tb->R[0], 0));
+#endif
+
+	reiserfs_invalidate_buffer(tb,tbS0, 1);									
+	return 0;
+    }
+
+
+    /* Fill new nodes that appear in place of S[0] */
+
+    /* I am told that this copying is because we need an array to enable
+       the looping code. -Hans */
+    snum[0] = tb->s1num,
+	snum[1] = tb->s2num;
+    sbytes[0] = tb->s1bytes;
+    sbytes[1] = tb->s2bytes;
+    for( i = tb->blknum[0] - 2; i >= 0; i-- ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (!snum[i])
+	    reiserfs_panic(tb->tb_sb,"PAP-12200: balance_leaf: snum[%d] == %d. Must be > 0", i, snum[i]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+	/* here we shift from S to S_new nodes */
+
+	S_new[i] = get_FEB(tb);
+
+	/* set block level */
+	set_leaf_node_level (S_new[i]);
+
+	n = B_NR_ITEMS(tbS0);
+	
+	switch (flag) {
+	case M_INSERT:   /* insert item */
+
+	    if ( n - snum[i] < item_pos ) {
+		/* new item or it's part falls to first new node S_new[i]*/
+		if ( item_pos == n - snum[i] + 1 && sbytes[i] != -1 ) {
+		    /* part of new item falls into S_new[i] */
+		    int old_key_comp, old_len, r_zeros_number;
+		    const char * r_body;
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( !I_IS_DIRECT_ITEM(ih) )
+			/* The items which can be inserted are: Stat_data
+			   item, direct item, indirect item and directory item
+			   which consist of only two entries "." and "..".
+			   These items must not be broken except for a direct
+			   one. */
+			reiserfs_panic(tb->tb_sb, "PAP-12205: balance_leaf: "
+				       "this item %h can not be broken when inserting", ih);
+#endif
+
+		    /* Move snum[i]-1 items from S[0] to S_new[i] */
+		    leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, -1, S_new[i]);
+
+		    /* Remember key component and item length */
+		    old_key_comp = get_offset (&ih->ih_key);
+		    old_len = ih->ih_item_len;
+
+		    /* Calculate key component and item length to insert into S_new[i] */
+		    //ih->ih_key.k_offset += (old_len - sbytes[i]);
+		    set_offset (key_format (&ih->ih_key), &ih->ih_key, old_key_comp + old_len - sbytes[i]);
+
+		    ih->ih_item_len = sbytes[i];
+
+		    /* Insert part of the item into S_new[i] before 0-th item */
+		    bi.bi_bh = S_new[i];
+		    bi.bi_parent = 0;
+		    bi.bi_position = 0;
+
+		    if ( get_offset (&ih->ih_key) - old_key_comp > zeros_number ) {
+			r_zeros_number = 0;
+			r_body = body + (get_offset (&ih->ih_key) - old_key_comp) - zeros_number;
+		    }
+		    else {
+			r_body = body;
+			r_zeros_number = zeros_number - (get_offset (&ih->ih_key) - old_key_comp);
+			zeros_number -= r_zeros_number;
+		    }
+
+		    leaf_insert_into_buf (tb->tb_sb, &bi, 0, ih, r_body, r_zeros_number);
+
+		    /* Calculate key component and item length to insert into S[i] */
+		    //ih->ih_key.k_offset = old_key_comp;
+		    set_offset (key_format (&ih->ih_key), &ih->ih_key, old_key_comp);
+		    ih->ih_item_len = old_len - sbytes[i];
+		    tb->insert_size[0] -= sbytes[i];
+		}
+		else /* whole new item falls into S_new[i] */
+		{
+		    /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */
+		    leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, sbytes[i], S_new[i]);
+
+		    /* Insert new item into S_new[i] */
+		    bi.bi_bh = S_new[i];
+		    bi.bi_parent = 0;
+		    bi.bi_position = 0;
+		    leaf_insert_into_buf (tb->tb_sb, &bi, item_pos - n + snum[i] - 1, ih, body, zeros_number);
+		    zeros_number = tb->insert_size[0] = 0;
+		}
+	    }
+
+	    else /* new item or it part don't falls into S_new[i] */
+	    {
+		leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
+	    }
+	    break;
+
+	case M_PASTE:   /* append item */
+
+	    if ( n - snum[i] <= item_pos )  /* pasted item or part if it falls to S_new[i] */
+	    {
+		if ( item_pos == n - snum[i] && sbytes[i] != -1 )
+		{ /* we must shift part of the appended item */
+		    struct item_head * aux_ih;
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( ih )
+			reiserfs_panic (tb->tb_sb, "PAP-12210: balance_leaf: ih must be 0");
+#endif /* CONFIG_REISERFS_CHECK */
+
+		    if ( I_IS_DIRECTORY_ITEM (aux_ih = B_N_PITEM_HEAD(tbS0,item_pos))) {
+			/* we append to directory item */
+
+			int entry_count;
+		
+			entry_count = ih_entry_count(aux_ih);
+
+			if ( entry_count - sbytes[i] < pos_in_item  && pos_in_item <= entry_count ) {
+			    /* new directory entry falls into S_new[i] */
+		  
+#ifdef CONFIG_REISERFS_CHECK
+			    if ( ! tb->insert_size[0] )
+				reiserfs_panic (tb->tb_sb, "PAP-12215: balance_leaif: insert_size is already 0");
+			    if ( sbytes[i] - 1 >= entry_count )
+				reiserfs_panic (tb->tb_sb, "PAP-12220: balance_leaf: "
+						"there are no so much entries (%d), only %d",
+						sbytes[i] - 1, entry_count);
+#endif
+
+			    /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
+			    leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i]-1, S_new[i]);
+
+			    /* Paste given directory entry to directory item */
+			    bi.bi_bh = S_new[i];
+			    bi.bi_parent = 0;
+			    bi.bi_position = 0;
+			    leaf_paste_in_buffer (tb->tb_sb, &bi, 0, pos_in_item - entry_count + sbytes[i] - 1,
+						  tb->insert_size[0], body,zeros_number);
+			    /* paste new directory entry */
+			    leaf_paste_entries (
+				bi.bi_bh, 0, pos_in_item - entry_count + sbytes[i] - 1,
+				1, (struct reiserfs_de_head *)body, body + DEH_SIZE,
+				tb->insert_size[0]
+				);
+			    tb->insert_size[0] = 0;
+			    pos_in_item++;
+			} else { /* new directory entry doesn't fall into S_new[i] */
+			    leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
+			}
+		    }
+		    else /* regular object */
+		    {
+			int n_shift, n_rem, r_zeros_number;
+			const char * r_body;
+			struct item_head * tmp;
+
+#ifdef CONFIG_REISERFS_CHECK
+			if ( pos_in_item != B_N_PITEM_HEAD(tbS0,item_pos)->ih_item_len ||
+			     tb->insert_size[0] <= 0 )
+			    reiserfs_panic (tb->tb_sb, "PAP-12225: balance_leaf: item too short or insert_size <= 0");
+#endif
+
+			/* Calculate number of bytes which must be shifted from appended item */
+			n_shift = sbytes[i] - tb->insert_size[0];
+			if ( n_shift < 0 )
+			    n_shift = 0;
+			leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], n_shift, S_new[i]);
+
+			/* Calculate number of bytes which must remain in body after append to S_new[i] */
+			n_rem = tb->insert_size[0] - sbytes[i];
+			if ( n_rem < 0 )
+			    n_rem = 0;
+			/* Append part of body into S_new[0] */
+			bi.bi_bh = S_new[i];
+			bi.bi_parent = 0;
+			bi.bi_position = 0;
+
+			if ( n_rem > zeros_number ) {
+			    r_zeros_number = 0;
+			    r_body = body + n_rem - zeros_number;
+			}
+			else {
+			    r_body = body;
+			    r_zeros_number = zeros_number - n_rem;
+			    zeros_number -= r_zeros_number;
+			}
+
+			leaf_paste_in_buffer(tb->tb_sb, &bi, 0, n_shift, tb->insert_size[0]-n_rem, r_body,r_zeros_number);
+			tmp = B_N_PITEM_HEAD (S_new[i], 0);
+			if (I_IS_INDIRECT_ITEM(tmp)) {
+			    if (n_rem)
+				reiserfs_panic ("PAP-12230: balance_leaf: "
+						"invalid action with indirect item");
+			    //tmp->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace;
+			    set_free_space (tmp, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+			}
+
+			//B_N_PKEY(S_new[i],0)->k_offset += n_rem;
+			set_offset (key_format (&tmp->ih_key), &tmp->ih_key, get_offset (&tmp->ih_key) + n_rem);
+
+			tb->insert_size[0] = n_rem;
+			if ( ! n_rem )
+			    pos_in_item++;
+		    }
+		}
+		else
+		    /* item falls wholly into S_new[i] */
+		{
+		    int ret_val;
+		    struct item_head * pasted;
+
+#ifdef CONFIG_REISERFS_CHECK
+		    struct item_head * ih = B_N_PITEM_HEAD(tbS0,item_pos);
+
+		    if ( ! I_IS_DIRECTORY_ITEM(ih) && (pos_in_item != ih->ih_item_len ||
+						       tb->insert_size[0] <= 0) )
+			reiserfs_panic (tb->tb_sb, "PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len");
+#endif /* CONFIG_REISERFS_CHECK */
+
+		    ret_val = leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( ret_val )
+			reiserfs_panic (tb->tb_sb, "PAP-12240: balance_leaf: "
+					"unexpected value returned by leaf_move_items (%d)",
+					ret_val);
+#endif /* CONFIG_REISERFS_CHECK */
+
+		    /* paste into item */
+		    bi.bi_bh = S_new[i];
+		    bi.bi_parent = 0;
+		    bi.bi_position = 0;
+		    leaf_paste_in_buffer(tb->tb_sb, &bi, item_pos - n + snum[i], pos_in_item, tb->insert_size[0], body, zeros_number);
+
+		    pasted = B_N_PITEM_HEAD(S_new[i], item_pos - n + snum[i]);
+		    if (I_IS_DIRECTORY_ITEM (pasted)) {
+			leaf_paste_entries (bi.bi_bh, item_pos - n + snum[i], pos_in_item, 1, 
+					    (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]);
+		    }
+
+		    /* if we paste to indirect item update ih_free_space */
+		    if (I_IS_INDIRECT_ITEM (pasted))
+			//pasted->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace;
+			set_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+		    zeros_number = tb->insert_size[0] = 0;
+		}
+	    } else {
+		/* pasted item doesn't fall into S_new[i] */
+		leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
+	    }
+	    break;
+
+	default:    /* cases d and t */
+	    reiserfs_panic ("PAP-12245: balance_leaf: blknum > 2: unexpectable mode: %s(%d)",
+			    (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
+	}
+
+	memcpy (insert_key + i,B_N_PKEY(S_new[i],0),KEY_SIZE);
+	insert_ptr[i] = S_new[i];
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (S_new[i]->b_count != 1) {
+	    if (buffer_journaled(S_new[i]) || buffer_journal_dirty(S_new[i])) {
+		;
+	    } else {
+		reiserfs_panic (tb->tb_sb, "PAP-12247: balance_leaf: S_new[%d]->b_count=%u blocknr = %lu\n", i, S_new[i]->b_count,
+				S_new[i]->b_blocknr);
+	    }
+	}
+#endif
+
+    }
+
+    /* if the affected item was not wholly shifted then we perform all
+       necessary operations on that part or whole of the affected item which
+       remains in S */
+    if ( 0 <= item_pos && item_pos < tb->s0num ) {
+	/* if we must insert or append into buffer S[0] */
+
+	switch (flag) {
+	case M_INSERT:   /* insert item into S[0] */
+	    bi.bi_bh = tbS0;
+	    bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
+	    bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
+	    leaf_insert_into_buf (tb->tb_sb, &bi, item_pos, ih, body, zeros_number);
+
+	    /* If we insert the first key change the delimiting key */
+	    if( item_pos == 0 ) {
+		if (tb->CFL[0]) /* can be 0 in reiserfsck */
+		    replace_key (tb->tb_sb, tb->CFL[0], tb->lkey[0],tbS0,0);
+	    }
+	    break;
+
+	case M_PASTE: {  /* append item in S[0] */
+	    struct item_head * pasted;
+
+	    pasted = B_N_PITEM_HEAD (tbS0, item_pos);
+	    /* when directory, may be new entry already pasted */
+	    if (I_IS_DIRECTORY_ITEM (pasted)) {
+		if ( pos_in_item >= 0 && pos_in_item <= ih_entry_count (pasted) ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( ! tb->insert_size[0] )
+			reiserfs_panic (tb->tb_sb, "PAP-12260: balance_leaf: insert_size is 0 already");
+#endif /* CONFIG_REISERFS_CHECK */
+
+		    /* prepare space */
+		    bi.bi_bh = tbS0;
+		    bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
+		    bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
+		    leaf_paste_in_buffer(tb->tb_sb, &bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_number);
+
+		    /* paste entry */
+		    leaf_paste_entries (bi.bi_bh, item_pos, pos_in_item, 1, (struct reiserfs_de_head *)body,
+					body + DEH_SIZE, tb->insert_size[0]);
+		    if ( ! item_pos && ! pos_in_item ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+			if (!tb->CFL[0])
+			    reiserfs_panic (tb->tb_sb, "PAP-12270: balance_leaf: "
+					    "is not able to update left dkey");
+#endif /* CONFIG_REISERFS_CHECK */
+
+			if (tb->CFL[0])  // can be 0 in reiserfsck
+			    replace_key(tb->tb_sb, tb->CFL[0], tb->lkey[0],tbS0,0);
+		    }
+		    tb->insert_size[0] = 0;
+		}
+	    } else { /* regular object */
+		if ( pos_in_item == pasted->ih_item_len ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( tb->insert_size[0] <= 0 )
+			reiserfs_panic (tb->tb_sb,
+					"PAP-12275: balance_leaf: insert size must not be %d", tb->insert_size[0]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+		    bi.bi_bh = tbS0;
+		    bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
+		    bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
+		    leaf_paste_in_buffer (tb->tb_sb, &bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_number);
+
+		    if (I_IS_INDIRECT_ITEM (pasted)) {
+
+#ifdef CONFIG_REISERFS_CHECK
+			if ( tb->insert_size[0] != UNFM_P_SIZE )
+			    reiserfs_panic (tb->tb_sb,
+					    "PAP-12280: balance_leaf: insert_size for indirect item must be %d, not %d",
+					    UNFM_P_SIZE, tb->insert_size[0]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+			//pasted->u.ih_free_space = ((struct unfm_nodeinfo*)body)->unfm_freespace;
+			set_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+		    }
+		    tb->insert_size[0] = 0;
+		}
+
+#ifdef CONFIG_REISERFS_CHECK
+		else {
+		    if ( tb->insert_size[0] ) {
+			print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12285");
+			reiserfs_panic (tb->tb_sb, "PAP-12285: balance_leaf: "
+					"insert_size must be 0 (%d), pos_in_item %d. (%h)",
+					tb->insert_size[0], pos_in_item, pasted);
+		    }
+		}
+#endif /* CONFIG_REISERFS_CHECK */
+	    
+	    }
+	} /* case M_PASTE: */
+	}
+    }
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( flag == M_PASTE && tb->insert_size[0] ) {
+	print_tb (M_PASTE, item_pos, pos_in_item, tb, "balance");
+	reiserfs_panic (tb->tb_sb, "PAP-12290: balance_leaf: insert_size is still not 0 (%d)", tb->insert_size[0]);
+    }
+#endif /* CONFIG_REISERFS_CHECK */
+
+    return 0;
+} /* Leaf level of the tree is balanced (end of balance_leaf) */
+
+
+
+/* Make empty node */
+void make_empty_node (struct buffer_info * bi)
+{
+    struct block_head * blkh;
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (bi->bi_bh == NULL)
+	reiserfs_panic (0, "PAP-12295: make_empty_node: pointer to the buffer is NULL");
+#endif
+
+    (blkh = B_BLK_HEAD(bi->bi_bh))->blk_nr_item = 0;
+    blkh->blk_free_space = MAX_CHILD_SIZE(bi->bi_bh); 
+
+    if (bi->bi_parent)
+	B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size = 0; 
+}
+
+
+/* Get first empty buffer */
+struct buffer_head * get_FEB (struct tree_balance * tb)
+{
+    int i;
+    struct buffer_head * first_b;
+    struct buffer_info bi;
+
+    for (i = 0; i < MAX_FEB_SIZE; i ++)
+	if (tb->FEB[i] != 0)
+	    break;
+
+    if (i == MAX_FEB_SIZE)
+	reiserfs_panic("vs-12300: get_FEB: FEB list is empty");
+
+    bi.bi_bh = first_b = tb->FEB[i];
+    bi.bi_parent = 0;
+    bi.bi_position = 0;
+    make_empty_node (&bi);
+    set_bit(BH_Uptodate, &first_b->b_state);
+
+    tb->FEB[i] = 0;
+    tb->used[i] = first_b;
+
+    return(first_b);
+}
+
+
+/* Replace n_dest'th key in buffer dest by n_src'th key of buffer src.*/
+void replace_key (reiserfs_filsys_t fs,
+		  struct buffer_head * dest, int n_dest,
+		  struct buffer_head * src, int n_src)
+{
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (dest == NULL || src == NULL)
+	reiserfs_panic (0, "vs-12305: replace_key: sourse or destination buffer is 0 (src=%p, dest=%p)", src, dest);
+
+    if ( ! B_IS_KEYS_LEVEL (dest) )
+	reiserfs_panic (0, "vs-12310: replace_key: invalid level (%d) for destination buffer. Must be > %d",
+			B_BLK_HEAD(dest)->blk_level, DISK_LEAF_NODE_LEVEL);
+
+    if (n_dest < 0 || n_src < 0)
+	reiserfs_panic (0, "vs-12315: replace_key: src(%d) or dest(%d) key number less than 0", n_src, n_dest);
+
+    if (n_dest >= B_NR_ITEMS(dest) || n_src >= B_NR_ITEMS(src))
+	reiserfs_panic (0, "vs-12320: replace_key: src(%d(%d)) or dest(%d(%d)) key number is too big",
+			n_src, B_NR_ITEMS(src), n_dest, B_NR_ITEMS(dest));
+#endif	/* CONFIG_REISERFS_CHECK */
+   
+    if (dest) {
+	if (is_leaf_node (src))
+	    /* source buffer contains leaf node */
+	    memcpy (B_N_PDELIM_KEY(dest,n_dest), B_N_PITEM_HEAD(src,n_src), KEY_SIZE);
+	else
+	    memcpy (B_N_PDELIM_KEY(dest,n_dest), B_N_PDELIM_KEY(src,n_src), KEY_SIZE);
+	
+	mark_buffer_dirty(dest);
+    }
+}
+
+
+void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head * bh, int do_free_block)
+{
+
+    B_BLK_HEAD (bh)->blk_level = FREE_LEVEL;
+    clear_bit(BH_Dirty, &bh->b_state);
+
+#ifdef CONFIG_REISERFS_CHECK
+    B_NR_ITEMS (bh) = 0;
+#endif
+    
+    if (do_free_block) {
+	struct buffer_head * to_be_forgotten;
+
+	to_be_forgotten = find_buffer (bh->b_dev, bh->b_blocknr, bh->b_size);
+	if (to_be_forgotten) {
+	    to_be_forgotten->b_count ++;
+	    bforget (to_be_forgotten);
+	}
+
+	reiserfs_free_block (tb->tb_sb, bh->b_blocknr);
+    }
+}
+
+
+int get_left_neighbor_position (
+				struct tree_balance * tb, 
+				int h
+				)
+{
+  int Sh_position = PATH_H_POSITION (tb->tb_path, h + 1);
+
+#ifdef CONFIG_REISERFS_CHECK
+  if (PATH_H_PPARENT (tb->tb_path, h) == 0 || tb->FL[h] == 0)
+    reiserfs_panic (tb->tb_sb, "vs-12325: get_left_neighbor_position: FL[%d](%p) or F[%d](%p) does not exist", 
+		    h, tb->FL[h], h, PATH_H_PPARENT (tb->tb_path, h));
+#endif
+
+  if (Sh_position == 0)
+    return B_NR_ITEMS (tb->FL[h]);
+  else
+    return Sh_position - 1;
+}
+
+
+int get_right_neighbor_position (struct tree_balance * tb, int h)
+{
+  int Sh_position = PATH_H_POSITION (tb->tb_path, h + 1);
+
+#ifdef CONFIG_REISERFS_CHECK
+  if (PATH_H_PPARENT (tb->tb_path, h) == 0 || tb->FR[h] == 0)
+    reiserfs_panic (tb->tb_sb, "vs-12330: get_right_neighbor_position: F[%d](%p) or FR[%d](%p) does not exist", 
+		    h, PATH_H_PPARENT (tb->tb_path, h), h, tb->FR[h]);
+#endif
+
+  if (Sh_position == B_NR_ITEMS (PATH_H_PPARENT (tb->tb_path, h)))
+    return 0;
+  else
+    return Sh_position + 1;
+}
+
+
+#ifdef CONFIG_REISERFS_CHECK
+
+int is_reusable (struct super_block * s, unsigned long block, int bit_value);
+static void check_internal_node (struct super_block * s, struct buffer_head * bh, char * mes)
+{
+    struct disk_child * dc;
+    int i;
+
+    if (!bh)
+	reiserfs_panic (s, "PAP-12336: check_internal_node: bh == 0");
+
+    if (!bh || !B_IS_IN_TREE (bh))
+	return;
+ 
+    if (!buffer_dirty (bh) && !buffer_journaled(bh) ) {
+	print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, mes);
+	reiserfs_panic (s, "PAP-12337: check_internal_node: buffer (%b) must be dirty", bh);
+    }
+
+    dc = B_N_CHILD (bh, 0);
+
+    for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
+	if (!is_reusable (s, dc->dc_block_number, 1) ) {
+	    print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, mes);
+	    reiserfs_panic (s, "PAP-12338: check_internal_node: invalid child pointer %y in %b", dc, bh);
+	}
+	if (dc->dc_size <= BLKH_SIZE) {
+	    print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, mes);
+	    reiserfs_panic (s, "PAP-12338: check_internal_node: empty node in the tree? %y", dc);
+	}
+    }
+}
+
+
+static int locked_or_not_in_tree (struct buffer_head * bh, char * which)
+{
+    if ( buffer_locked (bh) || !B_IS_IN_TREE (bh) ) {
+	reiserfs_warning ("vs-12339: locked_or_not_in_tree: %s (%b)\n", which, bh);
+	return 1;
+    }
+    return 0;
+}
+
+
+static int check_before_balancing (struct tree_balance * tb, int mode)
+{
+    int retval = 0;	
+    int pos_in_item = tb->tb_path->pos_in_item;
+
+    if (mode == M_PASTE) {
+	// make sure paste can be performed with given parameters
+	struct item_head * ih;
+
+	ih = get_ih (tb->tb_path);
+	if (I_IS_INDIRECT_ITEM (ih)) {
+	    // we can paste only to the end for now
+	    if (pos_in_item != I_UNFM_NUM (ih))
+		reiserfs_panic (tb->tb_sb, "vs-12333: check_before_balancing: "
+				"pos_in_item %d set improperly to paste indirect item %h",
+				pos_in_item, ih);
+	}
+	if (I_IS_DIRECT_ITEM (ih)) {
+	    // we can paste only to the end for now
+	    if (pos_in_item != ih_item_len (ih))
+		reiserfs_panic (tb->tb_sb, "vs-12334: check_before_balancing: "
+				"pos_in_item %d set improperly to paste direct item %h",
+				pos_in_item, ih);
+	}
+    }
+
+    if ( cur_tb ) {
+	reiserfs_panic (tb->tb_sb, "vs-12335: check_before_balancing: "
+			"suspect that schedule occurred based on cur_tb not being null at this point in code. "
+			"do_balance cannot properly handle schedule occuring while it runs.");
+    }
+  
+    /* double check that buffers that we will modify are unlocked. (fix_nodes
+       should already have prepped all of these for us). */
+    if ( tb->lnum[0] ) {
+	retval |= locked_or_not_in_tree (tb->L[0], "L[0]");
+	retval |= locked_or_not_in_tree (tb->FL[0], "FL[0]");
+	retval |= locked_or_not_in_tree (tb->CFL[0], "CFL[0]");
+	check_leaf (tb->L[0]);
+    }
+    if ( tb->rnum[0] ) {
+	retval |= locked_or_not_in_tree (tb->R[0], "R[0]");
+	retval |= locked_or_not_in_tree (tb->FR[0], "FR[0]");
+	retval |= locked_or_not_in_tree (tb->CFR[0], "CFR[0]");
+	check_leaf (tb->R[0]);
+    }
+    retval |= locked_or_not_in_tree (PATH_PLAST_BUFFER (tb->tb_path), "S[0]");
+    check_leaf (PATH_PLAST_BUFFER (tb->tb_path));
+    return retval;
+}
+
+
+static void check_after_balance_leaf (struct tree_balance * tb)
+{
+    if (tb->lnum[0]) {
+	if (B_BLK_HEAD (tb->L[0])->blk_free_space != 
+	    MAX_CHILD_SIZE (tb->L[0]) - B_N_CHILD (tb->FL[0], get_left_neighbor_position (tb, 0))->dc_size) {
+	    print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12221");
+	    reiserfs_panic (tb->tb_sb, "PAP-12355: check_after_balance_leaf: shift to left was incorrect");
+	}
+    }
+    if (tb->rnum[0]) {
+	if (B_BLK_HEAD (tb->R[0])->blk_free_space != 
+	    MAX_CHILD_SIZE (tb->R[0]) - B_N_CHILD (tb->FR[0], get_right_neighbor_position (tb, 0))->dc_size) {
+	    print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12222");
+	    reiserfs_panic (tb->tb_sb, "PAP-12360: check_after_balance_leaf: shift to right was incorrect");
+	}
+    }
+    if (PATH_H_PBUFFER(tb->tb_path,1) && 
+	B_BLK_HEAD (PATH_H_PBUFFER(tb->tb_path,0))->blk_free_space != 
+	MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)) -
+	B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1), 
+		   PATH_H_POSITION (tb->tb_path, 1))->dc_size) {
+	print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12223");
+	reiserfs_panic (tb->tb_sb, "PAP-12365: check_after_balance_leaf: S is incorrect");
+    }
+}
+
+
+static void compare_pair (struct buffer_head * bh1, struct buffer_head * bh2)
+{
+    int cur_free, node_size;
+
+    if (!bh1 || !bh2)
+	return;
+
+    cur_free = node_free_space (bh1);
+    node_size = bh1->b_size - BLKH_SIZE - ((is_left_mergeable (B_N_PITEM_HEAD (bh2, 0), bh1->b_size)) ? IH_SIZE : 0);
+    if (cur_free >= node_size) {
+	print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "12366");
+	reiserfs_panic (0, "vs-12366: check_leaf_level: balance condition denied bh1 %z, bh2 %z",
+			bh1, bh2);
+    }
+}
+
+
+static void check_leaf_level (struct tree_balance * tb)
+{
+    struct buffer_head * S0 = get_bh (tb->tb_path);
+    struct buffer_head * bhs[5] = {0, };
+    int i;
+
+    // check item types, internal structures of items, etc
+    check_leaf (tb->L[0]);
+    check_leaf (tb->R[0]);
+    check_leaf (S0);
+    
+    if (tb->blknum[0] > 2) {
+	reiserfs_warning ("More than one new node on the leaf level\n");
+	return;
+    }
+
+    // check balance condition for any neighboring buffers
+    i = 0;
+    if (tb->L[0] && B_IS_IN_TREE (tb->L[0]))
+	bhs[i ++] = tb->L[0];
+    if (B_IS_IN_TREE (S0))
+	bhs[i ++] = S0;
+    if (tb->blknum[0] == 2) {
+	if (!B_IS_ITEMS_LEVEL(tb->used[0])) {
+	    reiserfs_warning ("can not find new node\n");
+	    return;
+	}
+	bhs[i ++] = tb->used[0];
+    }
+    if (tb->R[0] && B_IS_IN_TREE (tb->R[0])) {
+	bhs[i ++] = tb->R[0];
+    }
+
+    for (i = 0; i < 4; i ++) {
+	compare_pair (bhs[i], bhs[i + 1]);
+    }
+	
+}
+
+
+static void check_after_balancing (struct tree_balance * tb)
+{
+    int h;
+
+    check_leaf_level (tb);
+
+    /* check all internal nodes */
+    for (h = 1; tb->insert_size[h]; h ++) {
+	check_internal_node (tb->tb_sb, PATH_H_PBUFFER (tb->tb_path, h), "BAD BUFFER ON PATH");
+	if (tb->lnum[h])
+	    check_internal_node (tb->tb_sb, tb->L[h], "BAD L");
+	if (tb->rnum[h])
+	    check_internal_node (tb->tb_sb, tb->R[h], "BAD R");
+    }
+
+}
+
+#endif
+
+
+
+
+
+
+/* Now we have all of the buffers that must be used in balancing of the tree.
+   We rely on the assumption that schedule() will not occur while do_balance
+   works. ( Only interrupt handlers are acceptable.)  We balance the tree
+   according to the analysis made before this, using buffers already obtained.
+   For SMP support it will someday be necessary to add ordered locking of
+   tb. */
+
+/* Some interesting rules of balancing:
+
+   we delete a maximum of two nodes per level per balancing: we never delete R, when we delete two
+   of three nodes L, S, R then we move them into R.
+
+   we only delete L if we are deleting two nodes, if we delete only one node we delete S
+
+   if we shift leaves then we shift as much as we can: this is a deliberate policy of extremism in
+   node packing which results in higher average utilization after repeated random balance
+   operations at the cost of more memory copies and more balancing as a result of small insertions
+   to full nodes.
+
+   if we shift internal nodes we try to evenly balance the node utilization, with consequent less
+   balancing at the cost of lower utilization.
+
+   one could argue that the policy for directories in leaves should be that of internal nodes, but
+   we will wait until another day to evaluate this....  It would be nice to someday measure and
+   prove these assumptions as to what is optimal....
+
+*/
+
+void do_balance (struct tree_balance * tb,		/* tree_balance structure 		*/
+		 struct item_head * ih,	/* item header of inserted item */
+		 const char * body, /* body  of inserted item or bytes to paste */
+		 int flag,  /* i - insert, d - delete
+			       c - cut, p - paste
+						      
+			       Cut means delete part of an item (includes
+			       removing an entry from a directory).
+						      
+			       Delete means delete whole item.
+						      
+			       Insert means add a new item into the tree.
+						      						      
+			       Paste means to append to the end of an existing
+			       file or to insert a directory entry.  */
+		 int zeros_num)
+{
+    //int pos_in_item = tb->tb_path->pos_in_item;
+    int child_pos, /* position of a child node in its parent */
+	h;	   /* level of the tree being processed */
+    struct item_head insert_key[2]; /* in our processing of one level we
+				       sometimes determine what must be
+				       inserted into the next higher level.
+				       This insertion consists of a key or two
+				       keys and their corresponding pointers */
+    struct buffer_head *insert_ptr[2]; /* inserted node-ptrs for the next
+					  level */
+
+
+#ifdef CONFIG_REISERFS_CHECK
+    memcpy(&init_tb, tb, sizeof(struct tree_balance));
+    init_item_pos = PATH_LAST_POSITION (tb->tb_path);
+    init_pos_in_item = tb->tb_path->pos_in_item;//pos_in_item;
+    init_mode = flag;
+
+    /* do not delete, just comment it out */
+    /*print_tb(flag, PATH_LAST_POSITION(tb->tb_path), pos_in_item, tb, "check");*/
+
+    if (check_before_balancing (tb/*, pos_in_item*/, flag))
+	reiserfs_panic (tb->tb_sb, "PAP-12340: do_balance: "
+			"balancing can not be performed");
+
+    cur_tb = tb;
+#endif /* CONFIG_REISERFS_CHECK */
+
+    /* if we have no real work to do  */
+    if ( ! tb->insert_size[0] ) {
+#ifdef CONFIG_REISERFS_CHECK
+	cur_tb = NULL;
+	if (flag != M_CUT)
+	    reiserfs_panic (tb->tb_sb, "PAP-12350: do_balance: insert_size == 0, mode == %c", flag);
+#endif
+	unfix_nodes(/*th,*/ tb);
+	return;
+    }
+
+#ifndef FU //REISERFS_FSCK
+    if (flag == M_INTERNAL) {
+	insert_ptr[0] = (struct buffer_head *)body;
+	/* we must prepare insert_key */
+
+	if (PATH_H_B_ITEM_ORDER (tb->tb_path, 0)/*LAST_POSITION (tb->tb_path)*//*item_pos*/ == -1) {
+		/* get delimiting key from buffer in tree */
+		copy_key (&insert_key[0].ih_key, B_N_PKEY (PATH_PLAST_BUFFER (tb->tb_path), 0));
+		/*insert_ptr[0]->b_item_order = 0;*/
+	} else {
+	    /* get delimiting key from new buffer */
+	    copy_key (&insert_key[0].ih_key, B_N_PKEY((struct buffer_head *)body,0));
+	    /*insert_ptr[0]->b_item_order = item_pos;*/
+	}
+      
+	/* and insert_ptr instead of balance_leaf */
+	child_pos = PATH_H_B_ITEM_ORDER (tb->tb_path, 0)/*item_pos*/;
+    } else
+#endif
+
+	/* balance leaf returns 0 except if combining L R and S into one node.
+	   see balance_internal() for explanation of this line of code.*/
+	child_pos = PATH_H_B_ITEM_ORDER (tb->tb_path, 0) +
+	    balance_leaf (/*th,*/ tb/*, pos_in_item*/, ih, body, flag, zeros_num, insert_key, insert_ptr);
+
+#ifdef CONFIG_REISERFS_CHECK
+    check_after_balance_leaf (tb);
+#endif
+
+    /* Balance internal level of the tree. */
+    for ( h = 1; h < MAX_HEIGHT && tb->insert_size[h]; h++ )
+	child_pos = balance_internal (/*th,*/ tb, h, child_pos, insert_key, insert_ptr);
+
+#ifdef CONFIG_REISERFS_CHECK
+    cur_tb = NULL;
+    check_after_balancing (tb);
+#endif
+
+    /* Release all (except for S[0]) non NULL buffers fixed by fix_nodes() */
+    unfix_nodes(/*th,*/ tb);
+
+#ifdef CONFIG_REISERFS_CHECK
+    tb->tb_sb->u.reiserfs_sb.s_do_balance ++;
+#endif
+
+}
+
+
+
+
+
+
+
+
+
diff --git a/reiserfscore/fix_node.c b/reiserfscore/fix_node.c
new file mode 100644
index 0000000..6b18240
--- /dev/null
+++ b/reiserfscore/fix_node.c
@@ -0,0 +1,2916 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+
+/**
+ ** old_item_num
+ ** old_entry_num
+ ** set_entry_sizes
+ ** create_virtual_node
+ ** check_left
+ ** check_right
+ ** directory_part_size
+ ** get_num_ver
+ ** item_length
+ ** set_parameters
+ ** is_leaf_removable
+ ** are_leaves_removable
+ ** get_empty_nodes
+ ** get_lfree
+ ** get_rfree
+ ** is_left_neighbor_in_cache
+ ** decrement_key
+ ** get_far_parent
+ ** get_parents
+ ** can_node_be_removed
+ ** ip_check_balance
+ ** dc_check_balance_internal
+ ** dc_check_balance_leaf
+ ** dc_check_balance
+ ** check_balance
+ ** get_direct_parent
+ ** get_neighbors
+ ** fix_nodes
+ ** 
+ ** 
+ **/
+
+
+#include "includes.h"
+
+__u64 get_bytes_number (struct item_head * ih, int blocksize)
+{
+    switch (get_type (&ih->ih_key)) {
+    case TYPE_DIRECT:
+	return ih_item_len (ih);
+    case TYPE_INDIRECT:
+	return I_UNFM_NUM(ih) * blocksize - ih_free_space (ih);
+    case TYPE_STAT_DATA:
+	return 0;
+    }
+    reiserfs_warning (stderr, "get_bytes_number: called for wrong type of item %h", ih);
+    return 0;
+}
+
+/* To make any changes in the tree we find a node, that contains item
+   to be changed/deleted or position in the node we insert a new item
+   to. We call this node S. To do balancing we need to decide what we
+   will shift to left/right neighbor, or to a new node, where new item
+   will be etc. To make this analysis simpler we build virtual
+   node. Virtual node is an array of items, that will replace items of
+   node S. (For instance if we are going to delete an item, virtual
+   node does not contain it). Virtual node keeps information about
+   item sizes and types, mergeability of first and last items, sizes
+   of all entries in directory item. We use this array of items when
+   calculating what we can shift to neighbors and how many nodes we
+   have to have if we do not any shiftings, if we shift to left/right
+   neighbor or to both. */
+
+
+/* taking item number in virtual node, returns number of item, that it has in source buffer */
+static inline int old_item_num (int new_num, int affected_item_num, int mode)
+{
+  if (mode == M_PASTE || mode == M_CUT || new_num < affected_item_num)
+    return new_num;
+
+  if (mode == M_INSERT) {
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (new_num == 0)
+      reiserfs_panic (0,"vs-8005: old_item_num: for INSERT mode and item number of inserted item");
+#endif
+
+    return new_num - 1;
+  }
+
+#ifdef CONFIG_REISERFS_CHECK
+  if (mode != M_DELETE)
+      reiserfs_panic (0, "vs-8010: old_item_num: mode must be M_DELETE (mode = \'%c\'", mode);
+#endif
+
+  /* delete mode */
+  return new_num + 1;
+}
+
+
+/*
+ * function returns old entry number in directory item in real node
+ * using new entry number in virtual item in virtual node */
+static inline int old_entry_num (int new_num, int affected_item_num, int new_entry_num, int pos_in_item, int mode)
+{
+  if ( mode == M_INSERT || mode == M_DELETE)
+    return new_entry_num;
+
+  if (new_num != affected_item_num) {
+    /* cut or paste is applied to another item */
+    return new_entry_num;
+  }
+
+  if (new_entry_num < pos_in_item)
+    return new_entry_num;
+
+  if (mode == M_CUT)
+    return new_entry_num + 1;
+
+#ifdef CONFIG_REISERFS_CHECK  
+  if (mode != M_PASTE)
+      reiserfs_panic (0, "vs-8015: old_entry_num: mode must be M_PASTE (mode = \'%c\'", mode);
+#endif
+
+  return new_entry_num - 1;
+}
+
+
+
+/*
+ * Create an array of sizes of directory entries for virtual item
+ */
+static void set_entry_sizes (struct tree_balance * tb,
+			     int old_num, int new_num,
+			     struct buffer_head * bh,
+			     struct item_head * ih
+    )
+{
+    struct virtual_node * vn = tb->tb_vn;
+    int i;
+    struct reiserfs_de_head * deh;
+    struct virtual_item * vi;
+  
+    deh = B_I_DEH (bh, ih);
+
+  /* seek to given virtual item in array of virtual items */
+    vi = vn->vn_vi + new_num;
+
+    /* virtual directory item have this amount of entry after */
+    vi->vi_entry_count = ih_entry_count (ih) + 
+	((old_num == vn->vn_affected_item_num) ? ((vn->vn_mode == M_CUT) ? -1 :
+						  (vn->vn_mode == M_PASTE ? 1 : 0)) : 0);
+
+#ifdef CONFIG_REISERFS_CHECK
+    /* check whether we have enough space for array of entry sizes */
+    if (tb->vn_buf + tb->vn_buf_size - vn->vn_free_ptr < vi->vi_entry_count * sizeof (__u16))
+	reiserfs_panic (tb->tb_sb, "vs-8020: set_entry_sizes: "
+			"no enough space for %d entries of virtual item", vi->vi_entry_count);
+#endif
+
+    vi->vi_entry_sizes = (__u16 *)vn->vn_free_ptr;
+    vn->vn_free_ptr += vi->vi_entry_count * sizeof (__u16);
+
+    /* set sizes of old entries */
+    for (i = 0; i < vi->vi_entry_count; i ++) {
+	int j;
+    
+	j = old_entry_num (old_num, vn->vn_affected_item_num, i, vn->vn_pos_in_item, vn->vn_mode);
+	vi->vi_entry_sizes[i] = entry_length (ih, &(deh[j]), j) + DEH_SIZE;
+    }
+  
+    /* set size of pasted entry */
+    if (old_num == vn->vn_affected_item_num && vn->vn_mode == M_PASTE)
+	vi->vi_entry_sizes[vn->vn_pos_in_item] = tb->insert_size[0];
+
+
+#ifdef CONFIG_REISERFS_CHECK
+  /* compare total size of entries with item length */
+  {
+    int k, l;
+    
+    l = 0;
+    for (k = 0; k < vi->vi_entry_count; k ++)
+      l += vi->vi_entry_sizes[k];
+    
+    if (l + IH_SIZE != vi->vi_item_len + 
+	((old_num == vn->vn_affected_item_num && (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT)) ? tb->insert_size[0] : 0) ) {
+      reiserfs_panic (0, "vs-8025: set_entry_sizes: (mode==%c, old_num==%d, aff_num==%d, insert_size==%d), invalid length of directory item",
+		      vn->vn_mode, old_num, vn->vn_affected_item_num, tb->insert_size[0]);
+    }
+  }
+#endif
+
+}
+
+
+static void create_virtual_node (struct tree_balance * tb, int h)
+{
+    struct item_head * ih;
+    struct virtual_node * vn = tb->tb_vn;
+    int new_num;
+    struct buffer_head * Sh;	/* this comes from tb->S[h] */
+
+    struct item_head * temp_ih;
+
+    Sh = PATH_H_PBUFFER (tb->tb_path, h);
+
+    temp_ih = B_N_PITEM_HEAD (PATH_PLAST_BUFFER (tb->tb_path), B_NR_ITEMS (PATH_PLAST_BUFFER (tb->tb_path)) - 1);
+
+    /* size of changed node */
+    vn->vn_size = MAX_CHILD_SIZE (Sh) - B_BLK_HEAD (Sh)->blk_free_space + tb->insert_size[h];
+
+    /* for internal nodes array if virtual items is not created */
+    if (h) {
+	vn->vn_nr_item = (vn->vn_size - DC_SIZE) / (DC_SIZE + KEY_SIZE);
+	return;
+    }
+
+    /* number of items in virtual node  */
+    vn->vn_nr_item = B_NR_ITEMS (Sh) + ((vn->vn_mode == M_INSERT)? 1 : 0) - ((vn->vn_mode == M_DELETE)? 1 : 0);
+
+    /* first virtual item */
+    vn->vn_vi = (struct virtual_item *)(tb->tb_vn + 1);
+    memset (vn->vn_vi, 0, vn->vn_nr_item * sizeof (struct virtual_item));
+    vn->vn_free_ptr += vn->vn_nr_item * sizeof (struct virtual_item);
+
+
+    /* first item in the node */
+    ih = B_N_PITEM_HEAD (Sh, 0);
+
+    /* define the mergeability for 0-th item (if it is not being deleted) */
+#ifndef FU //REISERFS_FSCK
+    if (is_left_mergeable (tb->tb_sb, tb->tb_path) == 1 && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num))
+#else
+	if (is_left_mergeable (ih, Sh->b_size) && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num))
+#endif
+	    vn->vn_vi[0].vi_type |= VI_TYPE_LEFT_MERGEABLE;
+
+    /* go through all items those remain in the virtual node (except for the new (inserted) one) */
+    for (new_num = 0; new_num < vn->vn_nr_item; new_num ++) {
+	int j;
+    
+	if (vn->vn_affected_item_num == new_num && vn->vn_mode == M_INSERT)
+	    continue;
+    
+	/* get item number in source node */
+	j = old_item_num (new_num, vn->vn_affected_item_num, vn->vn_mode);
+    
+	vn->vn_vi[new_num].vi_item_len += ih[j].ih_item_len + IH_SIZE;
+    
+	if (I_IS_STAT_DATA_ITEM (ih + j)) {
+	    vn->vn_vi[new_num].vi_type |= VI_TYPE_STAT_DATA;
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if (new_num == vn->vn_affected_item_num && (vn->vn_mode == M_CUT || vn->vn_mode == M_PASTE))
+		reiserfs_panic (0, "vs-8035: create_virtual_node: stat data cannot be affected item");
+#endif
+
+	    continue;
+	}
+
+	/* set type of item */
+	if (I_IS_DIRECT_ITEM (ih + j))
+	    vn->vn_vi[new_num].vi_type |= VI_TYPE_DIRECT;
+    
+	if (I_IS_INDIRECT_ITEM (ih + j))
+	    vn->vn_vi[new_num].vi_type |= VI_TYPE_INDIRECT;
+
+	if (I_IS_DIRECTORY_ITEM (ih + j)) {
+	    set_entry_sizes (tb, j, new_num, Sh, ih + j);
+	    vn->vn_vi[new_num].vi_type |= VI_TYPE_DIRECTORY;
+	    if (ih[j].ih_key.u.k_offset_v1.k_offset == DOT_OFFSET)
+		vn->vn_vi[new_num].vi_type |= VI_TYPE_FIRST_DIRECTORY_ITEM;
+	}
+    
+	if (new_num != vn->vn_affected_item_num)
+	    /* this is not being changed */
+	    continue;
+    
+	if (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT)
+	    vn->vn_vi[new_num].vi_item_len += tb->insert_size[0];
+    }
+  
+  
+    /* virtual inserted item is not defined yet */
+    if (vn->vn_mode == M_INSERT) {
+      
+#ifdef CONFIG_REISERFS_CHECK
+	if (vn->vn_ins_ih == 0)
+	    reiserfs_panic (0, "vs-8040: create_virtual_node: item header of inserted item is not specified");
+#endif
+
+	vn->vn_vi[vn->vn_affected_item_num].vi_item_len = tb->insert_size[0];
+    
+	switch (get_type (&vn->vn_ins_ih->ih_key)) {
+	case TYPE_STAT_DATA:
+	    vn->vn_vi[vn->vn_affected_item_num].vi_type |= VI_TYPE_STAT_DATA;
+	    break;
+	case TYPE_DIRECT:
+	    vn->vn_vi[vn->vn_affected_item_num].vi_type |= VI_TYPE_DIRECT;
+	    break;
+	case TYPE_INDIRECT:
+	    vn->vn_vi[vn->vn_affected_item_num].vi_type |= VI_TYPE_INDIRECT;
+	    break;
+	default:
+	    /* inseted item is directory (it must be item with "." and "..") */
+	    vn->vn_vi[vn->vn_affected_item_num].vi_type |= 
+		(VI_TYPE_DIRECTORY | VI_TYPE_FIRST_DIRECTORY_ITEM | VI_TYPE_INSERTED_DIRECTORY_ITEM);
+      
+	    /* this directory item can not be split, so do not set sizes of entries */
+	    break;
+	}
+    }
+  
+    /* set right merge flag we take right delimiting key and check whether it is a mergeable item */
+    if (tb->CFR[0]) {
+	ih = (struct item_head *)B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]);
+#ifndef FU //REISERFS_FSCK
+	if (is_right_mergeable (tb->tb_sb, tb->tb_path) == 1 && (vn->vn_mode != M_DELETE ||
+								 vn->vn_affected_item_num != B_NR_ITEMS (Sh) - 1))
+#else
+	    if (is_left_mergeable (ih, Sh->b_size) && (vn->vn_mode != M_DELETE ||
+						       vn->vn_affected_item_num != B_NR_ITEMS (Sh) - 1))
+#endif
+		vn->vn_vi[vn->vn_nr_item-1].vi_type |= VI_TYPE_RIGHT_MERGEABLE;
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (is_left_mergeable (ih, Sh->b_size) &&
+	    !(vn->vn_mode != M_DELETE || vn->vn_affected_item_num != B_NR_ITEMS (Sh) - 1) ) {
+	    /* we delete last item and it could be merged with right neighbor's first item */
+	    if (!(B_NR_ITEMS (Sh) == 1 && I_IS_DIRECTORY_ITEM (B_N_PITEM_HEAD (Sh, 0)) &&
+		  ih_entry_count (B_N_PITEM_HEAD (Sh, 0)) == 1)) {
+		/* node contains more than 1 item, or item is not directory item, or this item contains more than 1 entry */
+		print_block (Sh, 0, -1, -1);
+		reiserfs_panic (tb->tb_sb, "vs-8045: create_virtual_node: rdkey %k, affected item==%d (mode==%c) Must be %c", 
+				&(ih->ih_key), vn->vn_affected_item_num, vn->vn_mode, M_DELETE);
+	    } else
+		/* we can delete directory item, that has only one directory entry in it */
+		;
+	}
+#endif
+    
+    }
+}
+
+
+/* using virtual node check, how many items can be shifted to left
+   neighbor */
+static  int check_left (struct tree_balance * tb, int h, int cur_free)
+{
+    int i;
+    struct virtual_node * vn = tb->tb_vn;
+    int d_size, ih_size, bytes = -1;
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (cur_free < 0)
+	reiserfs_panic (0, "vs-8050: check_left: cur_free (%d) < 0", cur_free);
+#endif
+
+    /* internal level */
+    if (h > 0) {	
+	if (!cur_free ) {
+	    tb->lnum[h] = 0; 
+	    return 0;
+	}
+	tb->lnum[h] = cur_free / (DC_SIZE + KEY_SIZE);
+	return -1;
+    }
+
+    /* leaf level */
+
+    if (!cur_free || !vn->vn_nr_item) {
+	/* no free space */
+	tb->lnum[h] = 0;
+	tb->lbytes = -1;
+	return 0;
+    }
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (!PATH_H_PPARENT (tb->tb_path, 0))
+	reiserfs_panic (0, "vs-8055: check_left: parent does not exist or invalid");
+#endif
+
+    if ((unsigned int)cur_free >= (vn->vn_size - ((vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE) ? IH_SIZE : 0))) {
+	/* all contents of S[0] fits into L[0] */
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE) {
+	    reiserfs_panic (0, "vs-8055: check_left: invalid mode or balance condition failed (cur_free %d)vn->vn_size %d",
+			    cur_free, vn->vn_size);
+	}
+#endif
+
+	tb->lnum[0] = vn->vn_nr_item;
+	tb->lbytes = -1;
+	return -1;
+    }
+  
+
+    d_size = 0, ih_size = IH_SIZE;
+
+    /* first item may be merge with last item in left neighbor */
+    if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE)
+	d_size = -((int)IH_SIZE), ih_size = 0;
+
+    tb->lnum[0] = 0;
+    for (i = 0; i < vn->vn_nr_item; i ++, ih_size = IH_SIZE, d_size = 0) {
+	d_size += vn->vn_vi[i].vi_item_len;
+	if (cur_free >= d_size) {	
+	    /* the item can be shifted entirely */
+	    cur_free -= d_size;
+	    tb->lnum[0] ++;
+	    continue;
+	}
+      
+	/* the item cannot be shifted entirely, try to split it */
+	/* check whether L[0] can hold ih and at least one byte of the item body */
+	if (cur_free <= ih_size) {
+	    /* cannot shift even a part of the current item */
+	    tb->lbytes = -1;
+	    return -1;
+	}
+	cur_free -= ih_size;
+    
+	if (vn->vn_vi[i].vi_type & VI_TYPE_STAT_DATA ||
+	    vn->vn_vi[i].vi_type & VI_TYPE_INSERTED_DIRECTORY_ITEM)	{
+	    /* virtual item is a stat_data or empty directory body ("." and ".."), that is not split able */
+	    tb->lbytes = -1;
+	    return -1;
+	}
+    
+	if (vn->vn_vi[i].vi_type & VI_TYPE_DIRECT)
+	    /* body of a direct item can be split at any byte */
+	    tb->lbytes = bytes = cur_free;
+    
+	if (vn->vn_vi[i].vi_type & VI_TYPE_INDIRECT)
+	    /* body of a indirect item can be split at unformatted pointer bound */
+	    tb->lbytes = bytes = cur_free - cur_free % UNFM_P_SIZE;
+    
+	/* item is of directory type */     
+	if (vn->vn_vi[i].vi_type & VI_TYPE_DIRECTORY) {
+	    /* directory entries are the solid granules of the directory
+	       item, they cannot be split in the middle */
+      
+	    /* calculate number of dir entries that can be shifted, and
+	       their total size */
+	    int j;
+	    struct virtual_item * vi;
+      
+	    tb->lbytes = 0;
+	    bytes = 0;
+	    vi = &vn->vn_vi[i];
+      
+	    for (j = 0; j < vi->vi_entry_count; j ++) {
+		if (vi->vi_entry_sizes[j] > cur_free)
+		    /* j-th entry doesn't fit into L[0] */
+		    break;
+		  
+		bytes += vi->vi_entry_sizes[j];
+		cur_free -= vi->vi_entry_sizes[j];
+		tb->lbytes ++;
+	    }
+	    /* "." can not be cut from first directory item */
+	    if ((vn->vn_vi[i].vi_type & VI_TYPE_FIRST_DIRECTORY_ITEM) && tb->lbytes < 2)
+		tb->lbytes = 0;
+	}
+    
+
+	if (tb->lbytes <= 0) {
+	    /* nothing can flow from the item */
+	    tb->lbytes = -1;
+	    return -1;
+	}
+    
+	/* something can flow from the item */
+	tb->lnum[0] ++;
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (bytes == -1)
+	    reiserfs_panic (tb->tb_sb, "vs-8060: check_left: bytes is not initialized");
+#endif      
+
+	return bytes;	/* part of split item in bytes */
+    }
+  
+
+    reiserfs_panic (0, "vs: 8065: check_left: all items fit in the left neighbor");
+    return 0;
+}
+
+	
+
+/* using virtual node check, how many items can be shifted to right
+   neighbor */
+static int check_right (struct tree_balance * tb, int h, int cur_free)
+{
+  int i;
+  struct virtual_node * vn = tb->tb_vn;
+  int d_size, ih_size, bytes = -1;
+
+#ifdef CONFIG_REISERFS_CHECK
+  if (cur_free < 0)
+    reiserfs_panic (tb->tb_sb, "vs-8070: check_right: cur_free < 0");
+#endif
+    
+  /* internal level */
+  if (h > 0) {
+    if (!cur_free) {
+      tb->rnum[h] = 0; 
+      return 0;
+    }
+    tb->rnum[h] = cur_free / (DC_SIZE + KEY_SIZE);
+    return -1;
+  }
+
+  /* leaf level */
+
+  if (!cur_free || !vn->vn_nr_item) {
+    /* no free space  */
+    tb->rnum[h] = 0;
+    tb->rbytes = -1;
+    return 0;
+  }
+  
+#ifdef CONFIG_REISERFS_CHECK
+  if (!PATH_H_PPARENT (tb->tb_path, 0))
+    reiserfs_panic (tb->tb_sb, "vs-8075: check_right: parent does not exist or invalid");
+#endif
+  
+  if ((unsigned int)cur_free >= (vn->vn_size - ((vn->vn_vi[vn->vn_nr_item-1].vi_type & VI_TYPE_RIGHT_MERGEABLE) ? IH_SIZE : 0)))
+    {
+      /* all contents of S[0] fits into R[0] */
+
+#ifdef CONFIG_REISERFS_CHECK
+      if (vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE)
+	reiserfs_panic (tb->tb_sb, "vs-8080: check_right: invalid mode or balance condition failed");
+#endif
+
+      tb->rnum[h] = vn->vn_nr_item;
+      tb->rbytes = -1;
+      return -1;
+    }
+
+  d_size = 0, ih_size = IH_SIZE;
+
+  /* last item may be merge with first item in right neighbor */
+  if (vn->vn_vi[vn->vn_nr_item - 1].vi_type & VI_TYPE_RIGHT_MERGEABLE)
+    d_size = -(int)IH_SIZE, ih_size = 0;
+
+  tb->rnum[0] = 0;
+  for (i = vn->vn_nr_item - 1; i >= 0; i --, d_size = 0, ih_size = IH_SIZE)
+    {
+      d_size += vn->vn_vi[i].vi_item_len;
+      if (cur_free >= d_size)
+	{	
+	  /* the item can be shifted entirely */
+	  cur_free -= d_size;
+	  tb->rnum[0] ++;
+	  continue;
+	}
+
+      /* the item cannot be shifted entirely, try to split it */
+      if (vn->vn_vi[i].vi_type & VI_TYPE_STAT_DATA || vn->vn_vi[i].vi_type & VI_TYPE_INSERTED_DIRECTORY_ITEM)
+	{
+	  /* virtual item is a stat_data or empty directory body ("." and "..), that is not split able */
+	  tb->rbytes = -1;
+	  return -1;
+	}
+      
+      /* check whether R[0] can hold ih and at least one byte of the item body */
+      if ( cur_free <= ih_size )
+	/* cannot shift even a part of the current item */
+	{
+	  tb->rbytes = -1;
+	  return -1;
+	}
+      
+      /* R[0] can hold the header of the item and at least one byte of its body */
+      cur_free -= ih_size;	/* cur_free is still > 0 */
+
+      /* item is of direct type */
+      if (vn->vn_vi[i].vi_type & VI_TYPE_DIRECT)
+	/* body of a direct item can be split at any byte */
+	tb->rbytes = bytes = cur_free;
+	
+      /* item is of indirect type */
+      if (vn->vn_vi[i].vi_type & VI_TYPE_INDIRECT)
+	/* an unformatted node pointer (having size long) is a solid granule of the item */
+	tb->rbytes = bytes = cur_free - cur_free % UNFM_P_SIZE;
+
+      /* item is of directory type */
+      if (vn->vn_vi[i].vi_type & VI_TYPE_DIRECTORY)
+	{
+	  int j;
+	  struct virtual_item * vi;
+	  
+	  tb->rbytes = 0;
+	  bytes = 0;
+	  vi = &vn->vn_vi[i];
+	  
+	  for (j = vi->vi_entry_count - 1; j >= 0; j --)
+	    {
+	      if (vi->vi_entry_sizes[j] > cur_free)
+		/* j-th entry doesn't fit into L[0] */
+		break;
+	      
+	      bytes += vi->vi_entry_sizes[j];
+	      cur_free -= vi->vi_entry_sizes[j];
+	      tb->rbytes ++;
+	    }
+
+	  /* ".." can not be cut from first directory item */
+	  if ((vn->vn_vi[i].vi_type & VI_TYPE_FIRST_DIRECTORY_ITEM) && tb->rbytes > vi->vi_entry_count - 2) {
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if (tb->rbytes > vi->vi_entry_count - 1) {
+	      reiserfs_panic (tb->tb_sb, "vs-8085: check_right: all entries can be shifted to right neighbor");
+	    }
+#endif
+
+	    tb->rbytes = vi->vi_entry_count - 2;
+	  }
+	}
+	
+	if ( tb->rbytes <= 0 )
+	  {
+	    /* nothing can flow from the item */
+	    tb->rbytes = -1;
+	    return -1;
+	  }
+
+
+	/* something can flow from the item */
+	tb->rnum[0] ++;
+#ifdef CONFIG_REISERFS_CHECK
+	if (bytes == -1)
+	  reiserfs_panic (tb->tb_sb, "vs-8090: check_right: bytes is not initialized");
+#endif      
+	return bytes;	/* part of split item in bytes */
+    }
+
+  reiserfs_panic ("vs-8095: check_right: all items fit in the left neighbor");
+  return 0;
+}
+
+
+/* sum of entry sizes between from-th and to-th entries including both edges */
+static int directory_part_size (struct virtual_item * vi, int from, int to)
+{
+  int i, retval;
+
+  retval = 0;
+  for (i = from; i <= to; i ++)
+    retval += vi->vi_entry_sizes[i];
+
+  return retval;
+}
+
+
+/*
+ * from - number of items, which are shifted to left neighbor entirely
+ * to - number of item, which are shifted to right neighbor entirely
+ * from_bytes - number of bytes of boundary item (or directory entries) which are shifted to left neighbor
+ * to_bytes - number of bytes of boundary item (or directory entries) which are shifted to right neighbor */
+static int get_num_ver (int mode, struct tree_balance * tb, int h,
+			int from, int from_bytes,
+			int to,   int to_bytes,
+			short * snum012, int flow
+			)
+{
+  int i;
+  int bytes;
+  struct virtual_node * vn = tb->tb_vn;
+  struct virtual_item * vi;
+
+  int total_node_size, max_node_size, current_item_size;
+  int needed_nodes;
+  int start_item, 	/* position of item we start filling node from */
+    end_item,	/* position of item we finish filling node by */
+    start_bytes,/* number of first bytes (entries for directory) of start_item-th item 
+		   we do not include into node that is being filled */
+    end_bytes;	/* number of last bytes (entries for directory) of end_item-th item 
+		   we do node include into node that is being filled */
+  int splitted_item_positions[2];	/* these are positions in virtual item of items, 
+					   that are splitted between S[0] and S1new and S1new and S2new */
+
+
+#ifdef CONFIG_REISERFS_CHECK
+  /* We only create additional nodes if we are in insert or paste mode
+     or we are in replace mode at the internal level. If h is 0 and
+     the mode is M_REPLACE then in fix_nodes we change the mode to
+     paste or insert before we get here in the code.  */
+  if ( tb->insert_size[h] < 0  || (mode != M_INSERT && mode != M_PASTE))
+    reiserfs_panic (0, "vs-8100: get_num_ver: insert_size < 0 in overflow");
+#endif
+
+  max_node_size = MAX_CHILD_SIZE (PATH_H_PBUFFER (tb->tb_path, h));
+
+  /* snum012 [0-2] - number of items, that lay
+     to S[0], first new node and second new node */
+  snum012[3] = -1;	/* s1bytes */
+  snum012[4] = -1;	/* s2bytes */
+
+
+  /* internal level */
+  if (h > 0) {
+    i = ((to - from) * (KEY_SIZE + DC_SIZE) + DC_SIZE);
+    if (i == max_node_size)
+      return 1;
+    return (i / max_node_size + 1);
+  }
+
+
+  /* leaf level */
+  needed_nodes = 1;
+  total_node_size = 0;
+
+  start_item = from;
+  start_bytes = from_bytes;
+  end_item = vn->vn_nr_item - to - 1;
+  end_bytes = to_bytes;
+
+  /* go through all items begining from the start_item-th item and ending by
+     the end_item-th item. If start_bytes != -1 we skip first start_bytes
+     item units (entries in case of directory). If end_bytes != -1 we skip
+     end_bytes units of the end_item-th item. */
+  for (i = start_item; i <= end_item; i ++) {
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (needed_nodes > 3)
+      reiserfs_panic (0, "vs-8105: get_num_ver: too many nodes are needed");
+#endif
+
+    /* get size of current item */
+    current_item_size = (vi = &vn->vn_vi[i])->vi_item_len;
+
+    /* do not take in calculation head part (from_bytes) of from-th item */
+    if (i == start_item && start_bytes != -1) {
+      if (vi->vi_type & VI_TYPE_DIRECTORY)
+	current_item_size -= directory_part_size (vi, 0, start_bytes - 1);
+      else
+	current_item_size -= start_bytes;
+    }
+      
+    /* do not take in calculation tail part of (to-1)-th item */
+    if (i == end_item && end_bytes != -1) {
+      if (vi->vi_type & VI_TYPE_DIRECTORY)
+	/* first entry, that is not included */
+	current_item_size -= directory_part_size (vi, vi->vi_entry_count - end_bytes, vi->vi_entry_count - 1);
+      else
+	current_item_size -= end_bytes;
+    }
+
+    /* if item fits into current node entirely */
+    if (total_node_size + current_item_size <= max_node_size) {
+      snum012[needed_nodes - 1] ++;
+      total_node_size += current_item_size;
+      continue;
+    }
+
+    if (current_item_size > max_node_size) {
+      /* virtual item length is longer, than max size of item in a node. It is impossible for direct item */
+#ifdef CONFIG_REISERFS_CHECK
+      if (vi->vi_type & VI_TYPE_DIRECT)
+	reiserfs_panic (0, "vs-8110: get_num_ver: direct item length is %d. It can not be longer than %d", 
+			current_item_size, max_node_size);
+#endif
+      /* we will try to split it */
+      flow = 1;
+    }
+
+    if (!flow) {
+      /* as we do not split items, take new node and continue */
+      needed_nodes ++; i --; total_node_size = 0;
+      continue;
+    }
+
+    if (total_node_size + (int)IH_SIZE >= max_node_size) {
+      /* even minimal item does not fit into current node, take new node and continue */
+      needed_nodes ++, i--, total_node_size = 0;
+      continue;
+    }
+    if (vi->vi_type & VI_TYPE_STAT_DATA) {
+
+      /* stat data can not be split */
+      needed_nodes ++, i--, total_node_size = 0;
+      continue;
+    }
+
+    /* body of a direct item can be split at any byte */
+    /* bytes is free space in filled node */
+    bytes = max_node_size - total_node_size - IH_SIZE;
+
+    /* item is of indirect type */
+    if (vi->vi_type & VI_TYPE_INDIRECT)
+      /* an unformatted node pointer (having size long) is a solid granule of the item */
+      /* bytes of unformatted node pointers fits into free space of filled node */
+      bytes -= (bytes) % UNFM_P_SIZE;
+
+    /* S1bytes or S2bytes. It depends from needed_nodes */
+    snum012[needed_nodes - 1 + 3] = bytes;
+
+    /* item is of directory type */
+    if (vi->vi_type & VI_TYPE_DIRECTORY) {
+      /* calculate, how many entries can be put into current node */
+      int j;
+      int end_entry;
+
+      snum012[needed_nodes - 1 + 3] = 0;
+
+      total_node_size += IH_SIZE;
+      if (start_bytes == -1 || i != start_item)
+	start_bytes = 0;
+
+      end_entry = vi->vi_entry_count - ((i == end_item && end_bytes != -1) ? end_bytes : 0);
+      for (j = start_bytes; j < end_entry; j ++) {
+	/* j-th entry doesn't fit into current node */
+	if (total_node_size + vi->vi_entry_sizes[j] > max_node_size)
+	  break;
+	snum012[needed_nodes - 1 + 3] ++;
+	bytes += vi->vi_entry_sizes[j];
+	total_node_size += vi->vi_entry_sizes[j];
+      }
+      /* "." can not be cut from first directory item */
+      if (start_bytes == 0 && (vn->vn_vi[i].vi_type & VI_TYPE_FIRST_DIRECTORY_ITEM) && 
+	  snum012[needed_nodes - 1 + 3] < 2)
+	snum012[needed_nodes - 1 + 3] = 0;
+
+
+#ifdef CONFIG_REISERFS_CHECK
+      if (vi->vi_entry_count && 
+	  vi->vi_entry_count - ((i == end_item && end_bytes != -1) ? end_bytes : 0)
+	  - (start_bytes) <= snum012[needed_nodes - 1 + 3])
+	reiserfs_panic (0, "vs-8115: get_num_ver: required part of directory fits into current node");
+#endif
+    }
+
+    if (snum012[needed_nodes-1+3] <= 0 ) {
+      /* nothing fits into current node, take new node and continue */
+      needed_nodes ++, i--, total_node_size = 0;
+      continue;
+    }
+
+    /* something fits into the current node */
+    if (vi->vi_type & VI_TYPE_DIRECTORY)
+      start_bytes += snum012[needed_nodes - 1 + 3];
+    else
+      start_bytes = bytes;
+
+    snum012[needed_nodes - 1] ++;
+    splitted_item_positions[needed_nodes - 1] = i;
+
+    needed_nodes ++;
+    /* continue from the same item with start_bytes != -1 */
+    start_item = i;
+    i --;
+    total_node_size = 0;
+  }
+
+
+  /* snum012[3] and snum012[4] contain how many bytes (entries) of
+     split item can be in S[0] and S1new. s1bytes and s2bytes are how
+     many bytes (entries) can be in S1new and S2new. Recalculate it */
+  
+  if (snum012[4] > 0) {	/* s2bytes */
+    /* get number of item that is split between S1new and S2new */
+    int split_item_num;
+    int bytes_to_r, bytes_to_l;
+    
+    split_item_num = splitted_item_positions[1];
+    bytes_to_l = ((from == split_item_num && from_bytes != -1) ? from_bytes : 0);
+    bytes_to_r = ((end_item == split_item_num && end_bytes != -1) ? end_bytes : 0);
+    if (vn->vn_vi[split_item_num].vi_type & VI_TYPE_DIRECTORY) {
+      int entries_to_S2new;
+      
+      /* calculate number of entries fit into S2new */
+      entries_to_S2new =  vn->vn_vi[split_item_num].vi_entry_count - snum012[4] - bytes_to_r - bytes_to_l;
+      if (snum012[3] != -1 && snum012[1] == 1) {
+	/* directory split into 3 nodes */
+	int entries_to_S1new;
+
+	entries_to_S2new -= snum012[3];
+	entries_to_S1new = snum012[4];
+	snum012[3] = entries_to_S1new;
+	snum012[4] = entries_to_S2new;
+	return needed_nodes;
+      }
+      snum012[4] = entries_to_S2new;
+    } else {
+      /* item is not of directory type */
+      int bytes_to_S2new;
+      
+      bytes_to_S2new = vn->vn_vi[split_item_num].vi_item_len - IH_SIZE - snum012[4] - bytes_to_r - bytes_to_l;
+      snum012[4] = bytes_to_S2new;
+    }
+  }
+
+  /* now we know S2bytes, calculate S1bytes */
+  if (snum012[3] > 0) {	/* s1bytes */
+    /* get number of item that is split between S0 and S1new */
+    int split_item_num;
+    int bytes_to_r, bytes_to_l;
+    
+    split_item_num = splitted_item_positions[0];
+    bytes_to_l = ((from == split_item_num && from_bytes != -1) ? from_bytes : 0);
+    bytes_to_r = ((end_item == split_item_num && end_bytes != -1) ? end_bytes : 0);
+    if (vn->vn_vi[split_item_num].vi_type & VI_TYPE_DIRECTORY) {
+      /* entries, who go to S1new node */
+      snum012[3] =  vn->vn_vi[split_item_num].vi_entry_count - snum012[3] - bytes_to_r - bytes_to_l;
+    } else
+      /* bytes, who go to S1new node (not including HI_SIZE) */
+      snum012[3] = vn->vn_vi[split_item_num].vi_item_len - IH_SIZE - snum012[3] - bytes_to_r - bytes_to_l;
+  }
+
+  return needed_nodes;
+}
+
+
+#ifdef CONFIG_REISERFS_CHECK
+extern struct tree_balance * cur_tb;
+#endif
+
+
+/* size of item_num-th item in bytes when regular and in entries when
+   item is directory */
+static int item_length (struct tree_balance * tb, int item_num)
+{
+  struct virtual_node * vn = tb->tb_vn;
+
+#ifdef CONFIG_REISERFS_CHECK
+  if (item_num >= vn->vn_nr_item)
+    reiserfs_panic (tb->tb_sb, "vs-8120: item_length: invalid index of item: index = %d (item number = %d)", item_num, vn->vn_nr_item);
+#endif
+
+  if (vn->vn_vi[item_num].vi_type & VI_TYPE_DIRECTORY)
+    return vn->vn_vi[item_num].vi_entry_count;
+
+  return vn->vn_vi[item_num].vi_item_len - IH_SIZE;
+}
+
+
+/* Set parameters for balancing.
+ * Performs write of results of analysis of balancing into structure tb,
+ * where it will later be used by the functions that actually do the balancing. 
+ * Parameters:
+ *	tb	tree_balance structure;
+ *	h	current level of the node;
+ *	lnum	number of items from S[h] that must be shifted to L[h];
+ *	rnum	number of items from S[h] that must be shifted to R[h];
+ *	blk_num	number of blocks that S[h] will be splitted into;
+ *	s012	number of items that fall into splitted nodes.
+ *	lbytes	number of bytes which flow to the left neighbor from the item that is not
+ *		not shifted entirely
+ *	rbytes	number of bytes which flow to the right neighbor from the item that is not
+ *		not shifted entirely
+ *	s1bytes	number of bytes which flow to the first  new node when S[0] splits (this number is contained in s012 array)
+ */
+
+static void set_parameters (struct tree_balance * tb, int h, int lnum,
+			    int rnum, int blk_num, short * s012, int lb, int rb)
+{
+
+  tb->lnum[h] = lnum;
+  tb->rnum[h] = rnum;
+  tb->blknum[h] = blk_num;
+
+  if (h == 0)
+    {  /* only for leaf level */
+      if (s012 != NULL)
+	{
+	  tb->s0num = * s012 ++,
+	  tb->s1num = * s012 ++,
+	  tb->s2num = * s012 ++;
+	  tb->s1bytes = * s012 ++;
+	  tb->s2bytes = * s012;
+	}
+      tb->lbytes = lb;
+      tb->rbytes = rb;
+    }
+}
+
+static void decrement_key (struct key * p_s_key) 
+{
+    int type;
+
+    type = get_type (p_s_key);
+    switch (type) {
+    case TYPE_STAT_DATA:
+	p_s_key->k_objectid --;
+	set_type_and_offset (key_format (p_s_key), p_s_key,
+			     (loff_t)MAX_FILE_SIZE_V2, TYPE_INDIRECT);
+	return;
+
+    case TYPE_INDIRECT:
+    case TYPE_DIRECT:
+    case TYPE_DIRENTRY:
+	set_offset (key_format (p_s_key), p_s_key, get_offset (p_s_key) - 1);
+	if (get_offset (p_s_key) == 0)
+	    set_type (key_format (p_s_key), p_s_key, TYPE_STAT_DATA);
+	return;
+    }
+    reiserfs_warning (stderr, "vs-8125: decrement_key: item of wrong type found %k",
+		      p_s_key);
+#if 0
+
+    unsigned long * p_n_key_field = (unsigned long *)p_s_key + REISERFS_FULL_KEY_LEN - 1;
+    int		  n_counter;
+
+
+    for( n_counter = 0; n_counter < REISERFS_FULL_KEY_LEN; n_counter++, p_n_key_field-- )
+	if ( *p_n_key_field ) {
+	    (*p_n_key_field)--;
+	    break;
+	}
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( n_counter == REISERFS_FULL_KEY_LEN )
+	reiserfs_panic(NULL, "PAP-8175: decrement_key: zero key");
+#endif
+
+#endif
+
+}
+
+
+#ifdef FU //REISERFS_FSCK
+
+inline int is_left_mergeable (struct item_head * ih, unsigned long bsize)
+{
+    if (I_IS_DIRECT_ITEM (ih))
+	return ((get_offset (&ih->ih_key) & (bsize - 1)) != 1);
+
+    if (I_IS_INDIRECT_ITEM (ih))
+	return (get_offset (&ih->ih_key) != 1);
+
+    if (I_IS_DIRECTORY_ITEM (ih))
+	return ((ih)->ih_key.u.k_offset_v1.k_offset != DOT_OFFSET);
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( ! I_IS_STAT_DATA_ITEM (ih))
+	reiserfs_panic (0, "vs-16060: is_left_mergeable: item [%h] must be a stat data", ih);
+#endif
+
+    return 0;
+}
+
+#else
+
+int are_items_mergeable (struct item_head * left, struct item_head * right, int bsize)
+{
+    if (comp_keys (&left->ih_key, &right->ih_key) != -1) {
+	reiserfs_panic (0, "vs-16070: are_items_mergeable: left %k, right %k", &(left->ih_key), &(right->ih_key));
+    }
+
+    if (not_of_one_file (&left->ih_key, &right->ih_key))
+	return 0;
+
+    if (I_IS_DIRECTORY_ITEM (left)) {
+	return 1;
+    }
+
+    if ((I_IS_DIRECT_ITEM (left) && I_IS_DIRECT_ITEM (right)) || 
+	(I_IS_INDIRECT_ITEM (left) && I_IS_INDIRECT_ITEM (right)))
+	return (get_offset (&left->ih_key) + get_bytes_number (left, bsize) == get_offset (&right->ih_key)) ? 1 : 0;
+
+    return 0;
+}
+
+/* get left neighbor of the leaf node */
+static struct buffer_head * get_left_neighbor (struct super_block * s, struct path * path)
+{
+    struct key key;
+    struct path path_to_left_neighbor;
+    struct buffer_head * bh;
+    int repeat;
+
+    copy_key (&key, B_N_PKEY (PATH_PLAST_BUFFER (path), 0));
+    decrement_key (&key);
+
+    init_path (&path_to_left_neighbor);
+    search_by_key (s, &key, &path_to_left_neighbor, &repeat, DISK_LEAF_NODE_LEVEL);
+    if (PATH_LAST_POSITION (&path_to_left_neighbor) == 0) {
+	pathrelse (&path_to_left_neighbor);
+	return 0;
+    }
+    bh = PATH_PLAST_BUFFER (&path_to_left_neighbor);
+    bh->b_count ++;
+    pathrelse (&path_to_left_neighbor);
+    return bh;
+}
+
+extern struct key  MIN_KEY;
+static struct buffer_head * get_right_neighbor (struct super_block * s, struct path * path)
+{
+  struct key key;
+  struct key * rkey;
+  int repeat;
+  struct path path_to_right_neighbor;
+  struct buffer_head * bh;
+
+  rkey = get_rkey (path, s);
+  if (comp_keys (rkey, &MIN_KEY) == 0)
+    reiserfs_panic ("vs-16080: get_right_neighbor: get_rkey returned min key (path has changed)");
+  copy_key (&key, rkey);
+
+  
+  init_path (&path_to_right_neighbor);
+  search_by_key (s, &key, &path_to_right_neighbor, &repeat, DISK_LEAF_NODE_LEVEL);
+  if (PATH_PLAST_BUFFER (&path_to_right_neighbor) == PATH_PLAST_BUFFER (path)) {
+    pathrelse (&path_to_right_neighbor);
+    return 0;
+  }
+  bh = PATH_PLAST_BUFFER (&path_to_right_neighbor);
+  bh->b_count ++;
+  pathrelse (&path_to_right_neighbor);
+  return bh;
+}
+
+
+int is_left_mergeable (struct super_block * s, struct path * path)
+{
+  struct item_head * right;
+  struct buffer_head * bh;
+  int retval;
+  
+  right = B_N_PITEM_HEAD (PATH_PLAST_BUFFER (path), 0);
+
+  bh = get_left_neighbor (s, path);
+  if (bh == 0) {
+    return 0;
+  }
+  retval = are_items_mergeable (B_N_PITEM_HEAD (bh, B_NR_ITEMS (bh) - 1), right, bh->b_size);
+  brelse (bh);
+  return retval;
+}
+
+
+int is_right_mergeable (struct super_block * s, struct path * path)
+{
+  struct item_head * left;
+  struct buffer_head * bh;
+  int retval;
+  
+  left = B_N_PITEM_HEAD (PATH_PLAST_BUFFER (path), B_NR_ITEMS (PATH_PLAST_BUFFER (path)) - 1);
+
+  bh = get_right_neighbor (s, path);
+  if (bh == 0) {
+    return 0;
+  }
+  retval = are_items_mergeable (left, B_N_PITEM_HEAD (bh, 0), bh->b_size);
+  brelse (bh);
+  return retval;
+}
+
+#endif /* REISERFS_FSCK */
+
+
+
+/* check, does node disappear if we shift tb->lnum[0] items to left
+   neighbor and tb->rnum[0] to the right one. */
+static int is_leaf_removable (struct tree_balance * tb)
+{
+  struct virtual_node * vn = tb->tb_vn;
+  int to_left, to_right;
+  int size;
+  int remain_items;
+
+  /* number of items, that will be shifted to left (right) neighbor
+     entirely */
+  to_left = tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0);
+  to_right = tb->rnum[0] - ((tb->rbytes != -1) ? 1 : 0);
+  remain_items = vn->vn_nr_item;
+
+  /* how many items remain in S[0] after shiftings to neighbors */
+  remain_items -= (to_left + to_right);
+
+  if (remain_items < 1) {
+    /* all content of node can be shifted to neighbors */
+    set_parameters (tb, 0, to_left, vn->vn_nr_item - to_left, 0, NULL, -1, -1);    
+    return 1;
+  }
+  
+  if (remain_items > 1 || tb->lbytes == -1 || tb->rbytes == -1)
+    /* S[0] is not removable */
+    return 0;
+
+  /* check, whether we can divide 1 remaining item between neighbors */
+
+  /* get size of remaining item (in directory entry count if directory) */
+  size = item_length (tb, to_left);
+
+  if (tb->lbytes + tb->rbytes >= size) {
+    set_parameters (tb, 0, to_left + 1, to_right + 1, 0, NULL, tb->lbytes, -1);
+    return 1;
+  }
+
+  return 0;
+}
+
+
+/* check whether L, S, R can be joined in one node */
+static int are_leaves_removable (struct tree_balance * tb, int lfree, int rfree)
+{
+    struct virtual_node * vn = tb->tb_vn;
+    int ih_size;
+    struct buffer_head *S0;
+
+    S0 = PATH_H_PBUFFER (tb->tb_path, 0);
+
+    ih_size = 0;
+    if (vn->vn_nr_item) {
+	if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE)
+	    ih_size += IH_SIZE;
+    
+	if (vn->vn_vi[vn->vn_nr_item-1].vi_type & VI_TYPE_RIGHT_MERGEABLE)
+	    ih_size += IH_SIZE;
+    } else {
+	/* there was only one item and it will be deleted */
+	struct item_head * ih;
+    
+#ifdef CONFIG_REISERFS_CHECK
+	if (B_NR_ITEMS (S0) != 1)
+	    reiserfs_panic (0, "vs-8125: are_leaves_removable: item number must be 1: it is %d", B_NR_ITEMS(S0));
+#endif
+
+	ih = B_N_PITEM_HEAD (S0, 0);
+	if (tb->CFR[0] && !not_of_one_file (&(ih->ih_key), B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0])))
+	    if (I_IS_DIRECTORY_ITEM(ih)) {
+#ifdef FU //REISERFS_FSCK
+	
+		/* Directory must be in correct state here: that is
+		   somewhere at the left side should exist first
+		   directory item. But the item being deleted can not
+		   be that first one because its right neighbor is
+		   item of the same directory. (But first item always
+		   gets deleted in last turn). So, neighbors of
+		   deleted item can be merged, so we can save ih_size */
+		ih_size = IH_SIZE;
+
+#ifdef CONFIG_REISERFS_CHECK
+		/* we might check that left neighbor exists and is of
+                   the same directory */
+		if (get_offset (&ih->ih_key) == DOT_OFFSET)
+		    reiserfs_panic (tb->tb_sb, "vs-8130: are_leaves_removable: "
+				    "first directory item can not be removed until directory is not empty");
+#endif
+	
+	
+#else	/* REISERFS_FSCK */
+
+		/* we can delete any directory item in fsck (if it is unreachable) */
+		if (get_offset (&ih->ih_key) != DOT_OFFSET) {
+		    /* must get left neighbor here to make sure, that
+                       left neighbor is of the same directory */
+		    struct buffer_head * left;
+		    
+		    left = get_left_neighbor (tb->tb_sb, tb->tb_path);
+		    if (left) {
+			struct item_head * last;
+
+			if (B_NR_ITEMS (left) == 0)
+			    reiserfs_panic ("vs-8135: are_leaves_removable: "
+					    "empty node in the tree");
+			last = B_N_PITEM_HEAD (left, B_NR_ITEMS (left) - 1);
+			if (!comp_short_keys (&last->ih_key, &ih->ih_key))
+			    ih_size = IH_SIZE;
+			brelse (left);
+		    }
+		}
+#endif
+	    }
+    
+    }
+
+    if (MAX_CHILD_SIZE (S0) + vn->vn_size <= rfree + lfree + ih_size) {
+	set_parameters (tb, 0, -1, -1, -1, NULL, -1, -1);
+	return 1;  
+    }
+    return 0;
+  
+}
+
+
+
+/* when we do not split item, lnum and rnum are numbers of entire items */
+#define SET_PAR_SHIFT_LEFT \
+if (h)\
+{\
+   int to_l;\
+   \
+   to_l = (MAX_NR_KEY(Sh)+1 - lpar + vn->vn_nr_item + 1) / 2 -\
+	      (MAX_NR_KEY(Sh) + 1 - lpar);\
+	      \
+	      set_parameters (tb, h, to_l, 0, lnver, NULL, -1, -1);\
+}\
+else \
+{\
+   if (lset==LEFT_SHIFT_FLOW)\
+     set_parameters (tb, h, lpar, 0, lnver, snum012+lset,\
+		     tb->lbytes, -1);\
+   else\
+     set_parameters (tb, h, lpar - (tb->lbytes!=-1), 0, lnver, snum012+lset,\
+		     -1, -1);\
+}
+
+
+#define SET_PAR_SHIFT_RIGHT \
+if (h)\
+{\
+   int to_r;\
+   \
+   to_r = (MAX_NR_KEY(Sh)+1 - rpar + vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - rpar);\
+   \
+   set_parameters (tb, h, 0, to_r, rnver, NULL, -1, -1);\
+}\
+else \
+{\
+   if (rset==RIGHT_SHIFT_FLOW)\
+     set_parameters (tb, h, 0, rpar, rnver, snum012+rset,\
+		  -1, tb->rbytes);\
+   else\
+     set_parameters (tb, h, 0, rpar - (tb->rbytes!=-1), rnver, snum012+rset,\
+		  -1, -1);\
+}
+
+#if 0
+void free_buffers_in_tb (
+		       struct tree_balance * p_s_tb
+		       ) {
+  int n_counter;
+
+  decrement_counters_in_path(p_s_tb->tb_path);
+  
+  for ( n_counter = 0; n_counter < MAX_HEIGHT; n_counter++ ) {
+    decrement_bcount(p_s_tb->L[n_counter]);
+    p_s_tb->L[n_counter] = NULL;
+    decrement_bcount(p_s_tb->R[n_counter]);
+    p_s_tb->R[n_counter] = NULL;
+    decrement_bcount(p_s_tb->FL[n_counter]);
+    p_s_tb->FL[n_counter] = NULL;
+    decrement_bcount(p_s_tb->FR[n_counter]);
+    p_s_tb->FR[n_counter] = NULL;
+    decrement_bcount(p_s_tb->CFL[n_counter]);
+    p_s_tb->CFL[n_counter] = NULL;
+    decrement_bcount(p_s_tb->CFR[n_counter]);
+    p_s_tb->CFR[n_counter] = NULL;
+  }
+}
+#endif
+
+
+/* Get new buffers for storing new nodes that are created while balancing.
+ * Returns:	SCHEDULE_OCCURED - schedule occured while the function worked;
+ *	        CARRY_ON - schedule didn't occur while the function worked;
+ *	        NO_DISK_SPACE - no disk space.
+ */
+static int  get_empty_nodes (struct tree_balance * p_s_tb,
+			     int n_h)
+{
+    struct buffer_head  * p_s_new_bh,
+	*	p_s_Sh = PATH_H_PBUFFER (p_s_tb->tb_path, n_h);
+    unsigned long	      *	p_n_blocknr,
+	a_n_blocknrs[MAX_AMOUNT_NEEDED] = {0, };
+    int       		n_counter,
+	n_number_of_freeblk,
+	n_amount_needed,/* number of needed empty blocks */
+	n_repeat1,
+	n_repeat;
+    struct super_block *	p_s_sb = p_s_tb->tb_sb;
+
+
+    //#ifndef FU //REISERFS_FSCK
+    if (n_h == 0 && p_s_tb->insert_size[n_h] == 0x7fff)
+	return CARRY_ON;
+    //#endif
+    
+    /* number_of_freeblk is the number of empty blocks which have been
+       acquired for use by the balancing algorithm minus the number of
+       empty blocks used in the previous levels of the analysis,
+       number_of_freeblk = tb->cur_blknum can be non-zero if a
+       schedule occurs after empty blocks are acquired, and the
+       balancing analysis is then restarted, amount_needed is the
+       number needed by this level (n_h) of the balancing analysis.
+			    
+       Note that for systems with many processes writing, it would be
+       more layout optimal to calculate the total number needed by all
+       levels and then to run reiserfs_new_blocks to get all of them
+       at once.  */
+
+    /* Initiate number_of_freeblk to the amount acquired prior to the restart of
+       the analysis or 0 if not restarted, then subtract the amount needed
+       by all of the levels of the tree below n_h. */
+    /* blknum includes S[n_h], so we subtract 1 in this calculation */
+    for ( n_counter = 0, n_number_of_freeblk = p_s_tb->cur_blknum; n_counter < n_h; n_counter++ )
+	n_number_of_freeblk -= ( p_s_tb->blknum[n_counter] ) ? (p_s_tb->blknum[n_counter] - 1) : 0;
+
+    /* Allocate missing empty blocks. */
+    /* if p_s_Sh == 0  then we are getting a new root */
+    n_amount_needed = ( p_s_Sh ) ? (p_s_tb->blknum[n_h] - 1) : 1;
+    /*  Amount_needed = the amount that we need more than the amount that we have. */
+    if ( n_amount_needed > n_number_of_freeblk )
+	n_amount_needed -= n_number_of_freeblk;
+    else /* If we have enough already then there is nothing to do. */
+	return CARRY_ON;
+
+    if ( (n_repeat = reiserfs_new_blocknrs (p_s_tb->tb_sb, a_n_blocknrs,
+					    PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_blocknr, n_amount_needed)) != CARRY_ON ) {
+	return n_repeat; /* Out of disk space or schedule() occured. */ 
+    }
+
+
+    /* for each blocknumber we just got, get a buffer and stick it on FEB */
+    for ( p_n_blocknr = a_n_blocknrs, n_counter = 0; n_counter < n_amount_needed;
+	  p_n_blocknr++, n_counter++ ) { 
+	
+#ifdef CONFIG_REISERFS_CHECK
+	if ( ! *p_n_blocknr )
+	    reiserfs_panic(p_s_sb, "PAP-8135: get_empty_nodes: reiserfs_new_blocknrs failed when got new blocks");
+#endif
+
+	n_repeat1 = CARRY_ON;
+	p_s_new_bh = reiserfs_getblk(p_s_sb->s_dev, *p_n_blocknr, p_s_sb->s_blocksize, &n_repeat1);
+	n_repeat |= n_repeat1;
+	if (p_s_new_bh->b_count > 1) {
+	    die ("get_empty_nodes: not free empty buffer");
+	}
+#ifdef CONFIG_REISERFS_CHECK_NOCHECK
+	if ((p_s_new_bh->b_count != 1 && !buffer_journaled(p_s_new_bh)) 
+	    || (buffer_dirty (p_s_new_bh) && !buffer_journal_dirty(p_s_new_bh))) {
+	    reiserfs_panic(p_s_sb,"PAP-8140: get_empty_nodes: not free or dirty buffer %b for the new block",
+			   p_s_new_bh);
+	}
+#endif
+	//mark_buffer_journal_new(p_s_new_bh) ;
+	
+	/* Put empty buffers into the array. */
+	p_s_tb->FEB[p_s_tb->cur_blknum++] = p_s_new_bh;
+    }
+    
+    return n_repeat;
+}
+
+
+/* Get free space of the left neighbor,
+ * which is stored in the parent node of the left neighbor.
+ */
+static int get_lfree (struct tree_balance * tb, int h)
+{
+    struct buffer_head * l, * f;
+    int order;
+
+    if ((f = PATH_H_PPARENT (tb->tb_path, h)) == 0 || (l = tb->FL[h]) == 0)
+	return 0;
+
+    if (f == l)
+	order = PATH_H_B_ITEM_ORDER (tb->tb_path, h) - 1;
+    else {
+	order = B_BLK_HEAD(l)->blk_nr_item;
+	f = l;
+    }
+
+    if (B_N_CHILD(f,order)->dc_size == 0) {
+	reiserfs_warning (stderr, "get_lfree: block %u block_head %z has bad child pointer %y, order %d\n",
+			  l->b_blocknr, l, B_N_CHILD(f,order), order);
+    }
+    return (MAX_CHILD_SIZE(f) - B_N_CHILD(f,order)->dc_size);
+}
+
+
+/* Get free space of the right neighbor,
+ * which is stored in the parent node of the right neighbor.
+ */
+static int get_rfree (struct tree_balance * tb, int h)
+{
+  struct buffer_head * r, * f;
+  int order;
+
+  if ((f = PATH_H_PPARENT (tb->tb_path, h)) == 0 || (r = tb->FR[h]) == 0)
+    return 0;
+
+  if (f == r)
+      order = PATH_H_B_ITEM_ORDER (tb->tb_path, h) + 1;
+  else {
+      order = 0;
+      f = r;
+  }
+
+  return (MAX_CHILD_SIZE(f) - B_N_CHILD(f,order)->dc_size);
+
+}
+
+
+/* Check whether left neighbor is in memory. */
+static int  is_left_neighbor_in_cache(
+              struct tree_balance * p_s_tb,
+              int                   n_h
+            ) {
+  struct buffer_head  * p_s_father;
+  struct super_block  * p_s_sb = p_s_tb->tb_sb;
+  unsigned long         n_left_neighbor_blocknr;
+  int                   n_left_neighbor_position;
+
+  if ( ! p_s_tb->FL[n_h] ) /* Father of the left neighbor does not exist. */
+    return 0;
+
+  /* Calculate father of the node to be balanced. */
+  p_s_father = PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1);
+
+#ifdef CONFIG_REISERFS_CHECK
+  if ( ! p_s_father || ! B_IS_IN_TREE (p_s_father) || ! B_IS_IN_TREE (p_s_tb->FL[n_h]) ||
+       ! buffer_uptodate (p_s_father) || ! buffer_uptodate (p_s_tb->FL[n_h]) ) {
+    reiserfs_panic (p_s_sb, "vs-8165: is_left_neighbor_in_cache: F[h] (%b) or FL[h] (%b) is invalid",
+		    p_s_father, p_s_tb->FL[n_h]);
+  }
+#endif
+
+
+  /* Get position of the pointer to the left neighbor into the left father. */
+  n_left_neighbor_position = ( p_s_father == p_s_tb->FL[n_h] ) ?
+                      p_s_tb->lkey[n_h] : B_BLK_HEAD(p_s_tb->FL[n_h])->blk_nr_item;
+  /* Get left neighbor block number. */
+  n_left_neighbor_blocknr = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_left_neighbor_position);
+  /* Look for the left neighbor in the cache. */
+  if ( (p_s_father = find_buffer(p_s_sb->s_dev, n_left_neighbor_blocknr, p_s_sb->s_blocksize)) ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( buffer_uptodate (p_s_father) && ! B_IS_IN_TREE(p_s_father) ) {
+      reiserfs_panic(p_s_sb, "vs-8170: is_left_neighbor_in_cache: left neighbor (%b %z) is not in the tree",
+		     p_s_father, p_s_father);
+    }
+#endif
+
+    return 1;
+  }
+
+  return 0;
+}
+
+
+#define LEFT_PARENTS  'l'
+#define RIGHT_PARENTS 'r'
+
+
+
+
+void init_path (struct path * path)
+{
+  path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+}
+
+
+/* Calculate far left/right parent of the left/right neighbor of the current node, that
+ * is calculate the left/right (FL[h]/FR[h]) neighbor of the parent F[h].
+ * Calculate left/right common parent of the current node and L[h]/R[h].
+ * Calculate left/right delimiting key position.
+ * Returns:	PATH_INCORRECT   - path in the tree is not correct;
+ 		SCHEDULE_OCCURRED - schedule occured while the function worked;
+ *	        CARRY_ON         - schedule didn't occur while the function worked;
+ */
+static int  get_far_parent(
+              struct tree_balance *   p_s_tb,
+              int                     n_h,
+              struct buffer_head  **  pp_s_father,
+              struct buffer_head  **  pp_s_com_father,
+              char                    c_lr_par
+            ) {
+  struct buffer_head  * p_s_parent;
+  struct path         	s_path_to_neighbor_father,
+    		      * p_s_path = p_s_tb->tb_path;
+  struct key		s_lr_father_key;
+  int                   n_counter,
+                        n_position = INT_MAX,
+    			n_repeat,
+                        n_first_last_position = 0,
+                        n_path_offset = PATH_H_PATH_OFFSET(p_s_path, n_h);
+
+  /* Starting from F[n_h] go upwards in the tree, and look for the common
+      ancestor of F[n_h], and its neighbor l/r, that should be obtained. */
+
+  n_counter = n_path_offset;
+
+#ifdef CONFIG_REISERFS_CHECK
+  if ( n_counter < FIRST_PATH_ELEMENT_OFFSET )
+    reiserfs_panic(p_s_tb->tb_sb, "PAP-8180: get_far_parent: invalid path length");
+#endif
+
+  
+  for ( ; n_counter > FIRST_PATH_ELEMENT_OFFSET; n_counter--  )  {
+    /* Check whether parent of the current buffer in the path is really parent in the tree. */
+    if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_path, n_counter - 1)) )
+      return PATH_INCORRECT;
+    /* Check whether position in the parent is correct. */
+    if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_counter - 1)) > B_NR_ITEMS(p_s_parent) )
+      return PATH_INCORRECT;
+    /* Check whether parent at the path really points to the child. */
+    if ( B_N_CHILD_NUM(p_s_parent, n_position) !=
+                                          PATH_OFFSET_PBUFFER(p_s_path, n_counter)->b_blocknr )
+      return PATH_INCORRECT;
+    /* Return delimiting key if position in the parent is not equal to first/last one. */
+    if ( c_lr_par == RIGHT_PARENTS )
+      n_first_last_position = B_BLK_HEAD(p_s_parent)->blk_nr_item;
+    if ( n_position != n_first_last_position ) {
+      (*pp_s_com_father = p_s_parent)->b_count++;
+      break;
+    }
+  }
+
+  /* Hopefully we are in the root of the tree. */
+  if ( n_counter == FIRST_PATH_ELEMENT_OFFSET ) {
+    /* Check whether first buffer in the path is the root of the tree. */
+    if ( PATH_OFFSET_PBUFFER(p_s_tb->tb_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
+                                            SB_ROOT_BLOCK (p_s_tb->tb_sb) ) {
+      *pp_s_father = *pp_s_com_father = NULL;
+      return CARRY_ON;
+    }
+    return PATH_INCORRECT;
+  }
+
+#ifdef CONFIG_REISERFS_CHECK
+  if ( B_BLK_HEAD(*pp_s_com_father)->blk_level <= DISK_LEAF_NODE_LEVEL ) {
+    reiserfs_panic(p_s_tb->tb_sb, "PAP-8185: get_far_parent: (%b %z) level too small", *pp_s_com_father, *pp_s_com_father);
+  }
+#endif
+
+  /* Check whether the common parent is locked. */
+#if 0
+  if ( test_and_wait_on_buffer(*pp_s_com_father) == SCHEDULE_OCCURRED ) {
+    decrement_bcount(*pp_s_com_father);
+    return SCHEDULE_OCCURRED; /* schedule() occured */
+  }
+#endif
+
+  /* So, we got common parent of the current node and its left/right neighbor.
+     Now we are geting the parent of the left/right neighbor. */
+
+  /* Form key to get parent of the left/right neighbor. */
+  copy_key(&s_lr_father_key, B_N_PDELIM_KEY(*pp_s_com_father, ( c_lr_par == LEFT_PARENTS ) ?
+     (p_s_tb->lkey[n_h - 1] = n_position - 1) : (p_s_tb->rkey[n_h - 1] = n_position)));
+
+  if ( c_lr_par == LEFT_PARENTS ) {
+      //reiserfs_warning ("decrememnting key %k\n", &s_lr_father_key);
+      decrement_key(&s_lr_father_key);
+      //reiserfs_warning ("done: %k\n", &s_lr_father_key);
+  }
+
+  init_path (&s_path_to_neighbor_father);
+
+  if (search_by_key(p_s_tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father, &n_repeat, n_h + 1) == IO_ERROR)
+    return IO_ERROR;
+
+  if ( n_repeat != CARRY_ON ) {
+      pathrelse (&s_path_to_neighbor_father);
+      //decrement_counters_in_path(&s_path_to_neighbor_father);
+      brelse (*pp_s_com_father);
+      //decrement_bcount(*pp_s_com_father);
+      return n_repeat;
+  }
+
+  *pp_s_father = PATH_PLAST_BUFFER(&s_path_to_neighbor_father);
+
+#ifdef CONFIG_REISERFS_CHECK
+  if ( B_BLK_HEAD(*pp_s_father)->blk_level != n_h + 1 ) {
+    reiserfs_panic(p_s_tb->tb_sb, "PAP-8190: get_far_parent: (%b %z) level too small", *pp_s_father, *pp_s_father);
+  }
+  
+  if ( s_path_to_neighbor_father.path_length < FIRST_PATH_ELEMENT_OFFSET )
+    reiserfs_panic(0, "PAP-8192: get_far_parent: path length is too small");
+
+#endif
+
+  s_path_to_neighbor_father.path_length--;
+  pathrelse (&s_path_to_neighbor_father);
+  //decrement_counters_in_path(&s_path_to_neighbor_father);
+  return CARRY_ON;
+}
+
+
+/* Get parents of neighbors of node in the path(S[n_path_offset]) and common parents of
+ * S[n_path_offset] and L[n_path_offset]/R[n_path_offset]: F[n_path_offset], FL[n_path_offset],
+ * FR[n_path_offset], CFL[n_path_offset], CFR[n_path_offset].
+ * Calculate numbers of left and right delimiting keys position: lkey[n_path_offset], rkey[n_path_offset].
+ * Returns:	SCHEDULE_OCCURRED - schedule occured while the function worked;
+ *	        CARRY_ON - schedule didn't occur while the function worked;
+ */
+static int  get_parents (struct tree_balance * p_s_tb, int n_h)
+{
+    struct path         * p_s_path = p_s_tb->tb_path;
+    int                   n_position,
+	n_ret_value,
+	n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
+    struct buffer_head  * p_s_curf,
+	* p_s_curcf;
+
+    /* Current node is the root of the tree or will be root of the tree */
+    if ( n_path_offset <= FIRST_PATH_ELEMENT_OFFSET ) {
+	/* The root can not have parents.
+	   Release nodes which previously were obtained as parents of the current node neighbors. */
+	brelse(p_s_tb->FL[n_h]);
+	brelse(p_s_tb->CFL[n_h]);
+	brelse(p_s_tb->FR[n_h]);
+	brelse(p_s_tb->CFR[n_h]);
+	//decrement_bcount(p_s_tb->FL[n_h]);
+	//decrement_bcount(p_s_tb->CFL[n_h]);
+	//decrement_bcount(p_s_tb->FR[n_h]);
+	//decrement_bcount(p_s_tb->CFR[n_h]);
+	p_s_tb->FL[n_h] = p_s_tb->CFL[n_h] = p_s_tb->FR[n_h] = p_s_tb->CFR[n_h] = NULL;
+	return CARRY_ON;
+    }
+  
+    /* Get parent FL[n_path_offset] of L[n_path_offset]. */
+    if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1)) )  {
+	/* Current node is not the first child of its parent. */
+	(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2;
+	p_s_tb->lkey[n_h] = n_position - 1;
+    }
+    else  {
+	/* Calculate current parent of L[n_path_offset], which is the left neighbor of the current node.
+	   Calculate current common parent of L[n_path_offset] and the current node. Note that
+	   CFL[n_path_offset] not equal FL[n_path_offset] and CFL[n_path_offset] not equal F[n_path_offset].
+	   Calculate lkey[n_path_offset]. */
+	if ( (n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf,
+					   &p_s_curcf, LEFT_PARENTS)) != CARRY_ON )
+	    return n_ret_value; /*schedule() occured or path is not correct*/
+#ifdef CONFIG_REISERFS_CHECK
+	if (p_s_curf == PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1)) {
+	    reiserfs_panic (p_s_tb->tb_sb, "vs-8194: get_parents: "
+			    "get_far_parent fails");
+	}
+#endif
+
+    }
+
+    brelse(p_s_tb->FL[n_h]);	
+    p_s_tb->FL[n_h] = p_s_curf; /* New initialization of FL[n_h]. */
+ 
+    brelse(p_s_tb->CFL[n_h]);
+    p_s_tb->CFL[n_h] = p_s_curcf; /* New initialization of CFL[n_h]. */
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ((p_s_curf && !B_IS_IN_TREE (p_s_curf)) || (p_s_curcf && !B_IS_IN_TREE (p_s_curcf))) {
+	reiserfs_panic (p_s_tb->tb_sb, "PAP-8195: get_parents: FL (%b) or CFL (%b) is invalid", p_s_curf, p_s_curcf);
+    }
+#endif
+
+/* Get parent FR[n_h] of R[n_h]. */
+
+/* Current node is the last child of F[n_h]. FR[n_h] != F[n_h]. */
+    if ( n_position == B_BLK_HEAD(PATH_H_PBUFFER(p_s_path, n_h + 1))->blk_nr_item ) {
+/* Calculate current parent of R[n_h], which is the right neighbor of F[n_h].
+   Calculate current common parent of R[n_h] and current node. Note that CFR[n_h]
+   not equal FR[n_path_offset] and CFR[n_h] not equal F[n_h]. */
+	if ( (n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf,  &p_s_curcf, RIGHT_PARENTS)) != CARRY_ON )
+	    return n_ret_value; /*schedule() occured while get_far_parent() worked.*/
+    }
+    else {
+/* Current node is not the last child of its parent F[n_h]. */
+	(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2;
+	p_s_tb->rkey[n_h] = n_position;
+    }	
+
+    brelse/*decrement_bcount*/(p_s_tb->FR[n_h]);
+    p_s_tb->FR[n_h] = p_s_curf; /* New initialization of FR[n_path_offset]. */
+
+    brelse/*decrement_bcount*/(p_s_tb->CFR[n_h]);
+    p_s_tb->CFR[n_h] = p_s_curcf; /* New initialization of CFR[n_path_offset]. */
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ((p_s_curf && !B_IS_IN_TREE (p_s_curf)) || (p_s_curcf && !B_IS_IN_TREE (p_s_curcf))) {
+	reiserfs_panic (p_s_tb->tb_sb, "PAP-8205: get_parents: FR (%b) or CFR (%b) is invalid", p_s_curf, p_s_curcf);
+    }
+#endif
+
+    return CARRY_ON; /* schedule not occured while get_parents() worked. */
+}
+
+
+/* it is possible to remove node as result of shiftings to
+   neighbors even when we insert or paste item. */
+static inline int can_node_be_removed (int mode, int lfree, int sfree, int rfree, struct tree_balance * tb, int h)
+{
+    struct buffer_head * Sh = PATH_H_PBUFFER (tb->tb_path, h);
+    int levbytes = tb->insert_size[h];
+    struct item_head * ih;
+    struct item_head * r_ih = NULL;
+  
+    ih = B_N_PITEM_HEAD (Sh, 0);
+    if ( tb->CFR[h] )
+	r_ih = (struct item_head *)B_N_PDELIM_KEY(tb->CFR[h],tb->rkey[h]);
+  
+    if (
+	lfree + rfree + sfree < MAX_CHILD_SIZE(Sh) + levbytes
+	/* shifting may merge items which might save space */
+#ifndef FU //REISERFS_FSCK
+	- (( ! h && is_left_mergeable (tb->tb_sb, tb->tb_path) == 1 ) ? IH_SIZE : 0)
+	- (( ! h && r_ih && is_right_mergeable (tb->tb_sb, tb->tb_path) == 1 ) ? IH_SIZE : 0)
+#else
+	- (( ! h && is_left_mergeable (ih, Sh->b_size) ) ? IH_SIZE : 0)
+	- (( ! h && r_ih && is_left_mergeable (r_ih, Sh->b_size) ) ? IH_SIZE : 0)
+#endif
+	+ (( h ) ? KEY_SIZE : 0))
+    {
+	/* node can not be removed */
+	if (sfree >= levbytes ) /* new item fits into node S[h] without any shifting */
+	{
+	    if ( ! h )
+		tb->s0num = B_NR_ITEMS(Sh) + ((mode == M_INSERT ) ? 1 : 0);
+	    set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
+	    return NO_BALANCING_NEEDED;
+	}
+    }
+    return !NO_BALANCING_NEEDED;
+}
+
+
+
+/* Check whether current node S[h] is balanced when increasing its size by
+ * Inserting or Pasting.
+ * Calculate parameters for balancing for current level h.
+ * Parameters:
+ *	tb	tree_balance structure;
+ *	h	current level of the node;
+ *	inum	item number in S[h];
+ *	mode	i - insert, p - paste;
+ * Returns:	1 - schedule occured; 
+ *	        0 - balancing for higher levels needed;
+ *	       -1 - no balancing for higher levels needed;
+ *	       -2 - no disk space.
+ */
+/* ip means Inserting or Pasting */
+static int ip_check_balance (/*struct reiserfs_transaction_handle *th,*/ struct tree_balance * tb, int h)
+{
+  struct virtual_node * vn = tb->tb_vn;
+  int levbytes,  /* Number of bytes that must be inserted into (value
+		    is negative if bytes are deleted) buffer which
+		    contains node being balanced.  The mnemonic is
+		    that the attempted change in node space used level
+		    is levbytes bytes. */
+    n_ret_value;
+
+  int lfree, sfree, rfree /* free space in L, S and R */;
+
+  /* nver is short for number of vertixes, and lnver is the number if
+     we shift to the left, rnver is the number if we shift to the
+     right, and lrnver is the number if we shift in both directions.
+     The goal is to minimize first the number of vertixes, and second,
+     the number of vertixes whose contents are changed by shifting,
+     and third the number of uncached vertixes whose contents are
+     changed by shifting and must be read from disk.  */
+  int nver, lnver, rnver, lrnver;
+
+  /* used at leaf level only, S0 = S[0] is the node being balanced,
+     sInum [ I = 0,1,2 ] is the number of items that will
+     remain in node SI after balancing.  S1 and S2 are new
+     nodes that might be created. */
+  
+  /* we perform 8 calls to get_num_ver().  For each call we calculate five parameters.
+     where 4th parameter is s1bytes and 5th - s2bytes
+  */
+  short snum012[40] = {0,};	/* s0num, s1num, s2num for 8 cases 
+				   0,1 - do not shift and do not shift but bottle
+				   2 - shift only whole item to left
+				   3 - shift to left and bottle as much as possible
+				   4,5 - shift to right	(whole items and as much as possible
+				   6,7 - shift to both directions (whole items and as much as possible)
+				   */
+
+  /* Sh is the node whose balance is currently being checked */
+  struct buffer_head * Sh;
+  
+#ifndef FU //REISERFS_FSCK
+  /* special mode for insert pointer to the most low internal node */
+  if (h == 0 && vn->vn_mode == M_INTERNAL) {
+    /* blk_num == 2 is to get pointer inserted to the next level */
+    set_parameters (tb, h, 0, 0, 2, NULL, -1, -1);
+    return 0;
+  }
+#endif
+
+  Sh = PATH_H_PBUFFER (tb->tb_path, h);
+  levbytes = tb->insert_size[h];
+  
+     /* Calculate balance parameters for creating new root. */
+  if ( ! Sh )  {
+    if ( ! h )
+      reiserfs_panic ("vs-8210: ip_check_balance: S[0] can not be 0");
+    switch ( n_ret_value = get_empty_nodes (tb, h) )  {
+    case CARRY_ON:
+      set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
+      return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */
+
+    case NO_DISK_SPACE:
+    case SCHEDULE_OCCURRED:
+      return n_ret_value;
+    default:   
+      reiserfs_panic("vs-8215: ip_check_balance: incorrect return value of get_empty_nodes");
+    }
+  }
+  
+  if ( (n_ret_value = get_parents (tb, h)) != CARRY_ON ) /* get parents of S[h] neighbors. */
+    return n_ret_value;
+  
+     sfree = B_BLK_HEAD(Sh)->blk_free_space;
+
+     /* get free space of neighbors */
+     rfree = get_rfree (tb, h);
+     lfree = get_lfree (tb, h);
+
+     if (can_node_be_removed (vn->vn_mode, lfree, sfree, rfree, tb, h) == NO_BALANCING_NEEDED)
+       /* and new item fits into node S[h] without any shifting */
+       return NO_BALANCING_NEEDED;
+     
+     create_virtual_node (tb, h);
+
+     /*	
+	determine maximal number of items we can shift to the left neighbor (in tb structure)
+	and the maximal number of bytes that can flow to the left neighbor
+	from the left most liquid item that cannot be shifted from S[0] entirely (returned value)
+	*/
+     check_left (tb, h, lfree);
+
+     /*
+        determine maximal number of items we can shift to the right neighbor (in tb structure)
+	and the maximal number of bytes that can flow to the right neighbor
+	from the right most liquid item that cannot be shifted from S[0] entirely (returned value)
+	*/
+     check_right (tb, h, rfree);
+
+
+     /* all contents of internal node S[h] can be moved into its
+        neighbors, S[h] will be removed after balancing */
+     if (h && (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)) {
+       int to_r; 
+       
+       /* Since we are working on internal nodes, and our internal
+	  nodes have fixed size entries, then we can balance by the
+	  number of items rather than the space they consume.  In this
+	  routine we set the left node equal to the right node,
+	  allowing a difference of less than or equal to 1 child
+	  pointer. */
+       to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 - 
+	 (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]);
+       set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1);
+       return CARRY_ON;
+     }
+
+#ifdef CONFIG_REISERFS_CHECK
+     /* this checks balance condition, that any two neighboring nodes can not fit in one node */
+     if ( h && ( tb->lnum[h] >= vn->vn_nr_item + 1 || tb->rnum[h] >= vn->vn_nr_item + 1) )
+       reiserfs_panic (tb->tb_sb, "vs-8220: ip_check_balance: tree is not balanced on internal level");
+
+     if ( ! h && ((tb->lnum[h] >= vn->vn_nr_item && (tb->lbytes == -1)) ||
+		  (tb->rnum[h] >= vn->vn_nr_item && (tb->rbytes == -1)) ))
+       reiserfs_panic(tb->tb_sb, "vs-8225: ip_check_balance: tree is not balanced on leaf level");
+#endif
+
+     /* all contents of S[0] can be moved into its neighbors
+	S[0] will be removed after balancing. */
+     if (!h && is_leaf_removable (tb))
+       return CARRY_ON;
+
+
+     /* why do we perform this check here rather than earlier??
+        Answer: we can win 1 node in some cases above. Moreover we
+        checked it above, when we checked, that S[0] is not removable
+        in principle */
+     if (sfree >= levbytes) { /* new item fits into node S[h] without any shifting */
+       if ( ! h )
+	 tb->s0num = vn->vn_nr_item;
+       set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
+       return NO_BALANCING_NEEDED;
+     }
+
+
+     {
+       int lpar, rpar, nset, lset, rset, lrset;
+     /* 
+      * regular overflowing of the node
+      */
+
+     /* get_num_ver works in 2 modes (FLOW & NO_FLOW) 
+	lpar, rpar - number of items we can shift to left/right neighbor (including splitting item)
+	nset, lset, rset, lrset - shows, whether flowing items give better packing 
+	*/
+#define FLOW 1
+#define NO_FLOW 0	/* do not any splitting */
+
+     /* we choose one the following */
+#define NOTHING_SHIFT_NO_FLOW	0
+#define NOTHING_SHIFT_FLOW	5
+#define LEFT_SHIFT_NO_FLOW	10
+#define LEFT_SHIFT_FLOW		15
+#define RIGHT_SHIFT_NO_FLOW	20
+#define RIGHT_SHIFT_FLOW	25
+#define LR_SHIFT_NO_FLOW	30
+#define LR_SHIFT_FLOW		35
+
+
+       lpar = tb->lnum[h];
+       rpar = tb->rnum[h];
+
+
+     /* calculate number of blocks S[h] must be split into when
+	nothing is shifted to the neighbors,
+	as well as number of items in each part of the split node (s012 numbers),
+	and number of bytes (s1bytes) of the shared drop which flow to S1 if any */
+     nset = NOTHING_SHIFT_NO_FLOW;
+     nver = get_num_ver (vn->vn_mode, tb, h,
+			 0, -1, h?vn->vn_nr_item:0, -1, 
+			 snum012, NO_FLOW);
+
+     if (!h)
+       {
+	 int nver1;
+
+	 /* note, that in this case we try to bottle between S[0] and S1 (S1 - the first new node) */
+	 nver1 = get_num_ver (vn->vn_mode, tb, h, 
+			      0, -1, 0, -1, 
+			      snum012 + NOTHING_SHIFT_FLOW, FLOW);
+	 if (nver > nver1)
+	   nset = NOTHING_SHIFT_FLOW, nver = nver1;
+       }
+       
+ 
+     /* calculate number of blocks S[h] must be split into when
+	l_shift_num first items and l_shift_bytes of the right most
+	liquid item to be shifted are shifted to the left neighbor,
+	as well as number of items in each part of the splitted node (s012 numbers),
+	and number of bytes (s1bytes) of the shared drop which flow to S1 if any
+	*/
+     lset = LEFT_SHIFT_NO_FLOW;
+     lnver = get_num_ver (vn->vn_mode, tb, h, 
+			  lpar - (( h || tb->lbytes == -1 ) ? 0 : 1), -1, h ? vn->vn_nr_item:0, -1,
+			  snum012 + LEFT_SHIFT_NO_FLOW, NO_FLOW);
+     if (!h)
+       {
+	 int lnver1;
+
+	 lnver1 = get_num_ver (vn->vn_mode, tb, h, 
+			       lpar - ((tb->lbytes != -1) ? 1 : 0), tb->lbytes, 0, -1,
+			       snum012 + LEFT_SHIFT_FLOW, FLOW);
+	 if (lnver > lnver1)
+	   lset = LEFT_SHIFT_FLOW, lnver = lnver1;
+       }
+
+
+     /* calculate number of blocks S[h] must be split into when
+	r_shift_num first items and r_shift_bytes of the left most
+	liquid item to be shifted are shifted to the right neighbor,
+	as well as number of items in each part of the splitted node (s012 numbers),
+	and number of bytes (s1bytes) of the shared drop which flow to S1 if any
+	*/
+     rset = RIGHT_SHIFT_NO_FLOW;
+     rnver = get_num_ver (vn->vn_mode, tb, h, 
+			  0, -1, h ? (vn->vn_nr_item-rpar) : (rpar - (( tb->rbytes != -1 ) ? 1 : 0)), -1, 
+			  snum012 + RIGHT_SHIFT_NO_FLOW, NO_FLOW);
+     if (!h)
+       {
+	 int rnver1;
+
+	 rnver1 = get_num_ver (vn->vn_mode, tb, h, 
+			       0, -1, (rpar - ((tb->rbytes != -1) ? 1 : 0)), tb->rbytes, 
+			       snum012 + RIGHT_SHIFT_FLOW, FLOW);
+
+	 if (rnver > rnver1)
+	   rset = RIGHT_SHIFT_FLOW, rnver = rnver1;
+       }
+
+
+     /* calculate number of blocks S[h] must be split into when
+	items are shifted in both directions,
+	as well as number of items in each part of the splitted node (s012 numbers),
+	and number of bytes (s1bytes) of the shared drop which flow to S1 if any
+	*/
+     lrset = LR_SHIFT_NO_FLOW;
+     lrnver = get_num_ver (vn->vn_mode, tb, h, 
+			   lpar - ((h || tb->lbytes == -1) ? 0 : 1), -1, h ? (vn->vn_nr_item-rpar):(rpar - ((tb->rbytes != -1) ? 1 : 0)), -1,
+			   snum012 + LR_SHIFT_NO_FLOW, NO_FLOW);
+     if (!h)
+       {
+	 int lrnver1;
+
+	 lrnver1 = get_num_ver (vn->vn_mode, tb, h, 
+				lpar - ((tb->lbytes != -1) ? 1 : 0), tb->lbytes, (rpar - ((tb->rbytes != -1) ? 1 : 0)), tb->rbytes,
+				snum012 + LR_SHIFT_FLOW, FLOW);
+	 if (lrnver > lrnver1)
+	   lrset = LR_SHIFT_FLOW, lrnver = lrnver1;
+       }
+
+
+
+     /* Our general shifting strategy is:
+	1) to minimized number of new nodes;
+	2) to minimized number of neighbors involved in shifting;
+	3) to minimized number of disk reads; */
+
+     /* we can win TWO or ONE nodes by shifting in both directions */
+     if (lrnver < lnver && lrnver < rnver)
+       {
+#ifdef CONFIG_REISERFS_CHECK
+	 if (h && (tb->lnum[h] != 1 || tb->rnum[h] != 1 || lrnver != 1 || rnver != 2 || lnver != 2 || h != 1))
+	   reiserfs_panic (0, "vs-8230: check_balance: bad h");
+#endif
+	 if (lrset == LR_SHIFT_FLOW)
+	   set_parameters (tb, h, tb->lnum[h], tb->rnum[h], lrnver, snum012 + lrset,
+			   tb->lbytes, tb->rbytes);
+	 else
+ 	   set_parameters (tb, h, tb->lnum[h] - ((tb->lbytes == -1) ? 0 : 1), 
+			   tb->rnum[h] - ((tb->rbytes == -1) ? 0 : 1), lrnver, snum012 + lrset, -1, -1);
+
+	 return CARRY_ON;
+       }
+
+     /* if shifting doesn't lead to better packing then don't shift */
+     if (nver == lrnver)
+       {
+	 set_parameters (tb, h, 0, 0, nver, snum012 + nset, -1, -1);
+	 return CARRY_ON;
+       }
+
+
+     /* now we know that for better packing shifting in only one
+	direction either to the left or to the right is required */
+
+     /*  if shifting to the left is better than shifting to the right */
+     if (lnver < rnver)
+       {
+	 SET_PAR_SHIFT_LEFT;
+	 return CARRY_ON;
+       }
+
+     /* if shifting to the right is better than shifting to the left */
+     if (lnver > rnver)
+       {
+	 SET_PAR_SHIFT_RIGHT;
+	 return CARRY_ON;
+       }
+
+
+     /* now shifting in either direction gives the same number
+	of nodes and we can make use of the cached neighbors */
+     if (is_left_neighbor_in_cache (tb,h))
+       {
+	 SET_PAR_SHIFT_LEFT;
+	 return CARRY_ON;
+       }
+
+     /* shift to the right independently on whether the right neighbor in cache or not */
+     SET_PAR_SHIFT_RIGHT;
+     return CARRY_ON;
+     }
+}
+
+
+/* Check whether current node S[h] is balanced when Decreasing its size by
+ * Deleting or Cutting for INTERNAL node of S+tree.
+ * Calculate parameters for balancing for current level h.
+ * Parameters:
+ *	tb	tree_balance structure;
+ *	h	current level of the node;
+ *	inum	item number in S[h];
+ *	mode	i - insert, p - paste;
+ * Returns:	1 - schedule occured; 
+ *	        0 - balancing for higher levels needed;
+ *	       -1 - no balancing for higher levels needed;
+ *	       -2 - no disk space.
+ *
+ * Note: Items of internal nodes have fixed size, so the balance condition for
+ * the internal part of S+tree is as for the B-trees.
+ */
+static int dc_check_balance_internal (struct tree_balance * tb, int h)
+{
+  struct virtual_node * vn = tb->tb_vn;
+
+  /* Sh is the node whose balance is currently being checked,
+     and Fh is its father.  */
+  struct buffer_head * Sh, * Fh;
+  int maxsize,
+      n_ret_value;
+  int lfree, rfree /* free space in L and R */;
+
+  Sh = PATH_H_PBUFFER (tb->tb_path, h); 
+  Fh = PATH_H_PPARENT (tb->tb_path, h); 
+
+  maxsize = MAX_CHILD_SIZE(Sh); 
+
+/*   using tb->insert_size[h], which is negative in this case, create_virtual_node calculates: */
+/*   new_nr_item = number of items node would have if operation is */
+/* 	performed without balancing (new_nr_item); */
+  create_virtual_node (tb, h);
+
+  if ( ! Fh )
+    {   /* S[h] is the root. */
+      if ( vn->vn_nr_item > 0 )
+	{
+	  set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
+	  return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */
+	}
+      /* new_nr_item == 0.
+       * Current root will be deleted resulting in
+       * decrementing the tree height. */
+      set_parameters (tb, h, 0, 0, 0, NULL, -1, -1);
+      return CARRY_ON;
+    }
+
+  if ( (n_ret_value = get_parents(tb,h)) != CARRY_ON )
+    return n_ret_value;
+
+
+  /* get free space of neighbors */
+  rfree = get_rfree (tb, h);
+  lfree = get_lfree (tb, h);
+		
+  /* determine maximal number of items we can fit into neighbors */
+  check_left (tb, h, lfree);
+  check_right (tb, h, rfree);
+
+
+  if ( vn->vn_nr_item >= MIN_NR_KEY(Sh) )
+    { /* Balance condition for the internal node is valid.
+       * In this case we balance only if it leads to better packing. */ 
+      if ( vn->vn_nr_item == MIN_NR_KEY(Sh) )
+	{ /* Here we join S[h] with one of its neighbors,
+	   * which is impossible with greater values of new_nr_item. */
+	  if ( tb->lnum[h] >= vn->vn_nr_item + 1 )
+	    {
+	      /* All contents of S[h] can be moved to L[h]. */
+	      int n;
+	      int order_L;
+	      
+	      order_L = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==0) ? B_NR_ITEMS(tb->FL[h]) : n - 1;
+	      n = B_N_CHILD(tb->FL[h],order_L)->dc_size / (DC_SIZE + KEY_SIZE);
+	      set_parameters (tb, h, -n-1, 0, 0, NULL, -1, -1);
+	      return CARRY_ON;
+	    }
+
+	  if ( tb->rnum[h] >= vn->vn_nr_item + 1 )
+	    {
+	      /* All contents of S[h] can be moved to R[h]. */
+	      int n;
+	      int order_R;
+	    
+	      order_R = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==B_NR_ITEMS(Fh)) ? 0 : n + 1;
+	      n = B_N_CHILD(tb->FR[h],order_R)->dc_size / (DC_SIZE + KEY_SIZE);
+	      set_parameters (tb, h, 0, -n-1, 0, NULL, -1, -1);
+	      return CARRY_ON;   
+	    }
+	}
+
+      if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)
+	{
+	  /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */
+	  int to_r;
+
+	  to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 - 
+	    (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]);
+	  set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1);
+	  return CARRY_ON;
+	}
+
+      /* Balancing does not lead to better packing. */
+      set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
+      return NO_BALANCING_NEEDED;
+    }
+
+  /* Current node contain insufficient number of items. Balancing is required. */	
+  /* Check whether we can merge S[h] with left neighbor. */
+  if (tb->lnum[h] >= vn->vn_nr_item + 1)
+    if (is_left_neighbor_in_cache (tb,h) || tb->rnum[h] < vn->vn_nr_item + 1 || !tb->FR[h])
+      {
+	int n;
+	int order_L;
+	      
+	order_L = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==0) ? B_NR_ITEMS(tb->FL[h]) : n - 1;
+	n = B_N_CHILD(tb->FL[h],order_L)->dc_size / (DC_SIZE + KEY_SIZE);
+	set_parameters (tb, h, -n-1, 0, 0, NULL, -1, -1);
+	return CARRY_ON;
+      }
+
+  /* Check whether we can merge S[h] with right neighbor. */
+  if (tb->rnum[h] >= vn->vn_nr_item + 1)
+    {
+      int n;
+      int order_R;
+	    
+      order_R = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==B_NR_ITEMS(Fh)) ? 0 : (n + 1);
+      n = B_N_CHILD(tb->FR[h],order_R)->dc_size / (DC_SIZE + KEY_SIZE);
+      set_parameters (tb, h, 0, -n-1, 0, NULL, -1, -1);
+      return CARRY_ON;   
+    }
+
+  /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */
+  if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)
+    {
+      int to_r;
+	    
+      to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 - 
+	(MAX_NR_KEY(Sh) + 1 - tb->rnum[h]);
+      set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1);
+      return CARRY_ON;
+    }
+
+  /* For internal nodes try to borrow item from a neighbor */
+#ifdef CONFIG_REISERFS_CHECK
+  if (!tb->FL[h] && !tb->FR[h])
+    reiserfs_panic (0, "vs-8235: dc_check_balance_internal: trying to borrow for root");
+#endif
+
+  /* Borrow one or two items from caching neighbor */
+  if (is_left_neighbor_in_cache (tb,h) || !tb->FR[h])
+    {
+      int from_l;
+		
+      from_l = (MAX_NR_KEY(Sh) + 1 - tb->lnum[h] + vn->vn_nr_item + 1) / 2 -  (vn->vn_nr_item + 1);
+      set_parameters (tb, h, -from_l, 0, 1, NULL, -1, -1);
+      return CARRY_ON;
+    }
+
+  set_parameters (tb, h, 0, -((MAX_NR_KEY(Sh)+1-tb->rnum[h]+vn->vn_nr_item+1)/2-(vn->vn_nr_item+1)), 1, 
+		  NULL, -1, -1);
+  return CARRY_ON;
+}
+
+
+/* Check whether current node S[h] is balanced when Decreasing its size by
+ * Deleting or Truncating for LEAF node of S+tree.
+ * Calculate parameters for balancing for current level h.
+ * Parameters:
+ *	tb	tree_balance structure;
+ *	h	current level of the node;
+ *	inum	item number in S[h];
+ *	mode	i - insert, p - paste;
+ * Returns:	1 - schedule occured; 
+ *	        0 - balancing for higher levels needed;
+ *	       -1 - no balancing for higher levels needed;
+ *	       -2 - no disk space.
+ */
+static int dc_check_balance_leaf (struct tree_balance * tb, int h)
+{
+  struct virtual_node * vn = tb->tb_vn;
+
+  /* Number of bytes that must be deleted from
+     (value is negative if bytes are deleted) buffer which
+     contains node being balanced.  The mnemonic is that the
+     attempted change in node space used level is levbytes bytes. */
+  int levbytes;
+  /* the maximal item size */
+  int maxsize,
+      n_ret_value;
+  /* S0 is the node whose balance is currently being checked,
+     and F0 is its father.  */
+  struct buffer_head * S0, * F0;
+  int lfree, rfree /* free space in L and R */;
+
+  S0 = PATH_H_PBUFFER (tb->tb_path, 0);
+  F0 = PATH_H_PPARENT (tb->tb_path, 0);
+
+  levbytes = tb->insert_size[h];
+
+  maxsize = MAX_CHILD_SIZE(S0); 	/* maximal possible size of an item */
+
+  if ( ! F0 )
+    {  /* S[0] is the root now. */
+
+#ifdef CONFIG_REISERFS_CHECK
+      if ( -levbytes >= maxsize - B_BLK_HEAD(S0)->blk_free_space )
+	reiserfs_panic (tb->tb_sb, "vs-8240: dc_check_balance_leaf: attempt to create empty buffer tree");
+#endif
+
+      set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
+      return NO_BALANCING_NEEDED;
+    }
+
+  if ( (n_ret_value = get_parents(tb,h)) != CARRY_ON )
+    return n_ret_value;
+
+  /* get free space of neighbors */
+  rfree = get_rfree (tb, h);
+  lfree = get_lfree (tb, h);		
+
+  create_virtual_node (tb, h);
+
+  /* if 3 leaves can be merge to one, set parameters and return */
+  if (are_leaves_removable (tb, lfree, rfree))
+    return CARRY_ON;
+
+  /* determine maximal number of items we can shift to the left/right  neighbor
+     and the maximal number of bytes that can flow to the left/right neighbor
+     from the left/right most liquid item that cannot be shifted from S[0] entirely
+     */
+  check_left (tb, h, lfree);
+  check_right (tb, h, rfree);   
+
+  /* check whether we can merge S with left neighbor. */
+  if (tb->lnum[0] >= vn->vn_nr_item && tb->lbytes == -1)
+    if (is_left_neighbor_in_cache (tb,h) ||
+	((tb->rnum[0] - ((tb->rbytes == -1) ? 0 : 1)) < vn->vn_nr_item) || /* S can not be merged with R */
+	!tb->FR[h]) {
+      
+#ifdef CONFIG_REISERFS_CHECK
+      if (!tb->FL[h])
+	reiserfs_panic (0, "vs-8245: dc_check_balance_leaf: FL[h] must exist");
+#endif
+
+      /* set parameter to merge S[0] with its left neighbor */
+      set_parameters (tb, h, -1, 0, 0, NULL, -1, -1);
+      return CARRY_ON;
+    }
+
+  /* check whether we can merge S[0] with right neighbor. */
+  if (tb->rnum[0] >= vn->vn_nr_item && tb->rbytes == -1) {
+    set_parameters (tb, h, 0, -1, 0, NULL, -1, -1);
+    return CARRY_ON;
+  }
+  
+  /* All contents of S[0] can be moved to the neighbors (L[0] & R[0]). Set parameters and return */
+  if (is_leaf_removable (tb))
+    return CARRY_ON;
+  
+  /* Balancing is not required. */
+  tb->s0num = vn->vn_nr_item;
+  set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
+  return NO_BALANCING_NEEDED;
+}
+
+
+
+/* Check whether current node S[h] is balanced when Decreasing its size by
+ * Deleting or Cutting.
+ * Calculate parameters for balancing for current level h.
+ * Parameters:
+ *	tb	tree_balance structure;
+ *	h	current level of the node;
+ *	inum	item number in S[h];
+ *	mode	d - delete, c - cut.
+ * Returns:	1 - schedule occured; 
+ *	        0 - balancing for higher levels needed;
+ *	       -1 - no balancing for higher levels needed;
+ *	       -2 - no disk space.
+ */
+static int dc_check_balance (struct tree_balance * tb, int h)
+{
+
+#ifdef CONFIG_REISERFS_CHECK
+ if ( ! (PATH_H_PBUFFER (tb->tb_path, h)) )
+   reiserfs_panic(tb->tb_sb, "vs-8250: dc_check_balance: S is not initialized");
+#endif
+
+ if ( h )
+   return dc_check_balance_internal (tb, h);
+ else
+   return dc_check_balance_leaf (tb, h);
+}
+
+
+
+/* Check whether current node S[h] is balanced.
+ * Calculate parameters for balancing for current level h.
+ * Parameters:
+ *
+ *	tb	tree_balance structure:
+ *
+ *              tb is a large structure that must be read about in the header file
+ *              at the same time as this procedure if the reader is to successfully
+ *              understand this procedure
+ *
+ *	h	current level of the node;
+ *	inum	item number in S[h];
+ *	mode	i - insert, p - paste, d - delete, c - cut.
+ * Returns:	1 - schedule occured; 
+ *	        0 - balancing for higher levels needed;
+ *	       -1 - no balancing for higher levels needed;
+ *	       -2 - no disk space.
+ */
+static int check_balance (int mode, struct tree_balance * tb,
+			  int h, int inum, int pos_in_item,
+			  struct item_head * ins_ih)
+{
+    struct virtual_node * vn;
+    
+    vn = tb->tb_vn = (struct virtual_node *)(tb->vn_buf);// + ROUND_UP(SB_BMAP_NR (tb->tb_sb) * 2 / 8 + 1, 4));
+    vn->vn_free_ptr = (char *)(tb->tb_vn + 1);
+    vn->vn_mode = mode;
+    vn->vn_affected_item_num = inum;
+    vn->vn_pos_in_item = pos_in_item;
+    vn->vn_ins_ih = ins_ih;
+    
+#ifdef CONFIG_REISERFS_CHECK
+    if (mode == M_INSERT && !vn->vn_ins_ih)
+	reiserfs_panic (0, "vs-8255: check_balance: ins_ih can not be 0 in insert mode");
+#endif
+
+    if ( tb->insert_size[h] > 0 )
+	/* Calculate balance parameters when size of node is increasing. */
+	return ip_check_balance (tb, h);
+    
+    /* Calculate balance parameters when  size of node is decreasing. */
+    return dc_check_balance (tb, h);
+}
+
+
+
+/* Check whether parent at the path is the really parent of the current node.*/
+static int  get_direct_parent(
+              struct tree_balance * p_s_tb,
+              int                   n_h
+            ) {
+  struct buffer_head  * p_s_bh;
+  struct path         * p_s_path      = p_s_tb->tb_path;
+  int                   n_position,
+    			n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
+
+  /* We are in the root or in the new root. */
+  if ( n_path_offset <= FIRST_PATH_ELEMENT_OFFSET ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET - 1 )
+      reiserfs_panic(p_s_tb->tb_sb, "PAP-8260: get_direct_parent: illegal offset in the path");
+#endif
+
+    if ( PATH_OFFSET_PBUFFER(p_s_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
+                                      SB_ROOT_BLOCK (p_s_tb->tb_sb) ) {
+      /* Root is not changed. */
+      PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1) = NULL;
+	    PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1) = 0;
+      return CARRY_ON;
+    }
+    return PATH_INCORRECT; /* Root is changed and we must recalculate the path. */
+  }
+
+  if ( ! B_IS_IN_TREE(p_s_bh = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1)) )
+    return PATH_INCORRECT; /* Parent in the path is not in the tree. */
+
+  if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1)) > B_NR_ITEMS(p_s_bh) )
+    return PATH_INCORRECT;
+
+  if ( B_N_CHILD_NUM(p_s_bh, n_position) != PATH_OFFSET_PBUFFER(p_s_path, n_path_offset)->b_blocknr )
+     /* Parent in the path is not parent of the current node in the tree. */
+    return PATH_INCORRECT;
+
+#if 0
+  if ( test_and_wait_on_buffer(p_s_bh) == SCHEDULE_OCCURRED ) /* Buffer was locked. */
+    return SCHEDULE_OCCURRED;
+#endif
+  return CARRY_ON; /* Parent in the path is unlocked and really parent of the current node.  */
+}
+
+
+/* Using lnum[n_h] and rnum[n_h] we should determine what neighbors
+ * of S[n_h] we
+ * need in order to balance S[n_h], and get them if necessary.
+ * Returns:	SCHEDULE_OCCURRED - schedule occured while the function worked;
+ *	        CARRY_ON - schedule didn't occur while the function worked;
+ */
+static int get_neighbors(struct tree_balance * p_s_tb, int n_h)
+{
+    int		 	n_child_position,
+	n_repeat,
+	n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h + 1);
+    unsigned long		n_son_number;
+    struct super_block  *	p_s_sb = p_s_tb->tb_sb;
+    struct buffer_head  * p_s_bh;
+    /*struct virtual_node * vn = p_s_tb->tb_vn;*/
+    
+    if ( p_s_tb->lnum[n_h] ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+	if ( ! p_s_tb->lnum[n_h] && vn->vn_mode == M_CUT &&
+	     ! (vn->vn_vi[0].vi_type & VI_TYPE_DIRECTORY) )
+	    reiserfs_panic (p_s_tb->tb_sb, "PAP-8265: get_neighbors: item must be directory item");
+#endif
+
+	/* We need left neighbor to balance S[n_h]. */
+	p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
+	
+#ifdef CONFIG_REISERFS_CHECK
+	if ( p_s_bh == p_s_tb->FL[n_h] && ! PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset) )
+	    reiserfs_panic (p_s_tb->tb_sb, "PAP-8270: get_neighbors: invalid position in the parent");
+#endif
+	
+	n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_BLK_HEAD(p_s_tb->FL[n_h])->blk_nr_item;
+	n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position);
+	n_repeat = CARRY_ON;
+	p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize, &n_repeat);
+	if (!p_s_bh)
+	    return IO_ERROR;
+	if ( n_repeat != CARRY_ON ) {
+	    brelse /*decrement_bcount*/(p_s_bh);
+	    return SCHEDULE_OCCURRED;
+	}
+
+#ifdef CONFIG_REISERFS_CHECK
+	if ( ! B_IS_IN_TREE(p_s_tb->FL[n_h]) || n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) ||
+	     B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) != p_s_bh->b_blocknr )
+	    reiserfs_panic (p_s_tb->tb_sb, "PAP-8275: get_neighbors: invalid parent");
+	if ( ! B_IS_IN_TREE(p_s_bh) )
+	    reiserfs_panic (p_s_tb->tb_sb, "PAP-8280: get_neighbors: invalid child");
+	
+	if (! n_h && node_free_space (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - B_N_CHILD (p_s_tb->FL[0],n_child_position)->dc_size) {
+	    reiserfs_panic (p_s_tb->tb_sb, "PAP-8290: get_neighbors: invalid child size of left neighbor");
+	}
+#endif
+	
+	brelse /*decrement_bcount*/(p_s_tb->L[n_h]);
+	p_s_tb->L[n_h] = p_s_bh;
+    }
+
+    if ( p_s_tb->rnum[n_h] ) { /* We need right neighbor to balance S[n_path_offset]. */
+	p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
+
+#ifdef CONFIG_REISERFS_CHECK
+	if ( p_s_bh == p_s_tb->FR[n_h] && PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset) >= B_NR_ITEMS(p_s_bh) )
+	    reiserfs_panic (p_s_tb->tb_sb, "PAP-8295: get_neighbors: invalid position in the parent");
+#endif
+
+	n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0;
+	n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position);
+	n_repeat = CARRY_ON;
+	p_s_bh = reiserfs_bread(p_s_sb->s_dev, n_son_number, p_s_sb->s_blocksize, &n_repeat);
+	if (!p_s_bh)
+	    return IO_ERROR;
+	if ( n_repeat != CARRY_ON ) {
+	    brelse/*decrement_bcount*/(p_s_bh);
+	    return SCHEDULE_OCCURRED;
+	}
+	brelse/*decrement_bcount*/(p_s_tb->R[n_h]);
+	p_s_tb->R[n_h] = p_s_bh;
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (! n_h && node_free_space (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - B_N_CHILD (p_s_tb->FR[0],n_child_position)->dc_size) {
+	    reiserfs_panic (p_s_tb->tb_sb, "PAP-8300: get_neighbors: invalid child size of right neighbor (%d != %d - %d)",
+			    node_free_space (p_s_bh), MAX_CHILD_SIZE (p_s_bh), B_N_CHILD (p_s_tb->FR[0],n_child_position)->dc_size);
+	}
+#endif
+
+    }
+    return CARRY_ON;
+}
+
+
+void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s)
+{
+  void * vp;
+
+  vp = getmem (size);
+  return vp;
+}
+
+void reiserfs_kfree (/*const */void * vp, size_t size, struct super_block * s)
+{
+  freemem (vp);
+#if 0
+
+  kfree (vp);
+  
+  s->u.reiserfs_sb.s_kmallocs -= size;
+  if (s->u.reiserfs_sb.s_kmallocs < 0)
+    reiserfs_warning ("vs-8302: reiserfs_kfree: allocated memory %d\n", s->u.reiserfs_sb.s_kmallocs);
+#endif
+}
+
+
+static int get_virtual_node_size (struct super_block * sb, struct buffer_head * bh)
+{
+  //int size = sizeof (struct virtual_item); /* for new item in case of insert */
+  //int i, nr_items;
+  //struct item_head * ih;
+
+  return sb->s_blocksize;
+
+#if 0
+  size = sizeof (struct virtual_node) + sizeof (struct virtual_item);
+  ih = B_N_PITEM_HEAD (bh, 0);
+  nr_items = B_NR_ITEMS (bh);
+  for (i = 0; i < nr_items; i ++, ih ++) {
+    /* each item occupies some space in virtual node */
+    size += sizeof (struct virtual_item);
+    if (I_IS_DIRECTORY_ITEM (ih))
+      /* each entry and new one occupeis 2 byte in the virtual node */
+      size += (ih_entry_count (ih) + 1) * sizeof (__u16);
+  }
+  
+  /* 1 bit for each bitmap block to note whether bitmap block was
+     dirtied in the operation */
+  size += (SB_BMAP_NR (sb) * 2 / 8 + 4);
+  return size;
+#endif
+}
+
+
+static int get_mem_for_virtual_node (struct tree_balance * tb)
+{
+  int size;
+
+
+  size = get_virtual_node_size (tb->tb_sb, PATH_PLAST_BUFFER(tb->tb_path));
+  tb->vn_buf = getmem (size);
+  return CARRY_ON;
+}
+
+
+/* Prepare for balancing, that is
+ *	get all necessary parents, and neighbors;
+ *	analyze what and where should be moved;
+ *	get sufficient number of new nodes;
+ * Balancing will start only after all resources will be collected at a time.
+ * 
+ * When ported to SMP kernels, only at the last moment after all needed nodes
+ * are collected in cache, will the resources be locked using the usual
+ * textbook ordered lock acquisition algorithms.  Note that ensuring that
+ * this code neither write locks what it does not need to write lock nor locks out of order
+ * will be a pain in the butt that could have been avoided.  Grumble grumble. -Hans
+ * 
+ * fix is meant in the sense of render unchanging
+ * 
+ * Latency might be improved by first gathering a list of what buffers are needed
+ * and then getting as many of them in parallel as possible? -Hans
+ *
+ * Parameters:
+ *	op_mode	i - insert, d - delete, c - cut (truncate), p - paste (append)
+ *	tb	tree_balance structure;
+ *	inum	item number in S[h];
+ *      pos_in_item - comment this if you can
+ *      ins_ih & ins_sd are used when inserting
+ * Returns:	1 - schedule occurred while the function worked;
+ *	        0 - schedule didn't occur while the function worked;
+ *             -1 - if no_disk_space 
+ */
+
+
+int fix_nodes (/*struct reiserfs_transaction_handle *th,*/
+	       int n_op_mode, struct tree_balance * p_s_tb,
+	       struct item_head * p_s_ins_ih)
+{
+    int n_pos_in_item = p_s_tb->tb_path->pos_in_item;
+    int	n_ret_value,
+    	n_h,
+    	n_item_num = get_item_pos (p_s_tb->tb_path);
+    struct buffer_head  * p_s_tbS0 = get_bh (p_s_tb->tb_path);
+//    struct item_head * ih = get_ih (p_s_tb->tb_path);
+
+
+    /* if it possible in indirect_to_direct conversion */
+    if (buffer_locked (p_s_tbS0)) {
+	return SCHEDULE_OCCURRED;
+    }
+
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( cur_tb ) {
+	print_tb (n_op_mode, n_item_num, n_pos_in_item, cur_tb,"fix_nodes");
+	reiserfs_panic(p_s_tb->tb_sb,"PAP-8305: fix_nodes:  there is pending do_balance");
+    }
+
+    if (!buffer_uptodate (p_s_tbS0) || !B_IS_IN_TREE (p_s_tbS0)) {
+	reiserfs_panic (p_s_tb->tb_sb, "PAP-8320: fix_nodes: S[0] (%b %z) is not uptodate "
+			"at the beginning of fix_nodes or not in tree (mode %c)", p_s_tbS0, p_s_tbS0, n_op_mode);
+    }
+
+    /* Check parameters. */
+    switch (n_op_mode) {
+#ifndef FU //REISERFS_FSCK
+	// FIXME: REISERFS_CHECK can not be turned on for utils
+    case M_INTERNAL:
+	break;
+    case M_INSERT:
+	if ( n_item_num < 0 || n_item_num > B_NR_ITEMS(p_s_tbS0) )
+	    reiserfs_panic(p_s_tb->tb_sb,"PAP-8325: fix_nodes: Incorrect item number %d (in S0 - %d) in case of insert",
+			   n_item_num, B_NR_ITEMS(p_s_tbS0));
+#else
+    case M_INSERT:
+	if ( n_item_num <= 0 || n_item_num > B_NR_ITEMS(p_s_tbS0) )
+	    reiserfs_panic(p_s_tb->tb_sb,"PAP-8330: fix_nodes: Incorrect item number %d (in S0 - %d) in case of insert",
+			   n_item_num, B_NR_ITEMS(p_s_tbS0));
+#endif
+	break;
+    case M_PASTE:
+	if (I_IS_DIRECT_ITEM (get_ih (p_s_tb->tb_path))) {
+	    // we can paste only to the end for now
+	    if (n_pos_in_item != ih_item_len (get_ih (p_s_tb->tb_path)))
+		reiserfs_panic (th->t_super, "vs-8332: fix_nodes: "
+				"pos_in_item %d set improperly to paste direct item %h",
+				n_pos_in_item, get_ih (p_s_tb->tb_path));
+	}
+	// fall through
+    case M_DELETE:
+    case M_CUT:
+	if ( n_item_num < 0 || n_item_num >= B_NR_ITEMS(p_s_tbS0) ) {
+	    print_block (p_s_tbS0, 0, -1, -1);
+	    printk("mode = %c insert_size = %d\n", n_op_mode, p_s_tb->insert_size[0]);
+	    reiserfs_panic(p_s_tb->tb_sb,"PAP-8335: fix_nodes: Incorrect item number(%d)", n_item_num);
+	}
+	break;
+    default:
+	reiserfs_panic(p_s_tb->tb_sb,"PAP-8340: fix_nodes: Incorrect mode of operation");
+    }
+#endif
+
+
+    if (get_mem_for_virtual_node (p_s_tb) == SCHEDULE_OCCURRED) {
+	return SCHEDULE_OCCURRED;
+    }
+
+    /* Starting from the leaf level; for all levels n_h of the tree. */
+    for ( n_h = 0; n_h < MAX_HEIGHT && p_s_tb->insert_size[n_h]; n_h++ ) { 
+	if ( (n_ret_value = get_direct_parent(p_s_tb, n_h)) != CARRY_ON ) {
+	    return n_ret_value;
+	}
+
+	if ( (n_ret_value = check_balance (/*th,*/ n_op_mode, p_s_tb, n_h, n_item_num,
+					   n_pos_in_item, p_s_ins_ih)) != CARRY_ON ) {
+	    if ( n_ret_value == NO_BALANCING_NEEDED ) {
+		/* No balancing for higher levels needed. */
+		if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) {
+		    return n_ret_value;
+		}
+		if ( n_h != MAX_HEIGHT - 1 )  
+		    p_s_tb->insert_size[n_h + 1] = 0;
+		/* ok, analysis and resource gathering are complete */
+		break;
+	    }
+
+	    return n_ret_value;
+	}
+
+	if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) {
+	    return n_ret_value;
+	}
+
+	if ( (n_ret_value = get_empty_nodes(/*th,*/ p_s_tb, n_h)) != CARRY_ON ) {
+	    return n_ret_value; /* No disk space, or schedule occurred and
+				   analysis may be invalid and needs to be redone. */
+	}
+    
+	if ( ! PATH_H_PBUFFER(p_s_tb->tb_path, n_h) ) {
+	    /* We have a positive insert size but no nodes exist on this
+	       level, this means that we are creating a new root. */
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if ( p_s_tb->blknum[n_h] != 1 )
+		reiserfs_panic(p_s_tb->tb_sb,"PAP-8350: fix_nodes: creating new empty root");
+#endif /* CONFIG_REISERFS_CHECK */
+
+	    if ( n_h < MAX_HEIGHT - 1 )
+		p_s_tb->insert_size[n_h + 1] = 0;
+	}
+	else
+	    if ( ! PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1) ) {
+		if ( p_s_tb->blknum[n_h] > 1 ) {
+		    /* The tree needs to be grown, so this node S[n_h]
+		       which is the root node is split into two nodes, and
+		       a new node (S[n_h+1]) will be created to become the root node.  */
+	  
+#ifdef CONFIG_REISERFS_CHECK
+		    if ( n_h == MAX_HEIGHT - 1 )
+			reiserfs_panic(p_s_tb->tb_sb, "PAP-8355: fix_nodes: attempt to create too high of a tree");
+#endif /* CONFIG_REISERFS_CHECK */
+
+		    p_s_tb->insert_size[n_h + 1] = (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1) + DC_SIZE;
+		}
+		else
+		    if ( n_h < MAX_HEIGHT - 1 )
+			p_s_tb->insert_size[n_h + 1] = 0;
+	    }
+	    else
+		p_s_tb->insert_size[n_h + 1] = (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1);
+    }
+
+    return CARRY_ON; /* schedule did not occur */
+}
+
+
+void unfix_nodes(/* struct reiserfs_transaction_handle *th,*/struct tree_balance * p_s_tb)
+{
+    struct path * p_s_path = p_s_tb->tb_path;
+    int		n_counter;
+    //  int i, j;
+    //struct buffer_head * bh;
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( ! p_s_tb->vn_buf )
+	reiserfs_panic (p_s_tb->tb_sb,
+			"PAP-16050: unfix_nodes: pointer to the virtual node is NULL");
+#endif
+
+
+    /* Release path buffers. */
+    pathrelse(p_s_path);
+
+
+    for ( n_counter = 0; n_counter < MAX_HEIGHT; n_counter++ ) {
+	/* Release fathers and neighbors. */
+	brelse(p_s_tb->L[n_counter]);
+	brelse(p_s_tb->R[n_counter]);
+	brelse(p_s_tb->FL[n_counter]);
+	brelse(p_s_tb->FR[n_counter]);
+	brelse(p_s_tb->CFL[n_counter]);
+	brelse(p_s_tb->CFR[n_counter]);
+    }
+
+    /* Could be optimized. Will be done by PAP someday */
+    for ( n_counter = 0; n_counter < MAX_FEB_SIZE; n_counter++ ) {
+	if ( p_s_tb->FEB[n_counter] ) {
+	    /* release what was not used */
+	    reiserfs_free_block(p_s_tb->tb_sb, p_s_tb->FEB[n_counter]->b_blocknr);
+
+	    bforget(p_s_tb->FEB[n_counter]);
+	    /* tree balance bitmap of bitmaps has bit set already */
+	}
+	/* release used as new nodes including a new root */
+	brelse (p_s_tb->used[n_counter]);
+    }
+
+    reiserfs_kfree (p_s_tb->vn_buf, p_s_tb->vn_buf_size, p_s_tb->tb_sb);
+
+} 
+
+
+
+
+
+
diff --git a/reiserfscore/hashes.c b/reiserfscore/hashes.c
new file mode 100644
index 0000000..32628ce
--- /dev/null
+++ b/reiserfscore/hashes.c
@@ -0,0 +1,253 @@
+/*
+ * Keyed 32-bit hash function using TEA in a Davis-Meyer function
+ *   H0 = Key
+ *   Hi = E Mi(Hi-1) + Hi-1
+ *
+ * (see Applied Cryptography, 2nd edition, p448).
+ *
+ * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
+ * 
+ * Jeremy has agreed to the contents of reiserfs/README. -Hans
+ * Yura's function is added (04/07/2000)
+ */
+
+//
+// keyed_hash
+// yura_hash
+// r5
+//
+
+#include <asm/types.h>
+
+
+
+#define DELTA 0x9E3779B9
+#define FULLROUNDS 10		/* 32 is overkill, 16 is strong crypto */
+#define PARTROUNDS 6		/* 6 gets complete mixing */
+
+#ifndef __KERNEL__
+typedef __u32 u32;
+#endif
+
+/* a, b, c, d - data; h0, h1 - accumulated hash */
+#define TEACORE(rounds)							\
+	do {								\
+		u32 sum = 0;						\
+		int n = rounds;						\
+		u32 b0, b1;						\
+									\
+		b0 = h0;						\
+		b1 = h1;						\
+									\
+		do							\
+		{							\
+			sum += DELTA;					\
+			b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);	\
+			b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);	\
+		} while(--n);						\
+									\
+		h0 += b0;						\
+		h1 += b1;						\
+	} while(0)
+
+
+u32 keyed_hash(const char *msg, int len)
+{
+	u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3}; 
+
+	u32 h0 = k[0], h1 = k[1];
+	u32 a, b, c, d;
+	u32 pad;
+	int i;
+ 
+
+	//	assert(len >= 0 && len < 256);
+
+	pad = (u32)len | ((u32)len << 8);
+	pad |= pad << 16;
+
+	while(len >= 16)
+	{
+		a = (u32)msg[ 0]      |
+		    (u32)msg[ 1] << 8 |
+		    (u32)msg[ 2] << 16|
+		    (u32)msg[ 3] << 24;
+		b = (u32)msg[ 4]      |
+		    (u32)msg[ 5] << 8 |
+		    (u32)msg[ 6] << 16|
+		    (u32)msg[ 7] << 24;
+		c = (u32)msg[ 8]      |
+		    (u32)msg[ 9] << 8 |
+		    (u32)msg[10] << 16|
+		    (u32)msg[11] << 24;
+		d = (u32)msg[12]      |
+		    (u32)msg[13] << 8 |
+		    (u32)msg[14] << 16|
+		    (u32)msg[15] << 24;
+		
+		TEACORE(PARTROUNDS);
+
+		len -= 16;
+		msg += 16;
+	}
+
+	if (len >= 12)
+	{
+	    	//assert(len < 16);
+		if (len >= 16)
+		    *(int *)0 = 0;
+
+		a = (u32)msg[ 0]      |
+		    (u32)msg[ 1] << 8 |
+		    (u32)msg[ 2] << 16|
+		    (u32)msg[ 3] << 24;
+		b = (u32)msg[ 4]      |
+		    (u32)msg[ 5] << 8 |
+		    (u32)msg[ 6] << 16|
+		    (u32)msg[ 7] << 24;
+		c = (u32)msg[ 8]      |
+		    (u32)msg[ 9] << 8 |
+		    (u32)msg[10] << 16|
+		    (u32)msg[11] << 24;
+
+		d = pad;
+		for(i = 12; i < len; i++)
+		{
+			d <<= 8;
+			d |= msg[i];
+		}
+	}
+	else if (len >= 8)
+	{
+	    	//assert(len < 12);
+		if (len >= 12)
+		    *(int *)0 = 0;
+		a = (u32)msg[ 0]      |
+		    (u32)msg[ 1] << 8 |
+		    (u32)msg[ 2] << 16|
+		    (u32)msg[ 3] << 24;
+		b = (u32)msg[ 4]      |
+		    (u32)msg[ 5] << 8 |
+		    (u32)msg[ 6] << 16|
+		    (u32)msg[ 7] << 24;
+
+		c = d = pad;
+		for(i = 8; i < len; i++)
+		{
+			c <<= 8;
+			c |= msg[i];
+		}
+	}
+	else if (len >= 4)
+	{
+	    	//assert(len < 8);
+		if (len >= 8)
+		    *(int *)0 = 0;
+		a = (u32)msg[ 0]      |
+		    (u32)msg[ 1] << 8 |
+		    (u32)msg[ 2] << 16|
+		    (u32)msg[ 3] << 24;
+
+		b = c = d = pad;
+		for(i = 4; i < len; i++)
+		{
+			b <<= 8;
+			b |= msg[i];
+		}
+	}
+	else
+	{
+	    	//assert(len < 4);
+		if (len >= 4)
+		    *(int *)0 = 0;
+		a = b = c = d = pad;
+		for(i = 0; i < len; i++)
+		{
+			a <<= 8;
+			a |= msg[i];
+		}
+	}
+
+	TEACORE(FULLROUNDS);
+
+/*	return 0;*/
+	return h0^h1;
+}
+
+
+u32 yura_hash (const char *msg, int len)
+{
+    int j, pow;
+    u32 a, c;
+    int i;
+    
+    for (pow=1,i=1; i < len; i++) pow = pow * 10; 
+    
+    if (len == 1) 
+	a = msg[0]-48;
+    else
+	a = (msg[0] - 48) * pow;
+    
+    for (i=1; i < len; i++) {
+	c = msg[i] - 48; 
+	for (pow=1,j=i; j < len-1; j++) pow = pow * 10; 
+	a = a + c * pow;
+    }
+    
+    for (; i < 40; i++) {
+	c = '0' - 48; 
+	for (pow=1,j=i; j < len-1; j++) pow = pow * 10; 
+	a = a + c * pow;
+    }
+    
+    for (; i < 256; i++) {
+	c = i; 
+	for (pow=1,j=i; j < len-1; j++) pow = pow * 10; 
+	a = a + c * pow;
+    }
+    
+    a = a << 7;
+    return a;
+}
+
+
+u32 r5_hash (const char *msg, int len)
+{
+  u32 a=0;
+  int i;
+
+  for (i = 0; i < len; i ++) {
+    a += msg[i] << 4;
+    a += msg[i] >> 4;
+    a *= 11;
+  } 
+  return a;
+}
+
+#if 0
+
+#include <stdio.h>
+//#include <stddef.h>
+
+int main (void)
+{
+    char * name = 0;
+    size_t n = 0;
+
+    while (1) {
+	getline (&name, &n, stdin);
+	if (!strcmp (name, "\n"))
+	    break;
+	name [strlen (name) - 1] = 0;
+	printf ("tea %lu\n, r5 %lu\nyura %lu\n",
+		keyed_hash (name, strlen (name)) & 0x7fffff80,
+		r5_hash (name, strlen (name)) & 0x7fffff80,
+		yura_hash (name, strlen (name)) & 0x7fffff80);
+	free (name);
+	name = 0;
+	n = 0;
+    }
+}
+
+#endif
+
diff --git a/reiserfscore/ibalance.c b/reiserfscore/ibalance.c
new file mode 100644
index 0000000..782f099
--- /dev/null
+++ b/reiserfscore/ibalance.c
@@ -0,0 +1,1052 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+
+#include "includes.h"
+
+
+/* this is one and only function that is used outside (do_balance.c) */
+int	balance_internal (
+    /*struct reiserfs_transaction_handle *th,*/
+			  struct tree_balance * ,
+			  int,
+			  int,
+			  struct item_head * ,
+			  struct buffer_head ** 
+			  );
+
+/* modes of internal_shift_left, internal_shift_right and internal_insert_childs */
+#define INTERNAL_SHIFT_FROM_S_TO_L 0
+#define INTERNAL_SHIFT_FROM_R_TO_S 1
+#define INTERNAL_SHIFT_FROM_L_TO_S 2
+#define INTERNAL_SHIFT_FROM_S_TO_R 3
+#define INTERNAL_INSERT_TO_S 4
+#define INTERNAL_INSERT_TO_L 5
+#define INTERNAL_INSERT_TO_R 6
+
+static void	internal_define_dest_src_infos (
+						int shift_mode,
+						struct tree_balance * tb,
+						int h,
+						struct buffer_info * dest_bi,
+						struct buffer_info * src_bi,
+						int * d_key,
+						struct buffer_head ** cf
+						)
+{
+#ifdef CONFIG_REISERFS_CHECK
+  memset (dest_bi, 0, sizeof (struct buffer_info));
+  memset (src_bi, 0, sizeof (struct buffer_info));
+#endif
+  /* define dest, src, dest parent, dest position */
+  switch (shift_mode) {
+  case INTERNAL_SHIFT_FROM_S_TO_L:	/* used in internal_shift_left */
+    src_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
+    src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
+    src_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
+    dest_bi->bi_bh = tb->L[h];
+    dest_bi->bi_parent = tb->FL[h];
+    dest_bi->bi_position = get_left_neighbor_position (tb, h);
+    *d_key = tb->lkey[h];
+    *cf = tb->CFL[h];
+    break;
+  case INTERNAL_SHIFT_FROM_L_TO_S:
+    src_bi->bi_bh = tb->L[h];
+    src_bi->bi_parent = tb->FL[h];
+    src_bi->bi_position = get_left_neighbor_position (tb, h);
+    dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
+    dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
+    dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1); /* dest position is analog of dest->b_item_order */
+    *d_key = tb->lkey[h];
+    *cf = tb->CFL[h];
+    break;
+
+  case INTERNAL_SHIFT_FROM_R_TO_S:	/* used in internal_shift_left */
+    src_bi->bi_bh = tb->R[h];
+    src_bi->bi_parent = tb->FR[h];
+    src_bi->bi_position = get_right_neighbor_position (tb, h);
+    dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
+    dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
+    dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
+    *d_key = tb->rkey[h];
+    *cf = tb->CFR[h];
+    break;
+  case INTERNAL_SHIFT_FROM_S_TO_R:
+    src_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
+    src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
+    src_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
+    dest_bi->bi_bh = tb->R[h];
+    dest_bi->bi_parent = tb->FR[h];
+    dest_bi->bi_position = get_right_neighbor_position (tb, h);
+    *d_key = tb->rkey[h];
+    *cf = tb->CFR[h];
+    break;
+
+  case INTERNAL_INSERT_TO_L:
+    dest_bi->bi_bh = tb->L[h];
+    dest_bi->bi_parent = tb->FL[h];
+    dest_bi->bi_position = get_left_neighbor_position (tb, h);
+    break;
+
+  case INTERNAL_INSERT_TO_S:
+    dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
+    dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
+    dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
+    break;
+
+  case INTERNAL_INSERT_TO_R:
+    dest_bi->bi_bh = tb->R[h];
+    dest_bi->bi_parent = tb->FR[h];
+    dest_bi->bi_position = get_right_neighbor_position (tb, h);
+    break;
+
+  default:
+      reiserfs_panic ("internal_define_dest_src_infos", "shift type is unknown (%d)", shift_mode);
+  }
+}
+
+
+
+/* Insert 'count' node pointers into buffer cur before position 'to' + 1.
+ * Insert count items into buffer cur before position to.
+ * Items and node pointers are specified by inserted and bh respectively.
+ */ 
+static void internal_insert_childs (reiserfs_filsys_t fs, 
+				    struct buffer_info * cur_bi,
+				    int to, int count,
+				    struct item_head * inserted,
+				    struct buffer_head ** bh)
+{
+    struct buffer_head * cur = cur_bi->bi_bh;
+    int nr;
+    struct key * key;
+    struct disk_child new_dc[2];
+    struct disk_child * dc;
+    int i;
+    int from;
+    
+    if (count <= 0)
+	return;
+    
+    nr = node_item_number (cur);
+    
+#ifdef CONFIG_REISERFS_CHECK
+    if (count > 2)
+	reiserfs_panic (0, "internal_insert_childs", "too many children (%d) are to be inserted", count);
+    if (node_free_space (cur) < count * (KEY_SIZE + DC_SIZE))
+	reiserfs_panic (0, "internal_insert_childs", "no enough free space (%d), needed %d bytes", 
+			node_free_space (cur), count * (KEY_SIZE + DC_SIZE));
+#endif /* CONFIG_REISERFS_CHECK */
+    
+    /* prepare space for count disk_child */
+    dc = B_N_CHILD (cur,to+1);
+    
+    memmove (dc + count, dc, (nr+1-(to+1)) * DC_SIZE);
+    
+    /* make disk child array for insertion */
+    for (i = 0; i < count; i ++) {
+	new_dc[i].dc_size = cpu_to_le16 (MAX_CHILD_SIZE(bh[i]) - 
+					 node_free_space (bh[i]));
+	new_dc[i].dc_block_number = cpu_to_le32 (bh[i]->b_blocknr);
+    }
+    memcpy (dc, new_dc, DC_SIZE * count);
+    
+    /* prepare space for 'count' items  */
+    from = ((to == -1) ? 0 : to);
+    key = B_N_PDELIM_KEY (cur, from);
+    
+    memmove (key + count, key, (nr - from/*to*/) * KEY_SIZE + (nr + 1 + count) * DC_SIZE);
+
+    /* copy keys */
+    memcpy (key, inserted, KEY_SIZE);
+    if ( count > 1 )
+	memcpy (key + 1, inserted + 1, KEY_SIZE);
+    
+    /* sizes, item number */
+    set_node_item_number (cur, nr + count);
+    set_node_free_space (cur, node_free_space (cur) - 
+			 count * (DC_SIZE + KEY_SIZE));
+    mark_buffer_dirty (cur);
+    
+    if (cur_bi->bi_parent) {
+	B_N_CHILD (cur_bi->bi_parent,cur_bi->bi_position)->dc_size += count * (DC_SIZE + KEY_SIZE);
+	mark_buffer_dirty (cur_bi->bi_parent);
+    }
+    
+}
+
+
+/* Delete del_num items and node pointers from buffer cur starting from *
+ * the first_i'th item and first_p'th pointers respectively.		*/
+static void internal_delete_pointers_items (reiserfs_filsys_t fs,
+					    struct buffer_info * cur_bi,
+					    int first_p, int first_i, 
+					    int del_num)
+{
+    struct buffer_head * cur = cur_bi->bi_bh;
+    int nr;
+    struct block_head * blkh;
+    struct key * key;
+    struct disk_child * dc;
+
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (cur == NULL)
+	reiserfs_panic (0, "internal_delete_pointers_items1: buffer is 0");
+	
+    if (del_num < 0)
+	reiserfs_panic (0, "internal_delete_pointers_items2",
+			"negative number of items (%d) can not be deleted", del_num);
+
+    if (first_p < 0 || first_p + del_num > B_NR_ITEMS (cur) + 1 || first_i < 0)
+	reiserfs_panic (0, "internal_delete_pointers_items3",
+			"first pointer order (%d) < 0 or "
+			"no so many pointers (%d), only (%d) or "
+			"first key order %d < 0", first_p, 
+			first_p + del_num, B_NR_ITEMS (cur) + 1, first_i);
+#endif /* CONFIG_REISERFS_CHECK */
+    if ( del_num == 0 )
+	return;
+
+    nr = (blkh = B_BLK_HEAD(cur))->blk_nr_item;
+
+    if ( first_p == 0 && del_num == nr + 1 ) {
+#ifdef CONFIG_REISERFS_CHECK
+	if ( first_i != 0 )
+	    reiserfs_panic (0, "internal_delete_pointers_items5",
+			    "first deleted key must have order 0, not %d", first_i);
+#endif /* CONFIG_REISERFS_CHECK */
+	make_empty_node (cur_bi);
+	return;
+    }
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (first_i + del_num > B_NR_ITEMS (cur)) {
+	printk("first_i = %d del_num = %d\n",first_i,del_num);
+	reiserfs_panic (0, "internal_delete_pointers_items4: :"
+			"no so many keys (%d) in the node (%b)(%z)", first_i + del_num, cur, cur);
+    }
+#endif /* CONFIG_REISERFS_CHECK */
+
+
+    /* deleting */
+    dc = B_N_CHILD (cur, first_p);
+
+    memmove (dc, dc + del_num, (nr + 1 - first_p - del_num) * DC_SIZE);
+    key = B_N_PDELIM_KEY (cur, first_i);
+    memmove (key, key + del_num, (nr - first_i - del_num) * KEY_SIZE + (nr + 1 - del_num) * DC_SIZE);
+
+
+  /* sizes, item number */
+    blkh->blk_nr_item -= del_num;
+    blkh->blk_free_space += del_num * (KEY_SIZE +  DC_SIZE);
+
+    mark_buffer_dirty (cur);
+ 
+    if (cur_bi->bi_parent) {
+	B_N_CHILD (cur_bi->bi_parent, cur_bi->bi_position)->dc_size -= del_num * (KEY_SIZE +  DC_SIZE);
+	mark_buffer_dirty (cur_bi->bi_parent);
+    }
+}
+
+
+/* delete n node pointers and items starting from given position */
+static void internal_delete_childs (reiserfs_filsys_t fs,
+				    struct buffer_info * cur_bi, 
+				    int from, int n)
+{
+    int i_from;
+    
+    i_from = (from == 0) ? from : from - 1;
+    
+    /* delete n pointers starting from `from' position in CUR;
+       delete n keys starting from 'i_from' position in CUR;
+    */
+    internal_delete_pointers_items (fs, cur_bi, from, i_from, n);
+}
+
+
+/* copy cpy_num node pointers and cpy_num - 1 items from buffer src to buffer dest
+* last_first == FIRST_TO_LAST means, that we copy first items from src to tail of dest
+ * last_first == LAST_TO_FIRST means, that we copy last items from src to head of dest 
+ */
+static void internal_copy_pointers_items (reiserfs_filsys_t fs,
+					  struct buffer_info * dest_bi,
+					  struct buffer_head * src,
+					  int last_first, int cpy_num)
+{
+    /* ATTENTION! Number of node pointers in DEST is equal to number of items in DEST *
+     * as delimiting key have already inserted to buffer dest.*/
+    struct buffer_head * dest = dest_bi->bi_bh;
+    int nr_dest, nr_src;
+    int dest_order, src_order;
+    struct block_head * blkh;
+    struct key * key;
+    struct disk_child * dc;
+
+    nr_src = B_NR_ITEMS (src);
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( dest == NULL || src == NULL )
+	reiserfs_panic (0, "internal_copy_pointers_items", "src (%p) or dest (%p) buffer is 0", src, dest);
+
+    if (last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST)
+	reiserfs_panic (0, "internal_copy_pointers_items",
+			"invalid last_first parameter (%d)", last_first);
+
+    if ( nr_src < cpy_num - 1 )
+	reiserfs_panic (0, "internal_copy_pointers_items", "no so many items (%d) in src (%d)", cpy_num, nr_src);
+
+    if ( cpy_num < 0 )
+	reiserfs_panic (0, "internal_copy_pointers_items", "cpy_num less than 0 (%d)", cpy_num);
+
+    if (cpy_num - 1 + B_NR_ITEMS(dest) > (int)MAX_NR_KEY(dest))
+	reiserfs_panic (0, "internal_copy_pointers_items",
+			"cpy_num (%d) + item number in dest (%d) can not be more than MAX_NR_KEY(%d)",
+			cpy_num, B_NR_ITEMS(dest), MAX_NR_KEY(dest));
+#endif
+
+    if ( cpy_num == 0 )
+	return;
+
+	/* coping */
+    nr_dest = (blkh = B_BLK_HEAD(dest))->blk_nr_item;
+
+    /*dest_order = (last_first == LAST_TO_FIRST) ? 0 : nr_dest;*/
+    /*src_order = (last_first == LAST_TO_FIRST) ? (nr_src - cpy_num + 1) : 0;*/
+    (last_first == LAST_TO_FIRST) ?	(dest_order = 0, src_order = nr_src - cpy_num + 1) :
+	(dest_order = nr_dest, src_order = 0);
+
+    /* prepare space for cpy_num pointers */
+    dc = B_N_CHILD (dest, dest_order);
+
+    memmove (dc + cpy_num, dc, (nr_dest - dest_order) * DC_SIZE);
+
+	/* insert pointers */
+    memcpy (dc, B_N_CHILD (src, src_order), DC_SIZE * cpy_num);
+
+
+    /* prepare space for cpy_num - 1 item headers */
+    key = B_N_PDELIM_KEY(dest, dest_order);
+    memmove (key + cpy_num - 1, key,
+	     KEY_SIZE * (nr_dest - dest_order) + DC_SIZE * (nr_dest + cpy_num));
+
+
+    /* insert headers */
+    memcpy (key, B_N_PDELIM_KEY (src, src_order), KEY_SIZE * (cpy_num - 1));
+
+    /* sizes, item number */
+    blkh->blk_nr_item += cpy_num - 1;
+    blkh->blk_free_space -= KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num;
+
+    mark_buffer_dirty (dest);
+    if (dest_bi->bi_parent) {
+	B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position)->dc_size +=
+	    KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num;
+	mark_buffer_dirty (dest_bi->bi_parent);
+    }
+
+}
+
+
+/* Copy cpy_num node pointers and cpy_num - 1 items from buffer src to buffer dest.
+ * Delete cpy_num - del_par items and node pointers from buffer src.
+ * last_first == FIRST_TO_LAST means, that we copy/delete first items from src.
+ * last_first == LAST_TO_FIRST means, that we copy/delete last items from src.
+ */
+static void internal_move_pointers_items (reiserfs_filsys_t fs,
+					  struct buffer_info * dest_bi, 
+					  struct buffer_info * src_bi, 
+					  int last_first, int cpy_num, int del_par)
+{
+    int first_pointer;
+    int first_item;
+    
+    internal_copy_pointers_items (fs, dest_bi, src_bi->bi_bh, last_first, cpy_num);
+    
+    if (last_first == FIRST_TO_LAST) {	/* shift_left occurs */
+	first_pointer = 0;
+	first_item = 0;
+	/* delete cpy_num - del_par pointers and keys starting for pointers with first_pointer, 
+	   for key - with first_item */
+	internal_delete_pointers_items (fs, src_bi, first_pointer, first_item, cpy_num - del_par);
+    } else {			/* shift_right occurs */
+	int i, j;
+	
+	i = ( cpy_num - del_par == ( j = B_NR_ITEMS(src_bi->bi_bh)) + 1 ) ? 0 : j - cpy_num + del_par;
+	
+	internal_delete_pointers_items (fs, src_bi, j + 1 - cpy_num + del_par, i, cpy_num - del_par);
+    }
+}
+
+/* Insert n_src'th key of buffer src before n_dest'th key of buffer dest. */
+static void internal_insert_key (reiserfs_filsys_t fs,
+				 struct buffer_info * dest_bi, 
+				 int dest_position_before,                 /* insert key before key with n_dest number */
+				 struct buffer_head * src, 
+				 int src_position )
+{
+    struct buffer_head * dest = dest_bi->bi_bh;
+    int nr;
+    struct block_head * blkh;
+    struct key * key;
+
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (dest == NULL || src == NULL)
+	reiserfs_panic (0, "internal_insert_key", "sourse(%p) or dest(%p) buffer is 0", src, dest);
+
+    if (dest_position_before < 0 || src_position < 0)
+	reiserfs_panic (0, "internal_insert_key", "source(%d) or dest(%d) key number less than 0", 
+			src_position, dest_position_before);
+
+    if (dest_position_before > B_NR_ITEMS (dest) || src_position >= B_NR_ITEMS(src))
+	reiserfs_panic (0, "internal_insert_key", 
+			"invalid position in dest (%d (key number %d)) or in src (%d (key number %d))",
+			dest_position_before, B_NR_ITEMS (dest), src_position, B_NR_ITEMS(src));
+
+    if (B_BLK_HEAD(dest)->blk_free_space < KEY_SIZE)
+	reiserfs_panic (0, "internal_insert_key", 
+			"no enough free space (%d) in dest buffer", B_BLK_HEAD(dest)->blk_free_space);
+#endif
+
+    nr = (blkh=B_BLK_HEAD(dest))->blk_nr_item;
+
+    /* prepare space for inserting key */
+    key = B_N_PDELIM_KEY (dest, dest_position_before);
+    memmove (key + 1, key, (nr - dest_position_before) * KEY_SIZE + (nr + 1) * DC_SIZE);
+
+    /* insert key */
+    memcpy (key, B_N_PDELIM_KEY(src, src_position), KEY_SIZE);
+
+    /* Change dirt, free space, item number fields. */
+    blkh->blk_nr_item ++;
+    blkh->blk_free_space -= KEY_SIZE;
+
+    mark_buffer_dirty (dest);
+
+    if (dest_bi->bi_parent) {
+	B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position)->dc_size += KEY_SIZE;
+	mark_buffer_dirty (dest_bi->bi_parent);
+    }
+}
+
+
+
+/* Insert d_key'th (delimiting) key from buffer cfl to tail of dest. 
+ * Copy pointer_amount node pointers and pointer_amount - 1 items from buffer src to buffer dest.
+ * Replace  d_key'th key in buffer cfl.
+ * Delete pointer_amount items and node pointers from buffer src.
+ */
+/* this can be invoked both to shift from S to L and from R to S */
+static void internal_shift_left (int mode,	/* INTERNAL_FROM_S_TO_L | INTERNAL_FROM_R_TO_S */
+				 struct tree_balance * tb, int h,
+				 int pointer_amount)
+{
+    struct buffer_info dest_bi, src_bi;
+    struct buffer_head * cf;
+    int d_key_position;
+
+    internal_define_dest_src_infos (mode, tb, h, &dest_bi, &src_bi, &d_key_position, &cf);
+
+    /*printk("pointer_amount = %d\n",pointer_amount);*/
+
+    if (pointer_amount) {
+	/* insert delimiting key from common father of dest and src to node dest into position B_NR_ITEM(dest) */
+	internal_insert_key (tb->tb_sb, &dest_bi, B_NR_ITEMS(dest_bi.bi_bh), cf, d_key_position);
+
+	if (B_NR_ITEMS(src_bi.bi_bh) == pointer_amount - 1) {
+	    if (src_bi.bi_position/*src->b_item_order*/ == 0)
+		replace_key (tb->tb_sb, cf, d_key_position, src_bi.bi_parent/*src->b_parent*/, 0);
+	} else
+	    replace_key (tb->tb_sb, cf, d_key_position, src_bi.bi_bh, pointer_amount - 1);
+    }
+    /* last parameter is del_parameter */
+    internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, FIRST_TO_LAST, pointer_amount, 0);
+
+}
+
+/* Insert delimiting key to L[h].
+ * Copy n node pointers and n - 1 items from buffer S[h] to L[h].
+ * Delete n - 1 items and node pointers from buffer S[h].
+ */
+/* it always shifts from S[h] to L[h] */
+static void internal_shift1_left (struct tree_balance * tb, 
+				  int h, int pointer_amount)
+{
+    struct buffer_info dest_bi, src_bi;
+    struct buffer_head * cf;
+    int d_key_position;
+    
+    internal_define_dest_src_infos (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, &dest_bi, &src_bi, &d_key_position, &cf);
+    
+    if ( pointer_amount > 0 ) /* insert lkey[h]-th key  from CFL[h] to left neighbor L[h] */
+	internal_insert_key (tb->tb_sb, &dest_bi, B_NR_ITEMS(dest_bi.bi_bh), cf, d_key_position);
+    
+    /* last parameter is del_parameter */
+    internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, FIRST_TO_LAST, pointer_amount, 1);
+}
+
+
+/* Insert d_key'th (delimiting) key from buffer cfr to head of dest. 
+ * Copy n node pointers and n - 1 items from buffer src to buffer dest.
+ * Replace  d_key'th key in buffer cfr.
+ * Delete n items and node pointers from buffer src.
+ */
+static void internal_shift_right (int mode,	/* INTERNAL_FROM_S_TO_R | INTERNAL_FROM_L_TO_S */
+				  struct tree_balance * tb, int h,
+				  int pointer_amount)
+{
+    struct buffer_info dest_bi, src_bi;
+    struct buffer_head * cf;
+    int d_key_position;
+    int nr;
+
+
+    internal_define_dest_src_infos (mode, tb, h, &dest_bi, &src_bi, &d_key_position, &cf);
+
+    nr = B_NR_ITEMS (src_bi.bi_bh);
+
+    if (pointer_amount > 0) {
+	/* insert delimiting key from common father of dest and src to dest node into position 0 */
+	internal_insert_key (tb->tb_sb, &dest_bi, 0, cf, d_key_position);
+	if (nr == pointer_amount - 1) {
+#ifdef CONFIG_REISERFS_CHECK
+	    if ( src_bi.bi_bh != PATH_H_PBUFFER (tb->tb_path, h)/*tb->S[h]*/ || dest_bi.bi_bh != tb->R[h])
+		reiserfs_panic (tb->tb_sb, "internal_shift_right", "src (%p) must be == tb->S[h](%p) when it disappears",
+				src_bi.bi_bh, PATH_H_PBUFFER (tb->tb_path, h));
+#endif
+	    /* when S[h] disappers replace left delemiting key as well */
+	    if (tb->CFL[h])
+		replace_key(tb->tb_sb, cf, d_key_position, tb->CFL[h], tb->lkey[h]);
+	} else
+	    replace_key(tb->tb_sb, cf, d_key_position, src_bi.bi_bh, nr - pointer_amount);
+    }      
+
+    /* last parameter is del_parameter */
+    internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, pointer_amount, 0);
+}
+
+/* Insert delimiting key to R[h].
+ * Copy n node pointers and n - 1 items from buffer S[h] to R[h].
+ * Delete n - 1 items and node pointers from buffer S[h].
+ */
+/* it always shift from S[h] to R[h] */
+static void internal_shift1_right (struct tree_balance * tb, 
+				   int h, int pointer_amount)
+{
+    struct buffer_info dest_bi, src_bi;
+    struct buffer_head * cf;
+    int d_key_position;
+
+    internal_define_dest_src_infos (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, &dest_bi, &src_bi, &d_key_position, &cf);
+    
+    if (pointer_amount > 0) /* insert rkey from CFR[h] to right neighbor R[h] */
+	internal_insert_key (tb->tb_sb, &dest_bi, 0, cf, d_key_position);
+    
+    /* last parameter is del_parameter */
+    internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, pointer_amount, 1);
+}
+
+
+/* Delete insert_num node pointers together with their left items
+ * and balance current node.*/
+static void balance_internal_when_delete (struct tree_balance * tb, 
+					  int h, int child_pos)
+{
+    int insert_num;
+    int n;
+    struct buffer_head * tbSh = PATH_H_PBUFFER (tb->tb_path, h);
+    struct buffer_info bi;
+
+    insert_num = tb->insert_size[h] / ((int)(DC_SIZE + KEY_SIZE));
+  
+    /* delete child-node-pointer(s) together with their left item(s) */
+    bi.bi_bh = tbSh;
+
+    bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h);
+
+    bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
+
+    internal_delete_childs (tb->tb_sb, &bi, child_pos, -insert_num);
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( tb->blknum[h] > 1 )
+	reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "tb->blknum[%d]=%d when insert_size < 0",
+			h, tb->blknum[h]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+    n = B_NR_ITEMS(tbSh);
+
+    if ( tb->lnum[h] == 0 && tb->rnum[h] == 0 ) {
+	if ( tb->blknum[h] == 0 ) {
+	    /* node S[h] (root of the tree) is empty now */
+	    struct buffer_head *new_root;
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if (n || B_BLK_HEAD (tbSh)->blk_free_space != MAX_CHILD_SIZE(tbSh) - DC_SIZE)
+		reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "buffer must have only 0 keys (%d)",
+				n);
+
+	    if (bi.bi_parent)
+		reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "root has parent (%p)", bi.bi_parent);
+#endif /* CONFIG_REISERFS_CHECK */
+		
+	    /* choose a new root */
+	    if ( ! tb->L[h-1] || ! B_NR_ITEMS(tb->L[h-1]) )
+		new_root = tb->R[h-1];
+	    else
+		new_root = tb->L[h-1];
+
+	    /* update super block's tree height and pointer to a root block */
+	    tb->tb_sb->s_rs->s_v1.s_root_block = cpu_to_le32 (new_root->b_blocknr);
+	    tb->tb_sb->s_rs->s_v1.s_tree_height = SB_TREE_HEIGHT (tb->tb_sb) - 1;
+
+	    mark_buffer_dirty (tb->tb_sb->s_sbh);
+	    tb->tb_sb->s_dirt = 1;
+
+	    /* mark buffer S[h] not uptodate and put it in free list */
+	    reiserfs_invalidate_buffer(tb, tbSh, 1);
+	    return;
+	}
+	return;
+    }
+
+    if ( tb->L[h] && tb->lnum[h] == -B_NR_ITEMS(tb->L[h]) - 1 ) { /* join S[h] with L[h] */
+
+#ifdef CONFIG_REISERFS_CHECK
+	if ( tb->rnum[h] != 0 )
+	    reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->rnum[%d]==%d when joining S[h] with L[h]",
+			    h, tb->rnum[h]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+	internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, n + 1);/*tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], n+1);*/
+	reiserfs_invalidate_buffer(tb, tbSh, 1); /* preserve not needed, internal, 1 mean free block */
+
+	return;
+    }
+
+    if ( tb->R[h] &&  tb->rnum[h] == -B_NR_ITEMS(tb->R[h]) - 1 ) { /* join S[h] with R[h] */
+#ifdef CONFIG_REISERFS_CHECK
+	if ( tb->lnum[h] != 0 )
+	    reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->lnum[%d]==%d when joining S[h] with R[h]",
+			    h, tb->lnum[h]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+	internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, n + 1);
+	reiserfs_invalidate_buffer (tb, tbSh, 1);
+	return;
+    }
+
+    if ( tb->lnum[h] < 0 ) { /* borrow from left neighbor L[h] */
+#ifdef CONFIG_REISERFS_CHECK
+	if ( tb->rnum[h] != 0 )
+	    reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->rnum[%d]==%d when borrow from L[h]",
+			    h, tb->rnum[h]);
+#endif /* CONFIG_REISERFS_CHECK */
+
+	internal_shift_right (INTERNAL_SHIFT_FROM_L_TO_S, tb, h, -tb->lnum[h]);
+	return;
+    }
+
+    if ( tb->rnum[h] < 0 ) { /* borrow from right neighbor R[h] */
+#ifdef CONFIG_REISERFS_CHECK
+	if ( tb->lnum[h] != 0 )
+	    reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", "invalid tb->lnum[%d]==%d when borrow from R[h]",
+			    h, tb->lnum[h]);
+#endif /* CONFIG_REISERFS_CHECK */
+	internal_shift_left (INTERNAL_SHIFT_FROM_R_TO_S, tb, h, -tb->rnum[h]);/*tb->S[h], tb->CFR[h], tb->rkey[h], tb->R[h], -tb->rnum[h]);*/
+	return;
+    }
+
+    if ( tb->lnum[h] > 0 ) { /* split S[h] into two parts and put them into neighbors */
+#ifdef CONFIG_REISERFS_CHECK
+	if ( tb->rnum[h] == 0 || tb->lnum[h] + tb->rnum[h] != n + 1 )
+	    reiserfs_panic (tb->tb_sb, "balance_internal_when_delete", 
+			    "invalid tb->lnum[%d]==%d or tb->rnum[%d]==%d when S[h](item number == %d) is split between them",
+			    h, tb->lnum[h], h, tb->rnum[h], n);
+#endif /* CONFIG_REISERFS_CHECK */
+
+	internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h]);/*tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], tb->lnum[h]);*/
+	internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h]);
+	reiserfs_invalidate_buffer (tb, tbSh, 1);
+
+	return;
+    }
+    reiserfs_panic ("balance_internal_when_delete", "unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d",
+		    h, tb->lnum[h], h, tb->rnum[h]);
+}
+
+
+/* Replace delimiting key of buffers L[h] and S[h] by the given key.*/
+void replace_lkey (struct tree_balance * tb,
+		   int h, struct item_head * key)
+{
+#ifdef CONFIG_REISERFS_CHECK
+    if (tb->L[h] == NULL || tb->CFL[h] == NULL)
+	reiserfs_panic (tb->tb_sb, "replace_lkey: 12255: "
+			"L[h](%p) and CFL[h](%p) must exist in replace_lkey", tb->L[h], tb->CFL[h]);
+#endif
+
+    if (B_NR_ITEMS(PATH_H_PBUFFER(tb->tb_path, h)) == 0)
+	return;
+
+    memcpy (B_N_PDELIM_KEY(tb->CFL[h],tb->lkey[h]), key, KEY_SIZE);
+
+    mark_buffer_dirty (tb->CFL[h]);
+}
+
+
+/* Replace delimiting key of buffers S[h] and R[h] by the given key.*/
+void replace_rkey (struct tree_balance * tb,
+		   int h, struct item_head * key)
+{
+#ifdef CONFIG_REISERFS_CHECK
+    if (tb->R[h] == NULL || tb->CFR[h] == NULL)
+	reiserfs_panic (tb->tb_sb, "replace_rkey: 12260: "
+			"R[h](%p) and CFR[h](%p) must exist in replace_rkey", tb->R[h], tb->CFR[h]);
+
+    if (B_NR_ITEMS(tb->R[h]) == 0)
+	reiserfs_panic (tb->tb_sb, "replace_rkey: 12265: "
+			"R[h] can not be empty if it exists (item number=%d)", B_NR_ITEMS(tb->R[h]));
+#endif
+
+    memcpy (B_N_PDELIM_KEY(tb->CFR[h],tb->rkey[h]), key, KEY_SIZE);
+    
+    mark_buffer_dirty (tb->CFR[h]);
+}
+
+
+
+int balance_internal (struct tree_balance * tb,			/* tree_balance structure 		*/
+		      int h,					/* level of the tree 			*/
+		      int child_pos,
+		      struct item_head * insert_key,		/* key for insertion on higher level   	*/
+		      struct buffer_head ** insert_ptr)	/* node for insertion on higher level*/
+  /* if inserting/pasting
+   {
+   child_pos is the position of the node-pointer in S[h] that	 *
+   pointed to S[h-1] before balancing of the h-1 level;		 *
+   this means that new pointers and items must be inserted AFTER *
+   child_pos
+   }
+   else 
+   {
+   it is the position of the leftmost pointer that must be deleted (together with
+   its corresponding key to the left of the pointer)
+   as a result of the previous level's balancing.
+   }
+*/
+{
+    struct buffer_head * tbSh = PATH_H_PBUFFER (tb->tb_path, h);
+    struct buffer_info bi;
+    int order;		/* we return this: it is 0 if there is no S[h], else it is tb->S[h]->b_item_order */
+    int insert_num, n, k;
+    struct buffer_head * S_new;
+    struct item_head new_insert_key;
+    struct buffer_head * new_insert_ptr = NULL;
+    struct item_head * new_insert_key_addr = insert_key;
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( h < 1 )      
+	reiserfs_panic (tb->tb_sb, "balance_internal", "h (%d) can not be < 1 on internal level", h);
+#endif /* CONFIG_REISERFS_CHECK */
+
+    order = ( tbSh ) ? PATH_H_POSITION (tb->tb_path, h + 1)/*tb->S[h]->b_item_order*/ : 0;
+
+  /* Using insert_size[h] calculate the number insert_num of items
+     that must be inserted to or deleted from S[h]. */
+    insert_num = tb->insert_size[h]/((int)(KEY_SIZE + DC_SIZE));
+
+    /* Check whether insert_num is proper **/
+#ifdef CONFIG_REISERFS_CHECK
+    if ( insert_num < -2  ||  insert_num > 2 )
+	reiserfs_panic (tb->tb_sb, "balance_internal",
+			"incorrect number of items inserted to the internal node (%d)", insert_num);
+
+    if ( h > 1  && (insert_num > 1 || insert_num < -1) )
+	reiserfs_panic (tb->tb_sb, "balance_internal",
+			"incorrect number of items (%d) inserted to the internal node on a level (h=%d) higher than last internal level", 
+			insert_num, h);
+#endif /* CONFIG_REISERFS_CHECK */
+
+    /* Make balance in case insert_num < 0 */
+    if ( insert_num < 0 ) {
+	balance_internal_when_delete (tb, h, child_pos);
+	return order;
+    }
+ 
+    k = 0;
+    if ( tb->lnum[h] > 0 ) {
+	/* shift lnum[h] items from S[h] to the left neighbor L[h].
+	   check how many of new items fall into L[h] or CFL[h] after shifting */
+	n = B_BLK_HEAD(tb->L[h])->blk_nr_item; /* number of items in L[h] */
+	if ( tb->lnum[h] <= child_pos ) {
+	    /* new items don't fall into L[h] or CFL[h] */
+	    internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h]);
+	    child_pos -= tb->lnum[h];
+	} else if ( tb->lnum[h] > child_pos + insert_num ) {
+	    /* all new items fall into L[h] */
+	    internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h] - insert_num);
+
+	    /* insert insert_num keys and node-pointers into L[h] */
+	    bi.bi_bh = tb->L[h];
+	    bi.bi_parent = tb->FL[h];
+	    bi.bi_position = get_left_neighbor_position (tb, h);
+	    internal_insert_childs (tb->tb_sb, &bi,/*tb->L[h], tb->S[h-1]->b_next*/ n + child_pos + 1,
+				    insert_num,insert_key,insert_ptr);
+
+	    insert_num = 0; 
+	} else {
+	    struct disk_child * dc;
+
+	    /* some items fall into L[h] or CFL[h], but some don't fall */
+	    internal_shift1_left (tb, h, child_pos + 1);
+	    /* calculate number of new items that fall into L[h] */
+	    k = tb->lnum[h] - child_pos - 1;
+
+	    bi.bi_bh = tb->L[h];
+	    bi.bi_parent = tb->FL[h];
+	    bi.bi_position = get_left_neighbor_position (tb, h);
+	    internal_insert_childs (tb->tb_sb, &bi,/*tb->L[h], tb->S[h-1]->b_next,*/ n + child_pos + 1,k,
+				    insert_key,insert_ptr);
+
+	    replace_lkey(tb, h, insert_key + k);
+
+	    /* replace the first node-ptr in S[h] by node-ptr to insert_ptr[k] */
+	    (dc = B_N_CHILD(tbSh, 0))->dc_size =
+		MAX_CHILD_SIZE(insert_ptr[k]) -
+		B_BLK_HEAD(insert_ptr[k])->blk_free_space;
+	    dc->dc_block_number = insert_ptr[k]->b_blocknr; 
+
+	    mark_buffer_dirty (tbSh);
+
+	    k++;
+	    insert_key += k;
+	    insert_ptr += k;
+	    insert_num -= k;
+	    child_pos = 0;
+	}
+    }	/* tb->lnum[h] > 0 */
+
+    if ( tb->rnum[h] > 0 ) {
+	/*shift rnum[h] items from S[h] to the right neighbor R[h]*/
+	/* check how many of new items fall into R or CFR after shifting */
+	n = B_BLK_HEAD (tbSh)->blk_nr_item; /* number of items in S[h] */
+	if ( n - tb->rnum[h] >= child_pos )
+	    /* new items fall into S[h] */
+	    /*internal_shift_right(tb,h,tbSh,tb->CFR[h],tb->rkey[h],tb->R[h],tb->rnum[h]);*/
+	    internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h]);
+	else
+	    if ( n + insert_num - tb->rnum[h] < child_pos )
+	    {
+		/* all new items fall into R[h] */
+		internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h] - insert_num);
+
+		/* insert insert_num keys and node-pointers into R[h] */
+		bi.bi_bh = tb->R[h];
+		bi.bi_parent = tb->FR[h];
+		bi.bi_position = get_right_neighbor_position (tb, h);
+		internal_insert_childs (tb->tb_sb, &bi, /*tb->R[h],tb->S[h-1]->b_next*/ child_pos - n - insert_num + tb->rnum[h] - 1,
+					insert_num,insert_key,insert_ptr);
+		insert_num = 0;
+	    }
+	    else
+	    {
+		struct disk_child * dc;
+
+		/* one of the items falls into CFR[h] */
+		internal_shift1_right(tb, h, n - child_pos + 1);
+		/* calculate number of new items that fall into R[h] */
+		k = tb->rnum[h] - n + child_pos - 1;
+
+		bi.bi_bh = tb->R[h];
+		bi.bi_parent = tb->FR[h];
+		bi.bi_position = get_right_neighbor_position (tb, h);
+		internal_insert_childs (tb->tb_sb, &bi, /*tb->R[h], tb->R[h]->b_child,*/ 0, k, insert_key + 1, insert_ptr + 1);
+
+		replace_rkey(tb, h, insert_key + insert_num - k - 1);
+
+		/* replace the first node-ptr in R[h] by node-ptr insert_ptr[insert_num-k-1]*/
+		(dc = B_N_CHILD(tb->R[h], 0))->dc_size =
+		    MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) -
+		    B_BLK_HEAD(insert_ptr[insert_num-k-1])->blk_free_space;
+		dc->dc_block_number = insert_ptr[insert_num-k-1]->b_blocknr;
+
+		mark_buffer_dirty (tb->R[h]);
+		    
+		insert_num -= (k + 1);
+	    }
+    }
+
+    /** Fill new node that appears instead of S[h] **/
+#ifdef CONFIG_REISERFS_CHECK
+    if ( tb->blknum[h] > 2 )
+	reiserfs_panic(0, "balance_internal", "blknum can not be > 2 for internal level");
+    if ( tb->blknum[h] < 0 )
+	reiserfs_panic(0, "balance_internal", "blknum can not be < 0");
+#endif /* CONFIG_REISERFS_CHECK */
+
+    if ( ! tb->blknum[h] )
+    { /* node S[h] is empty now */
+#ifdef CONFIG_REISERFS_CHECK
+	if ( ! tbSh )
+	    reiserfs_panic(0,"balance_internal", "S[h] is equal NULL");
+#endif /* CONFIG_REISERFS_CHECK */
+
+	/* Mark buffer as invalid and put it to head of free list. */
+	reiserfs_invalidate_buffer(tb, tbSh, 1);/* do not preserve, internal node*/
+	return order;
+    }
+
+    if ( ! tbSh ) {
+	/* create new root */
+	struct disk_child  * dc;
+	struct buffer_head * tbSh_1 = PATH_H_PBUFFER (tb->tb_path, h - 1);
+
+
+	if ( tb->blknum[h] != 1 )
+	    reiserfs_panic(0, "balance_internal", "One new node required for creating the new root");
+	/* S[h] = empty buffer from the list FEB. */
+	tbSh = get_FEB (tb);
+	B_BLK_HEAD(tbSh)->blk_level = h + 1;
+	
+	/* Put the unique node-pointer to S[h] that points to S[h-1]. */
+
+	(dc = B_N_CHILD(tbSh, 0))->dc_block_number = tbSh_1->b_blocknr;
+	dc->dc_size = MAX_CHILD_SIZE (tbSh_1) - B_BLK_HEAD(tbSh_1)->blk_free_space;
+	
+	tb->insert_size[h] -= DC_SIZE;
+	B_BLK_HEAD(tbSh)->blk_free_space -= DC_SIZE;
+
+	mark_buffer_dirty (tbSh);
+	
+	/* put new root into path structure */
+	PATH_OFFSET_PBUFFER(tb->tb_path, ILLEGAL_PATH_ELEMENT_OFFSET) = tbSh;
+	
+	/* Change root in structure super block. */
+	tb->tb_sb->s_rs->s_v1.s_root_block = cpu_to_le32 (tbSh->b_blocknr);
+	tb->tb_sb->s_rs->s_v1.s_tree_height = cpu_to_le16 (SB_TREE_HEIGHT (tb->tb_sb) + 1);
+	
+	mark_buffer_dirty (tb->tb_sb->s_sbh);
+	tb->tb_sb->s_dirt = 1;
+    }
+    
+    if ( tb->blknum[h] == 2 ) {
+	int snum;
+	struct buffer_info dest_bi, src_bi;
+
+
+	/* S_new = free buffer from list FEB */
+	S_new = get_FEB(tb);
+
+	B_BLK_HEAD(S_new)->blk_level = h + 1;
+    
+
+	dest_bi.bi_bh = S_new;
+	dest_bi.bi_parent = 0;
+	dest_bi.bi_position = 0;
+	src_bi.bi_bh = tbSh;
+	src_bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h);
+	src_bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
+		
+	n = B_BLK_HEAD(tbSh)->blk_nr_item; /* number of items in S[h] */
+	snum = (insert_num + n + 1)/2;
+	if ( n - snum >= child_pos ) {
+	    /* new items don't fall into S_new */
+	    /*	store the delimiting key for the next level */
+	    /* new_insert_key = (n - snum)'th key in S[h] */
+	    memcpy (&new_insert_key,B_N_PDELIM_KEY(tbSh,n - snum),
+		    KEY_SIZE);
+	    /* last parameter is del_par */
+	    internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, snum, 0);
+	} else if ( n + insert_num - snum < child_pos ) {
+	    /* all new items fall into S_new */
+	    /*	store the delimiting key for the next level */
+	    /* new_insert_key = (n + insert_item - snum)'th key in S[h] */
+	    memcpy(&new_insert_key,B_N_PDELIM_KEY(tbSh,n + insert_num - snum),
+		   KEY_SIZE);
+	    /* last parameter is del_par */
+	    internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, snum - insert_num, 0);
+	    /*			internal_move_pointers_items(S_new,tbSh,1,snum - insert_num,0);*/
+
+	    /* insert insert_num keys and node-pointers into S_new */
+	    internal_insert_childs (tb->tb_sb, &dest_bi, /*S_new,tb->S[h-1]->b_next,*/child_pos - n - insert_num + snum - 1,
+				    insert_num,insert_key,insert_ptr);
+
+	    insert_num = 0;
+	} else {
+	    struct disk_child * dc;
+
+	    /* some items fall into S_new, but some don't fall */
+	    /* last parameter is del_par */
+	    internal_move_pointers_items (tb->tb_sb, &dest_bi, &src_bi, LAST_TO_FIRST, n - child_pos + 1, 1);
+	    /*			internal_move_pointers_items(S_new,tbSh,1,n - child_pos + 1,1);*/
+	    /* calculate number of new items that fall into S_new */
+	    k = snum - n + child_pos - 1;
+
+	    internal_insert_childs (tb->tb_sb, &dest_bi, /*S_new,*/ 0, k, insert_key + 1, insert_ptr+1);
+
+	    /* new_insert_key = insert_key[insert_num - k - 1] */
+	    memcpy(&new_insert_key,insert_key + insert_num - k - 1,
+		   KEY_SIZE);
+	    /* replace first node-ptr in S_new by node-ptr to insert_ptr[insert_num-k-1] */
+
+	    (dc = B_N_CHILD(S_new,0))->dc_size =
+		MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) -
+		B_BLK_HEAD(insert_ptr[insert_num-k-1])->blk_free_space;
+	    dc->dc_block_number =	insert_ptr[insert_num-k-1]->b_blocknr; 
+
+	    mark_buffer_dirty (S_new);
+			
+	    insert_num -= (k + 1);
+	}
+	/* new_insert_ptr = node_pointer to S_new */
+	new_insert_ptr = S_new;
+
+#ifdef CONFIG_REISERFS_CHECK
+	if ( buffer_locked(S_new) )
+	    reiserfs_panic (tb->tb_sb, "balance_internal", "locked buffer S_new[]");
+	if (S_new->b_count != 1)
+	    if (!(buffer_journaled(S_new) && S_new->b_count == 2)) {
+		printk ("REISERFS: balance_internal: S_new->b_count != 1 (%u)\n", S_new->b_count);
+	    }
+#endif /* CONFIG_REISERFS_CHECK */
+
+	/*
+	  S_new->b_count --;
+	*/
+	/*brelse(S_new);*/
+    }
+
+    n = B_BLK_HEAD(tbSh)->blk_nr_item; /*number of items in S[h] */
+
+#ifndef FU //REISERFS_FSCK
+    if ( -1 <= child_pos && child_pos <= n && insert_num > 0 ) {
+#else
+	if ( 0 <= child_pos && child_pos <= n && insert_num > 0 ) {
+#endif
+	    bi.bi_bh = tbSh;
+	    bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h);
+	    bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
+#ifndef FU //REISERFS_FSCK
+	    if (child_pos == -1) {
+		/* this is a little different from original do_balance: 
+		   here we insert the minimal keys in the tree, that has never happened when file system works */
+		if (tb->CFL[h-1] || insert_num != 1 || h != 1)
+		    die ("balance_internal: invalid child_pos");
+/*      insert_child (tb->S[h], tb->S[h-1], child_pos, insert_num, B_N_ITEM_HEAD(tb->S[0],0), insert_ptr);*/
+		internal_insert_childs (tb->tb_sb, &bi, child_pos, insert_num, B_N_PITEM_HEAD (PATH_PLAST_BUFFER (tb->tb_path), 0), insert_ptr);
+	    } else
+#endif
+		internal_insert_childs (tb->tb_sb, 
+					&bi, child_pos,insert_num,insert_key,insert_ptr);
+	}
+
+
+	memcpy (new_insert_key_addr,&new_insert_key,KEY_SIZE);
+	insert_ptr[0] = new_insert_ptr;
+
+	return order;
+    }
+
diff --git a/reiserfscore/includes.h b/reiserfscore/includes.h
new file mode 100644
index 0000000..b26aec9
--- /dev/null
+++ b/reiserfscore/includes.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <asm/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <time.h>
+#include "io.h"
+#include "misc.h"
+#include "reiserfs_lib.h"
diff --git a/reiserfscore/lbalance.c b/reiserfscore/lbalance.c
new file mode 100644
index 0000000..c5036fc
--- /dev/null
+++ b/reiserfscore/lbalance.c
@@ -0,0 +1,1367 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+
+#include "includes.h"
+
+
+/* these are used in do_balance.c */
+
+/* leaf_move_items
+   leaf_shift_left
+   leaf_shift_right
+   leaf_delete_items
+   leaf_insert_into_buf
+   leaf_paste_in_buffer
+   leaf_cut_from_buffer
+   leaf_paste_entries
+   */
+
+
+extern struct tree_balance init_tb;
+extern int init_item_pos;
+extern int init_pos_in_item;
+extern int init_mode;
+
+
+
+/* copy copy_count entries from source directory item to dest buffer (creating new item if needed) */
+static void leaf_copy_dir_entries (reiserfs_filsys_t fs,
+			           struct buffer_info * dest_bi, struct buffer_head * source, 
+				   int last_first, int item_num, int from, int copy_count)
+{
+    struct buffer_head * dest = dest_bi->bi_bh;
+    int item_num_in_dest;		/* either the number of target item,
+					   or if we must create a new item,
+					   the number of the item we will
+					   create it next to */
+    struct item_head * ih;
+    struct reiserfs_de_head * deh;
+    int copy_records_len;			/* length of all records in item to be copied */
+    char * records;
+
+    ih = B_N_PITEM_HEAD (source, item_num);
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (!I_IS_DIRECTORY_ITEM (ih))
+	reiserfs_panic(0, "vs-10000: leaf_copy_dir_entries: item must be directory item");
+#endif
+
+    /* length of all record to be copied and first byte of the last of them */
+    deh = B_I_DEH (source, ih);
+    if (copy_count) {
+	copy_records_len = (from ? deh[from - 1].deh_location : ih->ih_item_len) - 
+	    deh[from + copy_count - 1].deh_location;
+	records = source->b_data + ih->ih_item_location + deh[from + copy_count - 1].deh_location;
+    } else {
+	copy_records_len = 0;
+	records = 0;
+    }
+
+    /* when copy last to first, dest buffer can contain 0 items */
+    item_num_in_dest = (last_first == LAST_TO_FIRST) ? (( B_NR_ITEMS(dest) ) ? 0 : -1) : (B_NR_ITEMS(dest) - 1);
+
+    /* if there are no items in dest or the first/last item in dest is not item of the same directory */
+    if ( (item_num_in_dest == - 1) ||
+#ifndef FU //REISERFS_FSCK
+	 (last_first == FIRST_TO_LAST && are_items_mergeable (B_N_PITEM_HEAD (dest, item_num_in_dest), ih, dest->b_size) == 0) ||
+	 (last_first == LAST_TO_FIRST && are_items_mergeable (ih, B_N_PITEM_HEAD (dest, item_num_in_dest), dest->b_size) == 0)) {
+#else
+	(last_first == FIRST_TO_LAST && get_offset (&ih->ih_key) == DOT_OFFSET) ||
+	    (last_first == LAST_TO_FIRST && not_of_one_file (&ih->ih_key, B_N_PKEY (dest, item_num_in_dest)))) {
+#endif
+	/* create new item in dest */
+	struct item_head new_ih;
+
+	/* form item header */
+	memcpy (&new_ih.ih_key, &ih->ih_key, KEY_SIZE);
+
+	/* calculate item len */
+	new_ih.ih_item_len = cpu_to_le16 (DEH_SIZE * copy_count + copy_records_len);
+	set_entry_count (&new_ih, 0);
+    
+	if (last_first == LAST_TO_FIRST) {
+	    /* form key by the following way */
+	    if (from < ih_entry_count (ih)) {
+		new_ih.ih_key.u.k_offset_v1.k_offset = deh[from].deh_offset;
+		new_ih.ih_key.u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS;
+		/*memcpy (&new_ih.ih_key.k_offset, &deh[from].deh_offset, SHORT_KEY_SIZE);*/
+	    } else {
+		/* no entries will be copied to this item in this function */
+		new_ih.ih_key.u.k_offset_v1.k_offset = MAX_KEY1_OFFSET;
+		/* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */
+		new_ih.ih_key.u.k_offset_v1.k_uniqueness = DIRENTRY_UNIQUENESS/*TYPE_DIRECTORY_MAX*/;
+	    }
+	}
+	set_key_format (&new_ih, ih_key_format (ih));
+	new_ih.ih_format.fsck_need = ih->ih_format.fsck_need;
+    
+	/* insert item into dest buffer */
+	leaf_insert_into_buf (fs, dest_bi, (last_first == LAST_TO_FIRST) ? 0 : B_NR_ITEMS(dest), &new_ih, NULL, 0);
+    } else {
+	/* prepare space for entries */
+	leaf_paste_in_buffer (fs, dest_bi, (last_first==FIRST_TO_LAST) ? (B_NR_ITEMS(dest) - 1) : 0, USHRT_MAX,
+			      DEH_SIZE * copy_count + copy_records_len, records, 0);
+    }
+  
+    item_num_in_dest = (last_first == FIRST_TO_LAST) ? (B_NR_ITEMS(dest)-1) : 0;
+  
+    leaf_paste_entries (dest_bi->bi_bh, item_num_in_dest,
+			(last_first == FIRST_TO_LAST) ? ih_entry_count (B_N_PITEM_HEAD (dest, item_num_in_dest)) : 0,
+			copy_count, deh + from, records,
+			DEH_SIZE * copy_count + copy_records_len
+	);
+}
+
+
+/* Copy the first (if last_first == FIRST_TO_LAST) or last (last_first == LAST_TO_FIRST) item or 
+   part of it or nothing (see the return 0 below) from SOURCE to the end 
+   (if last_first) or beginning (!last_first) of the DEST */
+/* returns 1 if anything was copied, else 0 */
+static int leaf_copy_boundary_item (reiserfs_filsys_t fs,
+                                    struct buffer_info * dest_bi, struct buffer_head * src, int last_first,
+				    int bytes_or_entries)
+{
+    struct buffer_head * dest = dest_bi->bi_bh;
+    int dest_nr_item, src_nr_item; /* number of items in the source and destination buffers */
+    struct item_head * ih;
+    struct item_head * dih;
+  
+    dest_nr_item = B_NR_ITEMS(dest);
+  
+    if ( last_first == FIRST_TO_LAST ) {
+	/* if ( DEST is empty or first item of SOURCE and last item of DEST are the items of different objects
+	   or of different types ) then there is no need to treat this item differently from the other items
+	   that we copy, so we return */
+	ih = B_N_PITEM_HEAD (src, 0);
+	dih = B_N_PITEM_HEAD (dest, dest_nr_item - 1);
+#ifndef FU //REISERFS_FSCK
+	if (!dest_nr_item || (are_items_mergeable (dih, ih, src->b_size) == 0))
+#else
+	    if (!dest_nr_item || (!is_left_mergeable (ih, src->b_size)))
+#endif
+		/* there is nothing to merge */
+		return 0;
+      
+#ifdef CONFIG_REISERFS_CHECK
+	if ( ! ih->ih_item_len )
+	    reiserfs_panic (0, "vs-10010: leaf_copy_boundary_item: item can not have empty dynamic length");
+#endif
+      
+	if ( I_IS_DIRECTORY_ITEM(ih) ) {
+	    if ( bytes_or_entries == -1 )
+		/* copy all entries to dest */
+		bytes_or_entries = ih_entry_count(ih);
+	    leaf_copy_dir_entries (fs, dest_bi, src, FIRST_TO_LAST, 0, 0, bytes_or_entries);
+	    return 1;
+	}
+      
+	/* copy part of the body of the first item of SOURCE to the end of the body of the last item of the DEST
+	   part defined by 'bytes_or_entries'; if bytes_or_entries == -1 copy whole body; don't create new item header
+	*/
+	if ( bytes_or_entries == -1 )
+	    bytes_or_entries = ih->ih_item_len;
+
+#ifdef CONFIG_REISERFS_CHECK
+	else {
+	    if (bytes_or_entries == ih->ih_item_len && I_IS_INDIRECT_ITEM(ih))
+		if (ih_free_space (ih))
+		    reiserfs_panic (0, "vs-10020: leaf_copy_boundary_item: "
+				    "last unformatted node must be filled entirely (free_space=%d)",
+				    ih_free_space (ih));
+	}
+#endif
+      
+	/* merge first item (or its part) of src buffer with the last
+	   item of dest buffer. Both are of the same file */
+	leaf_paste_in_buffer (fs, dest_bi,
+			      dest_nr_item - 1, dih->ih_item_len, bytes_or_entries, B_I_PITEM(src,ih), 0
+	    );
+      
+	if (I_IS_INDIRECT_ITEM(dih)) {
+#ifdef CONFIG_REISERFS_CHECK
+	    if (ih_free_space (dih))
+		reiserfs_panic (0, "vs-10030: leaf_copy_boundary_item: " 
+				"merge to left: last unformatted node of non-last indirect item must be filled entirely (free_space=%d)",
+				ih_free_space (dih));
+#endif
+	    if (bytes_or_entries == ih->ih_item_len)
+		//dih->u.ih_free_space = ih->u.ih_free_space;
+		set_free_space (dih, ih_free_space (ih));
+	}
+    
+	return 1;
+    }
+  
+
+    /* copy boundary item to right (last_first == LAST_TO_FIRST) */
+
+    /* ( DEST is empty or last item of SOURCE and first item of DEST
+       are the items of different object or of different types )
+    */
+    src_nr_item = B_NR_ITEMS (src);
+    ih = B_N_PITEM_HEAD (src, src_nr_item - 1);
+    dih = B_N_PITEM_HEAD (dest, 0);
+
+#ifndef FU //REISERFS_FSCK
+    if (!dest_nr_item || are_items_mergeable (ih, dih, src->b_size) == 0)
+#else
+	if (!dest_nr_item || !is_left_mergeable (dih, src->b_size))
+#endif
+	    return 0;
+  
+    if ( I_IS_DIRECTORY_ITEM(ih)) {
+	if ( bytes_or_entries == -1 )
+	    /* bytes_or_entries = entries number in last item body of SOURCE */
+	    bytes_or_entries = ih_entry_count(ih);
+    
+	leaf_copy_dir_entries (fs, dest_bi, src, LAST_TO_FIRST, src_nr_item - 1, ih_entry_count(ih) - bytes_or_entries, 
+			       bytes_or_entries);
+	return 1;
+    }
+
+    /* copy part of the body of the last item of SOURCE to the begin of the body of the first item of the DEST;
+       part defined by 'bytes_or_entries'; if byte_or_entriess == -1 copy whole body; change first item key of the DEST;
+       don't create new item header
+    */
+  
+#ifdef CONFIG_REISERFS_CHECK  
+    if (I_IS_INDIRECT_ITEM(ih) && ih_free_space (ih))
+	reiserfs_panic (0, "vs-10040: leaf_copy_boundary_item: " 
+			"merge to right: last unformatted node of non-last indirect item must be filled entirely (free_space=%d)",
+			ih_free_space (ih));
+#endif
+
+    if ( bytes_or_entries == -1 ) {
+	/* bytes_or_entries = length of last item body of SOURCE */
+	bytes_or_entries = ih->ih_item_len;
+
+#ifdef CONFIG_REISERFS_CHECK
+	if (get_offset (&dih->ih_key) != get_offset (&ih->ih_key) + get_bytes_number (ih, src->b_size))/*I_DNM_DATA_LEN(ih))*/
+	    reiserfs_panic (0, "vs-10050: leaf_copy_boundary_item: right item offset (%lu) must not be (%lu),it must be %lu",
+			    get_offset (&dih->ih_key), get_offset (&ih->ih_key) + get_bytes_number (ih, src->b_size), get_offset (&dih->ih_key));
+#endif
+
+	/* change first item key of the DEST */
+	//dih->ih_key.k_offset = ih->ih_key.k_offset;
+	set_offset (key_format (&dih->ih_key), &dih->ih_key, get_offset (&ih->ih_key));
+
+	/* item becomes non-mergeable */
+	/* or mergeable if left item was */
+	//dih->ih_key.k_uniqueness = ih->ih_key.k_uniqueness;
+	set_type (key_format (&dih->ih_key), &dih->ih_key, get_type (&ih->ih_key));
+    } else {
+	/* merge to right only part of item */
+#ifdef CONFIG_REISERFS_CHECK
+	if ( ih->ih_item_len <= bytes_or_entries )
+	    reiserfs_panic (0, "vs-10060: leaf_copy_boundary_item: no so much bytes %lu (needed %lu)",
+			    ih->ih_item_len, bytes_or_entries);
+#endif
+    
+	/* change first item key of the DEST */
+	if ( I_IS_DIRECT_ITEM(dih) ) {
+#ifdef CONFIG_REISERFS_CHECK
+	    if (get_offset (&dih->ih_key) <= (unsigned long)bytes_or_entries)
+		reiserfs_panic (0, "vs-10070: leaf_copy_boundary_item: dih->ih_key.k_offset(%d) <= bytes_or_entries(%d)", 
+				get_offset (&dih->ih_key), bytes_or_entries);
+#endif
+	    //dih->ih_key.k_offset -= bytes_or_entries;
+	    set_offset (key_format (&dih->ih_key), &dih->ih_key, get_offset (&dih->ih_key) - bytes_or_entries);
+	} else {
+#ifdef CONFIG_REISERFS_CHECK
+	    if (get_offset (&dih->ih_key) <=(bytes_or_entries/UNFM_P_SIZE)*dest->b_size )
+		reiserfs_panic (0, "vs-10080: leaf_copy_boundary_item: dih->ih_key.k_offset(%d) <= bytes_or_entries(%d)",
+				get_offset (&dih->ih_key), (bytes_or_entries/UNFM_P_SIZE)*dest->b_size);
+#endif
+	    //dih->ih_key.k_offset -= ((bytes_or_entries/UNFM_P_SIZE)*dest->b_size);
+	    set_offset (key_format (&dih->ih_key), &dih->ih_key, 
+			get_offset (&dih->ih_key) - ((bytes_or_entries/UNFM_P_SIZE)*dest->b_size));
+	}
+    }
+  
+    leaf_paste_in_buffer (fs, dest_bi, 0, 0, bytes_or_entries, B_I_PITEM(src,ih) + ih->ih_item_len - bytes_or_entries, 0);
+    return 1;
+}
+
+
+/* copy cpy_mun items from buffer src to buffer dest
+ * last_first == FIRST_TO_LAST means, that we copy cpy_num  items beginning from first-th item in src to tail of dest
+ * last_first == LAST_TO_FIRST means, that we copy cpy_num  items beginning from first-th item in src to head of dest
+ */
+static void leaf_copy_items_entirely (reiserfs_filsys_t fs, struct buffer_info * dest_bi, 
+                                      struct buffer_head * src, int last_first,
+				      int first, int cpy_num)
+{
+    struct buffer_head * dest;
+    int nr;
+    int dest_before;
+    int last_loc, last_inserted_loc, location;
+    int i, j;
+    struct block_head * blkh;
+    struct item_head * ih;
+
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (last_first != LAST_TO_FIRST  && last_first != FIRST_TO_LAST) 
+	reiserfs_panic (0, "vs-10090: leaf_copy_items_entirely: bad last_first parameter %d", last_first);
+
+    if (B_NR_ITEMS (src) - first < cpy_num)
+	reiserfs_panic (0, "vs-10100: leaf_copy_items_entirely: too few items in source %d, required %d from %d",
+			B_NR_ITEMS(src), cpy_num, first);
+
+    if (cpy_num < 0)
+	reiserfs_panic (0, "vs-10110: leaf_copy_items_entirely: can not copy negative amount of items");
+
+    if ( ! dest_bi )
+	reiserfs_panic (0, "vs-10120: leaf_copy_items_entirely: can not copy negative amount of items");
+#endif
+
+    dest = dest_bi->bi_bh;
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( ! dest )
+	reiserfs_panic (0, "vs-10130: leaf_copy_items_entirely: can not copy negative amount of items");
+#endif
+
+    if (cpy_num == 0)
+	return;
+
+    nr = (blkh = B_BLK_HEAD(dest))->blk_nr_item;
+  
+    /* we will insert items before 0-th or nr-th item in dest buffer. It depends of last_first parameter */
+    dest_before = (last_first == LAST_TO_FIRST) ? 0 : nr;
+
+    /* location of head of first new item */
+    ih = B_N_PITEM_HEAD (dest, dest_before);
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (blkh->blk_free_space < cpy_num * IH_SIZE) {
+	reiserfs_panic (0, "vs-10140: leaf_copy_items_entirely: not enough free space for headers %d (needed %d)",
+			blkh->blk_free_space, cpy_num * IH_SIZE);
+    }
+#endif
+
+    /* prepare space for headers */
+    memmove (ih + cpy_num, ih, (nr-dest_before) * IH_SIZE);
+
+    /* copy item headers */
+    memcpy (ih, B_N_PITEM_HEAD (src, first), cpy_num * IH_SIZE);
+
+    blkh->blk_free_space -= IH_SIZE * cpy_num;
+
+    /* location of unmovable item */
+    j = location = (dest_before == 0) ? dest->b_size : (ih-1)->ih_item_location;
+    for (i = dest_before; i < nr + cpy_num; i ++)
+	ih[i-dest_before].ih_item_location =
+	    (location -= ih[i-dest_before].ih_item_len);
+
+    /* prepare space for items */
+    last_loc = ih[nr+cpy_num-1-dest_before].ih_item_location;
+    last_inserted_loc = ih[cpy_num-1].ih_item_location;
+
+    /* check free space */
+#ifdef CONFIG_REISERFS_CHECK
+    if (blkh->blk_free_space < j - last_inserted_loc) {
+	reiserfs_panic (0, "vs-10150: leaf_copy_items_entirely: not enough free space for items %d (needed %d)",
+			blkh->blk_free_space, j - last_inserted_loc);
+    }
+#endif
+
+    memmove (dest->b_data + last_loc,
+	     dest->b_data + last_loc + j - last_inserted_loc,
+	     last_inserted_loc - last_loc);
+
+    /* copy items */
+    memcpy (dest->b_data + last_inserted_loc, B_N_PITEM(src,(first + cpy_num - 1)),
+	    j - last_inserted_loc);
+
+    /* sizes, item number */
+    blkh->blk_nr_item += cpy_num;  
+    blkh->blk_free_space -= j - last_inserted_loc;
+  
+    mark_buffer_dirty (dest);
+
+    if (dest_bi->bi_parent) {
+#ifdef CONFIG_REISERFS_CHECK
+	if (B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_block_number != dest->b_blocknr) {
+	    reiserfs_panic (0, "vs-10160: leaf_copy_items_entirely: "
+			    "block number in bh does not match to field in disk_child structure %lu and %lu",
+			    dest->b_blocknr, B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_block_number);
+	}
+#endif
+	B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position)->dc_size +=
+	    j - last_inserted_loc + IH_SIZE * cpy_num;
+    
+	mark_buffer_dirty(dest_bi->bi_parent);
+    }
+}
+
+
+/* This function splits the (liquid) item into two items (useful when
+   shifting part of an item into another node.) */
+static void leaf_item_bottle (reiserfs_filsys_t fs,
+			      struct buffer_info * dest_bi, struct buffer_head * src, int last_first,
+			      int item_num, int cpy_bytes)
+{
+    struct buffer_head * dest = dest_bi->bi_bh;
+    struct item_head * ih;
+  
+#ifdef CONFIG_REISERFS_CHECK  
+    if ( cpy_bytes == -1 ) 
+	reiserfs_panic (0, "vs-10170: leaf_item_bottle: bytes == - 1 means: do not split item");
+#endif
+
+    if ( last_first == FIRST_TO_LAST ) {
+	/* if ( if item in position item_num in buffer SOURCE is directory item ) */
+	if (I_IS_DIRECTORY_ITEM(ih = B_N_PITEM_HEAD(src,item_num)))
+	    leaf_copy_dir_entries (fs, dest_bi, src, FIRST_TO_LAST, item_num, 0, cpy_bytes);
+	else {
+	    struct item_head n_ih;
+      
+	    /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST 
+	       part defined by 'cpy_bytes'; create new item header; change old item_header (????);
+	       n_ih = new item_header;
+	    */
+	    memcpy (&n_ih, ih, IH_SIZE);
+	    n_ih.ih_item_len = cpy_bytes;
+	    if (I_IS_INDIRECT_ITEM(ih)) {
+#ifdef CONFIG_REISERFS_CHECK
+		if (cpy_bytes == ih->ih_item_len && ih_free_space (ih))
+		    reiserfs_panic (0, "vs-10180: leaf_item_bottle: " 
+				    "when whole indirect item is bottle to left neighbor, it must have free_space==0 (not %lu)",
+				    ih_free_space (ih));
+#endif
+		//n_ih.u.ih_free_space = 0;
+		set_free_space (&n_ih, 0);;
+	    }
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if (is_left_mergeable (ih, src->b_size))
+		reiserfs_panic (0, "vs-10190: leaf_item_bottle: item %h should not be mergeable", ih);
+#endif
+	    //n_ih.ih_version = ih->ih_version;
+	    set_key_format (&n_ih, ih_key_format (ih));
+	    n_ih.ih_format.fsck_need = ih->ih_format.fsck_need;
+	    leaf_insert_into_buf (fs, dest_bi, B_NR_ITEMS(dest), &n_ih, B_N_PITEM (src, item_num), 0);
+	}
+    } else {
+	/*  if ( if item in position item_num in buffer SOURCE is directory item ) */
+	if (I_IS_DIRECTORY_ITEM(ih = B_N_PITEM_HEAD (src, item_num)))
+	    leaf_copy_dir_entries (fs, dest_bi, src, LAST_TO_FIRST, item_num, ih_entry_count(ih) - cpy_bytes, cpy_bytes);
+	else {
+	    struct item_head n_ih;
+      
+	    /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST 
+	       part defined by 'cpy_bytes'; create new item header;
+	       n_ih = new item_header;
+	    */
+	    memcpy (&n_ih, ih, SHORT_KEY_SIZE);
+      
+	    if (I_IS_DIRECT_ITEM(ih)) {
+		//n_ih.ih_key.k_offset = ih->ih_key.k_offset + ih->ih_item_len - cpy_bytes;
+		set_offset (key_format (&ih->ih_key), &n_ih.ih_key, get_offset (&ih->ih_key) + ih->ih_item_len - cpy_bytes);
+		//n_ih.ih_key.k_uniqueness = TYPE_DIRECT;
+		set_type (key_format (&ih->ih_key), &n_ih.ih_key, TYPE_DIRECT);
+		//n_ih.u.ih_free_space = USHRT_MAX;
+		set_free_space (&n_ih, USHRT_MAX);
+	    } else {
+		/* indirect item */
+#ifdef CONFIG_REISERFS_CHECK
+		if (!cpy_bytes && ih_free_space (ih))
+		    reiserfs_panic (0, "vs-10200: leaf_item_bottle: ih->ih_free_space must be 0 when indirect item will be appended");
+#endif
+		//n_ih.ih_key.k_offset = ih->ih_key.k_offset + (ih->ih_item_len - cpy_bytes) / UNFM_P_SIZE * dest->b_size;
+		set_offset (key_format (&ih->ih_key), &n_ih.ih_key,
+			    get_offset (&ih->ih_key) + (ih->ih_item_len - cpy_bytes) / UNFM_P_SIZE * dest->b_size);
+		//n_ih.ih_key.k_uniqueness = TYPE_INDIRECT;
+		set_type (key_format (&ih->ih_key), &n_ih.ih_key, TYPE_INDIRECT);
+		//n_ih.u.ih_free_space = ih->u.ih_free_space;
+		set_free_space (&n_ih, ih_free_space (ih));
+	    }
+      
+	    /* set item length */
+	    n_ih.ih_item_len = cpu_to_le16 (cpy_bytes);
+	    //n_ih.ih_version = ih->ih_version;
+	    set_key_format (&n_ih, ih_key_format (ih));
+	    n_ih.ih_format.fsck_need = ih->ih_format.fsck_need;
+	    leaf_insert_into_buf (fs, dest_bi, 0, &n_ih, B_N_PITEM(src,item_num) + ih->ih_item_len - cpy_bytes, 0);
+	}
+    }
+}
+
+
+/* If cpy_bytes equals minus one than copy cpy_num whole items from SOURCE to DEST.
+   If cpy_bytes not equal to minus one than copy cpy_num-1 whole items from SOURCE to DEST.
+   From last item copy cpy_num bytes for regular item and cpy_num directory entries for
+   directory item. */
+static int leaf_copy_items (reiserfs_filsys_t fs,
+                            struct buffer_info * dest_bi, struct buffer_head * src,
+			    int last_first, int cpy_num,
+			    int cpy_bytes)
+{
+    struct buffer_head * dest;
+    int pos, i, src_nr_item, bytes;
+
+    dest = dest_bi->bi_bh;
+#ifdef CONFIG_REISERFS_CHECK
+    if (!dest || !src)
+	reiserfs_panic (0, "vs-10210: leaf_copy_items: !dest || !src");
+  
+    if ( last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST )
+	reiserfs_panic (0, "vs-10220: leaf_copy_items: last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST");
+
+    if ( B_NR_ITEMS(src) < cpy_num )
+	reiserfs_panic (0, "vs-10230: leaf_copy_items: No enough items: %d, required %d", B_NR_ITEMS(src), cpy_num);
+
+    if ( cpy_num < 0 )
+	reiserfs_panic (0, "vs-10240: leaf_copy_items: cpy_num < 0 (%d)", cpy_num);
+#endif
+
+    if ( cpy_num == 0 )
+	return 0;
+ 
+    if ( last_first == FIRST_TO_LAST ) {
+	/* copy items to left */
+	pos = 0;
+	if ( cpy_num == 1 )
+	    bytes = cpy_bytes;
+	else
+	    bytes = -1;
+   
+	/* copy the first item or it part or nothing to the end of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,0,bytes)) */
+	i = leaf_copy_boundary_item (fs, dest_bi, src, FIRST_TO_LAST, bytes);
+	cpy_num -= i;
+	if ( cpy_num == 0 )
+	    return i;
+	pos += i;
+	if ( cpy_bytes == -1 )
+	    /* copy first cpy_num items starting from position 'pos' of SOURCE to end of DEST */
+	    leaf_copy_items_entirely(fs, dest_bi, src, FIRST_TO_LAST, pos, cpy_num);
+	else {
+	    /* copy first cpy_num-1 items starting from position 'pos-1' of the SOURCE to the end of the DEST */
+	    leaf_copy_items_entirely(fs, dest_bi, src, FIRST_TO_LAST, pos, cpy_num-1);
+	     
+	    /* copy part of the item which number is cpy_num+pos-1 to the end of the DEST */
+	    leaf_item_bottle (fs, dest_bi, src, FIRST_TO_LAST, cpy_num+pos-1, cpy_bytes);
+	} 
+    } else {
+	/* copy items to right */
+	src_nr_item = B_NR_ITEMS (src);
+	if ( cpy_num == 1 )
+	    bytes = cpy_bytes;
+	else
+	    bytes = -1;
+   
+	/* copy the last item or it part or nothing to the begin of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,1,bytes)); */
+	i = leaf_copy_boundary_item (fs, dest_bi, src, LAST_TO_FIRST, bytes);
+   
+	cpy_num -= i;
+	if ( cpy_num == 0 )
+	    return i;
+   
+	pos = src_nr_item - cpy_num - i;
+	if ( cpy_bytes == -1 ) {
+	    /* starting from position 'pos' copy last cpy_num items of SOURCE to begin of DEST */
+	    leaf_copy_items_entirely(fs, dest_bi, src, LAST_TO_FIRST, pos, cpy_num);
+	} else {
+	    /* copy last cpy_num-1 items starting from position 'pos+1' of the SOURCE to the begin of the DEST; */
+	    leaf_copy_items_entirely(fs, dest_bi, src, LAST_TO_FIRST, pos+1, cpy_num-1);
+
+	    /* copy part of the item which number is pos to the begin of the DEST */
+	    leaf_item_bottle (fs, dest_bi, src, LAST_TO_FIRST, pos, cpy_bytes);
+	}
+    }
+    return i;
+}
+
+
+/* there are types of coping: from S[0] to L[0], from S[0] to R[0],
+   from R[0] to L[0]. for each of these we have to define parent and
+   positions of destination and source buffers */
+static void leaf_define_dest_src_infos (int shift_mode, struct tree_balance * tb, struct buffer_info * dest_bi,
+					struct buffer_info * src_bi, int * first_last,
+					struct buffer_head * Snew)
+{
+#ifdef CONFIG_REISERFS_CHECK
+    memset (dest_bi, 0, sizeof (struct buffer_info));
+    memset (src_bi, 0, sizeof (struct buffer_info));
+#endif
+
+    /* define dest, src, dest parent, dest position */
+    switch (shift_mode) {
+    case LEAF_FROM_S_TO_L:    /* it is used in leaf_shift_left */
+	src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path);
+	src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
+	src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0);	/* src->b_item_order */
+	dest_bi->bi_bh = tb->L[0];
+	dest_bi->bi_parent = tb->FL[0];
+	dest_bi->bi_position = get_left_neighbor_position (tb, 0);
+	*first_last = FIRST_TO_LAST;
+	break;
+
+    case LEAF_FROM_S_TO_R:  /* it is used in leaf_shift_right */
+	src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path);
+	src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
+	src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0);
+	dest_bi->bi_bh = tb->R[0];
+	dest_bi->bi_parent = tb->FR[0];
+	dest_bi->bi_position = get_right_neighbor_position (tb, 0);
+	*first_last = LAST_TO_FIRST;
+	break;
+
+    case LEAF_FROM_R_TO_L:  /* it is used in balance_leaf_when_delete */
+	src_bi->bi_bh = tb->R[0];
+	src_bi->bi_parent = tb->FR[0];
+	src_bi->bi_position = get_right_neighbor_position (tb, 0);
+	dest_bi->bi_bh = tb->L[0];
+	dest_bi->bi_parent = tb->FL[0];
+	dest_bi->bi_position = get_left_neighbor_position (tb, 0);
+	*first_last = FIRST_TO_LAST;
+	break;
+    
+    case LEAF_FROM_L_TO_R:  /* it is used in balance_leaf_when_delete */
+	src_bi->bi_bh = tb->L[0];
+	src_bi->bi_parent = tb->FL[0];
+	src_bi->bi_position = get_left_neighbor_position (tb, 0);
+	dest_bi->bi_bh = tb->R[0];
+	dest_bi->bi_parent = tb->FR[0];
+	dest_bi->bi_position = get_right_neighbor_position (tb, 0);
+	*first_last = LAST_TO_FIRST;
+	break;
+
+    case LEAF_FROM_S_TO_SNEW:
+	src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path);
+	src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
+	src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0);
+	dest_bi->bi_bh = Snew;
+	dest_bi->bi_parent = 0;
+	dest_bi->bi_position = 0;
+	*first_last = LAST_TO_FIRST;
+	break;
+    
+    default:
+	reiserfs_panic (0, "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)", shift_mode);
+    }
+#ifdef CONFIG_REISERFS_CHECK
+    if (src_bi->bi_bh == 0 || dest_bi->bi_bh == 0) {
+	reiserfs_panic (0, "vs-10260: leaf_define_dest_src_etc: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly",
+			shift_mode, src_bi->bi_bh, dest_bi->bi_bh);
+    }
+#endif
+}
+
+
+
+
+/* copy mov_num items and mov_bytes of the (mov_num-1)th item to
+   neighbor. Delete them from source */
+int leaf_move_items (int shift_mode, struct tree_balance * tb, 
+		     int mov_num, int mov_bytes, struct buffer_head * Snew)
+{
+    int ret_value;
+    struct buffer_info dest_bi, src_bi;
+    int first_last;
+
+    leaf_define_dest_src_infos (shift_mode, tb, &dest_bi, &src_bi, &first_last, Snew);
+
+    ret_value = leaf_copy_items (tb->tb_sb, &dest_bi, src_bi.bi_bh, first_last, mov_num, mov_bytes);
+
+    leaf_delete_items (tb->tb_sb, &src_bi, first_last, (first_last == FIRST_TO_LAST) ? 0 : 
+		       (B_NR_ITEMS(src_bi.bi_bh) - mov_num), mov_num, mov_bytes);
+
+  
+    return ret_value;
+}
+
+
+/* Shift shift_num items (and shift_bytes of last shifted item if shift_bytes != -1)
+   from S[0] to L[0] and replace the delimiting key */
+int leaf_shift_left (struct tree_balance * tb, int shift_num, int shift_bytes)
+{
+    struct buffer_head * S0 = PATH_PLAST_BUFFER (tb->tb_path);
+    int i;
+
+    /* move shift_num (and shift_bytes bytes) items from S[0] to left neighbor L[0] */
+    i = leaf_move_items (LEAF_FROM_S_TO_L, tb, shift_num, shift_bytes, 0);
+
+    if ( shift_num ) {
+	if (B_NR_ITEMS (S0) == 0) { 
+	    /* everything is moved from S[0] */
+
+#ifdef CONFIG_REISERFS_CHECK
+	    if ( shift_bytes != -1 )
+		reiserfs_panic (tb->tb_sb, "vs-10270: leaf_shift_left: S0 is empty now, but shift_bytes != -1 (%d)", shift_bytes);
+
+	    if (init_mode == M_PASTE || init_mode == M_INSERT) {
+		print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "vs-10275");
+		reiserfs_panic (tb->tb_sb, "vs-10275: leaf_shift_left: balance condition corrupted (%c)", init_mode);
+	    }
+#endif
+
+	    if (PATH_H_POSITION (tb->tb_path, 1) == 0)
+		replace_key(tb->tb_sb, tb->CFL[0], tb->lkey[0], PATH_H_PPARENT (tb->tb_path, 0), 0);
+
+	} else {     
+	    /* replace lkey in CFL[0] by 0-th key from S[0]; */
+	    replace_key(tb->tb_sb, tb->CFL[0], tb->lkey[0], S0, 0);
+      
+#ifdef CONFIG_REISERFS_CHECK
+	    if (shift_bytes != -1 && !(I_IS_DIRECTORY_ITEM (B_N_PITEM_HEAD (S0, 0))
+				       && !ih_entry_count (B_N_PITEM_HEAD (S0, 0)))) {
+		if (!is_left_mergeable (B_N_PITEM_HEAD (S0, 0), S0->b_size)) {
+		    reiserfs_panic (tb->tb_sb, "vs-10280: leaf_shift_left: item must be mergeable");
+		}
+	    }
+#endif
+	}
+    }
+  
+    return i;
+}
+
+
+
+
+
+/* CLEANING STOPPED HERE */
+
+
+
+
+/* Shift shift_num (shift_bytes) items from S[0] to the right neighbor, and replace the delimiting key */
+int leaf_shift_right (struct tree_balance * tb, int shift_num, int shift_bytes)
+{
+    int ret_value;
+
+    /* move shift_num (and shift_bytes) items from S[0] to right neighbor R[0] */
+    ret_value = leaf_move_items (LEAF_FROM_S_TO_R, tb, shift_num, shift_bytes, 0);
+
+    /* replace rkey in CFR[0] by the 0-th key from R[0] */
+    if (shift_num) {
+	replace_key(tb->tb_sb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
+    }
+
+    return ret_value;
+}
+
+
+
+static void leaf_delete_items_entirely (struct super_block * sb,
+					/*struct reiserfs_transaction_handle *th,*/
+					struct buffer_info * bi,
+					int first,
+					int del_num);
+/*  If del_bytes == -1, starting from position 'first' delete del_num items in whole in buffer CUR.
+    If not. 
+    If last_first == 0. Starting from position 'first' delete del_num-1 items in whole. Delete part of body of
+    the first item. Part defined by del_bytes. Don't delete first item header
+    If last_first == 1. Starting from position 'first+1' delete del_num-1 items in whole. Delete part of body of
+    the last item . Part defined by del_bytes. Don't delete last item header.
+*/
+void leaf_delete_items (reiserfs_filsys_t fs,
+			struct buffer_info * cur_bi,
+			int last_first, 
+			int first, int del_num, int del_bytes)
+{
+    struct buffer_head * bh;
+    int item_amount = B_NR_ITEMS (bh = cur_bi->bi_bh);
+    
+#ifdef CONFIG_REISERFS_CHECK
+    if ( !bh )
+	reiserfs_panic (0, "leaf_delete_items: 10155: bh is not defined");
+    
+    if ( del_num < 0 )
+	reiserfs_panic (0, "leaf_delete_items: 10160: del_num can not be < 0. del_num==%d", del_num);
+    
+    if ( first < 0 || first + del_num > item_amount )
+	reiserfs_panic (0, "leaf_delete_items: 10165: invalid number of first item to be deleted (%d) or "
+			"no so much items (%d) to delete (only %d)", first, first + del_num, item_amount);
+#endif
+    
+    if ( del_num == 0 )
+	return;
+    
+    if ( first == 0 && del_num == item_amount && del_bytes == -1 ) {
+	make_empty_node (cur_bi);
+	mark_buffer_dirty (bh);
+	return;
+    }
+    
+    if ( del_bytes == -1 )
+	/* delete del_num items beginning from item in position first */
+	leaf_delete_items_entirely (fs, cur_bi, first, del_num);
+    else {
+	if ( last_first == FIRST_TO_LAST ) {
+	    /* delete del_num-1 items beginning from item in position first  */
+	    leaf_delete_items_entirely (fs, cur_bi, first, del_num-1);
+	    
+	    /* delete the part of the first item of the bh do not
+	       delete item header */
+	    leaf_cut_from_buffer (fs, cur_bi, 0, 0, del_bytes);
+	} else  {
+	    struct item_head * ih;
+	    int len;
+	    
+	    /* delete del_num-1 items beginning from item in position first+1  */
+	    leaf_delete_items_entirely (fs, cur_bi, first+1, del_num-1);
+	    
+	    if (I_IS_DIRECTORY_ITEM(ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh)-1))) 	/* the last item is directory  */
+	        /* len = numbers of directory entries in this item */
+	        len = ih_entry_count(ih);
+	    else
+		/* len = body len of item */
+ 	        len = ih->ih_item_len;
+	    
+	    /* delete the part of the last item of the bh 
+	       do not delete item header
+	    */
+	    leaf_cut_from_buffer (fs, cur_bi, B_NR_ITEMS(bh) - 1, len - del_bytes, del_bytes);
+	}
+    }
+}
+
+
+/* insert item into the leaf node in position before */
+void leaf_insert_into_buf (struct super_block * s,
+			   struct buffer_info * bi,
+			   int before,
+			   struct item_head * inserted_item_ih,
+			   const char * inserted_item_body,
+			   int zeros_number
+			   )
+{
+    struct buffer_head * bh = bi->bi_bh;
+    int nr;
+    struct block_head * blkh;
+    struct item_head * ih;
+    int i;
+    int last_loc, unmoved_loc;
+    char * to;
+
+    nr = (blkh = B_BLK_HEAD (bh))->blk_nr_item;
+
+#ifdef CONFIG_REISERFS_CHECK
+    /* check free space */
+    if (blkh->blk_free_space < inserted_item_ih->ih_item_len + IH_SIZE)
+	reiserfs_panic (0, "leaf_insert_into_buf: 10170: not enough free space: needed %d, available %d",
+			inserted_item_ih->ih_item_len + IH_SIZE, blkh->blk_free_space);
+    if (zeros_number > inserted_item_ih->ih_item_len)
+	reiserfs_panic (0, "vs-10172: leaf_insert_into_buf: zero number == %d, item length == %d", zeros_number, inserted_item_ih->ih_item_len);
+#endif /* CONFIG_REISERFS_CHECK */
+
+
+    /* get item new item must be inserted before */
+    ih = B_N_PITEM_HEAD (bh, before);
+
+    /* prepare space for the body of new item */
+    last_loc = nr ? ih[nr - before - 1].ih_item_location : bh->b_size;
+    unmoved_loc = before ? (ih-1)->ih_item_location : bh->b_size;
+
+    memmove (bh->b_data + last_loc - inserted_item_ih->ih_item_len, 
+	     bh->b_data + last_loc, unmoved_loc - last_loc);
+
+    to = bh->b_data + unmoved_loc - inserted_item_ih->ih_item_len;
+    memset (to, 0, zeros_number);
+    to += zeros_number;
+
+    /* copy body to prepared space */
+    if (inserted_item_body)
+	//if (mem_mode == REISERFS_USER_MEM)
+	//  copy_from_user (to, inserted_item_body, inserted_item_ih->ih_item_len - zeros_number);
+	//else {
+	memmove (to, inserted_item_body, inserted_item_ih->ih_item_len - zeros_number);
+    //}
+    else
+	memset(to, '\0', inserted_item_ih->ih_item_len - zeros_number);
+  
+    /* insert item header */
+    memmove (ih + 1, ih, IH_SIZE * (nr - before));
+    memmove (ih, inserted_item_ih, IH_SIZE);
+  
+    /* change locations */
+    for (i = before; i < nr + 1; i ++)
+	ih[i-before].ih_item_location =
+	    (unmoved_loc -= ih[i-before].ih_item_len);
+  
+    /* sizes, free space, item number */
+    blkh->blk_nr_item ++;
+    blkh->blk_free_space -= (IH_SIZE + inserted_item_ih->ih_item_len);
+
+    mark_buffer_dirty(bh) ;
+
+    if (bi->bi_parent) { 
+	B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size += (IH_SIZE + inserted_item_ih->ih_item_len);
+	mark_buffer_dirty(bi->bi_parent) ;
+    }
+
+    if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF)
+	reiserfs_panic ("leaf_insert_into_buf: bad leaf %lu: %b",
+			bh->b_blocknr, bh);
+}
+
+
+/* paste paste_size bytes to affected_item_num-th item. 
+   When item is a directory, this only prepare space for new entries */
+void leaf_paste_in_buffer (reiserfs_filsys_t fs,
+			   struct buffer_info * bi,
+			   int affected_item_num,
+			   int pos_in_item,
+			   int paste_size,
+			   const char * body,
+			   int zeros_number)
+{
+    struct buffer_head * bh = bi->bi_bh;
+    int nr;
+    struct block_head * blkh;
+    struct item_head * ih;
+    int i;
+    int last_loc, unmoved_loc;
+
+
+    nr = (blkh = B_BLK_HEAD(bh))->blk_nr_item;
+
+#ifdef CONFIG_REISERFS_CHECK
+    /* check free space */
+    if (blkh->blk_free_space < paste_size)
+	reiserfs_panic (th->t_super, "vs-10175: leaf_paste_in_buffer: "
+			"not enough free space: needed %d, available %d",
+			paste_size, blkh->blk_free_space);
+    if (zeros_number > paste_size) {
+	print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "10177");
+	reiserfs_panic (th->t_super, "vs-10177: leaf_paste_in_buffer: "
+			"zero number == %d, paste_size == %d", zeros_number, paste_size);
+    }
+#endif /* CONFIG_REISERFS_CHECK */
+
+
+    /* item to be appended */
+    ih = B_N_PITEM_HEAD(bh, affected_item_num);
+
+    last_loc = ih[nr - affected_item_num - 1].ih_item_location;
+    unmoved_loc = affected_item_num ? (ih-1)->ih_item_location : bh->b_size;  
+
+    /* prepare space */
+    memmove (bh->b_data + last_loc - paste_size, bh->b_data + last_loc,
+	     unmoved_loc - last_loc);
+
+
+    /* change locations */
+    for (i = affected_item_num; i < nr; i ++)
+	ih[i-affected_item_num].ih_item_location -= paste_size;
+
+    if ( body ) {
+	if (!I_IS_DIRECTORY_ITEM(ih)) {
+	    //if (mem_mode == REISERFS_USER_MEM) {
+	    //memset (bh->b_data + unmoved_loc - paste_size, 0, zeros_number);
+	    //copy_from_user (bh->b_data + unmoved_loc - paste_size + zeros_number, body, paste_size - zeros_number);
+	    //} else 
+	    {
+		if (!pos_in_item) {
+		    /* shift data to right */
+		    memmove (bh->b_data + ih->ih_item_location + paste_size, 
+			     bh->b_data + ih->ih_item_location, ih->ih_item_len);
+		    /* paste data in the head of item */
+		    memset (bh->b_data + ih->ih_item_location, 0, zeros_number);
+		    memcpy (bh->b_data + ih->ih_item_location + zeros_number, body, paste_size - zeros_number);
+		} else {
+		    memset (bh->b_data + unmoved_loc - paste_size, 0, zeros_number);
+		    memcpy (bh->b_data + unmoved_loc - paste_size + zeros_number, body, paste_size - zeros_number);
+		}
+	    }
+	}
+    }
+    else
+	memset(bh->b_data + unmoved_loc - paste_size,'\0',paste_size);
+
+    ih->ih_item_len += paste_size;
+
+    /* change free space */
+    blkh->blk_free_space -= paste_size;
+
+    mark_buffer_dirty(bh) ;
+
+    if (bi->bi_parent) { 
+	B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size += paste_size;
+	mark_buffer_dirty(bi->bi_parent);
+    }
+    if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF)
+	reiserfs_panic ("leaf_paste_in_buffer: bad leaf %lu: %b",
+			bh->b_blocknr, bh);
+}
+
+/* cuts DEL_COUNT entries beginning from FROM-th entry. Directory item
+   does not have free space, so it moves DEHs and remaining records as
+   necessary. Return value is size of removed part of directory item
+   in bytes. */
+static int leaf_cut_entries (struct buffer_head * bh,
+			     struct item_head * ih, 
+			     int from, int del_count)
+{
+    char * item;
+    struct reiserfs_de_head * deh;
+    int prev_record_offset;	/* offset of record, that is (from-1)th */
+    char * prev_record;		/* */
+    int cut_records_len;		/* length of all removed records */
+    int i;
+    int entry_count;
+
+
+    /* first byte of item */
+    item = bh->b_data + ih_location (ih);
+
+    /* entry head array */
+    deh = B_I_DEH (bh, ih);
+    entry_count = ih_entry_count (ih);
+
+    if (del_count == 0) {
+	int shift;
+	int last_location;
+
+	last_location = deh_location (deh + entry_count - 1);
+	shift = last_location - DEH_SIZE * entry_count;
+	
+	memmove (deh + entry_count, item + last_location,
+		 ih_item_len (ih) - last_location);
+	for (i = 0; i < entry_count; i ++)
+	    deh[i].deh_location = cpu_to_le16 (deh_location (deh + i) - shift);
+	return shift;
+    }
+
+    /* first byte of remaining entries, those are BEFORE cut entries
+       (prev_record) and length of all removed records (cut_records_len) */
+    prev_record_offset = (from ? deh[from - 1].deh_location : ih->ih_item_len);
+    cut_records_len = prev_record_offset/*from_record*/ - deh[from + del_count - 1].deh_location;
+    prev_record = item + prev_record_offset;
+
+
+    /* adjust locations of remaining entries */
+    for (i = ih_entry_count (ih) - 1; i > from + del_count - 1; i --)
+	deh[i].deh_location -= (DEH_SIZE * del_count);
+
+    for (i = 0; i < from; i ++)
+	deh[i].deh_location -= DEH_SIZE * del_count + cut_records_len;
+
+    set_entry_count (ih, ih_entry_count (ih) - del_count);
+
+    /* shift entry head array and entries those are AFTER removed entries */
+    memmove ((char *)(deh + from),
+	     deh + from + del_count, 
+	     prev_record - cut_records_len - (char *)(deh + from + del_count));
+  
+    /* shift records, those are BEFORE removed entries */
+    memmove (prev_record - cut_records_len - DEH_SIZE * del_count,
+	     prev_record, item + ih->ih_item_len - prev_record);
+
+    return DEH_SIZE * del_count + cut_records_len;
+}
+
+
+/*  when cut item is part of regular file
+        pos_in_item - first byte that must be cut
+        cut_size - number of bytes to be cut beginning from pos_in_item
+ 
+   when cut item is part of directory
+        pos_in_item - number of first deleted entry
+        cut_size - count of deleted entries
+    */
+void leaf_cut_from_buffer (reiserfs_filsys_t fs,
+			   struct buffer_info * bi, int cut_item_num,
+			   int pos_in_item, int cut_size)
+{
+    int nr;
+    struct buffer_head * bh = bi->bi_bh;
+    struct block_head * blkh;
+    struct item_head * ih;
+    int last_loc, unmoved_loc;
+    int i;
+
+    nr = (blkh = B_BLK_HEAD (bh))->blk_nr_item;
+
+    /* item head of truncated item */
+    ih = B_N_PITEM_HEAD (bh, cut_item_num);
+
+    if (I_IS_DIRECTORY_ITEM (ih)) {
+        /* first cut entry ()*/
+        cut_size = leaf_cut_entries (bh, ih, pos_in_item, cut_size);
+        if (pos_in_item == 0) {
+	        /* change key */
+#ifdef CONFIG_REISERFS_CHECK
+            if (cut_item_num)
+                reiserfs_panic (th->t_super, "leaf_cut_from_buffer: 10190: " 
+                    "when 0-th enrty of item is cut, that item must be first in the node, not %d-th", cut_item_num);
+#endif
+            /* change item key by key of first entry in the item */
+	    ih->ih_key.u.k_offset_v1.k_offset = B_I_DEH (bh, ih)->deh_offset;
+	    
+            /*memcpy (&ih->ih_key.k_offset, &(B_I_DEH (bh, ih)->deh_offset), SHORT_KEY_SIZE);*/
+	    }
+    } else {
+        /* item is direct or indirect */
+#ifdef CONFIG_REISERFS_CHECK
+        if (I_IS_STAT_DATA_ITEM (ih))
+	    reiserfs_panic (th->t_super, "leaf_cut_from_buffer: 10195: item is stat data");
+	
+        if (pos_in_item && pos_in_item + cut_size != ih->ih_item_len )
+            reiserfs_panic (th->t_super, "cut_from_buf: 10200: invalid offset (%lu) or trunc_size (%lu) or ih_item_len (%lu)",
+			    pos_in_item, cut_size, ih->ih_item_len);
+#endif
+
+        /* shift item body to left if cut is from the head of item */
+        if (pos_in_item == 0) {
+            memmove (bh->b_data + ih->ih_item_location, bh->b_data + ih->ih_item_location + cut_size,
+                ih->ih_item_len - cut_size);
+
+            /* change key of item */
+            if (I_IS_DIRECT_ITEM(ih)) {
+                //ih->ih_key.k_offset += cut_size;
+                set_offset (key_format (&ih->ih_key), &ih->ih_key, get_offset (&ih->ih_key) + cut_size);
+            } else {
+                //ih->ih_key.k_offset += (cut_size / UNFM_P_SIZE) * bh->b_size;
+                set_offset (key_format (&ih->ih_key), &ih->ih_key, 
+			    get_offset (&ih->ih_key) + (cut_size / UNFM_P_SIZE) * bh->b_size);
+#ifdef CONFIG_REISERFS_CHECK
+                if ( ih->ih_item_len == cut_size && ih_free_space (ih) )
+                    reiserfs_panic (th->t_super, "leaf_cut_from_buf: 10205: invalid ih_free_space (%lu)", ih_free_space (ih));
+#endif
+	        }
+	    }
+    }
+  
+
+    /* location of the last item */
+    last_loc = ih[nr - cut_item_num - 1].ih_item_location;
+
+    /* location of the item, which is remaining at the same place */
+    unmoved_loc = cut_item_num ? (ih-1)->ih_item_location : bh->b_size;
+
+
+    /* shift */
+    memmove (bh->b_data + last_loc + cut_size, bh->b_data + last_loc,
+	       unmoved_loc - last_loc - cut_size);
+
+    /* change item length */
+    ih->ih_item_len -= cut_size;
+  
+    if (I_IS_INDIRECT_ITEM(ih)) {
+        if (pos_in_item)
+            //ih->u.ih_free_space = 0;
+            set_free_space (ih, 0);
+    }
+
+    /* change locations */
+    for (i = cut_item_num; i < nr; i ++)
+        ih[i-cut_item_num].ih_item_location += cut_size;
+
+    /* size, free space */
+    blkh->blk_free_space += cut_size;
+
+    mark_buffer_dirty(bh);
+    
+    if (bi->bi_parent) { 
+      B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size -= cut_size; 
+      mark_buffer_dirty(bi->bi_parent);
+    }
+    if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF)
+	reiserfs_panic ("leaf_cut_from_buffer: bad leaf %lu: %b",
+			bh->b_blocknr, bh);
+}
+
+
+/* delete del_num items from buffer starting from the first'th item */
+static void leaf_delete_items_entirely (reiserfs_filsys_t fs,
+					struct buffer_info * bi,
+					int first, int del_num)
+{
+    struct buffer_head * bh = bi->bi_bh;
+    int nr;
+    int i, j;
+    int last_loc, last_removed_loc;
+    struct block_head * blkh;
+    struct item_head * ih;
+
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (bh == NULL)
+	reiserfs_panic (0, "leaf_delete_items_entirely: 10210: buffer is 0");
+
+    if (del_num < 0)
+	reiserfs_panic (0, "leaf_delete_items_entirely: 10215: del_num less than 0 (%d)", del_num);
+#endif /* CONFIG_REISERFS_CHECK */
+    
+    if (del_num == 0)
+	return;
+    
+    nr = (blkh = B_BLK_HEAD(bh))->blk_nr_item;
+
+#ifdef CONFIG_REISERFS_CHECK
+    if (first < 0 || first + del_num > nr)
+	reiserfs_panic (0, "leaf_delete_items_entirely: 10220: first=%d, number=%d, there is %d items", first, del_num, nr);
+#endif /* CONFIG_REISERFS_CHECK */
+
+    if (first == 0 && del_num == nr) {
+	/* this does not work */
+	make_empty_node (bi);
+	
+	mark_buffer_dirty(bh);
+	return;
+    }
+    
+    ih = B_N_PITEM_HEAD (bh, first);
+    
+    /* location of unmovable item */
+    j = (first == 0) ? bh->b_size : (ih-1)->ih_item_location;
+    
+    /* delete items */
+    last_loc = ih[nr-1-first].ih_item_location;
+    last_removed_loc = ih[del_num-1].ih_item_location;
+    
+    memmove (bh->b_data + last_loc + j - last_removed_loc,
+	     bh->b_data + last_loc, last_removed_loc - last_loc);
+    
+    /* delete item headers */
+    memmove (ih, ih + del_num, (nr - first - del_num) * IH_SIZE);
+    
+    /* change item location */
+    for (i = first; i < nr - del_num; i ++)
+	ih[i-first].ih_item_location += j - last_removed_loc;
+    
+    /* sizes, item number */
+    blkh->blk_nr_item -= del_num;
+    blkh->blk_free_space += j - last_removed_loc + IH_SIZE * del_num;
+    
+    mark_buffer_dirty(bh);
+    
+    if (bi->bi_parent) {
+	B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size -= j - last_removed_loc + IH_SIZE * del_num;
+	mark_buffer_dirty(bi->bi_parent);
+    }
+    if (who_is_this (bh->b_data, bh->b_size) != THE_LEAF)
+	reiserfs_panic ("leaf_delete_items_entirely: bad leaf %lu: %b",
+			bh->b_blocknr, bh);
+}
+
+
+
+
+
+/* paste new_entry_count entries (new_dehs, records) into position before to item_num-th item */
+void leaf_paste_entries (struct buffer_head * bh,
+			 int item_num, int before, int new_entry_count,
+			 struct reiserfs_de_head * new_dehs,
+			 const char * records, int paste_size)
+{
+    struct item_head * ih;
+    char * item;
+    struct reiserfs_de_head * deh;
+    char * insert_point;
+    int i, old_entry_num;
+
+    if (new_entry_count == 0)
+        return;
+
+    ih = B_N_PITEM_HEAD(bh, item_num);
+
+#ifdef CONFIG_REISERFS_CHECK
+    /* make sure, that item is directory, and there are enough records in it */
+    if (!I_IS_DIRECTORY_ITEM (ih))
+	reiserfs_panic (0, "leaf_paste_entries: 10225: item is not directory item");
+
+    if (ih_entry_count (ih) < before)
+	reiserfs_panic (0, "leaf_paste_entries: 10230: there are no entry we paste entries before. entry_count = %d, before = %d",
+			ih_entry_count (ih), before);
+#endif
+
+
+    /* first byte of dest item */
+    item = bh->b_data + ih->ih_item_location;
+
+    /* entry head array */
+    deh = B_I_DEH (bh, ih);
+
+    /* new records will be pasted at this point */
+    insert_point = item + (before ? deh[before - 1].deh_location : (ih->ih_item_len - paste_size));
+
+    /* adjust locations of records that will be AFTER new records */
+    for (i = ih_entry_count (ih) - 1; i >= before; i --)
+	deh[i].deh_location += DEH_SIZE * new_entry_count;
+
+    /* adjust locations of records that will be BEFORE new records */
+    for (i = 0; i < before; i ++)
+	deh[i].deh_location += paste_size;
+
+    old_entry_num = ih_entry_count (ih);
+    //I_ENTRY_COUNT(ih) += new_entry_count;
+    set_entry_count (ih, old_entry_num + new_entry_count);
+
+    /* prepare space for pasted records */
+    memmove (insert_point + paste_size, insert_point, item + (ih->ih_item_len - paste_size) - insert_point);
+
+    /* copy new records */
+    memcpy (insert_point + DEH_SIZE * new_entry_count, records,
+	    paste_size - DEH_SIZE * new_entry_count);
+  
+    /* prepare space for new entry heads */
+    deh += before;
+    memmove ((char *)(deh + new_entry_count), deh, insert_point - (char *)deh);
+
+    /* copy new entry heads */
+    deh = (struct reiserfs_de_head *)((char *)deh);
+    memcpy (deh, new_dehs, DEH_SIZE * new_entry_count);
+
+    /* set locations of new records */
+    for (i = 0; i < new_entry_count; i ++)
+	deh[i].deh_location +=
+	    (- new_dehs[new_entry_count - 1].deh_location + insert_point + DEH_SIZE * new_entry_count - item);
+
+
+    /* change item key if neccessary (when we paste before 0-th entry */
+    if (!before)
+	ih->ih_key.u.k_offset_v1.k_offset = new_dehs->deh_offset;
+
+
+#ifdef CONFIG_REISERFS_CHECK
+    {
+	int prev, next;
+	/* check record locations */
+	deh = B_I_DEH (bh, ih);
+	for (i = 0; i < ih_entry_count(ih); i ++) {
+	    next = (i < ih_entry_count(ih) - 1) ? deh[i + 1].deh_location : 0;
+	    prev = (i != 0) ? deh[i - 1].deh_location : 0;
+      
+	    if (prev && prev <= deh[i].deh_location)
+		reiserfs_warning ("vs-10240: leaf_paste_entries: directory item corrupted (%d %d)\n", prev, deh[i].deh_location);
+	    if (next && next >= deh[i].deh_location)
+		reiserfs_warning ("vs-10250: leaf_paste_entries: directory item corrupted (%d %d)\n", prev, deh[i].deh_location);
+	}
+    }
+#endif
+
+}
+
+
+
+/* wrappers for operations on one separated node */
+
+void delete_item (reiserfs_filsys_t fs,
+		  struct buffer_head * bh, int item_num)
+{
+    struct buffer_info bi;
+
+    bi.bi_bh = bh;
+    bi.bi_parent = 0;
+    bi.bi_position = 0;
+    leaf_delete_items_entirely (fs, &bi, item_num, 1);
+}
+
+
+void cut_entry (reiserfs_filsys_t fs, struct buffer_head * bh,
+		int item_num, int entry_num, int del_count)
+{
+    struct buffer_info bi;
+
+    bi.bi_bh = bh;
+    bi.bi_parent = 0;
+    bi.bi_position = 0;
+    leaf_cut_from_buffer (fs, &bi, item_num, entry_num, del_count);
+}
+
diff --git a/reiserfscore/node_formats.c b/reiserfscore/node_formats.c
new file mode 100644
index 0000000..43ed843
--- /dev/null
+++ b/reiserfscore/node_formats.c
@@ -0,0 +1,887 @@
+/*
+ *  Copyrright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+
+
+#include "includes.h"
+
+
+
+/* this only checks that the node looks like a correct leaf. Item
+   internals are not checked */
+static int is_correct_leaf (char * buf, int blocksize)
+{
+    struct block_head * blkh;
+    struct item_head * ih;
+    int used_space;
+    int prev_location;
+    int i;
+    int nr;
+
+    blkh = (struct block_head *)buf;
+    if (!is_leaf_block_head (buf))
+	return 0;
+
+    nr = le16_to_cpu (blkh->blk_nr_item);
+    if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN)))
+	/* item number is too big or too small */
+	return 0;
+
+    ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1;
+    used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location (ih));
+    if (used_space != blocksize - le16_to_cpu (blkh->blk_free_space))
+	/* free space does not match to calculated amount of use space */
+	return 0;
+
+    // FIXME: it is_leaf will hit performance too much - we may have
+    // return 1 here
+
+    /* check tables of item heads */
+    ih = (struct item_head *)(buf + BLKH_SIZE);
+    prev_location = blocksize;
+    for (i = 0; i < nr; i ++, ih ++) {
+	/* items of length are allowed - they may exist for short time
+           during balancing */
+	if (ih_location (ih) > blocksize || ih_location (ih) < IH_SIZE * nr)
+	    return 0;
+	if (/*ih_item_len (ih) < 1 ||*/ ih_item_len (ih) > MAX_ITEM_LEN (blocksize))
+	    return 0;
+	if (prev_location - ih_location (ih) != ih_item_len (ih))
+	    return 0;
+	prev_location = ih_location (ih);
+    }
+
+    // one may imagine much more checks
+    return 1;
+}
+
+
+/* returns 1 if buf looks like an internal node, 0 otherwise */
+static int is_correct_internal (char * buf, int blocksize)
+{
+    struct block_head * blkh;
+    int nr;
+    int used_space;
+
+    blkh = (struct block_head *)buf;
+
+    if (!is_internal_block_head (buf))
+	return 0;
+    
+    nr = le16_to_cpu (blkh->blk_nr_item);
+    if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE))
+	/* for internal which is not root we might check min number of keys */
+	return 0;
+
+    used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1);
+    if (used_space != blocksize - le16_to_cpu (blkh->blk_free_space))
+	return 0;
+
+    // one may imagine much more checks
+    return 1;
+}
+
+
+// make sure that bh contains formatted node of reiserfs tree of
+// 'level'-th level
+int is_tree_node (struct buffer_head * bh, int level)
+{
+    if (B_LEVEL (bh) != level)
+	return 0;
+    if (is_leaf_node (bh))
+	return is_correct_leaf (bh->b_data, bh->b_size);
+
+    return is_correct_internal (bh->b_data, bh->b_size);
+}
+
+
+static int is_desc_block (struct reiserfs_journal_desc * desc)
+{
+    if (!memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8) &&
+	le32_to_cpu (desc->j_len) > 0)
+	return 1;
+    return 0;
+}
+
+
+int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
+{
+    return (!strncmp (rs->s_v1.s_magic, REISERFS_SUPER_MAGIC_STRING, 
+		      strlen ( REISERFS_SUPER_MAGIC_STRING)));
+}
+
+
+int is_reiser2fs_magic_string (struct reiserfs_super_block * rs)
+{
+    return (!strncmp (rs->s_v1.s_magic, REISER2FS_SUPER_MAGIC_STRING, 
+		      strlen ( REISER2FS_SUPER_MAGIC_STRING)));
+}
+
+
+/* this one had signature in different place of the super_block
+   structure */
+int is_prejournaled_reiserfs (struct reiserfs_super_block * rs)
+{
+    return (!strncmp((char*)rs + REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ,
+		     REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING)));
+}
+
+
+/* compares description block with commit block.  returns 1 if they differ, 0 if they are the same */
+int does_desc_match_commit (struct reiserfs_journal_desc *desc, 
+			    struct reiserfs_journal_commit *commit) 
+{
+    if (commit->j_trans_id != desc->j_trans_id || commit->j_len != desc->j_len ||
+	commit->j_len > JOURNAL_TRANS_MAX || commit->j_len <= 0) {
+	return 1 ;
+    }
+    return 0 ;
+}
+
+
+/* returns code of reiserfs metadata block (leaf, internal, super
+   block, journal descriptor), unformatted */
+int who_is_this (char * buf, int blocksize)
+{
+    if (is_correct_leaf (buf, blocksize))
+	/* block head and item head array seem matching (node level, free
+           space, item number, item locations and length) */
+	return THE_LEAF;
+
+    if (is_correct_internal (buf, blocksize))
+	return THE_INTERNAL;
+
+    /* super block? */
+    if (is_reiser2fs_magic_string ((void *)buf) || 
+	is_reiserfs_magic_string ((void *)buf) ||
+	is_prejournaled_reiserfs ((void *)buf))
+	return THE_SUPER;
+
+    /* journal descriptor block? */
+    if (is_desc_block ((void *)buf))
+	return THE_JDESC;
+
+    /* contents of buf does not look like reiserfs metadata. Bitmaps
+       are possible here */
+    return THE_UNKNOWN;
+}
+
+
+int block_of_journal (reiserfs_filsys_t fs, unsigned long block)
+{
+    if (block >= SB_JOURNAL_BLOCK (fs) && 
+	block <= SB_JOURNAL_BLOCK (fs) + JOURNAL_BLOCK_COUNT)
+	return 1;
+
+    return 0;
+}
+
+
+int block_of_bitmap (reiserfs_filsys_t fs, unsigned long block)
+{
+    if (spread_bitmaps (fs)) {
+	if (!(block % (fs->s_blocksize * 8)))
+	    /* bitmap block */
+	    return 1;
+	return block == 17;
+    } else {
+	/* bitmap in */
+	if (block > 2 && block < 3 + SB_BMAP_NR (fs))
+	    return 1;
+	return 0;
+    }
+#if 0
+    int i;
+    int bmap_nr;
+
+    bmap_nr = SB_BMAP_NR (fs);
+    for (i = 0; i < bmap_nr; i ++)
+	if (block == SB_AP_BITMAP (fs)[i]->b_blocknr)
+	    return 1;
+#endif
+    return 0;
+}
+
+
+/* check whether 'block' can be pointed to by an indirect item */
+int not_data_block (reiserfs_filsys_t fs, unsigned long block)
+{
+    if (block_of_bitmap (fs, block))
+	/* it is one of bitmap blocks */
+	return 1;
+
+    if (block > 32768)
+	return 0;
+
+    if (block_of_journal (fs, block))
+	/* block of journal area */
+	return 1;
+
+    if (block <= fs->s_sbh->b_blocknr)
+	/* either super block or a block from skipped area at the
+           beginning of filesystem */
+	return 1;
+
+    return 0;
+}
+
+
+/* check whether 'block' can be logged */
+int not_journalable (reiserfs_filsys_t fs, unsigned long block)
+{   
+    /* we should not update SB with journal copy during fsck */
+    if (block < fs->s_sbh->b_blocknr)
+	return 1;
+
+    if (block_of_journal (fs, block))
+	return 1;
+
+    if (block >= SB_BLOCK_COUNT (fs))
+	return 1;
+
+    return 0;
+}
+
+
+// in reiserfs version 0 (undistributed bitmap)
+// FIXME: what if number of bitmaps is 15?
+int get_journal_old_start_must (struct reiserfs_super_block * rs)
+{
+    return 3 + rs_bmap_nr (rs);
+}
+
+
+// in reiserfs version 1 (distributed bitmap) journal starts at 18-th
+//
+int get_journal_start_must (int blocksize)
+{
+    return (REISERFS_DISK_OFFSET_IN_BYTES / blocksize) + 2;
+}
+
+int get_bmap_num (struct super_block * s)
+{
+    return ((is_prejournaled_reiserfs (s->s_rs)) ?
+	    (((struct reiserfs_super_block_v0 *)s->s_rs)->s_bmap_nr) :
+	    SB_BMAP_NR (s));
+}
+
+int get_block_count (struct super_block * s)
+{
+    return ((is_prejournaled_reiserfs (s->s_rs)) ?
+	    (((struct reiserfs_super_block_v0 *)s->s_rs)->s_block_count) :
+	    SB_BLOCK_COUNT (s));
+}
+
+int get_root_block (struct super_block * s)
+{
+    return  ((is_prejournaled_reiserfs (s->s_rs)) ?
+	     (((struct reiserfs_super_block_v0 *)s->s_rs)->s_root_block) :
+	     SB_ROOT_BLOCK (s));
+}
+
+
+
+int journal_size (struct super_block * s)
+{
+    return JOURNAL_BLOCK_COUNT;
+}
+
+
+
+int check_item_f (reiserfs_filsys_t fs, struct item_head * ih, char * item);
+
+
+/* make sure that key format written in item_head matches to key format
+   defined looking at the key */
+static int is_key_correct (struct item_head * ih)
+{
+    if (is_stat_data_ih (ih)) {
+	/* stat data key looks identical in both formats */
+	if (ih_item_len (ih) == SD_SIZE && ih_key_format (ih) == KEY_FORMAT_2) {
+	    /*printf ("new stat data\n");*/
+	    return 1;
+	}
+	if (ih_item_len (ih) == SD_V1_SIZE && ih_key_format (ih) == KEY_FORMAT_1) {
+	    /*printf ("old stat data\n");*/
+	    return 1;
+	}
+	return 0;
+    }
+    if (ih_key_format (ih) == key_format (&ih->ih_key))
+	return 1;
+    return 0;
+}
+
+
+/* check stat data item length, ih_free_space, mode */
+static int is_bad_sd (reiserfs_filsys_t fs, struct item_head * ih, char * item)
+{
+    mode_t mode;
+
+    if (ih_entry_count (ih) != 0xffff)
+	return 1;
+
+    if (ih_key_format (ih) == KEY_FORMAT_1) {
+	struct stat_data_v1 * sd = (struct stat_data_v1 *)item;
+
+	if (ih_item_len (ih) != SD_V1_SIZE)
+	    /* old stat data must be 32 bytes long */
+	    return 1;
+	mode = le16_to_cpu (sd->sd_mode);
+    } else if (ih_key_format (ih) == KEY_FORMAT_2) {
+	struct stat_data * sd = (struct stat_data *)item;
+
+	if (ih_item_len (ih) != SD_SIZE)
+	    /* new stat data must be 44 bytes long */
+	    return 1;
+	mode = le16_to_cpu (sd->sd_mode);
+    } else
+	return 1;
+    
+    if (!S_ISDIR (mode) && !S_ISREG (mode) && !S_ISCHR (mode) && 
+	!S_ISBLK (mode) && !S_ISLNK (mode) && !S_ISFIFO (mode) &&
+	!S_ISSOCK (mode))
+	return 1;
+
+    return 0;
+}
+
+
+/* symlinks created by 3.6.x have direct items with ih_free_space == 0 */
+static int is_bad_direct (reiserfs_filsys_t fs, struct item_head * ih, char * item)
+{
+    if (ih_entry_count (ih) != 0xffff && ih_entry_count (ih) != 0)
+	return 1;
+    return 0;
+}
+
+
+/* check item length, ih_free_space for pure 3.5 format, unformatted node
+   pointers */
+static int is_bad_indirect (reiserfs_filsys_t fs, struct item_head * ih, char * item,
+			    check_unfm_func_t check_unfm_func)
+{
+    int i;
+    __u32 * ind = (__u32 *)item;
+
+    if (ih_item_len (ih) % UNFM_P_SIZE)
+	return 1;
+
+    for (i = 0; i < I_UNFM_NUM (ih); i ++) {
+	if (!ind [i])
+	    continue;
+	if (check_unfm_func && check_unfm_func (fs, ind [i]))
+	    return 1;
+    }
+
+    if (fs->s_version == REISERFS_VERSION_1) {
+	/* check ih_free_space for 3.5 format only */
+	if (ih_free_space (ih) > fs->s_blocksize - 1)
+	    return 1;
+    }
+    
+    return 0;
+}
+
+
+static const struct {
+    hashf_t func;
+    char * name;
+} hashes[] = {{0, "not set"},
+	      {keyed_hash, "\"tea\""},
+	      {yura_hash, "\"rupasov\""},
+	      {r5_hash, "\"r5\""}};
+
+#define HASH_AMOUNT (sizeof (hashes) / sizeof (hashes [0]))
+
+
+int known_hashes (void)
+{
+    return HASH_AMOUNT;
+}
+
+
+#define good_name(hashfn,name,namelen,deh_offset) \
+(GET_HASH_VALUE ((hashfn) (name, namelen)) == GET_HASH_VALUE (deh_offset))
+
+
+/* this also sets hash function */
+int is_properly_hashed (reiserfs_filsys_t fs,
+			char * name, int namelen, __u32 offset)
+{
+    int i;
+
+    if (namelen == 1 && name[0] == '.') {
+	if (offset == DOT_OFFSET)
+	    return 1;
+	return 0;
+    }
+
+    if (namelen == 2 && name[0] == '.' && name[1] == '.') {
+	if (offset == DOT_DOT_OFFSET)
+	    return 1;
+	return 0;
+    }
+
+    if (hash_func_is_unknown (fs)) {
+	/* try to find what hash function the name is sorted with */
+	for (i = 1; i < HASH_AMOUNT; i ++) {
+	    if (good_name (hashes [i].func, name, namelen, offset)) {
+		if (!hash_func_is_unknown (fs)) {
+		    /* two or more hash functions give the same value for this
+                       name */
+		    fprintf (stderr, "Detecting hash code: could not detect hash with name \"%.*s\"\n",
+			     namelen, name);
+		    reiserfs_hash (fs) = 0;
+		    return 1;
+		}
+
+		/* set hash function */
+		reiserfs_hash(fs) = hashes [i].func;
+	    }
+	}
+    }
+
+    if (good_name (reiserfs_hash(fs), name, namelen, offset))
+	return 1;
+#if 0
+    fprintf (stderr, "is_properly_hashed: namelen %d, name \"%s\", offset %u, hash %u\n",
+	    namelen, name_from_entry (name, namelen), GET_HASH_VALUE (offset),
+	    GET_HASH_VALUE (reiserfs_hash(fs) (name, namelen)));
+
+    /* we could also check whether more than one hash function match on the
+       name */
+    for (i = 1; i < sizeof (hashes) / sizeof (hashes [0]); i ++) {
+	if (i == g_real_hash)
+	    continue;
+	if (good_name (hashes[i], name, namelen, deh_offset)) {
+	    die ("bad_hash: at least two hashes got screwed up with this name: \"%s\"",
+		 bad_name (name, namelen));
+	}
+    }
+#endif
+    return 0;
+}
+
+
+int find_hash_in_use (char * name, int namelen, __u32 hash_value_masked, int code_to_try_first)
+{
+    int i;
+
+    if (code_to_try_first) {
+	if (hash_value_masked == GET_HASH_VALUE (hashes [code_to_try_first].func (name, namelen)))
+	    return code_to_try_first;
+    }
+    for (i = 1; i < HASH_AMOUNT; i ++) {
+	if (i == code_to_try_first)
+	    continue;
+	if (hash_value_masked == GET_HASH_VALUE (hashes [i].func (name, namelen)))
+	    return i;
+    }
+
+    /* not matching hash found */
+    return UNSET_HASH;
+}
+
+
+char * code2name (int code)
+{
+    if (code >= HASH_AMOUNT)
+	code = 0;
+    return hashes [code].name;
+}
+
+
+int func2code (hashf_t func)
+{
+    int i;
+    
+    for (i = 0; i < HASH_AMOUNT; i ++)
+	if (func == hashes [i].func)
+	    return i;
+
+    reiserfs_panic ("func2code: no hashes matches this function\n");
+    return 0;
+}
+
+
+hashf_t code2func (int code)
+{
+    if (code >= HASH_AMOUNT) {
+	reiserfs_warning (stderr, "code2func: wrong hash code %d.\n"
+			  "Using default %s hash function\n", code,
+			  code2name (DEFAULT_HASH));
+	code = DEFAULT_HASH;
+    }
+    return hashes [code].func;
+}
+
+
+int dir_entry_bad_location (struct reiserfs_de_head * deh, struct item_head * ih, int first)
+{
+    if (deh_location (deh) < DEH_SIZE * ih_entry_count (ih))
+	return 1;
+    
+    if (deh_location (deh) >= ih_item_len (ih))
+	return 1;
+
+    if (!first && deh_location (deh) >= deh_location (deh - 1))
+	return 1;
+
+    return 0;
+}
+
+
+/* the only corruption which is not considered fatal - is hash mismatching. If
+   bad_dir is set - directory item having such names is considered bad */
+static int is_bad_directory (reiserfs_filsys_t fs, struct item_head * ih, char * item,
+			     int bad_dir)
+{
+    int i;
+    int namelen;
+    struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item;
+    __u32 prev_offset = 0;
+    __u16 prev_location = ih_item_len (ih);
+    
+    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
+	if (deh_location (deh) >= prev_location)
+	    return 1;
+	prev_location = deh_location (deh);
+	    
+	namelen = name_length (ih, deh, i);
+	if (namelen > REISERFS_MAX_NAME_LEN (fs->s_blocksize)) {
+	    return 1;
+	}
+	if (deh_offset (deh) <= prev_offset)
+	    return 1;
+	prev_offset = deh_offset (deh);
+	
+	/* check hash value */
+	if (!is_properly_hashed (fs, item + prev_location, namelen, prev_offset)) {
+	    if (bad_dir)
+		/* make is_bad_leaf to not insert whole leaf. Node will be
+		   marked not-insertable and put into tree item by item in
+		   pass 2 */
+		return 1;
+	}
+    }
+
+    return 0;
+}
+
+/* used by debugreisrefs -p only yet */
+#if 1
+int is_it_bad_item (reiserfs_filsys_t fs, struct item_head * ih, char * item,
+		    check_unfm_func_t check_unfm, int bad_dir)
+{
+    int retval;
+
+    if (!is_key_correct (ih)) {
+	reiserfs_warning (stderr, "is_key_correct %H\n", ih);
+	return 1;
+    }
+
+    if (is_stat_data_ih (ih)) {
+	retval = is_bad_sd (fs, ih, item);
+	/*
+	if (retval)
+	reiserfs_warning (stderr, "is_bad_sd %H\n", ih);*/
+	return retval;
+    }
+    if (is_direntry_ih (ih)) {
+	retval =  is_bad_directory (fs, ih, item, bad_dir);
+	/*
+	if (retval)
+	reiserfs_warning (stderr, "is_bad_directory %H\n", ih);*/
+	return retval;
+    }
+    if (is_indirect_ih (ih)) {
+	retval = is_bad_indirect (fs, ih, item, check_unfm);
+	/*
+	if (retval)
+	reiserfs_warning (stderr, "is_bad_indirect %H\n", ih);*/
+	return retval;
+    }
+    if (is_direct_ih (ih)) {
+	retval =  is_bad_direct (fs, ih, item);
+	/*
+	  if (retval)
+	  reiserfs_warning (stderr, "is_bad_direct %H\n", ih);*/
+	return retval;
+    }
+    return 1;
+}
+#endif
+
+
+
+/* prepare new or old stat data for the new directory */
+void make_dir_stat_data (int blocksize, int key_format, 
+			 __u32 dirid, __u32 objectid, 
+			 struct item_head * ih, void * sd)
+{
+    memset (ih, 0, IH_SIZE);
+    ih->ih_key.k_dir_id = cpu_to_le32 (dirid);
+    ih->ih_key.k_objectid = cpu_to_le32 (objectid);
+    set_offset (key_format, &ih->ih_key, SD_OFFSET);
+    set_type (key_format, &ih->ih_key, TYPE_STAT_DATA);
+
+    set_key_format (ih, key_format);
+    set_free_space (ih, MAX_US_INT);
+
+    if (key_format == KEY_FORMAT_2)
+    {
+        struct stat_data *sd_v2 = (struct stat_data *)sd;
+
+	set_ih_item_len (ih, SD_SIZE);
+        sd_v2->sd_mode = cpu_to_le16 (S_IFDIR + 0755);
+        sd_v2->sd_nlink = cpu_to_le32 (2);
+        sd_v2->sd_uid = 0;
+        sd_v2->sd_gid = 0;
+        sd_v2->sd_size = cpu_to_le64 (EMPTY_DIR_SIZE);
+        sd_v2->sd_atime = sd_v2->sd_ctime = sd_v2->sd_mtime = cpu_to_le32 (time (NULL));
+        sd_v2->u.sd_rdev = 0;
+        sd_v2->sd_blocks = cpu_to_le32 (dir_size2st_blocks (blocksize, EMPTY_DIR_SIZE));
+    }else{
+        struct stat_data_v1 *sd_v1 = (struct stat_data_v1 *)sd;
+
+	set_ih_item_len (ih, SD_V1_SIZE);
+        sd_v1->sd_mode = cpu_to_le16 (S_IFDIR + 0755);
+        sd_v1->sd_nlink = cpu_to_le16 (2);
+        sd_v1->sd_uid = 0;
+        sd_v1->sd_gid = 0;
+        sd_v1->sd_size = cpu_to_le32 (EMPTY_DIR_SIZE_V1);
+        sd_v1->sd_atime = sd_v1->sd_ctime = sd_v1->sd_mtime = cpu_to_le32 (time (NULL));
+        sd_v1->u.sd_blocks = cpu_to_le32 (dir_size2st_blocks (blocksize, EMPTY_DIR_SIZE_V1));
+	sd_v1->sd_first_direct_byte = cpu_to_le32 (NO_BYTES_IN_DIRECT_ITEM);
+    }
+}
+
+
+static void _empty_dir_item (int format, char * body, __u32 dirid, __u32 objid,
+			     __u32 par_dirid, __u32 par_objid)
+{
+    struct reiserfs_de_head * deh;
+
+    memset (body, 0, (format == KEY_FORMAT_2 ? EMPTY_DIR_SIZE : EMPTY_DIR_SIZE_V1));
+    deh = (struct reiserfs_de_head *)body;
+    
+    /* direntry header of "." */
+    deh[0].deh_offset = cpu_to_le32 (DOT_OFFSET);
+    deh[0].deh_dir_id = cpu_to_le32 (dirid);
+    deh[0].deh_objectid = cpu_to_le32 (objid);
+    deh[0].deh_state = 0;
+    set_bit (DEH_Visible, &(deh[0].deh_state));
+  
+    /* direntry header of ".." */
+    deh[1].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
+    /* key of ".." for the root directory */
+    deh[1].deh_dir_id = cpu_to_le32 (par_dirid);
+    deh[1].deh_objectid = cpu_to_le32 (par_objid);
+    deh[1].deh_state = 0;
+    set_bit (DEH_Visible, &(deh[1].deh_state));
+
+    if (format == KEY_FORMAT_2) {
+	deh[0].deh_location = cpu_to_le16 (EMPTY_DIR_SIZE - ROUND_UP (strlen (".")));
+	deh[1].deh_location = cpu_to_le16 (deh_location (&deh[0]) - ROUND_UP (strlen ("..")));
+    } else {
+	deh[0].deh_location = cpu_to_le16 (EMPTY_DIR_SIZE_V1 - strlen ("."));
+	deh[1].deh_location = cpu_to_le16 (deh_location (&deh[0]) - strlen (".."));
+    }
+
+    /* copy ".." and "." */
+    memcpy (body + deh_location (&deh[0]), ".", 1);
+    memcpy (body + deh_location (&deh[1]), "..", 2);
+    
+}
+
+
+void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
+			     __u32 par_dirid, __u32 par_objid)
+{
+    _empty_dir_item (KEY_FORMAT_1, body, dirid, objid, par_dirid, par_objid);
+}
+
+
+void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
+			  __u32 par_dirid, __u32 par_objid)
+{
+    _empty_dir_item (KEY_FORMAT_2, body, dirid, objid, par_dirid, par_objid);
+}
+
+
+
+/* for every item call common action and an action corresponding to
+   item type */
+void for_every_item (struct buffer_head * bh, item_head_action_t action,
+		     item_action_t * actions)
+{
+    int i;
+    struct item_head * ih;
+    item_action_t iaction;
+
+    ih = B_N_PITEM_HEAD (bh, 0);
+    for (i = 0; i < node_item_number (bh); i ++, ih ++) {
+	if (action)
+	    action (ih);
+
+	iaction = actions[get_type (&ih->ih_key)];
+	if (iaction)
+	    iaction (bh, ih);
+    }
+}
+
+
+/* old keys (on i386) have k_offset_v2.k_type == 15 (direct and
+   indirect) or == 0 (dir items and stat data) */
+
+/* */
+int key_format (const struct key * key)
+{
+    int type;
+
+    type = le16_to_cpu (key->u.k_offset_v2.k_type);
+
+    if (type == 0 || type == 15)
+	return KEY_FORMAT_1;
+
+    return KEY_FORMAT_2;
+}
+
+
+loff_t get_offset (const struct key * key)
+{
+    if (key_format (key) == KEY_FORMAT_1)
+	return le32_to_cpu (key->u.k_offset_v1.k_offset);
+
+    return le64_to_cpu (key->u.k_offset_v2.k_offset);
+}
+
+
+int uniqueness2type (__u32 uniqueness)
+{
+    switch (uniqueness) {
+    case V1_SD_UNIQUENESS: return TYPE_STAT_DATA;
+    case V1_INDIRECT_UNIQUENESS: return TYPE_INDIRECT;
+    case V1_DIRECT_UNIQUENESS: return TYPE_DIRECT;
+    case V1_DIRENTRY_UNIQUENESS: return TYPE_DIRENTRY;
+    }
+    return TYPE_UNKNOWN;
+}
+
+
+__u32 type2uniqueness (int type)
+{
+    switch (type) {
+    case TYPE_STAT_DATA: return V1_SD_UNIQUENESS;
+    case TYPE_INDIRECT: return V1_INDIRECT_UNIQUENESS;
+    case TYPE_DIRECT: return V1_DIRECT_UNIQUENESS;
+    case TYPE_DIRENTRY: return V1_DIRENTRY_UNIQUENESS;
+    } 
+    return V1_UNKNOWN_UNIQUENESS;
+}
+
+
+int get_type (const struct key * key)
+{
+    if (key_format (key) == KEY_FORMAT_1)
+	return uniqueness2type (le32_to_cpu (key->u.k_offset_v1.k_uniqueness));
+    return le16_to_cpu (key->u.k_offset_v2.k_type);
+}
+
+
+char * key_of_what (const struct key * key)
+{
+    switch (get_type (key)) {
+    case TYPE_STAT_DATA: return "SD";
+    case TYPE_INDIRECT: return "IND";
+    case TYPE_DIRECT: return "DRCT";
+    case TYPE_DIRENTRY: return "DIR";
+    default: return "???";
+    }
+}
+
+
+int type_unknown (struct key * key)
+{
+    int type = get_type (key);
+    
+    switch (type) {
+    case TYPE_STAT_DATA:
+    case TYPE_INDIRECT:
+    case TYPE_DIRECT:
+    case TYPE_DIRENTRY:
+	return 0;
+    default:
+	break;
+    }
+    return 1;
+}
+
+
+// this sets key format as well as type of item key belongs to
+//
+void set_type (int format, struct key * key, int type)
+{
+    if (format == KEY_FORMAT_1)
+	key->u.k_offset_v1.k_uniqueness = cpu_to_le32 (type2uniqueness (type));
+    else
+	key->u.k_offset_v2.k_type = cpu_to_le16 (type);
+}
+
+
+// 
+void set_offset (int format, struct key * key, loff_t offset)
+{
+    if (format == KEY_FORMAT_1)
+	key->u.k_offset_v1.k_offset = cpu_to_le32 (offset);
+    else
+	key->u.k_offset_v2.k_offset = cpu_to_le64 (offset);
+	
+}
+
+
+void set_type_and_offset (int format, struct key * key, loff_t offset, int type)
+{
+    set_type (format, key, type);
+    set_offset (format, key, offset);
+}
+
+
+/* length of the directory entry in directory item. This define calculates
+   length of i-th directory entry using directory entry locations from dir
+   entry head. When it calculates length of 0-th directory entry, it uses
+   length of whole item in place of entry location of the non-existent
+   following entry in the calculation.  See picture above.*/
+
+
+// NOTE: this is not name length. This is length of whole entry
+int entry_length (struct item_head * ih, struct reiserfs_de_head * deh, int pos_in_item)
+{
+    if (pos_in_item)
+	return (deh_location (deh - 1) - deh_location (deh));
+    return (ih_item_len (ih) - deh_location (deh));
+}
+
+
+char * name_in_entry (struct reiserfs_de_head * deh, int pos_in_item)
+{
+    return ((char *)(deh - pos_in_item) + deh_location(deh));
+}
+
+
+int name_length (struct item_head * ih,
+		 struct reiserfs_de_head * deh, int pos_in_item)
+{
+    int len;
+    char * name;
+
+    len = entry_length (ih, deh, pos_in_item);
+    name = name_in_entry (deh, pos_in_item);
+
+    // name might be padded with 0s
+    while (!name [len - 1])
+	len --;
+
+    return len;
+}
diff --git a/reiserfscore/prints.c b/reiserfscore/prints.c
new file mode 100644
index 0000000..70acc7b
--- /dev/null
+++ b/reiserfscore/prints.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+
+#include "includes.h"
+#include <stdarg.h>
+#include <limits.h>
+#include <printf.h>
+
+
+static int _arginfo (const struct printf_info *info, size_t n,
+		     int *argtypes)
+{
+    if (n > 0)
+	argtypes[0] = PA_POINTER;
+    return 1;
+}
+
+#if 0
+static int _arginfo2 (const struct printf_info *info, size_t n,
+		     int *argtypes)
+{
+    if (n > 0)
+	argtypes[0] = PA_INT;
+    return 1;
+}
+#endif
+
+
+#define FPRINTF \
+    if (len == -1) {\
+	return -1;\
+    }\
+    len = fprintf (stream, "%*s",\
+		   info->left ? -info->width : info->width, buffer);\
+    free (buffer);\
+    return len;\
+
+
+/* %z */
+static int print_block_head (FILE * stream,
+			     const struct printf_info *info,
+			     const void *const *args)
+{
+    const struct buffer_head * bh;
+    char * buffer;
+    int len;
+
+    bh = *((const struct buffer_head **)(args[0]));
+    len = asprintf (&buffer, "level=%d, nr_items=%d, free_space=%d rdkey",
+		    B_LEVEL (bh), B_NR_ITEMS (bh), node_free_space (bh));
+    FPRINTF;
+}
+
+
+/* %K */
+static int print_short_key (FILE * stream,
+			    const struct printf_info *info,
+			    const void *const *args)
+{
+    const struct key * key;
+    char * buffer;
+    int len;
+
+    key = *((const struct key **)(args[0]));
+    len = asprintf (&buffer, "%u %u", key->k_dir_id, key->k_objectid);
+    FPRINTF;
+}
+
+
+/* %k */
+static int print_key (FILE * stream,
+		      const struct printf_info *info,
+		      const void *const *args)
+{
+    const struct key * key;
+    char * buffer;
+    int len;
+
+    key = *((const struct key **)(args[0]));
+    len = asprintf (&buffer, "%u %u 0x%Lx %s",  
+		    key->k_dir_id, key->k_objectid, get_offset (key), key_of_what (key));
+    FPRINTF;
+}
+
+
+/* %H */
+static int print_item_head (FILE * stream,
+			    const struct printf_info *info,
+			    const void *const *args)
+{
+    const struct item_head * ih;
+    char * buffer;
+    int len;
+
+    ih = *((const struct item_head **)(args[0]));
+    len = asprintf (&buffer, "%u %u 0x%Lx %s, "
+		    "len %u, entry count %u, fsck need %u, format %s",
+		    ih->ih_key.k_dir_id, ih->ih_key.k_objectid, 
+		    get_offset (&ih->ih_key), key_of_what (&ih->ih_key),
+		    ih->ih_item_len, ih_entry_count (ih), 
+		    ih->ih_format.fsck_need,
+		    ih_key_format (ih) == KEY_FORMAT_2 ? "new" : 
+		    ((ih_key_format (ih) == KEY_FORMAT_1) ? "old" : "BAD"));
+    FPRINTF;
+}
+
+
+static int print_disk_child (FILE * stream,
+			     const struct printf_info *info,
+			     const void *const *args)
+{
+    const struct disk_child * dc;
+    char * buffer;
+    int len;
+
+    dc = *((const struct disk_child **)(args[0]));
+    len = asprintf (&buffer, "[dc_number=%u, dc_size=%u]", le32_to_cpu (dc->dc_block_number),
+		    le16_to_cpu (dc->dc_size));
+    FPRINTF;
+}
+
+
+char ftypelet (mode_t mode)
+{
+    if (S_ISBLK (mode))
+	return 'b';
+    if (S_ISCHR (mode))
+	return 'c';
+    if (S_ISDIR (mode))
+	return 'd';
+    if (S_ISREG (mode))
+	return '-';
+    if (S_ISFIFO (mode))
+	return 'p';
+    if (S_ISLNK (mode))
+	return 'l';
+    if (S_ISSOCK (mode))
+	return 's';
+    return '?';
+}
+
+
+static int rwx (FILE * stream, mode_t mode)
+{
+    return fprintf (stream, "%c%c%c",
+		    (mode & S_IRUSR) ? 'r' : '-',
+		    (mode & S_IWUSR) ? 'w' : '-',
+		    (mode & S_IXUSR) ? 'x' : '-');
+}
+
+
+/* %M */
+static int print_sd_mode (FILE * stream,
+			  const struct printf_info *info,
+			  const void *const *args)
+{
+    int len = 0;
+    mode_t mode;
+
+    mode = *(mode_t *)args[0];
+    len = fprintf (stream, "%c", ftypelet (mode));
+    len += rwx (stream, (mode & 0700) << 0);
+    len += rwx (stream, (mode & 0070) << 3);
+    len += rwx (stream, (mode & 0007) << 6);
+    return len;
+}
+
+
+
+void reiserfs_warning (FILE * fp, const char * fmt, ...)
+{
+    static int registered = 0;
+    va_list args;
+
+    if (!registered) {
+	registered = 1;
+	
+	register_printf_function ('K', print_short_key, _arginfo);
+	register_printf_function ('k', print_key, _arginfo);
+	register_printf_function ('H', print_item_head, _arginfo);
+	register_printf_function ('b', print_block_head, _arginfo);
+	register_printf_function ('y', print_disk_child, _arginfo);
+	register_printf_function ('M', print_sd_mode, _arginfo);
+    }
+
+    va_start (args, fmt);
+    vfprintf (fp, fmt, args);
+    va_end (args);
+}
+
+
+static char * vi_type (struct virtual_item * vi)
+{
+    static char *types[]={"directory", "direct", "indirect", "stat data"};
+
+    if (vi->vi_type & VI_TYPE_STAT_DATA)
+	return types[3];
+    if (vi->vi_type & VI_TYPE_INDIRECT)
+	return types[2];
+    if (vi->vi_type & VI_TYPE_DIRECT)
+	return types[1];
+    if (vi->vi_type & VI_TYPE_DIRECTORY)
+	return types[0];
+
+    reiserfs_panic ("vi_type: 6000: unknown type (0x%x)", vi->vi_type);
+    return NULL;
+}
+
+
+void print_virtual_node (struct virtual_node * vn)
+{
+    int i, j;
+  
+    printf ("VIRTUAL NODE CONTAINS %d items, has size %d,%s,%s, ITEM_POS=%d POS_IN_ITEM=%d MODE=\'%c\'\n",
+	    vn->vn_nr_item, vn->vn_size,
+	    (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE )? "left mergeable" : "", 
+	    (vn->vn_vi[vn->vn_nr_item - 1].vi_type & VI_TYPE_RIGHT_MERGEABLE) ? "right mergeable" : "",
+	    vn->vn_affected_item_num, vn->vn_pos_in_item, vn->vn_mode);
+
+
+    for (i = 0; i < vn->vn_nr_item; i ++) {
+	printf ("%s %d %d", vi_type (&vn->vn_vi[i]), i, vn->vn_vi[i].vi_item_len);
+	if (vn->vn_vi[i].vi_entry_sizes)
+	{
+	    printf ("It is directory with %d entries: ", vn->vn_vi[i].vi_entry_count);
+	    for (j = 0; j < vn->vn_vi[i].vi_entry_count; j ++)
+		printf ("%d ", vn->vn_vi[i].vi_entry_sizes[j]);
+	}
+	printf ("\n");
+    }
+}
+
+
+void print_path (struct tree_balance * tb, struct path * path)
+{
+    int offset = path->path_length;
+    struct buffer_head * bh;
+
+    printf ("Offset    Bh     (b_blocknr, b_count) Position Nr_item\n");
+    while ( offset > ILLEGAL_PATH_ELEMENT_OFFSET ) {
+	bh = PATH_OFFSET_PBUFFER (path, offset);
+	printf ("%6d %10p (%9lu, %7d) %8d %7d\n", offset, 
+		bh, bh ? bh->b_blocknr : 0, bh ? bh->b_count : 0,
+		PATH_OFFSET_POSITION (path, offset), bh ? B_NR_ITEMS (bh) : -1);
+	
+	offset --;
+    }
+}
+
+
+#if 0
+void print_de (struct reiserfs_dir_entry * de)
+{
+    reiserfs_warning ("entry key: [%k], object_key: [%u %u], b_blocknr=%lu, item_num=%d, pos_in_item=%d\n",
+		      &de->de_entry_key, de->de_dir_id, de->de_objectid,
+		      de->de_bh->b_blocknr, de->de_item_num, de->de_entry_num);
+}
+
+static char * item_type (struct item_head * ih)
+{
+    static char * types[] = {
+        "SD", "DIR", "DRCT", "IND", "???"
+    };
+
+    if (I_IS_STAT_DATA_ITEM(ih))
+        return types[0];
+    if (I_IS_DIRECTORY_ITEM(ih))
+        return types[1];
+    if (I_IS_DIRECT_ITEM(ih))
+        return types[2];
+    if (I_IS_INDIRECT_ITEM(ih))
+        return types[3];
+    return types[4];
+}
+
+#endif
+
+
+void print_directory_item (FILE * fp, reiserfs_filsys_t fs,
+			   struct buffer_head * bh, struct item_head * ih)
+{
+    int i;
+    int namelen;
+    struct reiserfs_de_head * deh;
+    char * name;
+/*    static char namebuf [80];*/
+
+    if (!I_IS_DIRECTORY_ITEM (ih))
+	return;
+
+    //printk ("\n%2%-25s%-30s%-15s%-15s%-15s\n", "    Name", "length", "Object key", "Hash", "Gen number", "Status");
+    reiserfs_warning (fp, "%3s: %-25s%s%-22s%-12s%s\n", "###", "Name", "length", "    Object key", "   Hash", "Gen number");
+    deh = B_I_DEH (bh, ih);
+    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
+	if (dir_entry_bad_location (deh, ih, i == 0 ? 1 : 0)) {
+	    reiserfs_warning (fp, "%3d: wrong entry location %u, deh_offset %u\n",
+			      i, deh_location (deh), deh_offset (deh));
+	    continue;
+	}
+	if (i && dir_entry_bad_location (deh - 1, ih, ((i - 1) == 0) ? 1 : 0))
+	    /* previous entry has bad location so we can not calculate entry
+               length */
+	    namelen = 25;
+	else
+	    namelen = name_length (ih, deh, i);
+
+	name = name_in_entry (deh, i);
+	reiserfs_warning (fp, "%3d: \"%-25.*s\"(%3d)%20K%12d%5d, loc %u, state %x %s\n", 
+			  i, namelen, name, namelen,
+			  (struct key *)&(deh->deh_dir_id),
+			  GET_HASH_VALUE (deh->deh_offset), GET_GENERATION_NUMBER (deh->deh_offset),
+			  deh_location (deh), deh->deh_state,
+			  fs ? (is_properly_hashed (fs, name, namelen, deh_offset (deh)) ? "" : "(BROKEN)") : "??");
+    }
+}
+
+
+//
+// printing of indirect item
+//
+static void start_new_sequence (__u32 * start, int * len, __u32 new)
+{
+    *start = new;
+    *len = 1;
+}
+
+
+static int sequence_finished (__u32 start, int * len, __u32 new)
+{
+    if (start == INT_MAX)
+	return 1;
+
+    if (start == 0 && new == 0) {
+	(*len) ++;
+	return 0;
+    }
+    if (start != 0 && (start + *len) == new) {
+	(*len) ++;
+	return 0;
+    }
+    return 1;
+}
+
+static void print_sequence (FILE * fp, __u32 start, int len)
+{
+    if (start == INT_MAX)
+	return;
+
+    if (len == 1)
+	reiserfs_warning (fp, " %d", start);
+    else
+	reiserfs_warning (fp, " %d(%d)", start, len);
+}
+
+
+void print_indirect_item (FILE * fp, struct buffer_head * bh, int item_num)
+{
+    struct item_head * ih;
+    int j;
+    __u32 * unp, prev = INT_MAX;
+    int num;
+
+    ih = B_N_PITEM_HEAD (bh, item_num);
+    unp = (__u32 *)B_I_PITEM (bh, ih);
+
+    if (ih->ih_item_len % UNFM_P_SIZE)
+	reiserfs_warning (fp, "print_indirect_item: invalid item len");  
+
+    reiserfs_warning (fp, "%d pointers\n[ ", I_UNFM_NUM (ih));
+    for (j = 0; j < I_UNFM_NUM (ih); j ++) {
+	if (sequence_finished (prev, &num, unp[j])) {
+	    print_sequence (fp, prev, num);
+	    start_new_sequence (&prev, &num, unp[j]);
+	}
+    }
+    print_sequence (fp, prev, num);
+    reiserfs_warning (fp, "]\n");
+}
+
+
+char timebuf[256];
+
+char * timestamp (time_t t)
+{
+    strftime (timebuf, 256, "%m/%d/%Y %T", localtime (&t));
+    return timebuf;
+}
+
+static int print_stat_data (FILE * fp, struct buffer_head * bh, struct item_head * ih, int alltimes)
+{
+    struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih);
+    struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
+    int retval;
+    
+
+    /* we can not figure out whether it is new stat data or old by key_format
+       macro. Stat data's key looks identical in both formats */
+    if (ih_key_format (ih) == KEY_FORMAT_1) {
+	reiserfs_warning (fp, "(OLD SD), mode %M, size %u, nlink %u, uid %d, FDB %d, mtime %s blocks %d", 
+		sd_v1->sd_mode, sd_v1->sd_size, sd_v1->sd_nlink, sd_v1->sd_uid, 
+		sd_v1->sd_first_direct_byte, timestamp (sd_v1->sd_mtime), sd_v1->u.sd_blocks);
+	retval = (S_ISLNK (sd_v1->sd_mode)) ? 1 : 0;
+    } else {
+	reiserfs_warning (fp, "(NEW SD), mode %M, size %Lu, nlink %u, mtime %s blocks %d", 
+		sd->sd_mode, sd->sd_size, sd->sd_nlink,
+		timestamp (sd->sd_mtime), sd->sd_blocks);
+	retval = (S_ISLNK (sd->sd_mode)) ? 1 : 0;
+    }
+
+    if (alltimes)
+	reiserfs_warning (fp, "%s %s\n", timestamp (sd->sd_ctime), timestamp (sd->sd_atime));
+    reiserfs_warning (fp, "\n");
+    return retval;
+}
+
+
+/* this prints internal nodes (4 keys/items in line) (dc_number,
+   dc_size)[k_dirid, k_objectid, k_offset, k_uniqueness](dc_number,
+   dc_size)...*/
+static int print_internal (FILE * fp, struct buffer_head * bh, int first, int last)
+{
+    struct key * key;
+    struct disk_child * dc;
+    int i;
+    int from, to;
+
+    if (!is_internal_node (bh))
+	return 1;
+
+    if (first == -1) {
+	from = 0;
+	to = B_NR_ITEMS (bh);
+    } else {
+	from = first;
+	to = last < B_NR_ITEMS (bh) ? last : B_NR_ITEMS (bh);
+    }
+
+    reiserfs_warning (fp, "INTERNAL NODE (%ld) contains %b\n",  bh->b_blocknr, bh);
+
+    dc = B_N_CHILD (bh, from);
+    reiserfs_warning (fp, "PTR %d: %y ", from, dc);
+
+    for (i = from, key = B_N_PDELIM_KEY (bh, from), dc ++; i < to; i ++, key ++, dc ++) {
+	reiserfs_warning (fp, "KEY %d: %20k PTR %d: %20y ", i, key, i + 1, dc);
+	if (i && i % 4 == 0)
+	    reiserfs_warning (fp, "\n");
+    }
+    reiserfs_warning (fp, "\n");
+    return 0;
+}
+
+
+
+static int is_symlink = 0;
+static int print_leaf (FILE * fp, reiserfs_filsys_t fs, struct buffer_head * bh,
+		       int print_mode, int first, int last)
+{
+    struct block_head * blkh;
+    struct item_head * ih;
+    int i;
+    int from, to;
+
+    if (!is_leaf_node (bh))
+	return 1;
+
+    blkh = B_BLK_HEAD (bh);
+    ih = B_N_PITEM_HEAD (bh,0);
+
+    reiserfs_warning (fp, "\n===================================================================\n");
+    reiserfs_warning (fp, "LEAF NODE (%ld) contains %b\n", bh->b_blocknr, bh);
+
+    if (!(print_mode & PRINT_LEAF_ITEMS)) {
+	reiserfs_warning (fp, "FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n",
+			   &(ih->ih_key), &((ih + blkh->blk_nr_item - 1)->ih_key));
+	return 0;
+    }
+
+    if (first < 0 || first > blkh->blk_nr_item - 1) 
+	from = 0;
+    else 
+	from = first;
+
+    if (last < 0 || last > blkh->blk_nr_item)
+	to = blkh->blk_nr_item;
+    else
+	to = last;
+
+
+    reiserfs_warning (fp,
+		       "-------------------------------------------------------------------------------\n"
+		       "|###|type|ilen|f/sp| loc|fmt|fsck|                   key                      |\n"
+		       "|   |    |    |e/cn|    |   |need|                                            |\n");
+    for (i = from; i < to; i++) {
+	reiserfs_warning (fp,
+			   "-------------------------------------------------------------------------------\n"
+			  "|%3d|%30H|\n", i, ih + i);
+
+	if (I_IS_STAT_DATA_ITEM(ih+i) && print_mode & PRINT_ITEM_DETAILS) {
+	    is_symlink = print_stat_data (fp, bh, ih + i, 0/*all times*/);
+	    continue;
+	}
+
+	if (I_IS_DIRECTORY_ITEM(ih+i) && print_mode & PRINT_ITEM_DETAILS) {
+	    print_directory_item (fp, fs, bh, ih+i);
+	    continue;
+	}
+
+	if (I_IS_INDIRECT_ITEM(ih+i) && print_mode & PRINT_ITEM_DETAILS) {
+	    print_indirect_item (fp, bh, i);
+	    continue;
+	}
+
+	if (I_IS_DIRECT_ITEM(ih+i)) {
+	    int j = 0;
+	    if (is_symlink || print_mode & PRINT_DIRECT_ITEMS) {
+		reiserfs_warning (fp, "\"");
+		while (j < ih[i].ih_item_len) {
+		    if (B_I_PITEM(bh,ih+i)[j] == 10)
+			reiserfs_warning (fp, "\\n");
+		    else
+			reiserfs_warning (fp, "%c", B_I_PITEM(bh,ih+i)[j]);
+		    j ++;
+		}
+		reiserfs_warning (fp, "\"\n");
+	    }
+	    continue;
+	}
+    }
+    reiserfs_warning (fp, "===================================================================\n");
+    return 0;
+}
+
+
+
+/* return 1 if this is not super block */
+static int print_super_block (FILE * fp, struct buffer_head * bh)
+{
+    struct reiserfs_super_block * rs = (struct reiserfs_super_block *)(bh->b_data);
+    int skipped, data_blocks;
+    
+    if (is_reiser2fs_magic_string (rs))
+	reiserfs_warning (fp, "Super block of format 3.6 found on the 0x%x in block %ld\n", 
+			   bh->b_dev, bh->b_blocknr);
+    else if (is_reiserfs_magic_string (rs))
+	reiserfs_warning (fp, "Super block of format 3.5 found on the 0x%x in block %ld\n",
+			  bh->b_dev, bh->b_blocknr);
+    else if (is_prejournaled_reiserfs (rs)) {
+	reiserfs_warning (fp, "Prejournaled reiserfs super block found. Not supported here. Use proper tools instead\n");
+	return 1;
+    } else
+	// no reiserfs signature found in the block
+	return 1;
+
+    reiserfs_warning (fp, "Block count %u\n", rs_block_count (rs));
+    reiserfs_warning (fp, "Blocksize %d\n", rs_blocksize (rs));
+    reiserfs_warning (fp, "Free blocks %u\n", rs_free_blocks (rs));
+    skipped = bh->b_blocknr; // FIXME: this would be confusing if
+    // someone stores reiserfs super block in reiserfs ;)
+    data_blocks = rs_block_count (rs) - skipped - 1 -
+	rs_bmap_nr (rs) - (rs_journal_size (rs) + 1) - rs_free_blocks (rs);
+    reiserfs_warning (fp, "Busy blocks (skipped %d, bitmaps - %d, journal blocks - %d\n"
+	    "1 super blocks, %d data blocks\n", 
+	    skipped, rs_bmap_nr (rs), 
+	    (rs_journal_size (rs) + 1), data_blocks);
+    reiserfs_warning (fp, "Root block %u\n", rs_root_block (rs));
+    reiserfs_warning (fp, "Journal block (first) %d\n", rs_journal_start (rs));
+    reiserfs_warning (fp, "Journal dev %d\n", rs->s_v1.s_journal_dev);    
+    reiserfs_warning (fp, "Journal orig size %d\n", rs_journal_size (rs));
+    reiserfs_warning (fp, "Filesystem state %s\n", (rs->s_v1.s_state == REISERFS_VALID_FS) ? "VALID" : "ERROR");
+    if (fsck_state (rs) == TREE_IS_BUILT)
+	reiserfs_warning (fp, "fsck pass 2 completion code set\n");
+ 
+#if 0
+    __u32 s_journal_trans_max ;           /* max number of blocks in a transaction.  */
+    __u32 s_journal_block_count ;         /* total size of the journal. can change over time  */
+    __u32 s_journal_max_batch ;           /* max number of blocks to batch into a trans */
+    __u32 s_journal_max_commit_age ;      /* in seconds, how old can an async commit be */
+    __u32 s_journal_max_trans_age ;       /* in seconds, how old can a transaction be */
+#endif
+    reiserfs_warning (fp, "Tree height %d\n", rs_tree_height (rs));
+    reiserfs_warning (fp, "Hash function used to sort names: %s\n",
+		      code2name (rs_hash (rs)));
+    reiserfs_warning (fp, "Objectid map size %d, max %d\n", rs_objectid_map_size (rs),
+		       rs_objectid_map_max_size (rs));
+    reiserfs_warning (fp, "Version %d\n", rs_version (rs));
+    return 0;
+}
+
+
+static int print_desc_block (FILE * fp, struct buffer_head * bh)
+{
+    struct reiserfs_journal_desc * desc;
+
+    desc = (struct reiserfs_journal_desc *)(bh->b_data);
+
+    if (memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8))
+	return 1;
+
+    reiserfs_warning (fp, "Desc block %lu (j_trans_id %ld, j_mount_id %ld, j_len %ld)",
+		       bh->b_blocknr, desc->j_trans_id, desc->j_mount_id, desc->j_len);
+
+    return 0;
+}
+
+
+void print_block (FILE * fp, reiserfs_filsys_t fs, 
+		  struct buffer_head * bh, ...)//int print_mode, int first, int last)
+{
+    va_list args;
+    int mode, first, last;
+    
+    va_start (args, bh);
+
+    if ( ! bh ) {
+	reiserfs_warning (stderr, "print_block: buffer is NULL\n");
+	return;
+    }
+
+    mode = va_arg (args, int);
+    first = va_arg (args, int);
+    last = va_arg (args, int);
+    if (print_desc_block (fp, bh))
+	if (print_super_block (fp, bh))
+	    if (print_leaf (fp, fs, bh, mode, first, last))
+		if (print_internal (fp, bh, first, last))
+		    reiserfs_warning (fp, "Block %ld contains unformatted data\n", bh->b_blocknr);
+}
+
+
+void print_tb (int mode, int item_pos, int pos_in_item, struct tree_balance * tb, char * mes)
+{
+  int h = 0;
+  int i;
+  struct buffer_head * tbSh, * tbFh;
+
+
+  if (!tb)
+    return;
+
+  printf ("\n********************** PRINT_TB for %s *******************\n", mes);
+  printf ("MODE=%c, ITEM_POS=%d POS_IN_ITEM=%d\n", mode, item_pos, pos_in_item);
+  printf ("*********************************************************************\n");
+
+  printf ("* h *    S    *    L    *    R    *   F   *   FL  *   FR  *  CFL  *  CFR  *\n");
+/*
+01234567890123456789012345678901234567890123456789012345678901234567890123456789
+       1        2         3         4         5         6         7         8
+  printk ("*********************************************************************\n");
+*/
+  
+  
+  for (h = 0; h < sizeof(tb->insert_size) / sizeof (tb->insert_size[0]); h ++) {
+    if (PATH_H_PATH_OFFSET (tb->tb_path, h) <= tb->tb_path->path_length && 
+	PATH_H_PATH_OFFSET (tb->tb_path, h) > ILLEGAL_PATH_ELEMENT_OFFSET) {
+      tbSh = PATH_H_PBUFFER (tb->tb_path, h);
+      tbFh = PATH_H_PPARENT (tb->tb_path, h);
+    } else {
+      /*      printk ("print_tb: h=%d, PATH_H_PATH_OFFSET=%d, path_length=%d\n", 
+	      h, PATH_H_PATH_OFFSET (tb->tb_path, h), tb->tb_path->path_length);*/
+      tbSh = 0;
+      tbFh = 0;
+    }
+    printf ("* %d * %3ld(%2d) * %3ld(%2d) * %3ld(%2d) * %5ld * %5ld * %5ld * %5ld * %5ld *\n",
+	    h, 
+	    (tbSh) ? (tbSh->b_blocknr):(-1),
+	    (tbSh) ? tbSh->b_count : -1,
+	    (tb->L[h]) ? (tb->L[h]->b_blocknr):(-1),
+	    (tb->L[h]) ? tb->L[h]->b_count : -1,
+	    (tb->R[h]) ? (tb->R[h]->b_blocknr):(-1),
+	    (tb->R[h]) ? tb->R[h]->b_count : -1,
+	    (tbFh) ? (tbFh->b_blocknr):(-1),
+	    (tb->FL[h]) ? (tb->FL[h]->b_blocknr):(-1),
+	    (tb->FR[h]) ? (tb->FR[h]->b_blocknr):(-1),
+	    (tb->CFL[h]) ? (tb->CFL[h]->b_blocknr):(-1),
+	    (tb->CFR[h]) ? (tb->CFR[h]->b_blocknr):(-1));
+  }
+
+  printf ("*********************************************************************\n");
+
+
+  /* print balance parameters for leaf level */
+  h = 0;
+  printf ("* h * size * ln * lb * rn * rb * blkn * s0 * s1 * s1b * s2 * s2b * curb * lk * rk *\n");
+  printf ("* %d * %4d * %2d * %2d * %2d * %2d * %4d * %2d * %2d * %3d * %2d * %3d * %4d * %2d * %2d *\n",
+	  h, tb->insert_size[h], tb->lnum[h], tb->lbytes, tb->rnum[h],tb->rbytes, tb->blknum[h], 
+	  tb->s0num, tb->s1num,tb->s1bytes,  tb->s2num, tb->s2bytes, tb->cur_blknum, tb->lkey[h], tb->rkey[h]);
+
+
+/* this prints balance parameters for non-leaf levels */
+  do {
+    h++;
+    printf ("* %d * %4d * %2d *    * %2d *    * %2d *\n",
+    h, tb->insert_size[h], tb->lnum[h], tb->rnum[h], tb->blknum[h]);
+  } while (tb->insert_size[h]);
+
+  printf ("*********************************************************************\n");
+
+
+  /* print FEB list (list of buffers in form (bh (b_blocknr, b_count), that will be used for new nodes) */
+  h = 0;
+  for (i = 0; i < sizeof (tb->FEB) / sizeof (tb->FEB[0]); i ++)
+    printf ("%s%p (%lu %d)", i == 0 ? "FEB list: " : ", ", tb->FEB[i], tb->FEB[i] ? tb->FEB[i]->b_blocknr : 0,
+	    tb->FEB[i] ? tb->FEB[i]->b_count : 0);
+  printf ("\n");
+
+  printf ("********************** END OF PRINT_TB *******************\n\n");
+
+}
+
+
+static void print_bmap_block (FILE * fp, int i, struct buffer_head * bmap, int blocks, int silent)
+{
+    int j, k;
+    int bits = bmap->b_size * 8;
+    int zeros = 0, ones = 0;
+  
+    reiserfs_warning (fp, "#%d: block %lu: ", i, bmap->b_blocknr);
+
+    if (test_bit (0, bmap->b_data)) {
+	/* first block addressed by this bitmap block is used */
+	ones ++;
+	if (!silent)
+	    reiserfs_warning (fp, "Busy (%d-", i * bits);
+	for (j = 1; j < blocks; j ++) {
+	    while (test_bit (j, bmap->b_data)) {
+		ones ++;
+		if (j == blocks - 1) {
+		    if (!silent)
+			reiserfs_warning (fp, "%d)\n", j + i * bits);
+		    goto end;
+		}
+		j++;
+	    }
+	    if (!silent)
+		reiserfs_warning (fp, "%d) Free(%d-", j - 1 + i * bits, j + i * bits);
+
+	    while (!test_bit (j, bmap->b_data)) {
+		zeros ++;
+		if (j == blocks - 1) {
+		    if (!silent)
+			reiserfs_warning (fp, "%d)\n", j + i * bits);
+		    goto end;
+		}
+		j++;
+	    }
+	    if (!silent)
+		reiserfs_warning (fp, "%d) Busy(%d-", j - 1 + i * bits, j + i * bits);
+
+	    j --;
+	end:
+	}
+    } else {
+	/* first block addressed by this bitmap is free */
+	zeros ++;
+	if (!silent)
+	    reiserfs_warning (fp, "Free (%d-", i * bits);
+	for (j = 1; j < blocks; j ++) {
+	    k = 0;
+	    while (!test_bit (j, bmap->b_data)) {
+		k ++;
+		if (j == blocks - 1) {
+		    if (!silent)
+			reiserfs_warning (fp, "%d)\n", j + i * bits);
+		    zeros += k;
+		    goto end2;
+		}
+		j++;
+	    }
+	    zeros += k;
+	    if (!silent)
+		reiserfs_warning (fp, "%d) Busy(%d-", j - 1 + i * bits, j + i * bits);
+	    
+	    k = 0;
+	    while (test_bit (j, bmap->b_data)) {
+		ones ++;
+		if (j == blocks - 1) {
+		    if (!silent)
+			reiserfs_warning (fp, "%d)\n", j + i * bits);
+		    ones += k;
+		    goto end2;
+		}
+		j++;
+	    }
+	    ones += k;
+	    if (!silent)
+		reiserfs_warning (fp, "%d) Free(%d-", j - 1 + i * bits, j + i * bits);
+	
+	    j --;
+	end2:
+	}
+    }
+
+    reiserfs_warning (fp, "used %d, free %d\n", ones, zeros);
+}
+
+
+/* if silent == 1, do not print details */
+void print_bmap (FILE * fp, reiserfs_filsys_t s, int silent)
+{
+    int bmapnr = SB_BMAP_NR (s);
+    int i;
+    int blocks = s->s_blocksize * 8; /* adressed by bitmap */
+
+    reiserfs_warning (fp, "Bitmap blocks are:\n");
+    for (i = 0; i < bmapnr; i ++) {
+
+	if (i == bmapnr - 1)
+	    if (SB_BLOCK_COUNT (s) % (s->s_blocksize * 8))
+		blocks = SB_BLOCK_COUNT (s) % (s->s_blocksize * 8);
+	print_bmap_block (fp, i, SB_AP_BITMAP(s)[i], blocks, silent);
+    }
+
+    /* check unused part of last bitmap */
+    {
+	int bad_unused_bitmap = 0;
+	int ones;
+
+	ones = s->s_blocksize * 8 - SB_BLOCK_COUNT (s) % (s->s_blocksize * 8);
+	if (ones == s->s_blocksize * 8)
+	    ones = 0;
+      
+	for (i = s->s_blocksize * 8; --i >= blocks; )
+	    if (!test_bit (i, SB_AP_BITMAP (s)[bmapnr - 1]->b_data))
+		bad_unused_bitmap ++;
+
+	if (bad_unused_bitmap) {
+	    reiserfs_warning (fp, "Unused part of bitmap is wrong: should be %d ones, found %d zeros\n",
+			       ones, bad_unused_bitmap);
+	}
+    }
+    
+}
+
+
+
+void print_objectid_map (FILE * fp, reiserfs_filsys_t fs)
+{
+    int i;
+    struct reiserfs_super_block * rs;
+    __u32 * omap;
+
+    rs = fs->s_rs;
+    if (fs->s_version == REISERFS_VERSION_2)
+	omap = (__u32 *)(rs + 1);
+    else if (fs->s_version == REISERFS_VERSION_1)
+	omap = (__u32 *)((struct reiserfs_super_block_v1 *)rs + 1);
+    else {
+	reiserfs_warning (fp, "print_objectid_map: proper signature is not found\n");
+	return;
+    }
+	
+    reiserfs_warning (fp, "Map of objectids (super block size %d)\n", (char *)omap - (char *)rs);
+      
+    for (i = 0; i < SB_OBJECTID_MAP_SIZE (fs); i ++) {
+	if (i % 2 == 0)
+	    reiserfs_warning (fp, "busy(%u-%u) ", omap[i], omap[i+1] - 1); 
+	else
+	    reiserfs_warning (fp, "free(%u-%u) ", 
+			       omap[i], ((i+1) == SB_OBJECTID_MAP_SIZE (fs)) ? -1 : omap[i+1] - 1);
+    }
+
+    reiserfs_warning (fp, "\nObject id array has size %d (max %d):", SB_OBJECTID_MAP_SIZE (fs), 
+		       SB_OBJECTID_MAP_MAXSIZE (fs));
+  
+    for (i = 0; i < SB_OBJECTID_MAP_SIZE (fs); i ++)
+	reiserfs_warning (fp, "%s%u ", i % 2 ? "" : "*", omap[i]); 
+    reiserfs_warning (fp, "\n");
+
+}
+
+#if 0
+/* the below is from fileutils-4.0-66 (shortened) */
+
+/* Look at read, write, and execute bits in BITS and set
+   flags in CHARS accordingly.  */
+
+static void
+rwx (short unsigned int bits, char *chars)
+{
+  chars[0] = (bits & S_IRUSR) ? 'r' : '-';
+  chars[1] = (bits & S_IWUSR) ? 'w' : '-';
+  chars[2] = (bits & S_IXUSR) ? 'x' : '-';
+}
+
+/* snip */
+
+/* Return a character indicating the type of file described by
+   file mode BITS:
+   'd' for directories
+   'b' for block special files
+   'c' for character special files
+   'l' for symbolic links
+   's' for sockets
+   'p' for fifos
+   '-' for regular files
+   '?' for any other file type.  */
+
+static char
+ftypelet (long int bits)
+{
+#ifdef S_ISBLK
+  if (S_ISBLK (bits))
+    return 'b';
+#endif
+  if (S_ISCHR (bits))
+    return 'c';
+  if (S_ISDIR (bits))
+    return 'd';
+  if (S_ISREG (bits))
+    return '-';
+#ifdef S_ISFIFO
+  if (S_ISFIFO (bits))
+    return 'p';
+#endif
+#ifdef S_ISLNK
+  if (S_ISLNK (bits))
+    return 'l';
+#endif
+#ifdef S_ISSOCK
+  if (S_ISSOCK (bits))
+    return 's';
+#endif
+
+  return '?';
+}
+
+/* Like filemodestring, but only the relevant part of the `struct stat'
+   is given as an argument.  */
+
+static void
+mode_string (short unsigned int mode, char *str)
+{
+  str[0] = ftypelet ((long) mode);
+  rwx ((mode & 0700) << 0, &str[1]);
+  rwx ((mode & 0070) << 3, &str[4]);
+  rwx ((mode & 0007) << 6, &str[7]);
+}
+
+
+char * st_mode2string (short unsigned int mode, char * buf)
+{
+    mode_string (mode, buf);
+    buf[10] = 0;
+    return buf;
+}
+
+
+#endif
diff --git a/reiserfscore/reiserfslib.c b/reiserfscore/reiserfslib.c
new file mode 100644
index 0000000..b024ac8
--- /dev/null
+++ b/reiserfscore/reiserfslib.c
@@ -0,0 +1,766 @@
+/*
+ *  Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+
+#include "includes.h"
+
+
+/* fixme: this assumes that journal start and journal size are set
+   correctly */
+static void check_first_bitmap (reiserfs_filsys_t fs, char * bitmap)
+{
+    int i;
+    int bad;
+
+    bad = 0;
+    for (i = 0; i < rs_journal_start (fs->s_rs) +
+	     rs_journal_size (fs->s_rs) + 1; i ++) {
+	if (!test_bit (i, bitmap)) {
+	    bad = 1;
+	    /*reiserfs_warning ("block %d is marked free in the first bitmap, fixed\n", i);*/
+	    /*set_bit (i, bitmap);*/
+	}
+    }
+    if (bad)
+	reiserfs_warning (stderr, "reiserfs_open: first bitmap looks corrupted\n");
+}
+
+
+/* read bitmap blocks */
+void reiserfs_read_bitmap_blocks (reiserfs_filsys_t fs)
+{
+	struct reiserfs_super_block * rs = fs->s_rs;
+	struct buffer_head * bh = SB_BUFFER_WITH_SB(fs);
+	int fd = fs->s_dev;
+	unsigned long block;
+	int i;
+	
+	/* read bitmaps, and correct a bit if necessary */
+	SB_AP_BITMAP (fs) = getmem (sizeof (void *) * rs_bmap_nr (rs));
+	for (i = 0, block = bh->b_blocknr + 1;
+	     i < rs_bmap_nr (rs); i ++) {
+		SB_AP_BITMAP (fs)[i] = bread (fd, block, fs->s_blocksize);
+		if (!SB_AP_BITMAP (fs)[i]) {
+		    	reiserfs_warning (stderr, "reiserfs_open: bread failed reading bitmap #%d (%lu)\n", i, block);
+			SB_AP_BITMAP (fs)[i] = getblk (fd, block, fs->s_blocksize);
+			memset (SB_AP_BITMAP (fs)[i]->b_data, 0xff, fs->s_blocksize);
+			set_bit (BH_Uptodate, &SB_AP_BITMAP (fs)[i]->b_state);
+		}
+		
+		/* all bitmaps have to have itself marked used on it */
+		if (bh->b_blocknr == 16) {
+			if (!test_bit (block % (fs->s_blocksize * 8), SB_AP_BITMAP (fs)[i]->b_data)) {
+				reiserfs_warning (stderr, "reiserfs_open: bitmap %d was marked free\n", i);
+				/*set_bit (block % (fs->s_blocksize * 8), SB_AP_BITMAP (fs)[i]->b_data);*/
+			}
+		} else {
+			/* bitmap not spread over partition: fixme: does not
+			   work when number of bitmaps => 32768 */
+			if (!test_bit (block, SB_AP_BITMAP (fs)[0]->b_data)) {
+			    	reiserfs_warning (stderr, "reiserfs_open: bitmap %d was marked free\n", i);
+				/*set_bit (block, SB_AP_BITMAP (fs)[0]->b_data);*/
+			}
+		}
+
+		if (i == 0) {
+			/* first bitmap has to have marked used super block
+			   and journal areas */
+			check_first_bitmap (fs, SB_AP_BITMAP (fs)[i]->b_data);
+		}
+
+		block = (bh->b_blocknr == 16 ? ((i + 1) * fs->s_blocksize * 8) : (block + 1));
+    }
+}
+
+
+void reiserfs_free_bitmap_blocks (reiserfs_filsys_t fs)
+{
+	int i;
+	
+    /* release bitmaps if they were read */
+    if (SB_AP_BITMAP (fs)) {
+		for (i = 0; i < SB_BMAP_NR (fs); i ++)
+			brelse (SB_AP_BITMAP (fs) [i]);
+		freemem (SB_AP_BITMAP (fs));
+	}
+
+}
+
+/* read super block and bitmaps. fixme: only 4k blocks, pre-journaled format
+   is refused */
+reiserfs_filsys_t reiserfs_open (char * filename, int flags, int *error, void * vp)
+{
+    reiserfs_filsys_t fs;
+    struct buffer_head * bh;
+    struct reiserfs_super_block * rs;
+    int fd, i;
+    
+    fd = open (filename, flags | O_LARGEFILE);
+    if (fd == -1) {
+	if (error)
+	    *error = errno;
+	return 0;
+    }
+
+    fs = getmem (sizeof (*fs));
+    fs->s_dev = fd;
+    fs->s_vp = vp;
+    asprintf (&fs->file_name, "%s", filename);
+
+    /* reiserfs super block is either in 16-th or in 2-nd 4k block of the
+       device */
+    for (i = 16; i > 0; i -= 14) {
+	bh = bread (fd, i, 4096);
+	if (!bh) {
+	    reiserfs_warning (stderr, "reiserfs_open: bread failed reading block %d\n", i);
+	} else {
+	    rs = (struct reiserfs_super_block *)bh->b_data;
+	    
+	    if (is_reiser2fs_magic_string (rs) || is_reiserfs_magic_string (rs))
+		goto found;
+
+	    /* reiserfs signature is not found at the i-th 4k block */
+	    brelse (bh);
+	}
+    }
+
+    reiserfs_warning (stderr, "reiserfs_open: neither new nor old reiserfs format "
+		      "found on %s\n", filename);
+    if (error)
+	*error = 0;
+    return fs;
+
+ found:
+
+    /* fixme: we could make some check to make sure that super block looks
+       correctly */
+    fs->s_version = is_reiser2fs_magic_string (rs) ? REISERFS_VERSION_2 :
+	REISERFS_VERSION_1;
+    fs->s_blocksize = rs_blocksize (rs);
+    fs->s_hash_function = code2func (rs_hash (rs));
+    SB_BUFFER_WITH_SB (fs) = bh;
+    fs->s_rs = rs;
+    fs->s_flags = flags; /* O_RDONLY or O_RDWR */
+    fs->s_vp = vp;
+
+	
+    reiserfs_read_bitmap_blocks(fs);
+	
+    return fs;
+
+}
+
+
+int no_reiserfs_found (reiserfs_filsys_t fs)
+{
+    return (fs->s_blocksize == 0) ? 1 : 0;
+}
+
+
+int new_format (reiserfs_filsys_t fs)
+{
+    return fs->s_sbh->b_blocknr != 2;
+}
+
+
+int spread_bitmaps (reiserfs_filsys_t fs)
+{
+    return fs->s_sbh->b_blocknr != 2;
+}
+
+
+void reiserfs_reopen (reiserfs_filsys_t fs, int flag)
+{
+    close (fs->s_dev);
+    fs->s_dev = open (fs->file_name, flag | O_LARGEFILE);
+    if (fs->s_dev == -1)
+	die ("reiserfs_reopen: could not reopen device: %m");
+}
+
+
+int filesystem_dirty (reiserfs_filsys_t fs)
+{
+    return fs->s_dirt;
+}
+
+
+void mark_filesystem_dirty (reiserfs_filsys_t fs)
+{
+    fs->s_dirt = 1;
+}
+
+
+/* flush all changes made on a filesystem */
+void reiserfs_flush (reiserfs_filsys_t fs)
+{
+    flush_buffers ();
+}
+
+
+/* free all memory involved into manipulating with filesystem */
+void reiserfs_free (reiserfs_filsys_t fs)
+{
+    reiserfs_free_bitmap_blocks(fs);
+    
+    /* release super block and memory used by filesystem handler */
+    brelse (SB_BUFFER_WITH_SB (fs));
+    
+    free_buffers ();
+
+    free (fs->file_name);
+    freemem (fs);
+}
+
+
+void reiserfs_close (reiserfs_filsys_t fs)
+{
+    reiserfs_flush (fs);
+    reiserfs_free (fs);
+}
+
+
+int reiserfs_new_blocknrs (reiserfs_filsys_t fs, 
+			   unsigned long * free_blocknrs, unsigned long start, int amount_needed)
+{
+    if (fs->block_allocator)
+	return fs->block_allocator (fs, free_blocknrs, start, amount_needed);
+    die ("block allocator is not defined\n");
+    return 0;
+}
+
+
+int reiserfs_free_block (reiserfs_filsys_t fs, unsigned long block)
+{
+    if (fs->block_deallocator)
+	return fs->block_deallocator (fs, block);
+    die ("block allocator is not defined\n");
+    return 0;
+}
+
+
+typedef int (comp_function_t) (void * key1, void * key2);
+
+inline int _bin_search (void * key, void * base, int num, int width, __u32 *ppos, comp_function_t comp_func)
+{
+    int rbound, lbound, j;
+
+    if (num == 0) {
+	/* objectid map may be 0 elements long */
+        *ppos = 0;
+        return ITEM_NOT_FOUND;
+    }
+
+    lbound = 0;
+    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;
+}
+
+#if 0
+static inline int _bin_search (void * key, void * base, int num, int width, __u32 *ppos)
+{
+    __u32 rbound, lbound, j;
+
+    lbound = 0;
+    rbound = num - 1;
+    for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) {
+	switch (comp_keys ((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;
+}
+#endif
+
+static int _search_by_key (reiserfs_filsys_t fs, struct key * key, struct path * path)
+{
+    struct buffer_head * bh;
+    unsigned long block = SB_ROOT_BLOCK (fs);
+    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 (fs->s_dev, block, fs->s_blocksize);
+        if (bh == 0) {
+	    path->path_length --;
+	    pathrelse (path);
+	    return ITEM_NOT_FOUND;
+	}
+	retval = _bin_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);
+    }
+    printf ("search_by_key: you can not get here\n");
+    return ITEM_NOT_FOUND;
+}
+
+
+static int comp_dir_entries (void * p1, void * p2)
+{
+    __u32 deh_offset;
+    __u32 * off1, * off2;
+
+    off1 = p1;
+    off2 = p2;
+    deh_offset = le32_to_cpu (*off1);
+
+    if (deh_offset < *off2)
+	return -1;
+    if (deh_offset > *off2)
+	return 1;
+    return 0;
+}
+
+
+static struct key * _get_rkey (struct path * path)
+{
+    int pos, offset = path->path_length;
+    struct buffer_head * bh;
+
+    if (offset < FIRST_PATH_ELEMENT_OFFSET)
+	die ("_get_rkey: illegal offset in the path (%d)", offset);
+
+    while (offset-- > FIRST_PATH_ELEMENT_OFFSET) {
+	if (! buffer_uptodate (PATH_OFFSET_PBUFFER (path, offset)))
+	    die ("_get_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 ("_get_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 ("_get_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 ("_get_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;
+}
+
+
+/* NOTE: this only should be used to look for keys who exists */
+int _search_by_entry_key (reiserfs_filsys_t fs, struct key * key, 
+			  struct path * path)
+{
+    struct buffer_head * bh;
+    int item_pos;
+    struct item_head * ih;
+    struct key tmpkey;
+
+    if (_search_by_key (fs, key, path) == ITEM_FOUND) {
+        path->pos_in_item = 0;
+        return POSITION_FOUND;
+    }
+
+    bh = get_bh (path);
+    item_pos = get_item_pos (path);
+    ih = get_ih (path);
+
+    if (item_pos == 0) {
+	/* key is less than the smallest key in the tree */
+	if (not_of_one_file (&(ih->ih_key), key))
+	    /* there are no items of that directory */
+	    return DIRECTORY_NOT_FOUND;
+
+	if (!is_direntry_ih (ih))
+	    reiserfs_panic ("_search_by_entry_key: found item is not of directory type %H",
+			    ih);
+
+	/* key we looked for should be here */
+        path->pos_in_item = 0;
+	return POSITION_NOT_FOUND;
+    }
+
+    /* take previous item */
+    item_pos --;
+    ih --;
+    PATH_LAST_POSITION (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 */
+
+	item_pos ++;
+	PATH_LAST_POSITION (path) ++;
+
+        if (item_pos < B_NR_ITEMS (bh)) {
+	    /* next item is in the same node */
+	    ih ++;
+            if (not_of_one_file (&(ih->ih_key), key)) {
+		/* there are no items of that directory */
+                path->pos_in_item = 0;
+                return DIRECTORY_NOT_FOUND;
+            }
+
+            if (!is_direntry_ih (ih))
+		reiserfs_panic ("_search_by_entry_key: %k is not a directory",
+				key);
+        } else {
+	    /* next item is in right neighboring node */
+            struct key * next_key = _get_rkey (path);
+
+            if (next_key == 0 || not_of_one_file (next_key, key)) {
+                /* there are no items of that directory */
+                path->pos_in_item = 0;
+                return DIRECTORY_NOT_FOUND;
+            }
+
+            if (!is_direntry_key (next_key))
+		reiserfs_panic ("_search_by_entry_key: %k is not a directory",
+				key);
+
+            /* we got right delimiting key - search for it - the entry will be
+	       pasted in position 0 */
+            copy_key (&tmpkey, next_key);
+            pathrelse (path);
+            if (_search_by_key (fs, &tmpkey, path) != ITEM_FOUND || PATH_LAST_POSITION (path) != 0)
+                reiserfs_panic ("_search_by_entry_key: item corresponding to delimiting key %k not found",
+				&tmpkey);
+        }
+
+        /* 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 (_bin_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;
+}
+
+
+static void _init_tb_struct (struct tree_balance * tb, reiserfs_filsys_t fs,
+			     struct path * path, int size)
+{
+    memset (tb, '\0', sizeof(struct tree_balance));
+    tb->tb_sb = fs;
+    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;
+}
+
+
+int reiserfs_remove_entry (reiserfs_filsys_t fs, struct key * key)
+{
+    struct path path;
+    struct tree_balance tb;
+    struct item_head * ih;
+    struct reiserfs_de_head * deh;
+
+    if (_search_by_entry_key (fs, key, &path) != POSITION_FOUND) {
+	pathrelse (&path);
+	return 1;
+    }
+
+    ih = get_ih (&path);
+    if (ih_entry_count (ih) == 1) {
+	_init_tb_struct (&tb, fs, &path, -(IH_SIZE + ih_item_len (ih)));
+	if (fix_nodes (M_DELETE, &tb, 0) != CARRY_ON) {
+	    unfix_nodes (&tb);
+	    return 1;
+	}
+	do_balance (&tb, 0, 0, M_DELETE, 0);
+	return 0;
+    }
+
+    deh = B_I_DEH (get_bh (&path), ih) + path.pos_in_item;
+    _init_tb_struct (&tb, fs, &path, -(DEH_SIZE + entry_length (ih, deh, path.pos_in_item)));
+    if (fix_nodes (M_CUT, &tb, 0) != CARRY_ON) {
+	unfix_nodes (&tb);
+	return 1;
+    }
+    do_balance (&tb, 0, 0, M_CUT, 0);
+    return 0;
+}
+
+
+
+void reiserfs_paste_into_item (reiserfs_filsys_t fs, struct path * path,
+			       const void * body, int size)
+{
+    struct tree_balance tb;
+  
+    _init_tb_struct (&tb, fs, path, size);
+
+    if (fix_nodes (M_PASTE, &tb, 0/*ih*/) != CARRY_ON)
+	reiserfs_panic ("reiserfs_paste_into_item: fix_nodes failed");
+
+    do_balance (&tb, 0, body, M_PASTE, 0/*zero num*/);
+}
+
+
+void reiserfs_insert_item (reiserfs_filsys_t fs, struct path * path,
+			   struct item_head * ih, const void * body)
+{
+    struct tree_balance tb;
+    
+    _init_tb_struct (&tb, fs, path, IH_SIZE + ih_item_len(ih));
+    if (fix_nodes (M_INSERT, &tb, ih) != CARRY_ON)
+	die ("reiserfs_insert_item: fix_nodes failed");
+
+    do_balance (&tb, ih, body, M_INSERT, 0/*zero num*/);
+}
+
+
+/*===========================================================================*/
+
+static __u32 hash_value (reiserfs_filsys_t fs, char * name)
+{
+    __u32 res;
+
+    if (!strcmp (name, "."))
+	return DOT_OFFSET;
+    if (!strcmp (name, ".."))
+	return DOT_DOT_OFFSET;
+
+    res = reiserfs_hash (fs) (name, strlen (name));    
+    res = GET_HASH_VALUE(res);
+    if (res == 0)
+	res = 128;
+
+    return res;
+}
+
+
+
+/* returns 0 if name is not found in a directory and objectid of
+   pointed object otherwise and returns minimal not used generation
+   counter.  dies if found object is not a directory. */
+int reiserfs_find_entry (reiserfs_filsys_t fs, struct key * dir, char * name, 
+			 int * min_gen_counter)
+{
+    struct key entry_key;
+    int retval;
+    int i;
+    INITIALIZE_PATH (path);
+    struct item_head * ih;
+    struct reiserfs_de_head * deh;
+    struct key * rdkey;
+    __u32 hash;
+
+    entry_key.k_dir_id = dir->k_dir_id;
+    entry_key.k_objectid = dir->k_objectid;
+    hash = hash_value (fs, name);
+    set_type_and_offset (KEY_FORMAT_1, &entry_key, hash, TYPE_DIRENTRY);    
+    *min_gen_counter = 0;
+
+    if (_search_by_entry_key (fs, &entry_key, &path) == DIRECTORY_NOT_FOUND) {
+	pathrelse (&path);
+	return 0;
+    }
+
+    do {
+	ih = get_ih (&path);
+	deh = B_I_DEH (get_bh (&path), ih) + path.pos_in_item;
+	for (i = path.pos_in_item; i < ih_entry_count (ih); i ++, deh ++) {
+	    if (GET_HASH_VALUE (deh_offset (deh)) != GET_HASH_VALUE (hash)) {
+		/* all entries having the same hash were scanned */
+		pathrelse (&path);
+		return 0;
+	    }
+
+	    if (GET_GENERATION_NUMBER (deh_offset (deh)) == *min_gen_counter)
+		(*min_gen_counter) ++;
+
+	    if (!memcmp (name_in_entry (deh, i), name, strlen (name))) {
+		pathrelse (&path);
+		return deh_objectid (deh) ? deh_objectid (deh) : 1;
+	    }
+	}
+
+	rdkey = _get_rkey (&path);
+	if (!rdkey || not_of_one_file (rdkey, dir)) {
+	    pathrelse (&path);
+	    return 0;
+	}
+	
+	if (!is_direntry_key (rdkey))
+	    reiserfs_panic ("reiserfs_find_entry: can not find name in broken directory yet");
+
+	/* next item is the item of the directory we are looking name in */
+	if (GET_HASH_VALUE (get_offset (rdkey)) != hash) {
+	    /* but there is no names with given hash */
+	    pathrelse (&path);
+	    return 0;
+	}
+
+	/* first name of that item may be a name we are looking for */
+	entry_key = *rdkey;
+	pathrelse (&path);
+	retval = _search_by_entry_key (fs, &entry_key, &path);
+	if (retval != POSITION_FOUND)
+	    reiserfs_panic ("reiserfs_find_entry: wrong delimiting key in the tree");
+
+    } while (1);
+    
+    return 0;
+}
+
+
+/* compose directory entry: dir entry head and name itself */
+char * make_entry (char * entry, char * name, struct key * key, __u32 offset)
+{
+    struct reiserfs_de_head * deh;
+
+    if (!entry)
+	entry = getmem (DEH_SIZE + ROUND_UP (strlen (name)));
+
+    memset (entry, 0, DEH_SIZE + ROUND_UP (strlen (name)));
+    deh = (struct reiserfs_de_head *)entry;
+    deh->deh_location = 0;
+    deh->deh_offset = cpu_to_le32 (offset);
+    deh->deh_state = 0;
+    mark_de_visible (deh);
+
+    /* key of object entry will point to */
+    deh->deh_dir_id = cpu_to_le32 (key->k_dir_id);
+    deh->deh_objectid = cpu_to_le32 (key->k_objectid);
+
+    memcpy ((char *)(deh + 1), name, strlen (name));
+    return entry;
+}
+
+
+/* add new name into a directory. If it exists in a directory - do
+   nothing */
+int reiserfs_add_entry (reiserfs_filsys_t fs, struct key * dir, char * name,
+			 struct key * key, int fsck_need)
+{
+    struct item_head entry_ih = {{0,}, };
+    char * entry;
+    int retval;
+    INITIALIZE_PATH(path);
+    int gen_counter;
+    int item_len;
+    __u32 hash;
+
+    if (reiserfs_find_entry (fs, dir, name, &gen_counter))
+	return 0;
+
+    /* compose entry key to look for its place in the tree */
+    entry_ih.ih_key.k_dir_id = cpu_to_le32 (dir->k_dir_id);
+    entry_ih.ih_key.k_objectid = cpu_to_le32 (dir->k_objectid);
+    hash = hash_value (fs, name) + gen_counter;
+    if (!strcmp (name, "."))
+	hash = DOT_OFFSET;
+    if (!strcmp (name, ".."))
+	hash = DOT_DOT_OFFSET;
+    set_type_and_offset (KEY_FORMAT_1, &(entry_ih.ih_key),
+			 hash, TYPE_DIRENTRY);
+    set_key_format (&entry_ih, KEY_FORMAT_1);
+    set_entry_count (&entry_ih, 1);
+    if (SB_VERSION (fs) == REISERFS_VERSION_2)
+	item_len = DEH_SIZE + ROUND_UP (strlen (name));
+    else
+	item_len = DEH_SIZE + strlen (name);
+    set_ih_item_len (&entry_ih, item_len);
+
+    /* fsck may need to insert item which was not reached yet */
+    entry_ih.ih_format.fsck_need = fsck_need;
+
+    entry = make_entry (0, name, key, get_offset (&(entry_ih.ih_key)));
+
+    retval = _search_by_entry_key (fs, &(entry_ih.ih_key), &path);
+    switch (retval) {
+    case POSITION_NOT_FOUND:
+	reiserfs_paste_into_item (fs, &path, entry, item_len);
+	break;
+
+    case DIRECTORY_NOT_FOUND:
+	((struct reiserfs_de_head *)entry)->deh_location = cpu_to_le16 (DEH_SIZE);
+	reiserfs_insert_item (fs, &path, &entry_ih, entry);
+	break;
+
+    default:
+	reiserfs_panic ("reiserfs_add_entry: looking for %k (inserting name \"%s\") "
+			"search_by_entry_key returned %d",
+			&(entry_ih.ih_key), name, retval);
+    }
+
+    freemem (entry);
+    return item_len;
+}
+
+
+void copy_key (void * to, void * from)
+{
+    memcpy (to, from, KEY_SIZE);
+}
+
+
+void copy_short_key (void * to, void * from)
+{
+    memcpy (to, from, SHORT_KEY_SIZE);
+}
+
+
+void copy_item_head(void * p_v_to, void * p_v_from)
+{
+    memcpy (p_v_to, p_v_from, IH_SIZE);
+}
diff --git a/reiserfscore/stree.c b/reiserfscore/stree.c
new file mode 100644
index 0000000..aa81791
--- /dev/null
+++ b/reiserfscore/stree.c
@@ -0,0 +1,475 @@
+/*
+ *  Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details
+ */
+
+/*
+ *  Written by Anatoly P. Pinchuk pap@namesys.botik.ru
+ *  Programm System Institute
+ *  Pereslavl-Zalessky Russia
+ */
+
+/*
+ *  This file contains functions dealing with S+tree
+ *
+ * comp_keys
+ * comp_short_keys
+ * bin_search
+ * get_lkey
+ * get_rkey
+ * key_in_buffer
+ * decrement_bcount
+ * decrement_counters_in_path
+ * pathrelse
+ * search_by_key
+ * search_for_position_by_key
+ * comp_items
+ * prepare_for_delete_or_cut
+ * calc_deleted_bytes_number
+ * init_tb_struct
+ * reiserfs_delete_item
+ * indirect_to_direct
+ * maybe_indirect_to_direct
+ * reiserfs_cut_from_item
+ * reiserfs_cut_dir_entry
+ * reiserfs_paste_into_item
+ * reiserfs_insert_item
+ */
+#include "includes.h"
+
+
+/* Does the buffer contain a disk block which is in the tree. */
+inline int B_IS_IN_TREE (struct buffer_head * p_s_bh)
+{
+
+#ifdef CONFIG_REISERFS_CHECK
+  if ( node_level (p_s_bh) > MAX_HEIGHT ) {
+    reiserfs_panic(0, "PAP-1010: B_IS_IN_TREE: block (%b) has too big level (%z)",
+		   p_s_bh, p_s_bh);
+  }
+#endif
+
+  return ( node_level (p_s_bh) != FREE_LEVEL );
+}
+
+
+/*
+ Compare keys using REISERFS_SHORT_KEY_LEN fields.
+ Returns:  -1 if key1 < key2
+            0 if key1 = key2
+            1 if key1 > key2
+*/
+int comp_short_keys (void * k1, void * k2)
+{
+    __u32 * p_s_key1, * p_s_key2;
+    int n_key_length = REISERFS_SHORT_KEY_LEN;
+
+    p_s_key1 = (__u32 *)k1;
+    p_s_key2 = (__u32 *)k2;
+
+    for( ; n_key_length--; ++p_s_key1, ++p_s_key2 ) {
+	if ( *p_s_key1 < *p_s_key2 )
+	    return -1;
+	if ( *p_s_key1 > *p_s_key2 )
+	    return 1;
+    }
+
+    return 0;
+}
+
+
+/*
+ Compare keys using all 4 key fields.
+ Returns:  -1 if key1 < key2
+            0 if key1 = key2
+            1 if key1 > key2
+*/
+int comp_keys (void * p1, void * p2)
+{
+    int retval;
+    struct key * k1, * k2;
+    
+    k1 = p1;
+    k2 = p2;
+
+    retval = comp_short_keys (k1, k2);
+    if (retval)
+	return retval;
+
+    if (get_offset (k1) < get_offset (k2))
+	return -1;
+
+    if (get_offset (k1) > get_offset (k2))
+	return 1;
+
+    /* this part is needed only when tail conversion is in progress */
+    if (get_type (k1) < get_type (k2))
+	return -1;
+
+    if (get_type (k1) > get_type (k2))
+	return 1;
+
+    return 0;
+}
+
+
+/**************************************************************************
+ *  Binary search toolkit function                                        *
+ *  Search for an item in the array by the item key                       *
+ *  Returns:    1 if found,  0 if not found;                              *
+ *        *p_n_pos = number of the searched element if found, else the    *
+ *        number of the first element that is larger than p_v_key.        *
+ **************************************************************************/
+/* For those not familiar with binary search: n_lbound is the leftmost item that it
+ could be, n_rbound the rightmost item that it could be.  We examine the item
+ halfway between n_lbound and n_rbound, and that tells us either that we can increase
+ n_lbound, or decrease n_rbound, or that we have found it, or if n_lbound <= n_rbound that
+ there are no possible items, and we have not found it. With each examination we
+ cut the number of possible items it could be by one more than half rounded down,
+ or we find it. */
+inline	int bin_search (
+              void    * p_v_key,    /* Key to search for.                   */
+	      void    * p_v_base,   /* First item in the array.             */
+	      int       p_n_num,    /* Number of items in the array.        */
+	      int       p_n_width,  /* Item size in the array.
+				       searched. Lest the reader be
+				       confused, note that this is crafted
+				       as a general function, and when it
+				       is applied specifically to the array
+				       of item headers in a node, p_n_width
+				       is actually the item header size not
+				       the item size.                      */
+	      int     * p_n_pos     /* Number of the searched for element. */
+            ) {
+    int   n_rbound, n_lbound, n_j;
+
+    for ( n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0))/2; n_lbound <= n_rbound; n_j = (n_rbound + n_lbound)/2 )
+	switch( COMP_KEYS((struct key *)((char * )p_v_base + n_j * p_n_width), p_v_key) )  {
+	case -1: n_lbound = n_j + 1; continue;
+	case  1: n_rbound = n_j - 1; continue;
+	case  0: *p_n_pos = n_j;     return ITEM_FOUND; /* Key found in the array.  */
+	}
+
+    /* bin_search did not find given key, it returns position of key,
+     that is minimal and greater than the given one. */
+    *p_n_pos = n_lbound;
+    return ITEM_NOT_FOUND;
+}
+
+#ifdef CONFIG_REISERFS_CHECK
+extern struct tree_balance * cur_tb;
+extern struct tree_balance init_tb;
+extern int init_item_pos, init_pos_in_item, init_mode;
+#endif
+
+
+
+/* Minimal possible key. It is never in the tree. */
+struct key  MIN_KEY = {0, 0, {{0, 0},}};
+
+/* Maximal possible key. It is never in the tree. */
+struct key  MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}};
+
+
+/* Get delimiting key of the buffer by looking for it in the buffers in the
+   path, starting from the bottom of the path, and going upwards.  We must
+   check the path's validity at each step.  If the key is not in the path,
+   there is no delimiting key in the tree (buffer is first or last buffer in
+   tree), and in this case we return a special key, either MIN_KEY or
+   MAX_KEY. */
+inline	struct  key * get_lkey  (
+    struct path         * p_s_chk_path,
+    struct super_block  * p_s_sb
+    ) {
+    int                   n_position, n_path_offset = p_s_chk_path->path_length;
+    struct buffer_head  * p_s_parent;
+  
+#ifdef CONFIG_REISERFS_CHECK
+    if ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET )
+	reiserfs_panic(p_s_sb,"PAP-5010: get_lkey: illegal offset in the path");
+#endif
+
+    /* While not higher in path than first element. */
+    while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+	if ( ! buffer_uptodate(PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
+	    reiserfs_panic(p_s_sb, "PAP-5020: get_lkey: parent is not uptodate");
+#endif
+
+	/* Parent at the path is not in the tree now. */
+	if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
+	    return &MAX_KEY;
+	/* Check whether position in the parent is correct. */
+	if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )
+	    return &MAX_KEY;
+	/* Check whether parent at the path really points to the child. */
+	if ( B_N_CHILD_NUM(p_s_parent, n_position) !=
+	     PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr )
+	    return &MAX_KEY;
+	/* Return delimiting key if position in the parent is not equal to zero. */
+	if ( n_position )
+	    return B_N_PDELIM_KEY(p_s_parent, n_position - 1);
+    }
+    /* Return MIN_KEY if we are in the root of the buffer tree. */
+    if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
+	 SB_ROOT_BLOCK (p_s_sb) )
+	return &MIN_KEY;
+    return  &MAX_KEY;
+}
+
+
+/* Get delimiting key of the buffer at the path and its right neighbor. */
+inline	struct  key * get_rkey  (
+    struct path         * p_s_chk_path,
+    struct super_block  * p_s_sb
+    ) {
+    int                   n_position,
+	n_path_offset = p_s_chk_path->path_length;
+    struct buffer_head  * p_s_parent;
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( n_path_offset < FIRST_PATH_ELEMENT_OFFSET )
+	reiserfs_panic(p_s_sb,"PAP-5030: get_rkey: illegal offset in the path");
+#endif
+
+    while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+	if ( ! buffer_uptodate(PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
+	    reiserfs_panic(p_s_sb, "PAP-5040: get_rkey: parent is not uptodate");
+#endif
+
+	/* Parent at the path is not in the tree now. */
+	if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
+	    return &MIN_KEY;
+	/* Check whether position in the parrent is correct. */
+	if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )
+	    return &MIN_KEY;
+	/* Check whether parent at the path really points to the child. */
+	if ( B_N_CHILD_NUM(p_s_parent, n_position) !=
+	     PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr )
+	    return &MIN_KEY;
+	/* Return delimiting key if position in the parent is not the last one. */
+	if ( n_position != B_NR_ITEMS(p_s_parent) )
+	    return B_N_PDELIM_KEY(p_s_parent, n_position);
+    }
+    /* Return MAX_KEY if we are in the root of the buffer tree. */
+    if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
+	 SB_ROOT_BLOCK (p_s_sb) )
+	return &MAX_KEY;
+    return  &MIN_KEY;
+}
+
+
+/* Check whether a key is contained in the tree rooted from a buffer at a
+   path.  This works by looking at the left and right delimiting keys for the
+   buffer in the last path_element in the path.  These delimiting keys are
+   stored at least one level above that buffer in the tree. If the buffer is
+   the first or last node in the tree order then one of the delimiting keys
+   may be absent, and in this case get_lkey and get_rkey return a special key
+   which is MIN_KEY or MAX_KEY. */
+static  inline  int key_in_buffer (
+    struct path         * p_s_chk_path, /* Path which should be checked.  */
+    struct key          * p_s_key,      /* Key which should be checked.   */
+    struct super_block  * p_s_sb        /* Super block pointer.           */
+    ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+    if ( ! p_s_key || p_s_chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET ||
+	 p_s_chk_path->path_length > MAX_HEIGHT )
+	reiserfs_panic(p_s_sb, "PAP-5050: key_in_buffer:  pointer to the key(%p) is NULL or illegal path length(%d)",
+		       p_s_key, p_s_chk_path->path_length);
+  
+    if ( PATH_PLAST_BUFFER(p_s_chk_path)->b_dev == NODEV )
+	reiserfs_panic(p_s_sb, "PAP-5060: key_in_buffer: device must not be NODEV");
+#endif
+
+    if ( COMP_KEYS(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1 )
+	return 0;
+    if ( COMP_KEYS(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 )
+	return 0;
+    return 1;
+}
+
+
+/* Release all buffers in the path. */
+void  pathrelse (struct path * p_s_search_path) 
+{
+    int n_path_offset = p_s_search_path->path_length;
+    
+#ifdef CONFIG_REISERFS_CHECK
+    if ( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET )
+	reiserfs_panic(NULL, "PAP-5090: pathrelse: illegal path offset");
+#endif
+    
+    while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET ) 
+	brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));
+
+    p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+}
+
+
+/**************************************************************************
+ * Algorithm   SearchByKey                                                *
+ *             look for item in the Disk S+Tree by its key                *
+ * Input:  p_s_sb   -  super block                                        *
+ *         p_s_key  - pointer to the key to search                        *
+ * Output: true value -  1 - found,  0 - not found                        *
+ *         p_s_search_path - path from the root to the needed leaf        *
+ **************************************************************************/
+
+/* This function fills up the path from the root to the leaf as it
+   descends the tree looking for the key.  It uses reiserfs_bread to
+   try to find buffers in the cache given their block number.  If it
+   does not find them in the cache it reads them from disk.  For each
+   node search_by_key finds using reiserfs_bread it then uses
+   bin_search to look through that node.  bin_search will find the
+   position of the block_number of the next node if it is looking
+   through an internal node.  If it is looking through a leaf node
+   bin_search will find the position of the item which has key either
+   equal to given key, or which is the maximal key less than the given
+   key.  search_by_key returns a path that must be checked for the
+   correctness of the top of the path but need not be checked for the
+   correctness of the bottom of the path */
+int search_by_key(
+    struct super_block  * p_s_sb,         /* Super block.                           */
+    struct key          * p_s_key,        /* Key to search.                         */
+    struct path         * p_s_search_path,/* This structure was allocated and initialized by
+					     the calling function. It is filled up by this
+					     function.  */
+    int                 * p_n_repeat,     /* Whether schedule occured. */
+    int                   n_stop_level   /* How far down the tree to search.*/
+    ) {
+    dev_t                      n_dev           = p_s_sb->s_dev;
+    int                         n_repeat,
+	n_block_number  = SB_ROOT_BLOCK (p_s_sb),
+	expected_level = SB_TREE_HEIGHT (p_s_sb),
+	n_block_size    = p_s_sb->s_blocksize;
+    struct buffer_head  *       p_s_bh;
+    struct path_element *       p_s_last_element;
+    int				n_retval;
+    int 			right_neighbor_of_leaf_node;
+
+#ifdef CONFIG_REISERFS_CHECK
+    int n_repeat_counter = 0;
+#endif
+
+    /* As we add each node to a path we increase its count.  This
+       means that we must be careful to release all nodes in a path
+       before we either discard the path struct or re-use the path
+       struct, as we do here. */
+    pathrelse (p_s_search_path);
+
+    *p_n_repeat = CARRY_ON;
+
+    /* With each iteration of this loop we search through the items in
+       the current node, and calculate the next current node(next path
+       element) for the next iteration of this loop.. */
+    while ( 1 ) {
+
+#ifdef CONFIG_REISERFS_CHECK
+	if ( !(++n_repeat_counter % 50000) )
+	    printk ("PAP-5100: search_by_key(pid %u): there were %d searches from the tree_root lokking for key %p\n",
+		    current->pid, n_repeat_counter, p_s_key);
+#endif
+
+	/* prep path to have another element added to it. */
+	p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length);
+	expected_level --;
+	n_repeat = CARRY_ON;
+
+	/* Read the next tree node, and set the last element in the
+           path to have a pointer to it. */
+	if ( ! (p_s_bh = p_s_last_element->pe_buffer =
+		reiserfs_bread(n_dev, n_block_number, n_block_size, &n_repeat)) ) {
+	    p_s_search_path->path_length --;
+	    pathrelse(p_s_search_path);
+	    *p_n_repeat |= n_repeat;
+	    return IO_ERROR;
+	}
+
+	*p_n_repeat |= n_repeat;
+
+	/* It is possible that schedule occured. We must check whether
+	   the key to search is still in the tree rooted from the
+	   current buffer. If not then repeat search from the root. */
+	if ( n_repeat != CARRY_ON && 
+	     (!B_IS_IN_TREE (p_s_bh) || (! key_in_buffer(p_s_search_path, p_s_key, p_s_sb))) ) {
+	    pathrelse (p_s_search_path);
+
+	    /* Get the root block number so that we can repeat the
+               search starting from the root. */
+	    n_block_number  = SB_ROOT_BLOCK (p_s_sb);
+	    expected_level = SB_TREE_HEIGHT (p_s_sb);
+	    right_neighbor_of_leaf_node = 0;
+
+	    /* repeat search from the root */
+	    continue;
+	}
+
+#ifdef CONFIG_REISERFS_CHECK
+
+	if ( ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb) )
+	    reiserfs_panic(p_s_sb, "PAP-5130: search_by_key: key is not in the buffer");
+	if ( cur_tb ) {
+/*	print_tb (init_mode, init_item_pos, init_pos_in_item, &init_tb, "5140");*/
+	    reiserfs_panic(p_s_sb, "PAP-5140: search_by_key: schedule occurred in do_balance!");
+	}
+
+#endif
+
+	// make sure, that the node contents look like a nod of
+	// certain level
+	if (!is_tree_node (p_s_bh, expected_level)) {
+	    print_block (stderr, 0, p_s_bh, 3, -1, -1);
+	    reiserfs_panic ("vs-5150: search_by_key: expeced level %d", expected_level);
+	    pathrelse (p_s_search_path);
+	    return IO_ERROR;
+	}
+
+	/* ok, we have acquired next formatted node in the tree */
+	n_retval = bin_search (p_s_key, B_N_PITEM_HEAD(p_s_bh, 0), B_NR_ITEMS(p_s_bh),
+			       is_leaf_node (p_s_bh) ? IH_SIZE : KEY_SIZE, &(p_s_last_element->pe_position));
+	if (node_level (p_s_bh) == n_stop_level)
+	    return n_retval;
+
+	/* we are not in the stop level */
+	if (n_retval == ITEM_FOUND)
+	    /* item has been found, so we choose the pointer which is to the right of the found one */
+	    p_s_last_element->pe_position++;
+	/* if item was not found we choose the position which is to the left of the found item. This
+	   requires no code, bin_search did it already.*/
+
+
+	/* So we have chosen a position in the current node which is an
+	   internal node.  Now we calculate child block number by position in the node. */
+	n_block_number = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position);
+    }
+}
+
+
+int bin_search_in_dir_item (struct item_head * ih, struct reiserfs_de_head * deh, 
+			    struct key * key, int * pos_in_item)
+{
+    int rbound, lbound, j;
+
+    lbound = 0;
+    rbound = ih_entry_count (ih) - 1;
+
+    for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) {
+	if (get_offset (key) < deh_offset (deh + j)) {
+	    rbound = j - 1;
+	    continue;
+	}
+	if (get_offset (key) > deh_offset (deh + j)) {
+	    lbound = j + 1;
+	    continue;
+	}
+	/* key found */
+	*pos_in_item = j;
+	return POSITION_FOUND;
+    }
+    
+    *pos_in_item = lbound;
+    return POSITION_NOT_FOUND;
+}
diff --git a/reiserfsprogs.spec b/reiserfsprogs.spec
new file mode 100644
index 0000000..ad24125
--- /dev/null
+++ b/reiserfsprogs.spec
@@ -0,0 +1,62 @@
+Vendor:       Hans Reiser
+Distribution: Hans Reiser
+Name:         reiserfsprogs
+Release:      1
+Copyright:    2001 Hans Reiser
+Group:        Unsorted
+
+Packager:     anthon@mnt.org
+
+Version:      3.x.0j
+Summary:      utilities belonging to the Reiser filesystem
+Source:       reiserfsprogs-%{version}.tar.gz
+BuildRoot:    /var/tmp/rpm-reiserfsprogs
+%description
+
+The reiserfsprogs package contains programs for creating (mkreiserfs),
+checking and correcting any inconsistencies (reiserfsck) and resizing
+(resize_reiserfs) of a reiserfs filesystem.
+
+Authors:
+--------
+Hans Reiser <reiser@namesys.com>
+Vitaly Fertman <vetalf@inbox.ru>
+Alexander Zarochentcev <zam@namesys.com>
+Vladimir Saveliev <vs@namesys.botik.ru>
+
+%prep
+%setup -q
+# %patch
+%build
+  MANDIR=$(dirname $(dirname $(man -w fsck | cut -d ' ' -f 1)))
+  ./configure --prefix="" --mandir=$MANDIR
+  make all
+%install
+    mkdir -p $RPM_BUILD_ROOT/sbin
+    make DESTDIR=$RPM_BUILD_ROOT install
+# do we need this?
+    cd $RPM_BUILD_ROOT/sbin
+    ln -sf reiserfsck fsck.reiserfs
+
+# __os_install_post is normally executed after %install disable it
+%define ___build_post %{nil} 
+# explicitly call it now, so manpages get compressed, exec's stripped etc.
+%{?__os_install_post}
+%define __os_install_post %{nil}
+# now we have all the files execpt for docs, but their owner is unimportant
+cd $RPM_BUILD_ROOT
+
+rm -f rpm-filelist
+# we do not have special directories to make
+#find . -type d \
+# | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' >> rpm-filelist
+find . -type f \
+ | sed 's,^\.,\%attr(-\,root\,root) ,' | fgrep -v rpm-filelist >> rpm-filelist
+find . -type l \
+ | sed 's,^\.,\%attr(-\,root\,root) ,' >> rpm-filelist
+
+%clean
+# in case some overrides buildroot with / don't remove the whole tree
+    rm -rf /var/tmp/rpm-reiserfsprogs
+%files -f /var/tmp/rpm-reiserfsprogs/rpm-filelist
+%doc README
diff --git a/resize_reiserfs/Makefile.am b/resize_reiserfs/Makefile.am
new file mode 100644
index 0000000..0af4bea
--- /dev/null
+++ b/resize_reiserfs/Makefile.am
@@ -0,0 +1,9 @@
+sbin_PROGRAMS = resize_reiserfs
+
+resize_reiserfs_SOURCES = fe.c resize_reiserfs.c do_shrink.c resize.h
+man_MANS = resize_reiserfs.8
+EXTRA_DIST = $(man_MANS)
+
+LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
+
+INCLUDES = -I../include
diff --git a/resize_reiserfs/Makefile.in b/resize_reiserfs/Makefile.in
new file mode 100644
index 0000000..d03f545
--- /dev/null
+++ b/resize_reiserfs/Makefile.in
@@ -0,0 +1,331 @@
+# 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 = resize_reiserfs
+
+resize_reiserfs_SOURCES = fe.c resize_reiserfs.c do_shrink.c resize.h
+man_MANS = resize_reiserfs.8
+EXTRA_DIST = $(man_MANS)
+
+LDADD = ../lib/libmisc.a ../reiserfscore/libcore.a
+
+INCLUDES = -I../include
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES = 
+PROGRAMS =  $(sbin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) 
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+resize_reiserfs_OBJECTS =  fe.o resize_reiserfs.o do_shrink.o
+resize_reiserfs_LDADD = $(LDADD)
+resize_reiserfs_DEPENDENCIES =  ../lib/libmisc.a \
+../reiserfscore/libcore.a
+resize_reiserfs_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 = $(resize_reiserfs_SOURCES)
+OBJECTS = $(resize_reiserfs_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 resize_reiserfs/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:
+
+resize_reiserfs: $(resize_reiserfs_OBJECTS) $(resize_reiserfs_DEPENDENCIES)
+	@rm -f resize_reiserfs
+	$(LINK) $(resize_reiserfs_LDFLAGS) $(resize_reiserfs_OBJECTS) $(resize_reiserfs_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 = resize_reiserfs
+
+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
+do_shrink.o: do_shrink.c resize.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h
+fe.o: fe.c resize.h ../include/io.h ../include/misc.h \
+	../include/reiserfs_lib.h ../include/reiserfs_fs.h ../version.h
+resize_reiserfs.o: resize_reiserfs.c resize.h ../include/io.h \
+	../include/misc.h ../include/reiserfs_lib.h \
+	../include/reiserfs_fs.h ../version.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:
diff --git a/resize_reiserfs/do_shrink.c b/resize_reiserfs/do_shrink.c
new file mode 100644
index 0000000..62b3026
--- /dev/null
+++ b/resize_reiserfs/do_shrink.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+#include <time.h>
+#include "resize.h"
+
+
+static unsigned long int_node_cnt   = 0, int_moved_cnt   = 0;
+static unsigned long leaf_node_cnt  = 0, leaf_moved_cnt  = 0;
+static unsigned long unfm_node_cnt  = 0, unfm_moved_cnt  = 0;
+static unsigned long total_node_cnt = 0;
+static unsigned long total_moved_cnt = 0;
+
+static unsigned long unused_block;
+static unsigned long blocks_used;
+static int block_count_mismatch = 0;
+
+static reiserfs_bitmap_t  bmp;
+static reiserfs_filsys_t fs;
+static struct reiserfs_super_block * rs;
+
+/* abnornal exit from block reallocation process */
+static void quit_resizer()
+{
+	/* save changes to bitmap blocks */
+	reiserfs_flush_bitmap (bmp, fs);
+	reiserfs_close (fs);
+	/* leave fs in ERROR state */
+	die ("resize_reiserfs: fs shrinking was not completed successfully, run reiserfsck.\n");
+}
+
+/* block moving */
+static unsigned long move_generic_block(unsigned long block, unsigned long bnd, int h)
+{
+    struct buffer_head * bh, * bh2;
+
+	/* primitive fsck */
+	if (block > rs_block_count(rs)) {
+		fprintf(stderr, "resize_reiserfs: invalid block number (%lu) found.\n", block);
+		quit_resizer();
+	}
+	/* progress bar, 3D style :) */
+	if (opt_verbose)
+	    print_how_far(&total_node_cnt, blocks_used, 1, 0);
+	else
+	    total_node_cnt ++;
+
+	/* infinite loop check */
+	if( total_node_cnt > blocks_used && !block_count_mismatch) {
+		fputs("resize_reiserfs: warning: block count exeeded\n",stderr);
+		block_count_mismatch = 1;
+	}
+
+	if (block < bnd) /* block will not be moved */
+		return 0;
+	
+	/* move wrong block */ 
+	bh = bread(fs->s_dev, block, fs->s_blocksize);
+
+	reiserfs_bitmap_find_zero_bit(bmp, &unused_block);
+	if (unused_block == 0 || unused_block >= bnd) {
+		fputs ("resize_reiserfs: can\'t find free block\n", stderr);
+		quit_resizer();
+	}
+
+	/* blocknr changing */
+	bh2 = getblk(fs->s_dev, unused_block, fs->s_blocksize);
+	memcpy(bh2->b_data, bh->b_data, bh2->b_size);
+	reiserfs_bitmap_clear_bit(bmp, block);
+	reiserfs_bitmap_set_bit(bmp, unused_block);
+
+	brelse(bh);
+	mark_buffer_uptodate(bh2,1);
+	mark_buffer_dirty(bh2);
+	bwrite(bh2);
+	brelse(bh2);
+
+	total_moved_cnt++;
+	return unused_block;
+}
+
+static unsigned long move_unformatted_block(unsigned long block, unsigned long bnd, int h)
+{
+	unsigned long b;
+	unfm_node_cnt++;
+	b = move_generic_block(block, bnd, h);
+	if (b)
+		unfm_moved_cnt++;
+	return b;		
+}
+
+
+/* recursive function processing all tree nodes */
+static unsigned long move_formatted_block(unsigned long block, unsigned long bnd, int h)
+{
+	struct buffer_head * bh;
+	struct item_head *ih;
+	unsigned long new_blocknr = 0;
+	int node_is_internal = 0;
+	int i, j;
+	
+	bh = bread(fs->s_dev, block, fs->s_blocksize);
+	
+	if (is_leaf_node (bh)) {
+		
+		leaf_node_cnt++;
+		
+		for (i=0; i < B_NR_ITEMS(bh); i++) {
+			ih = B_N_PITEM_HEAD(bh, i);
+			if (is_indirect_ih(ih)) {
+				__u32 * indirect;
+
+				indirect = (__u32 *)B_I_PITEM (bh, ih);
+				for (j = 0; j < I_UNFM_NUM(ih); j++) {
+					unsigned long  unfm_block;
+
+					if (indirect [j] == 0) /* hole */
+						continue;
+					unfm_block = move_unformatted_block(le32_to_cpu (indirect [j]), bnd, h + 1);
+					if (unfm_block) {
+						indirect [j] = cpu_to_le32 (unfm_block);
+						mark_buffer_dirty(bh);
+					}
+				}
+			}	
+		}
+	} else if (is_internal_node (bh)) { /* internal node */
+		
+		int_node_cnt++;
+		node_is_internal = 1;
+		
+		for (i=0; i <= B_NR_ITEMS(bh); i++) {
+			unsigned long moved_block;
+			moved_block = move_formatted_block(B_N_CHILD_NUM(bh, i), bnd, h+1);
+			if (moved_block) {
+				set_dc_block_number (bh, i, moved_block);
+				mark_buffer_dirty(bh);
+			}
+		}	
+	} else {
+		die ("resize_reiserfs: block (%lu) has invalid format\n", block);
+	}
+	
+	if (buffer_dirty(bh)) {
+		mark_buffer_uptodate(bh,1);
+		bwrite(bh);
+	}
+	
+	brelse(bh);	
+	
+	new_blocknr = move_generic_block(block, bnd, h);
+	if (new_blocknr) {
+		if (node_is_internal)
+			int_moved_cnt++;
+		else
+			leaf_moved_cnt++;
+	}
+	
+	return new_blocknr;
+}
+
+int shrink_fs(reiserfs_filsys_t reiserfs, unsigned long blocks)
+{
+	unsigned long n_root_block;
+	unsigned int bmap_nr_new;
+	unsigned long int i;
+	
+	fs = reiserfs;
+	rs = fs->s_rs;
+	
+	/* warn about alpha version */
+	{
+		int c;
+
+		printf(
+			"You are running BETA version of reiserfs shrinker.\n"
+			"This version is only for testing or VERY CAREFUL use.\n"
+			"Backup of you data is recommended.\n\n"
+			"Do you want to continue? [y/N]:"
+			);
+		c = getchar();
+		if (c != 'y' && c != 'Y')
+			exit(1);
+	}
+
+	bmap_nr_new = (blocks - 1) / (8 * fs->s_blocksize) + 1;
+	
+	/* is shrinking possible ? */
+	if (rs_block_count(rs) - blocks > rs_free_blocks(rs) + rs_bmap_nr(rs) - bmap_nr_new) {
+	    fprintf(stderr, "resize_reiserfs: can\'t shrink fs; too many blocks already allocated\n");
+	    return -1;
+	}
+
+	reiserfs_reopen(fs, O_RDWR);
+	set_state (fs->s_rs, REISERFS_ERROR_FS);
+	mark_buffer_uptodate(SB_BUFFER_WITH_SB(fs), 1);
+	mark_buffer_dirty(SB_BUFFER_WITH_SB(fs));
+	bwrite(SB_BUFFER_WITH_SB(fs));
+
+	/* calculate number of data blocks */		
+	blocks_used = 
+	    SB_BLOCK_COUNT(fs)
+	    - SB_FREE_BLOCKS(fs)
+	    - SB_BMAP_NR(fs)
+	    - SB_JOURNAL_SIZE(fs)
+	    - REISERFS_DISK_OFFSET_IN_BYTES / fs->s_blocksize
+	    - 2; /* superblock itself and 1 descriptor after the journal */
+
+	bmp = reiserfs_create_bitmap(rs_block_count(rs));
+	reiserfs_fetch_disk_bitmap(bmp, fs);
+
+	unused_block = 1;
+
+	if (opt_verbose) {
+		printf("Processing the tree: ");
+		fflush(stdout);
+	}
+
+	n_root_block = move_formatted_block(rs_root_block(rs), blocks, 0);
+	if (n_root_block) {
+		set_root_block (rs, n_root_block);
+	}
+
+	if (opt_verbose)
+	    printf ("\n\nnodes processed (moved):\n"
+		    "int        %lu (%lu),\n"
+		    "leaves     %lu (%lu),\n" 
+		    "unfm       %lu (%lu),\n"
+		    "total      %lu (%lu).\n\n",
+		    int_node_cnt, int_moved_cnt,
+		    leaf_node_cnt, leaf_moved_cnt, 
+		    unfm_node_cnt, unfm_moved_cnt,
+		    (unsigned long)total_node_cnt, total_moved_cnt);
+
+	if (block_count_mismatch) {
+	    fprintf(stderr, "resize_reiserfs: data block count %lu"
+		    " doesn\'t match data block count %lu from super block\n",
+		    (unsigned long)total_node_cnt, blocks_used);
+	}
+#if 0
+	printf("check for used blocks in truncated region\n");
+	{
+		unsigned long l;
+		for (l = blocks; l < rs_block_count(rs); l++)
+			if (is_block_used(bmp, l))
+				printf("<%lu>", l);
+		printf("\n");
+	}
+#endif /* 0 */
+
+	reiserfs_free_bitmap_blocks(fs);
+	
+	set_free_blocks (rs, rs_free_blocks(rs) - (rs_block_count(rs) - blocks) + (rs_bmap_nr(rs) - bmap_nr_new));
+	set_block_count (rs, blocks);
+	set_bmap_nr (rs, bmap_nr_new);
+
+	reiserfs_read_bitmap_blocks(fs);
+	
+	for (i = blocks; i < bmap_nr_new * fs->s_blocksize; i++)
+		reiserfs_bitmap_set_bit(bmp, i);
+#if 0
+	PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (SB_BLOCK_COUNT(s) - blocks) + (SB_BMAP_NR(s) - bmap_nr_new));
+	PUT_SB_BLOCK_COUNT(s, blocks);
+	PUT_SB_BMAP_NR(s, bmap_nr_new);
+#endif
+	reiserfs_flush_bitmap(bmp, fs);
+
+	return 0;
+}
diff --git a/resize_reiserfs/fe.c b/resize_reiserfs/fe.c
new file mode 100644
index 0000000..c14c2c5
--- /dev/null
+++ b/resize_reiserfs/fe.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+
+#include "resize.h"
+
+
+/* the front-end for kernel on-line resizer */
+int resize_fs_online(char * devname, unsigned long blocks)
+{
+	static char buf[40];
+	FILE * f;
+	struct mntent * mnt;
+	
+	if ((f = setmntent (MOUNTED, "r")) == NULL)
+		goto fail;
+
+    while ((mnt = getmntent (f)) != NULL)
+        if(strcmp(devname, mnt->mnt_fsname) == 0) {
+
+			if (strcmp(mnt->mnt_type,"reiserfs")) 			
+				die ("resize_reiserfs: can\'t resize fs other than reiserfs\n");
+				
+			sprintf(buf,"resize=%lu", blocks);
+
+			if (mount(mnt->mnt_fsname, mnt->mnt_dir, mnt->mnt_type,
+          			  (unsigned long)(MS_MGC_VAL | MS_REMOUNT), buf)) 
+				die ("resize_reiserfs: remount failed: %s\n", strerror(errno));
+			
+			endmntent(f);
+			return 0;
+		}
+fail:
+   die ("resize_reiserfs: can't find mount entry\n");
+   return 1;
+}
+
diff --git a/resize_reiserfs/resize.h b/resize_reiserfs/resize.h
new file mode 100644
index 0000000..937b500
--- /dev/null
+++ b/resize_reiserfs/resize.h
@@ -0,0 +1,48 @@
+/* 
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <asm/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <mntent.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#if __GLIBC__ >= 2
+#include <sys/mount.h>
+#else
+#include <linux/fs.h>
+#endif
+
+
+#include "io.h"
+#include "misc.h"
+#include "reiserfs_lib.h"
+#include "../version.h"
+
+
+#define print_usage_and_exit()\
+ die ("Usage: %s  [-s[+|-]#[G|M|K]] [-fqv] device", argv[0])
+ 
+
+/* reiserfs_resize.c */
+extern struct buffer_head * g_sb_bh;
+
+extern int opt_force;
+extern int opt_verbose;
+extern int opt_nowrite;
+extern int opt_safe;
+
+int expand_fs(struct super_block * s, unsigned long block_count_new);
+
+/* fe.c */
+int resize_fs_online(char * devname, unsigned long blocks);
+
+/* do_shrink.c */
+int shrink_fs(struct super_block * s, unsigned long blocks);
diff --git a/resize_reiserfs/resize_reiserfs.8 b/resize_reiserfs/resize_reiserfs.8
new file mode 100644
index 0000000..66a3f25
--- /dev/null
+++ b/resize_reiserfs/resize_reiserfs.8
@@ -0,0 +1,116 @@
+.\" -*- nroff -*-
+.\" Copyright 1996-2001 Hans Reiser.
+.\" 
+.TH RESIZE_REISERFS 8 "March 2001" "Reiserfsprogs-3.x.0j"
+.SH NAME
+resize_reiserfs \- Reiserfs filesystem resizer
+.SH SYNOPSIS
+.BR resize_reiserfs
+[
+.B \-s
+.IR \fR[\fB+\fR|\fB\- ]\fIsize [\fBK\fR|\fBM\fR|\fBG\fR]
+] [
+.B \-fqv
+]
+.I device
+.SH DESCRIPTION
+The
+.B resize_reiserfs
+tool resizes an unmounted reiserfs file system.  It enlarges or shrinks an
+reiserfs file system located on a
+.I device
+so that it will have
+.I size
+bytes or size=old_size +(\-)
+.I size
+bytes if the + or \- prefix is used.
+If the
+.B \-s
+option is not specified, the filesystem will be resized to fill the
+given device.
+The
+.I size
+parameter may have one of the optional modifiers
+.BR K ", " M ", " G ,
+which means the
+.I size
+parameter is given in kilo\-, mega\-, gigabytes respectively.
+.PP
+The
+.B resize_reiserfs
+program does not manipulate the size of the device. If you wish to
+enlarge a filesystem, you must make sure you expand the underlying
+device first. This can be done using
+.BR cfdisk (8)
+for partitions, by deleting the partition and recreating it with a
+larger size (assuming there is free space
+.I after
+the partition in question).  Make sure you re\-create it with the
+same starting disk cylinder as before!  Otherwise, the resize operation
+will certainly not work, and you may lose your entire filesystem.
+.PP
+The
+.B resize_reiserfs
+program allows to grow a reiserfs on-line if there is a free
+space on block
+.I device.
+
+.PP
+If you wish to shrink an reiserfs partition, first use
+.B resize_reiserfs
+to shrink the file system. You may then use
+.BR cfdisk (8)
+to shrink the device. When shrinking the size of the device, make sure
+you do not make it smaller than the reduced size of the reiserfs filesystem.
+
+.SH OPTIONS
+.TP
+.BR \-s\ [+|\-]\fIsize
+Set the new size in bytes.
+.TP
+.BR \-f
+Force, do not perform checks.
+.TP
+.BR \-q
+Do not print anything but error messages.
+.TP
+.BR \-v 
+Turn on extra progress status messages (default).
+
+.SH RETURN VALUES
+0	Resizing successful.
+.TP
+\-1	In another case.
+
+.SH EXAMPLES
+The following example shows how to test
+.B resize_reiserfs\fR.
+Suppose 2Gb reiserfs filesystem is created on the device /dev/hda8
+and is mounted on /mnt. 
+For shrinking the device we need to unmount it first, then run
+.B resize_reiserfs
+with a
+.I size \fR parameter (in this case -1Gb):
+.PP
+\	df
+.br
+\	umount /mnt
+.br
+\	resize_reiserfs -s -1G /dev/hda8
+.br
+\	mount /dev/hda8 /mnt
+.br
+\	df /mnt
+
+.SH WARNING
+Note that this is a BETA program and may corrupt filesystems.
+.SH AUTHOR
+This version of
+.B resize_reiserfs
+has been written by Alexander Zarochentcev <zam@namesys.com>.
+.SH BUGS
+Please, report about the bugs to Alexander Zarochentcev <zam@namesys.com> or 
+to Hans Reiser <reiser@namesys.com>.
+.SH SEE ALSO
+.BR cfsck (8),
+.BR debugreiserfs (8)
diff --git a/resize_reiserfs/resize_reiserfs.c b/resize_reiserfs/resize_reiserfs.c
new file mode 100644
index 0000000..3db3d21
--- /dev/null
+++ b/resize_reiserfs/resize_reiserfs.c
@@ -0,0 +1,257 @@
+/* 
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ */
+ 
+/*  
+ * Written by Alexander Zarochentcev.
+ * 
+ * FS resize utility 
+ *
+ */
+
+#include "resize.h"
+
+int opt_force = 0;
+int opt_verbose = 1;			/* now "verbose" option is default */
+int opt_nowrite = 0;
+int opt_safe = 0;
+
+#if 0
+/* Given a file descriptor and an offset, check whether the offset is
+   a valid offset for the file - return 0 if it isn't valid or 1 if it
+   is */
+int valid_offset( int fd, loff_t offset )
+{
+    char ch;
+
+    if (lseek64 (fd, offset, 0) < 0)
+	return 0;
+
+    if (read (fd, &ch, 1) < 1)
+	return 0;
+
+    return 1;
+}
+#endif
+
+/* calculate the new fs size (in blocks) from old fs size and the string
+   representation of new size */
+static unsigned long calc_new_fs_size(unsigned long count, int bs,
+				      char *bytes_str)
+{
+    long long int bytes;
+    unsigned long blocks;
+    int c;
+	
+    bytes = atoll(bytes_str);
+    c = bytes_str[strlen(bytes_str) - 1];
+
+    switch (c) {
+    case 'G':
+    case 'g':
+	bytes *= 1024;
+    case 'M':
+    case 'm':
+	bytes *= 1024;
+    case 'K':
+    case 'k':
+	bytes *= 1024;
+    }
+	
+    blocks = bytes / bs;
+
+    if (bytes_str[0] == '+' || bytes_str[0] == '-')
+	return (count + blocks);
+
+    return blocks;
+}
+
+/* print some fs parameters */
+static void sb_report(struct reiserfs_super_block * sb1,
+		      struct reiserfs_super_block * sb2)
+{
+    printf(
+	"ReiserFS report:\n"
+	"blocksize             %d\n"
+	"block count           %d (%d)\n"
+	"free blocks           %d (%d)\n"
+	"bitmap block count    %d (%d)\n", 
+	rs_blocksize(sb1),
+	rs_block_count(sb1), rs_block_count(sb2),
+	rs_free_blocks(sb1), rs_free_blocks(sb2),
+	rs_bmap_nr(sb1), rs_bmap_nr(sb2));
+};
+
+/* conditional bwrite */
+static int bwrite_cond (struct buffer_head * bh)
+{
+    if(!opt_nowrite) { 
+	mark_buffer_uptodate(bh,1);
+	mark_buffer_dirty(bh);
+	bwrite(bh);
+    }
+    return 0;
+}
+
+
+/* the first one of the mainest functions */
+int expand_fs (reiserfs_filsys_t fs, unsigned long block_count_new) {
+    int block_r, block_r_new;
+    unsigned int bmap_nr_new, bmap_nr_old;
+    int i;
+
+    reiserfs_bitmap_t bmp;
+    struct reiserfs_super_block * rs = fs->s_rs;
+
+    reiserfs_reopen(fs, O_RDWR);
+    set_state (fs->s_rs, REISERFS_ERROR_FS);
+    bwrite_cond(SB_BUFFER_WITH_SB(fs));
+	
+    bmp = reiserfs_create_bitmap(rs_block_count(rs));
+    if (!bmp)
+	die ("cannot create bitmap\n");
+    reiserfs_fetch_disk_bitmap(bmp, fs);
+    reiserfs_free_bitmap_blocks(fs);
+    if (reiserfs_expand_bitmap(bmp, block_count_new))
+	die ("cannot expand bitmap\n");
+
+    /* clean bits in old bitmap tail */
+    for (i = rs_block_count(rs);
+	 i < rs_bmap_nr(rs) * rs_blocksize(rs) * 8 && i < block_count_new;
+	 i++) {
+	reiserfs_bitmap_clear_bit(bmp, i);
+    }
+    
+    /* count used bits in last bitmap block */
+    block_r = rs_block_count(rs) - ((rs_bmap_nr(rs) - 1) * rs_blocksize(rs) * 8);
+
+    /* count bitmap blocks in new fs */
+    bmap_nr_new = (block_count_new - 1) / (rs_blocksize(rs) * 8) + 1;
+    block_r_new = block_count_new - (bmap_nr_new - 1) * rs_blocksize(rs) * 8;
+
+    bmap_nr_old = rs_bmap_nr(rs);
+	
+    /* update super block buffer*/
+    set_free_blocks (rs, rs_free_blocks(rs) + block_count_new
+		     - rs_block_count(rs) - (bmap_nr_new - rs_bmap_nr(rs)));
+    set_block_count (rs, block_count_new);
+    set_bmap_nr (rs, bmap_nr_new);
+
+    reiserfs_read_bitmap_blocks(fs); 
+    for (i = bmap_nr_old; i < bmap_nr_new; i++) /* fix new bitmap blocks */
+	reiserfs_bitmap_set_bit(bmp, SB_AP_BITMAP(fs)[i]->b_blocknr);
+    reiserfs_flush_bitmap(bmp, fs);
+    
+    return 0;
+}
+
+int main(int argc, char *argv[]) {
+    char * bytes_count_str = NULL;
+    char * devname;
+    reiserfs_filsys_t fs;
+    struct reiserfs_super_block * rs;
+	
+    int c;
+    int error;
+
+    struct reiserfs_super_block *sb_old;
+
+    unsigned long block_count_new;
+
+    print_banner ("resize_reiserfs");
+	
+    while ((c = getopt(argc, argv, "fvcqs:")) != EOF) {
+	switch (c) {
+	case 's' :
+	    if (!optarg) 
+		die("%s: Missing argument to -s option", argv[0]);		
+	    bytes_count_str = optarg;
+	    break;
+	case 'f':
+	    opt_force = 1;
+	    break;		 
+	case 'v':
+	    opt_verbose++; 
+	    break;
+	case 'n':
+	    /* no nowrite option at this moment */
+	    /* opt_nowrite = 1; */
+	    break;
+	case 'c':
+	    opt_safe = 1;
+	    break;
+	case 'q':
+	    opt_verbose = 0;
+	    break;
+	default:
+	    print_usage_and_exit ();
+	}
+    }
+
+    if (optind == argc )
+	print_usage_and_exit();
+    devname = argv[optind];
+
+    fs = reiserfs_open(devname, O_RDONLY, &error, 0);
+    if (!fs)
+	die ("%s: can not open '%s': %s", argv[0], devname, strerror(error));
+
+    if (no_reiserfs_found (fs)) {
+	die ("resize_reiserfs: no reiserfs found on the device");
+    }
+    if (!spread_bitmaps (fs)) {
+	die ("resize_reiserfs: cannot resize reiserfs in old (not spread bitmap) format.\n");
+    }
+
+    rs = fs->s_rs;
+	
+    if(bytes_count_str) {	/* new fs size is specified by user */
+	block_count_new = calc_new_fs_size(rs_block_count(rs), fs->s_blocksize, bytes_count_str);
+    } else {		/* use whole device */
+	block_count_new = count_blocks(devname, fs->s_blocksize, -1);
+    }
+
+    if (is_mounted (devname)) {
+	reiserfs_close(fs);
+	return resize_fs_online(devname, block_count_new);
+    }	
+	
+    if (rs_state(rs) != REISERFS_VALID_FS)
+	die ("%s: the file system isn't in valid state\n", argv[0]);
+		
+    if(!valid_offset(fs->s_dev, (loff_t) block_count_new * fs->s_blocksize - 1))
+	die ("%s: %s too small", argv[0], devname);
+
+    sb_old = 0;		/* Needed to keep idiot compiler from issuing false warning */
+    /* save SB for reporting */
+    if(opt_verbose) {
+	sb_old = getmem(SB_SIZE);
+	memcpy(sb_old, SB_DISK_SUPER_BLOCK(fs), SB_SIZE);
+    }
+
+    if (block_count_new == SB_BLOCK_COUNT(fs)) 
+	die ("%s: Calculated fs size is the same as the previous one.", argv[0]);
+
+    if (block_count_new > SB_BLOCK_COUNT(fs))
+	expand_fs(fs, block_count_new);
+    else
+	shrink_fs(fs, block_count_new);
+
+    if(opt_verbose) {
+	sb_report(rs, sb_old);
+	freemem(sb_old);
+    }
+
+    set_state (rs, REISERFS_VALID_FS);
+    bwrite_cond(SB_BUFFER_WITH_SB(fs));
+	
+    if (opt_verbose) {
+	printf("\nSyncing..");
+	fflush(stdout);
+    }
+    reiserfs_close (fs);
+    if (opt_verbose)
+	printf("done\n");
+	
+    return 0;
+}
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..542da44
--- /dev/null
+++ b/version.h
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2000 Hans Reiser
+ */
+
+#define REISERFSPROGS_VERSION "3.x.0j"
+
+#define print_banner(prog) \
+fprintf (stderr, "\n<-------------%s, 2001------------->\nreiserfsprogs %s\n", \
+prog, REISERFSPROGS_VERSION)