aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2012-10-11 11:26:22 -0400
committerJeff Mahoney <jeffm@suse.com>2012-10-11 11:26:22 -0400
commite7102bdb66ffebd7d55ac54c46124706e15a4233 (patch)
tree2a455f22a881b0c33605e887a461c63d5ecd65bb
downloadreiserfsprogs-e7102bdb66ffebd7d55ac54c46124706e15a4233.tar.gz
Initial commit -- seeded with reiserfsprogs 3.x.0jv3.x.0j
-rw-r--r--AUTHORS0
-rw-r--r--COPYING340
-rw-r--r--ChangeLog120
-rw-r--r--INSTALL182
-rw-r--r--Makefile.am4
-rw-r--r--Makefile.in318
-rw-r--r--NEWS0
-rw-r--r--README157
-rw-r--r--aclocal.m4104
-rwxr-xr-xconfigure2066
-rw-r--r--configure.in48
-rw-r--r--debugreiserfs/Makefile.am10
-rw-r--r--debugreiserfs/Makefile.in339
-rw-r--r--debugreiserfs/debugreiserfs.868
-rw-r--r--debugreiserfs/debugreiserfs.c1044
-rw-r--r--debugreiserfs/debugreiserfs.h135
-rw-r--r--debugreiserfs/pack.c765
-rw-r--r--debugreiserfs/unpack.c558
-rw-r--r--fsck/Makefile.am11
-rw-r--r--fsck/Makefile.in358
-rw-r--r--fsck/check.c329
-rw-r--r--fsck/check_tree.c915
-rw-r--r--fsck/fsck.h425
-rw-r--r--fsck/info.c134
-rw-r--r--fsck/journal.c219
-rw-r--r--fsck/lost+found.c269
-rw-r--r--fsck/main.c709
-rw-r--r--fsck/pass0.c1502
-rw-r--r--fsck/pass1.c881
-rw-r--r--fsck/pass2.c485
-rw-r--r--fsck/pass4.c79
-rw-r--r--fsck/reiserfsck.891
-rw-r--r--fsck/segments.c202
-rw-r--r--fsck/semantic.c1346
-rw-r--r--fsck/ubitmap.c189
-rw-r--r--fsck/ufile.c1069
-rw-r--r--fsck/uobjectid.c391
-rw-r--r--fsck/ustree.c704
-rw-r--r--include/Makefile.am1
-rw-r--r--include/Makefile.in197
-rw-r--r--include/io.h57
-rw-r--r--include/misc.h42
-rw-r--r--include/reiserfs_fs.h1392
-rw-r--r--include/reiserfs_lib.h199
-rwxr-xr-xinstall-sh251
-rw-r--r--lib/Makefile.am23
-rw-r--r--lib/Makefile.in260
-rw-r--r--lib/io.c508
-rw-r--r--lib/misc.c613
-rwxr-xr-xmissing190
-rwxr-xr-xmkinstalldirs40
-rw-r--r--mkreiserfs/Makefile.am9
-rw-r--r--mkreiserfs/Makefile.in325
-rw-r--r--mkreiserfs/mkreiserfs.862
-rw-r--r--mkreiserfs/mkreiserfs.c504
-rw-r--r--reiserfscore/Makefile.am5
-rw-r--r--reiserfscore/Makefile.in280
-rw-r--r--reiserfscore/bitmap.c448
-rw-r--r--reiserfscore/do_balan.c1720
-rw-r--r--reiserfscore/fix_node.c2916
-rw-r--r--reiserfscore/hashes.c253
-rw-r--r--reiserfscore/ibalance.c1052
-rw-r--r--reiserfscore/includes.h18
-rw-r--r--reiserfscore/lbalance.c1367
-rw-r--r--reiserfscore/node_formats.c887
-rw-r--r--reiserfscore/prints.c949
-rw-r--r--reiserfscore/reiserfslib.c766
-rw-r--r--reiserfscore/stree.c475
-rw-r--r--reiserfsprogs.spec62
-rw-r--r--resize_reiserfs/Makefile.am9
-rw-r--r--resize_reiserfs/Makefile.in331
-rw-r--r--resize_reiserfs/do_shrink.c269
-rw-r--r--resize_reiserfs/fe.c37
-rw-r--r--resize_reiserfs/resize.h48
-rw-r--r--resize_reiserfs/resize_reiserfs.8116
-rw-r--r--resize_reiserfs/resize_reiserfs.c257
-rw-r--r--version.h9
77 files changed, 33513 insertions, 0 deletions
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)