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