mirror of https://github.com/vitalif/e2fsprogs
Check in ext2ed version 0.1
parent
7de6577cd9
commit
583a1ce5d1
|
@ -0,0 +1,346 @@
|
|||
EXT2ED is hereby placed under the terms of the GNU General Public License.
|
||||
Follows the GNU license.
|
||||
|
||||
Gadi Oxman, August 1995
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, 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
|
||||
|
||||
Appendix: 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) 19yy <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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy 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,78 @@
|
|||
# /gadi/project/Makefile
|
||||
#
|
||||
# Makefile for the extended-2 filesystem editor.
|
||||
#
|
||||
# First created : April 8 1995
|
||||
#
|
||||
# Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# EXT2ED, ncurses and readline
|
||||
# ------------------------------------------------------------------------
|
||||
#
|
||||
# EXT2ED requires the ncurses and readline libraries.
|
||||
#
|
||||
# Please define OLD_NCURSES below if you are using an old version of ncurses.
|
||||
# I don't know the exact threshold, but from my experience this flag is needed
|
||||
# for version 1.8.5 and not needed for 1.9.2c and up. In any case, you will
|
||||
# notice immediately that this flag is wrong - The main window will be totally
|
||||
# corrupted.
|
||||
|
||||
# FLAGS = -DOLD_NCURSES
|
||||
|
||||
# Define the directories below to insure that the compiler will find the
|
||||
# required ncurses and readline include files / libraries. Be sure that you
|
||||
# don't mix two two versions of ncurses.
|
||||
|
||||
# NCURSES_INCLUDE = -I/usr/local/include -I/usr/local/include/ncurses
|
||||
# NCURSES_LIB = -L/usr/local/lib
|
||||
# READLINE_INCLUDE = -I/usr/include -I/usr/include/readline
|
||||
# READLINE_LIB = -L/usr/lib
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Install Directories
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
# The executable will go into BIN_DIR.
|
||||
# The configuration file, log file, etc will go into VAR_DIR.
|
||||
# The manual page will go into MAN_DIR.
|
||||
# The EXT2ED documentation will go into DOC_DIR.
|
||||
|
||||
BIN_DIR = /usr/bin
|
||||
VAR_DIR = /var/lib/ext2ed
|
||||
MAN_DIR = /usr/man/man8
|
||||
DOC_DIR = /usr/doc/ext2ed
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
CC = gcc
|
||||
CCFLAGS = -O $(FLAGS) -DVAR_DIR=\"$(VAR_DIR)\" $(NCURSES_INCLUDE) $(READLINE_INCLUDE)
|
||||
LINKFLAGS = $(NCURSES_LIB) $(READLINE_LIB)
|
||||
LIBS = -lreadline -lncurses
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CCFLAGS) $(INCLUDE_DIR) -c $<
|
||||
|
||||
OBJS= main.o init.o general_com.o inode_com.o dir_com.o super_com.o \
|
||||
disk.o win.o group_com.o file_com.o blockbitmap_com.o ext2_com.o \
|
||||
inodebitmap_com.o
|
||||
|
||||
ext2ed: $(OBJS)
|
||||
$(CC) $(OBJS) $(LINKFLAGS) $(LIBS) -o ext2ed
|
||||
|
||||
clean:
|
||||
rm ext2ed *.o
|
||||
|
||||
install: ext2ed
|
||||
install -d $(VAR_DIR)
|
||||
install -d $(DOC_DIR)
|
||||
install -m 755 ext2ed $(BIN_DIR)
|
||||
install -m 644 ext2.descriptors $(VAR_DIR)
|
||||
install -m 644 ext2ed.conf $(VAR_DIR)
|
||||
install -m 644 doc/ext2ed.8 $(MAN_DIR)
|
||||
install -m 644 doc/user-guide-0.1.sgml $(DOC_DIR)
|
||||
install -m 644 doc/user-guide-0.1.ps $(DOC_DIR)
|
||||
install -m 644 doc/Ext2fs-overview-0.1.sgml $(DOC_DIR)
|
||||
install -m 644 doc/Ext2fs-overview-0.1.ps $(DOC_DIR)
|
||||
install -m 644 doc/ext2ed-design-0.1.sgml $(DOC_DIR)
|
||||
install -m 644 doc/ext2ed-design-0.1.ps $(DOC_DIR)
|
|
@ -0,0 +1,101 @@
|
|||
ext2ed - The extended-2 filesystem editor, version 0.1
|
||||
------------------------------------------------------
|
||||
|
||||
This is version 0.1 of ext2ed - The extended-2 filesystem editor.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
ext2ed's documentation consists of three documents:
|
||||
|
||||
1. The user's guide.
|
||||
2. Technical overview of the ext2 filesystem.
|
||||
3. The EXT2ED design and implementation document.
|
||||
|
||||
Those documents are available in the doc directory, in linuxdoc-sgml and
|
||||
postscript formats.
|
||||
|
||||
The documentation is also available online at:
|
||||
|
||||
http://tochnapc2.technion.ac.il
|
||||
|
||||
under the ext2ed section.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
ext2ed requires the kernel sources and the readline and ncurses packages.
|
||||
Please edit the makefile if you are using an "old" version of ncurses (See the
|
||||
details below) or if gcc can't find the various header files and libraries.
|
||||
|
||||
To install, simply issue a 'make' command to compile and a 'make install'
|
||||
command to install. I have also included an already compiled linux a.out
|
||||
binary.
|
||||
|
||||
ext2ed and ncurses
|
||||
------------------
|
||||
|
||||
ext2ed uses the ncurses library for terminal output. It is very important
|
||||
that ncurses will be properly installed on your system:
|
||||
|
||||
1. Old versions of ncurses (around 1.8.5) need the OLD_NCURSES compile
|
||||
time option in EXT2ED.
|
||||
|
||||
At least from 1.9.2c, this flag should not be used. I would recommend
|
||||
upgrading the ncurses library to the newer versions.
|
||||
|
||||
2. ncurses uses its own terminfo database rather then the termcap file.
|
||||
It is important that the terminfo database will be found by ncurses.
|
||||
If this is not the case, you will see on startup some lines which
|
||||
refer to /etc/termcap. This will mean that there is a problem with
|
||||
the terminfo database.
|
||||
|
||||
3. Newer versions of ncurses (and the 1.3 series of the kernel) describe
|
||||
the linux console in the entry 'linux' and not 'console', as it was
|
||||
before. If you run ext2ed in the linux console, you should either
|
||||
set your TERM environment variable to 'linux' or link
|
||||
l/linux to c/console in the terminfo database.
|
||||
|
||||
4. The percompiled binary was linked with ncurses 1.9.4 and will search
|
||||
for the terminfo database on /usr/local/lib/terminfo. If you are
|
||||
using it, and your 1.9.4 compatible terminfo database is not on the
|
||||
directory above, use the TERMINFO environment variable to specify
|
||||
an alternate location.
|
||||
|
||||
Running ext2ed
|
||||
--------------
|
||||
|
||||
For those of you who don't like reading lengthy articles, here are a few
|
||||
basic guidelines:
|
||||
|
||||
1. Don't use ext2ed to change a mounted filesystem !
|
||||
|
||||
Using ext2ed in read-only mode on a mounted filesystem can be allowed
|
||||
by using the configuration file option 'AllowMountedRead on'. However,
|
||||
note that the displayed data will be unreliable.
|
||||
|
||||
2. ext2ed currently can't handle filesystems bigger than 2 GB. I am
|
||||
sorry for the inconvenience. This will hopefully be fixed in future
|
||||
releases.
|
||||
|
||||
3. Before running ext2ed, edit the configuration file
|
||||
/var/lib/ext2ed/ext2ed.conf to suit your needs. The various
|
||||
configuration options are documented there.
|
||||
|
||||
4. Use the 'setdevice' command to open an ext2 filesystem.
|
||||
e.g. 'setdevice /dev/hda1'.
|
||||
|
||||
5. If the filesystem is an ext2 filesystem and ext2ed fails to
|
||||
autodetect this, use the 'ForceExt2 on' configuration file option.
|
||||
|
||||
6. The filesystem will always be opened in read-only mode. Feel free to
|
||||
experiment, but take care with the 'enablewrite' command.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Feel free to send me feedback with anything regarding to ext2ed.
|
||||
|
||||
Enjoy,
|
||||
|
||||
Gadi Oxman <tgud@tochnapc2.technion.ac.il>
|
||||
Haifa, August 23 1995
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/blockbitmap_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
-------------------------
|
||||
Handles the block bitmap.
|
||||
-------------------------
|
||||
|
||||
This file implements the commands which are specific to the blockbitmap type.
|
||||
|
||||
First written on: July 5 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
/*
|
||||
|
||||
The functions in this file use the flobal structure block_bitmap_info. This structure contains the current
|
||||
position in the bitmap.
|
||||
|
||||
*/
|
||||
|
||||
void type_ext2_block_bitmap___entry (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
This function changes the current entry in the bitmap. It just changes the entry_num variable in block_bitmap_info
|
||||
and dispatches a show command to show the new entry.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
unsigned long entry_num;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
|
||||
|
||||
ptr=parse_word (command_line,buffer); /* Get the requested entry */
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - No argument specified\n");
|
||||
refresh_command_win (); return;
|
||||
}
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
entry_num=atol (buffer);
|
||||
|
||||
|
||||
if (entry_num >= file_system_info.super_block.s_blocks_per_group) { /* Check if it is a valid entry number */
|
||||
|
||||
wprintw (command_win,"Error - Entry number out of bounds\n");
|
||||
refresh_command_win ();return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
block_bitmap_info.entry_num=entry_num; /* If it is, just change entry_num and */
|
||||
strcpy (buffer,"show");dispatch (buffer); /* dispatch a show command */
|
||||
}
|
||||
|
||||
void type_ext2_block_bitmap___next (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
This function passes to the next entry in the bitmap. We just call the above entry command.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
long entry_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
entry_offset=atol (buffer);
|
||||
}
|
||||
|
||||
sprintf (buffer,"entry %ld",block_bitmap_info.entry_num+entry_offset);
|
||||
dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_block_bitmap___prev (char *command_line)
|
||||
|
||||
{
|
||||
long entry_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
entry_offset=atol (buffer);
|
||||
}
|
||||
|
||||
sprintf (buffer,"entry %ld",block_bitmap_info.entry_num-entry_offset);
|
||||
dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_block_bitmap___allocate (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
This function starts allocating block from the current position. Allocating involves setting the correct bits
|
||||
in the bitmap. This function is a vector version of allocate_block below - We just run on the blocks that
|
||||
we need to allocate, and call allocate_block for each one.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
long entry_num,num=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer); /* Get the number of blocks to allocate */
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
num=atol (buffer);
|
||||
}
|
||||
|
||||
entry_num=block_bitmap_info.entry_num;
|
||||
/* Check for limits */
|
||||
if (num > file_system_info.super_block.s_blocks_per_group-entry_num) {
|
||||
wprintw (command_win,"Error - There aren't that much blocks in the group\n");
|
||||
refresh_command_win ();return;
|
||||
}
|
||||
|
||||
while (num) { /* And call allocate_block */
|
||||
allocate_block (entry_num); /* for each block */
|
||||
num--;entry_num++;
|
||||
}
|
||||
|
||||
dispatch ("show"); /* Show the result */
|
||||
}
|
||||
|
||||
void type_ext2_block_bitmap___deallocate (char *command_line)
|
||||
|
||||
/* This is the opposite of the above function - We call deallocate_block instead of allocate_block */
|
||||
|
||||
{
|
||||
long entry_num,num=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
num=atol (buffer);
|
||||
}
|
||||
|
||||
entry_num=block_bitmap_info.entry_num;
|
||||
if (num > file_system_info.super_block.s_blocks_per_group-entry_num) {
|
||||
wprintw (command_win,"Error - There aren't that much blocks in the group\n");
|
||||
refresh_command_win ();return;
|
||||
}
|
||||
|
||||
while (num) {
|
||||
deallocate_block (entry_num);
|
||||
num--;entry_num++;
|
||||
}
|
||||
|
||||
dispatch ("show");
|
||||
}
|
||||
|
||||
|
||||
void allocate_block (long entry_num)
|
||||
|
||||
/* In this function we convert the bit number into the right byte and inner bit positions. */
|
||||
|
||||
{
|
||||
unsigned char bit_mask=1;
|
||||
int byte_offset,j;
|
||||
|
||||
byte_offset=entry_num/8; /* Find the correct byte - entry_num/8 */
|
||||
/* The position inside the byte is entry_num %8 */
|
||||
for (j=0;j<entry_num%8;j++)
|
||||
bit_mask*=2; /* Generate the or mask - 1 at the right place */
|
||||
type_data.u.buffer [byte_offset] |= bit_mask; /* And apply it */
|
||||
}
|
||||
|
||||
void deallocate_block (long entry_num)
|
||||
|
||||
/* This is the opposite of allocate_block above. We use an and mask instead of an or mask. */
|
||||
|
||||
{
|
||||
unsigned char bit_mask=1;
|
||||
int byte_offset,j;
|
||||
|
||||
byte_offset=entry_num/8;
|
||||
for (j=0;j<entry_num%8;j++)
|
||||
bit_mask*=2;
|
||||
bit_mask^=0xff;
|
||||
|
||||
type_data.u.buffer [byte_offset] &= bit_mask;
|
||||
}
|
||||
|
||||
void type_ext2_block_bitmap___show (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
We show the bitmap as a series of bits, grouped at 8-bit intervals. We display 8 such groups on each line.
|
||||
The current position (as known from block_bitmap_info.entry_num) is highlighted.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int i,j;
|
||||
unsigned char *ptr;
|
||||
unsigned long block_num,entry_num;
|
||||
|
||||
ptr=type_data.u.buffer;
|
||||
show_pad_info.line=0;show_pad_info.max_line=-1;
|
||||
|
||||
wmove (show_pad,0,0);
|
||||
for (i=0,entry_num=0;i<file_system_info.super_block.s_blocks_per_group/8;i++,ptr++) {
|
||||
for (j=1;j<=128;j*=2) { /* j contains the and bit mask */
|
||||
if (entry_num==block_bitmap_info.entry_num) { /* Highlight the current entry */
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
show_pad_info.line=show_pad_info.max_line-show_pad_info.display_lines/2;
|
||||
}
|
||||
|
||||
if ((*ptr) & j) /* Apply the mask */
|
||||
wprintw (show_pad,"1");
|
||||
else
|
||||
wprintw (show_pad,"0");
|
||||
|
||||
if (entry_num==block_bitmap_info.entry_num)
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
|
||||
entry_num++; /* Pass to the next entry */
|
||||
}
|
||||
wprintw (show_pad," ");
|
||||
if (i%8==7) { /* Display 8 groups in a row */
|
||||
wprintw (show_pad,"\n");
|
||||
show_pad_info.max_line++;
|
||||
}
|
||||
}
|
||||
|
||||
refresh_show_pad ();
|
||||
show_info (); /* Show the usual information */
|
||||
|
||||
/* Show the group number */
|
||||
wmove (show_win,1,0);
|
||||
wprintw (show_win,"Block bitmap of block group %ld\n",block_bitmap_info.group_num);
|
||||
/* Show the block number */
|
||||
|
||||
block_num=block_bitmap_info.entry_num+block_bitmap_info.group_num*file_system_info.super_block.s_blocks_per_group;
|
||||
block_num+=file_system_info.super_block.s_first_data_block;
|
||||
|
||||
wprintw (show_win,"Status of block %ld - ",block_num); /* and the allocation status */
|
||||
ptr=type_data.u.buffer+block_bitmap_info.entry_num/8;
|
||||
j=1;
|
||||
for (i=block_bitmap_info.entry_num % 8;i>0;i--)
|
||||
j*=2;
|
||||
if ((*ptr) & j)
|
||||
wprintw (show_win,"Allocated\n");
|
||||
else
|
||||
wprintw (show_win,"Free\n");
|
||||
refresh_show_win ();
|
||||
}
|
|
@ -0,0 +1,675 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/dir_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
--------------------
|
||||
Handles directories.
|
||||
--------------------
|
||||
|
||||
This file contains the codes which allows the user to handle directories.
|
||||
|
||||
Most of the functions use the global variable file_info (along with the special directory fields there) to save
|
||||
information and pass it between them.
|
||||
|
||||
Since a directory is just a big file which is composed of directory entries, you will find that
|
||||
the functions here are a superset of those in the file_com.c source.
|
||||
|
||||
We assume that the user reached here using the dir command of the inode type and not by using settype dir, so
|
||||
that init_dir_info is indeed called to gather the required information.
|
||||
|
||||
type_data is not changed ! It still contains the inode of the file - We handle the directory in our own
|
||||
variables, so that settype ext2_inode will "go back" to the inode of this directory.
|
||||
|
||||
First written on: April 28 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
char name_search [80];
|
||||
long entry_num_search;
|
||||
|
||||
int init_dir_info (struct struct_file_info *info_ptr)
|
||||
|
||||
/*
|
||||
|
||||
This function is called by the inode of the directory when the user issues the dir command from the inode.
|
||||
It is used to gather information about the inode and to reset some variables which we need in order to handle
|
||||
directories.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
struct ext2_inode *ptr;
|
||||
|
||||
ptr=&type_data.u.t_ext2_inode; /* type_data contains the inode */
|
||||
|
||||
info_ptr->inode_ptr=ptr;
|
||||
info_ptr->inode_offset=device_offset; /* device offset contains the inode's offset */
|
||||
|
||||
/* Reset the current position to the start */
|
||||
|
||||
info_ptr->global_block_num=ptr->i_block [0];
|
||||
info_ptr->global_block_offset=ptr->i_block [0]*file_system_info.block_size;
|
||||
info_ptr->block_num=0;
|
||||
info_ptr->file_offset=0;
|
||||
/* Set the size of the directory */
|
||||
|
||||
info_ptr->blocks_count=(ptr->i_size+file_system_info.block_size-1)/file_system_info.block_size;
|
||||
info_ptr->file_length=ptr->i_size;
|
||||
|
||||
info_ptr->level=0; /* We start using direct blocks */
|
||||
info_ptr->display=HEX; /* This is not actually used */
|
||||
|
||||
info_ptr->dir_entry_num=0;info_ptr->dir_entries_count=0; /* We'll start at the first directory entry */
|
||||
info_ptr->dir_entry_offset=0;
|
||||
|
||||
/* Find dir_entries_count */
|
||||
|
||||
info_ptr->dir_entries_count=count_dir_entries (); /* Set the total number of entries */
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
struct struct_file_info search_dir_entries (int (*action) (struct struct_file_info *info),int *status)
|
||||
|
||||
/*
|
||||
This is the main function in this source file. Various actions are implemented using this basic function.
|
||||
|
||||
This routine runs on all directory entries in the current directory.
|
||||
For each entry, action is called. We'll act according to the return code of action:
|
||||
|
||||
ABORT - Current dir entry is returned.
|
||||
CONTINUE - Continue searching.
|
||||
FOUND - Current dir entry is returned.
|
||||
|
||||
If the last entry is reached, it is returned, along with an ABORT status.
|
||||
|
||||
status is updated to the returned code of action.
|
||||
*/
|
||||
|
||||
{
|
||||
struct struct_file_info info; /* Temporary variables used to */
|
||||
struct ext2_dir_entry *dir_entry_ptr; /* contain the current search entries */
|
||||
|
||||
int return_code;
|
||||
|
||||
info=first_file_info; /* Start from the first entry - Read it */
|
||||
low_read (info.buffer,file_system_info.block_size,info.global_block_offset);
|
||||
dir_entry_ptr=(struct ext2_dir_entry *) (info.buffer+info.dir_entry_offset);
|
||||
|
||||
while (info.file_offset < info.file_length) { /* While we haven't reached the end */
|
||||
|
||||
*status=return_code=action (&info); /* Call the client function to test */
|
||||
/* the current entry */
|
||||
if (return_code==ABORT || return_code==FOUND)
|
||||
return (info); /* Stop, if so asked */
|
||||
|
||||
/* Pass to the next entry */
|
||||
|
||||
dir_entry_ptr=(struct ext2_dir_entry *) (info.buffer+info.dir_entry_offset);
|
||||
|
||||
info.dir_entry_num++;
|
||||
info.dir_entry_offset+=dir_entry_ptr->rec_len;
|
||||
info.file_offset+=dir_entry_ptr->rec_len;
|
||||
|
||||
if (info.file_offset >= info.file_length) break;
|
||||
|
||||
if (info.dir_entry_offset >= file_system_info.block_size) { /* We crossed a block boundary */
|
||||
/* Find the next block, */
|
||||
info.block_num++;
|
||||
info.global_block_num=file_block_to_global_block (info.block_num,&info);
|
||||
info.global_block_offset=info.global_block_num*file_system_info.block_size;
|
||||
info.file_offset=info.block_num*file_system_info.block_size;
|
||||
info.dir_entry_offset=0;
|
||||
/* read it and update the pointer */
|
||||
|
||||
low_read (info.buffer,file_system_info.block_size,info.global_block_offset);
|
||||
dir_entry_ptr=(struct ext2_dir_entry *) (info.buffer+info.dir_entry_offset);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*status=ABORT;return (info); /* There was no match */
|
||||
}
|
||||
|
||||
long count_dir_entries (void)
|
||||
|
||||
/*
|
||||
|
||||
This function counts the number of entries in the directory. We just call search_dir_entries till the end.
|
||||
The client function is action_count, which just tell search_dir_entries to continue.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int status;
|
||||
|
||||
return (search_dir_entries (&action_count,&status).dir_entry_num);
|
||||
}
|
||||
|
||||
int action_count (struct struct_file_info *info)
|
||||
|
||||
/*
|
||||
|
||||
Used by count_dir_entries above - This function is called by search_dir_entries, and it tells it to continue
|
||||
searching, until we get to the last entry.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
return (CONTINUE); /* Just continue searching */
|
||||
}
|
||||
|
||||
void type_dir___cd (char *command_line)
|
||||
|
||||
/*
|
||||
Changes to a directory, relative to the current directory.
|
||||
|
||||
This is a complicated operation, so I would repeat here the explanation from the design and
|
||||
implementation document.
|
||||
|
||||
1. The path is checked that it is not an absolute path (from /). If it is, we let the general cd to do the job by
|
||||
calling directly type_ext2___cd.
|
||||
|
||||
2. The path is divided into the nearest path and the rest of the path. For example, cd 1/2/3/4 is divided into
|
||||
1 and into 2/3/4.
|
||||
|
||||
3. It is the first part of the path that we need to search for in the current directory. We search for it using
|
||||
search_dir_entries, which accepts the action_name function as the client function.
|
||||
|
||||
4. search_dir_entries will scan the entire entries and will call our action_name function for each entry.
|
||||
In action_name, the required name will be checked against the name of the current entry, and FOUND will be
|
||||
returned when a match occurs.
|
||||
|
||||
5. If the required entry is found, we dispatch a remember command to insert the current inode (remember that
|
||||
type_data is still intact and contains the inode of the current directory) into the object memory.
|
||||
This is required to easily support symbolic links - If we find later that the inode pointed by the entry is
|
||||
actually a symbolic link, we'll need to return to this point, and the above inode doesn't have (and can't have,
|
||||
because of hard links) the information necessary to "move back".
|
||||
|
||||
6. We then dispatch a followinode command to reach the inode pointed by the required entry. This command will
|
||||
automatically change the type to ext2_inode - We are now at an inode, and all the inode commands are available.
|
||||
|
||||
7. We check the inode's type to see if it is a directory. If it is, we dispatch a dir command to "enter the directory",
|
||||
and recursively call ourself (The type is dir again) by dispatching a cd command, with the rest of the path
|
||||
as an argument.
|
||||
|
||||
8. If the inode's type is a symbolic link (only fast symbolic link were meanwhile implemented. I guess this is
|
||||
typically the case.), we note the path it is pointing at, the saved inode is recalled, we dispatch dir to
|
||||
get back to the original directory, and we call ourself again with the link path/rest of the path argument.
|
||||
|
||||
9. In any other case, we just stop at the resulting inode.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int status;
|
||||
char *ptr,full_dir_name [500],dir_name [500],temp [500],temp2 [500];
|
||||
struct struct_file_info info;
|
||||
struct ext2_dir_entry *dir_entry_ptr;
|
||||
|
||||
dir_entry_ptr=(struct ext2_dir_entry *) (file_info.buffer+file_info.dir_entry_offset);
|
||||
|
||||
ptr=parse_word (command_line,dir_name);
|
||||
|
||||
if (*ptr==0) { /* cd alone will enter the highlighted directory */
|
||||
strncpy (full_dir_name,dir_entry_ptr->name,dir_entry_ptr->name_len);
|
||||
full_dir_name [dir_entry_ptr->name_len]=0;
|
||||
}
|
||||
else
|
||||
ptr=parse_word (ptr,full_dir_name);
|
||||
|
||||
ptr=strchr (full_dir_name,'/');
|
||||
|
||||
if (ptr==full_dir_name) { /* Pathname is from root - Let the general cd do the job */
|
||||
sprintf (temp,"cd %s",full_dir_name);type_ext2___cd (temp);return;
|
||||
}
|
||||
|
||||
if (ptr==NULL) {
|
||||
strcpy (dir_name,full_dir_name);
|
||||
full_dir_name [0]=0;
|
||||
}
|
||||
|
||||
else {
|
||||
strncpy (dir_name,full_dir_name,ptr-full_dir_name);
|
||||
dir_name [ptr-full_dir_name]=0;
|
||||
strcpy (full_dir_name,++ptr);
|
||||
}
|
||||
/* dir_name contains the current entry, while */
|
||||
/* full_dir_name contains the rest */
|
||||
|
||||
strcpy (name_search,dir_name); /* name_search is used to hold the required entry name */
|
||||
|
||||
if (dir_entry_ptr->name_len != strlen (dir_name) ||
|
||||
strncmp (dir_name,dir_entry_ptr->name,dir_entry_ptr->name_len)!=0)
|
||||
info=search_dir_entries (&action_name,&status); /* Search for the entry. Answer in info. */
|
||||
else {
|
||||
status=FOUND;info=file_info;
|
||||
}
|
||||
|
||||
if (status==FOUND) { /* If found */
|
||||
file_info=info; /* Switch to it, by setting the global file_info */
|
||||
dispatch ("remember internal_variable"); /* Move the inode into the objects memory */
|
||||
|
||||
dispatch ("followinode"); /* Go to the inode pointed by this directory entry */
|
||||
|
||||
if (S_ISLNK (type_data.u.t_ext2_inode.i_mode)) {/* Symbolic link ? */
|
||||
|
||||
if (type_data.u.t_ext2_inode.i_size > 60) { /* I'm lazy, I guess :-) */
|
||||
wprintw (command_win,"Error - Sorry, Only fast symbolic link following is currently supported\n");
|
||||
refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
/* Get the pointed name and append the previous path */
|
||||
|
||||
strcpy (temp2,(unsigned char *) &type_data.u.t_ext2_inode.i_block);
|
||||
strcat (temp2,"/");
|
||||
strcat (temp2,full_dir_name);
|
||||
|
||||
dispatch ("recall internal_variable"); /* Return to the original inode */
|
||||
dispatch ("dir"); /* and to the directory */
|
||||
|
||||
sprintf (temp,"cd %s",temp2); /* And continue from there by dispatching a cd command */
|
||||
dispatch (temp); /* (which can call ourself or the general cd) */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_ISDIR (type_data.u.t_ext2_inode.i_mode)) { /* Is it an inode of a directory ? */
|
||||
|
||||
dispatch ("dir"); /* Yes - Pass to the pointed directory */
|
||||
|
||||
if (full_dir_name [0] != 0) { /* And call ourself with the rest of the pathname */
|
||||
sprintf (temp,"cd %s",full_dir_name);
|
||||
dispatch (temp);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
else { /* If we can't continue from here, we'll just stop */
|
||||
wprintw (command_win,"Can\'t continue - Stopping at last inode\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wprintw (command_win,"Error - Directory entry %s not found.\n",dir_name); /* Hmm, an invalid path somewhere */
|
||||
refresh_command_win ();
|
||||
}
|
||||
|
||||
int action_name (struct struct_file_info *info)
|
||||
|
||||
/*
|
||||
|
||||
Compares the current search entry name (somewhere inside info) with the required name (in name_search).
|
||||
Returns FOUND if found, or CONTINUE if not found.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
struct ext2_dir_entry *dir_entry_ptr;
|
||||
|
||||
dir_entry_ptr=(struct ext2_dir_entry *) (info->buffer+info->dir_entry_offset);
|
||||
|
||||
if (dir_entry_ptr->name_len != strlen (name_search))
|
||||
return (CONTINUE);
|
||||
|
||||
if (strncmp (dir_entry_ptr->name,name_search,dir_entry_ptr->name_len)==0)
|
||||
return (FOUND);
|
||||
|
||||
return (CONTINUE);
|
||||
}
|
||||
|
||||
void type_dir___entry (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
Selects a directory entry according to its number.
|
||||
search_dir_entries is used along with action_entry_num, in the same fashion as the previous usage of search_dir_entries.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int status;
|
||||
struct struct_file_info info;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Argument_not_specified\n");wrefresh (command_win);
|
||||
return;
|
||||
}
|
||||
ptr=parse_word (ptr,buffer);
|
||||
entry_num_search=atol (buffer);
|
||||
|
||||
if (entry_num_search < 0 || entry_num_search >= file_info.dir_entries_count) {
|
||||
wprintw (command_win,"Error - Entry number out of range\n");wrefresh (command_win);
|
||||
return;
|
||||
}
|
||||
|
||||
info=search_dir_entries (&action_entry_num,&status);
|
||||
if (status==FOUND) {
|
||||
file_info=info;
|
||||
dispatch ("show");
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
internal_error ("dir_com","type_dir___entry","According to our gathered data, we should have found this entry");
|
||||
#endif
|
||||
}
|
||||
|
||||
int action_entry_num (struct struct_file_info *info)
|
||||
|
||||
/*
|
||||
|
||||
Used by the above function. Just compares the current number (in info) with the required one.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
if (info->dir_entry_num == entry_num_search)
|
||||
return (FOUND);
|
||||
|
||||
return (CONTINUE);
|
||||
}
|
||||
|
||||
void type_dir___followinode (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
Here we pass to the inode pointed by the current entry.
|
||||
It involves computing the device offset of the inode and using directly the setoffset and settype commands.
|
||||
|
||||
*/
|
||||
{
|
||||
long inode_offset;
|
||||
char buffer [80];
|
||||
|
||||
struct ext2_dir_entry *dir_entry_ptr;
|
||||
|
||||
low_read (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
|
||||
dir_entry_ptr=(struct ext2_dir_entry *) (file_info.buffer+file_info.dir_entry_offset);
|
||||
|
||||
inode_offset=inode_num_to_inode_offset (dir_entry_ptr->inode); /* Compute the inode's offset */
|
||||
sprintf (buffer,"setoffset %ld",inode_offset);dispatch (buffer); /* Move to it */
|
||||
sprintf (buffer,"settype ext2_inode");dispatch (buffer); /* and set the type to an inode */
|
||||
}
|
||||
|
||||
void type_dir___inode (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
Returns to the parent inode of the current directory.
|
||||
This is trivial, as we type_data is still intact and contains the parent inode !
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
dispatch ("settype ext2_inode");
|
||||
}
|
||||
|
||||
|
||||
void type_dir___show (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
We use search_dir_entries to run on all the entries. Each time, action_show will be called to show one entry.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int status;
|
||||
|
||||
wmove (show_pad,0,0);
|
||||
show_pad_info.max_line=-1;
|
||||
|
||||
search_dir_entries (&action_show,&status);
|
||||
show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2;
|
||||
refresh_show_pad ();
|
||||
show_dir_status ();
|
||||
}
|
||||
|
||||
int action_show (struct struct_file_info *info)
|
||||
|
||||
/*
|
||||
|
||||
Show the current search entry (info) in one line. If the entry happens to be the current edited entry, it is highlighted.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
unsigned char temp [80];
|
||||
struct ext2_dir_entry *dir_entry_ptr;
|
||||
|
||||
dir_entry_ptr=(struct ext2_dir_entry *) (info->buffer+info->dir_entry_offset);
|
||||
|
||||
if (info->dir_entry_num == file_info.dir_entry_num) /* Highlight the current entry */
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
|
||||
strncpy (temp,dir_entry_ptr->name,dir_entry_ptr->name_len); /* The name is not terminated */
|
||||
temp [dir_entry_ptr->name_len]=0;
|
||||
if (dir_entry_ptr->name_len > (COLS - 55) && COLS > 55)
|
||||
temp [COLS-55]=0;
|
||||
wprintw (show_pad,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n", /* Display the various fields */
|
||||
dir_entry_ptr->inode,dir_entry_ptr->rec_len,dir_entry_ptr->name_len,temp);
|
||||
|
||||
show_pad_info.max_line++;
|
||||
|
||||
if (info->dir_entry_num == file_info.dir_entry_num)
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
|
||||
return (CONTINUE); /* And pass to the next */
|
||||
}
|
||||
|
||||
void type_dir___next (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
This function moves to the next directory entry. It just uses the current information and the entry command.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
offset*=atol (buffer);
|
||||
}
|
||||
|
||||
sprintf (buffer,"entry %ld",file_info.dir_entry_num+offset);dispatch (buffer);
|
||||
|
||||
}
|
||||
|
||||
void type_dir___prev (char *command_line)
|
||||
|
||||
{
|
||||
int offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
offset*=atol (buffer);
|
||||
}
|
||||
|
||||
sprintf (buffer,"entry %ld",file_info.dir_entry_num-offset);dispatch (buffer);
|
||||
}
|
||||
|
||||
void show_dir_status (void)
|
||||
|
||||
/*
|
||||
|
||||
Various statistics about the directory.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
long inode_num;
|
||||
|
||||
wmove (show_win,0,0);
|
||||
wprintw (show_win,"Directory listing. Block %ld. ",file_info.global_block_num);
|
||||
wprintw (show_win,"Directory entry %ld of %ld.\n",file_info.dir_entry_num,file_info.dir_entries_count-1);
|
||||
wprintw (show_win,"Directory Offset %ld of %ld. ",file_info.file_offset,file_info.file_length-1);
|
||||
|
||||
inode_num=inode_offset_to_inode_num (file_info.inode_offset);
|
||||
wprintw (show_win,"File inode %ld. Indirection level %ld.\n",inode_num,file_info.level);
|
||||
|
||||
refresh_show_win ();
|
||||
}
|
||||
|
||||
void type_dir___remember (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
This is overrided here because we don't remember a directory - It is too complicated. Instead, we remember the
|
||||
inode of the current directory.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int found=0;
|
||||
long entry_num;
|
||||
char *ptr,buffer [80];
|
||||
struct struct_descriptor *descriptor_ptr;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Argument not specified\n");wrefresh (command_win);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
entry_num=remember_lifo.entries_count++;
|
||||
if (entry_num>REMEMBER_COUNT-1) {
|
||||
entry_num=0;
|
||||
remember_lifo.entries_count--;
|
||||
}
|
||||
|
||||
descriptor_ptr=first_type;
|
||||
while (descriptor_ptr!=NULL && !found) {
|
||||
if (strcmp (descriptor_ptr->name,"ext2_inode")==0)
|
||||
found=1;
|
||||
else
|
||||
descriptor_ptr=descriptor_ptr->next;
|
||||
}
|
||||
|
||||
|
||||
remember_lifo.offset [entry_num]=device_offset;
|
||||
remember_lifo.type [entry_num]=descriptor_ptr;
|
||||
strcpy (remember_lifo.name [entry_num],buffer);
|
||||
|
||||
wprintw (command_win,"Object %s in Offset %ld remembered as %s\n",descriptor_ptr->name,device_offset,buffer);
|
||||
wrefresh (command_win);
|
||||
}
|
||||
|
||||
void type_dir___set (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
Since the dir object doesn't have variables, we provide the impression that it has here. ext2_dir_entry was not used
|
||||
because it is of variable length.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int found=0;
|
||||
unsigned char *ptr,buffer [80],variable [80],value [80],temp [80];
|
||||
struct ext2_dir_entry *dir_entry_ptr;
|
||||
|
||||
dir_entry_ptr=(struct ext2_dir_entry *) (file_info.buffer+file_info.dir_entry_offset);
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Missing arguments\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
parse_word (ptr,buffer);
|
||||
ptr=strchr (buffer,'=');
|
||||
if (ptr==NULL) {
|
||||
wprintw (command_win,"Error - Bad syntax\n");refresh_command_win ();return;
|
||||
}
|
||||
strncpy (variable,buffer,ptr-buffer);variable [ptr-buffer]=0;
|
||||
strcpy (value,++ptr);
|
||||
|
||||
if (strcasecmp ("inode",variable)==0) {
|
||||
found=1;
|
||||
dir_entry_ptr->inode=atol (value);
|
||||
wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->inode);refresh_command_win ();
|
||||
|
||||
}
|
||||
|
||||
if (strcasecmp ("rec_len",variable)==0) {
|
||||
found=1;
|
||||
dir_entry_ptr->rec_len=(unsigned int) atol (value);
|
||||
wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->rec_len);refresh_command_win ();
|
||||
|
||||
}
|
||||
|
||||
if (strcasecmp ("name_len",variable)==0) {
|
||||
found=1;
|
||||
dir_entry_ptr->name_len=(unsigned int) atol (value);
|
||||
wprintw (command_win,"Variable %s set to %lu\n",variable,dir_entry_ptr->name_len);refresh_command_win ();
|
||||
|
||||
}
|
||||
|
||||
if (strcasecmp ("name",variable)==0) {
|
||||
found=1;
|
||||
if (strlen (value) > dir_entry_ptr->name_len) {
|
||||
wprintw (command_win,"Error - Length of name greater then name_len\n");
|
||||
refresh_command_win ();return;
|
||||
}
|
||||
strncpy (dir_entry_ptr->name,value,strlen (value));
|
||||
wprintw (command_win,"Variable %s set to %s\n",variable,value);refresh_command_win ();
|
||||
|
||||
}
|
||||
|
||||
if (found) {
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
strncpy (temp,dir_entry_ptr->name,dir_entry_ptr->name_len);
|
||||
temp [dir_entry_ptr->name_len]=0;
|
||||
wmove (show_pad,file_info.dir_entry_num,0);
|
||||
wprintw (show_pad,"inode = %-8lu rec_len = %-4lu name_len = %-3lu name = %s\n",
|
||||
dir_entry_ptr->inode,dir_entry_ptr->rec_len,dir_entry_ptr->name_len,temp);
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
show_pad_info.line=file_info.dir_entry_num-show_pad_info.display_lines/2;
|
||||
refresh_show_pad ();
|
||||
show_dir_status ();
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Variable %s not found\n",variable);
|
||||
refresh_command_win ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void type_dir___writedata (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
We need to override this since the data is not in type_data. Instead, we have to write the buffer which corresponds
|
||||
to the current block.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
low_write (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/disk.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
-------------------------------------------------
|
||||
The filesystem's disk activity pass through here.
|
||||
-------------------------------------------------
|
||||
|
||||
This file is acting as a filter - Before we pass an actual read or write request to the operating system, we
|
||||
double check the various permissions and possible errors here.
|
||||
|
||||
The major update which needs to be done here is switching to the use of the llseek system call, so that we will
|
||||
be able to support ext2 filesystems up to 4 TB. Currently, due to the standard fseek usage, we can't handle
|
||||
filesystems bigger than 4 GB. The limit is actually 2 GB because I used long rather than unsigned long long at too
|
||||
many places in the program. To conclude - This upgrade needs to be done carefuly; There are many places to change.
|
||||
|
||||
First written on: April 9 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
int write_access;
|
||||
|
||||
int low_read (unsigned char *buffer,unsigned long length,unsigned long offset)
|
||||
|
||||
/*
|
||||
|
||||
This function is used when we need to read something from the filesystem.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
char temp [80];
|
||||
|
||||
if (device_handle==NULL) { /* Check that a device is indeed open */
|
||||
internal_error ("No device opened yet read requested","disk","low_read");
|
||||
return (0);
|
||||
}
|
||||
if (offset > file_system_info.file_system_size) { /* Check that the offset is within limits */
|
||||
sprintf (temp,"Seek offset %ld is out of range",offset);
|
||||
internal_error (temp,"disk","low_read");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ( (fseek (device_handle,offset,SEEK_SET))==-1) { /* Seek to the required offset */
|
||||
wprintw (command_win,"Error - Failed to seek to offset %ld in device %s\n",offset,device_name);
|
||||
refresh_command_win ();
|
||||
return (0);
|
||||
};
|
||||
|
||||
if ( (fread (buffer,1,length,device_handle))==-1) { /* And do the actual reading */
|
||||
wprintw (command_win,"Error - Failed to read from offset %ld in device %s\n",offset,device_name);
|
||||
refresh_command_win ();return (0);
|
||||
};
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int low_write (unsigned char *buffer,unsigned long length,unsigned long offset)
|
||||
|
||||
/*
|
||||
|
||||
This is used to change something in the filesystem.
|
||||
write_access is checked to see if we are allowed to do the actual writing.
|
||||
As a double safety measure, AllowChanges is rechecked here.
|
||||
If logging is enabled, we log the change before writing it to the device.
|
||||
|
||||
*/
|
||||
{
|
||||
char temp [80];
|
||||
|
||||
if (!write_access) {
|
||||
wprintw (command_win,"Error - Write access not aviable (use enablewrite)\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
if (!AllowChanges) {
|
||||
internal_error ("AllowChanges=0 yet enablewrite succeeded","disk","low_write");
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (device_handle==NULL) {
|
||||
internal_error ("No device opened yet read requested","disk","low_write");
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (offset > file_system_info.file_system_size) {
|
||||
sprintf (temp,"Seek offset %ld is out of range",offset);
|
||||
internal_error (temp,"disk","low_write");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (LogChanges)
|
||||
if (!log_changes (buffer,length,offset))
|
||||
return (0);
|
||||
|
||||
if ( (fseek (device_handle,offset,SEEK_SET))==-1) {
|
||||
wprintw (command_win,"Error - Failed to seek to offset %ld in device %s\n",offset,device_name);
|
||||
refresh_command_win ();return (0);
|
||||
};
|
||||
|
||||
|
||||
if ( (fwrite (buffer,1,length,device_handle))==-1) {
|
||||
wprintw (command_win,"Error - Failed to write to offset %ld in device %s\n",offset,device_name);
|
||||
refresh_command_win ();return (0);
|
||||
};
|
||||
|
||||
wprintw (command_win,"Data written");refresh_command_win ();
|
||||
return (1);
|
||||
}
|
||||
|
||||
int log_changes (unsigned char *buffer,unsigned long length,unsigned long offset)
|
||||
|
||||
/*
|
||||
|
||||
Log the change in a primitive form - An hex dump of the data before the change and after the change.
|
||||
The hex bytes are converted to text, so that they will be readable with a standard text editor.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
unsigned char *original;
|
||||
|
||||
int i;
|
||||
time_t current_time;
|
||||
FILE *fp;
|
||||
|
||||
if ((fp=fopen (LogFile,"a+"))==NULL) {
|
||||
wprintw (command_win,"Error - Unable to open log file %s\n",LogFile);
|
||||
refresh_command_win ();return (0);
|
||||
};
|
||||
|
||||
current_time=time (NULL);
|
||||
|
||||
fprintf (fp,"\n----- EXT2ED log begin -----\n\n");
|
||||
fprintf (fp,"Time: %s\nDevice: %s\n",ctime ((time_t *) ¤t_time),device_name);
|
||||
fprintf (fp,"Offset: %lu\nLength: %lu\n",offset,length);
|
||||
|
||||
original=(unsigned char *) malloc (length*sizeof (unsigned char));
|
||||
|
||||
if (original==NULL) {
|
||||
wprintw (command_win,"Fatal error - Can\'t allocate %lu bytes !");
|
||||
refresh_command_win ();fclose (fp);return (0);
|
||||
}
|
||||
|
||||
if (!low_read (original,length,offset)) {
|
||||
fclose (fp);return (0);
|
||||
}
|
||||
|
||||
fprintf (fp,"\nOriginal data:\n\n");
|
||||
|
||||
for (i=0;i<length;i++) {
|
||||
if (i%16==0 && i!=0) fprintf (fp,"\n");
|
||||
fprintf (fp,"%02x ",original [i]);
|
||||
}
|
||||
|
||||
fprintf (fp,"\n\nNew data:\n\n");
|
||||
|
||||
for (i=0;i<length;i++) {
|
||||
if (i%16==0 && i!=0) fprintf (fp,"\n");
|
||||
fprintf (fp,"%02x ",buffer [i]);
|
||||
}
|
||||
|
||||
fprintf (fp,"\n----- EXT2ED log end -----\n");
|
||||
|
||||
fclose (fp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
int load_type_data (void)
|
||||
|
||||
/*
|
||||
|
||||
Just read from the current position into type data.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
if (device_handle==NULL) {
|
||||
printf ("Error - No device opened\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (device_offset==-1) {
|
||||
printf ("Error - No offset set\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (low_read (type_data.u.buffer,EXT2_MAX_BLOCK_SIZE,device_offset)==0)
|
||||
return (0);
|
||||
|
||||
if (current_type!=NULL)
|
||||
if (strcmp (current_type->name,"ext2_dir_entry")==0)
|
||||
current_type->length=type_data.u.t_ext2_dir_entry.rec_len;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int write_type_data (void)
|
||||
|
||||
{
|
||||
if (device_handle==NULL) {
|
||||
wprintw (command_win,"Error - No device opened\n");
|
||||
refresh_command_win ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (device_offset==-1) {
|
||||
wprintw (command_win,"Error - No offset set\n");
|
||||
refresh_command_win ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (low_write (type_data.u.buffer,file_system_info.block_size,device_offset)==0)
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
|
@ -0,0 +1,898 @@
|
|||
<!doctype linuxdoc system>
|
||||
|
||||
<!-- EXT2 filesystem overview -->
|
||||
<!-- First written: August 1 1995 -->
|
||||
<!-- Last updated: August 3 1995 -->
|
||||
<!-- This document is written Using the Linux documentation project Linuxdoc-SGML DTD -->
|
||||
|
||||
<article>
|
||||
|
||||
<title>The extended-2 filesystem overview
|
||||
<author>Gadi Oxman, tgud@tochnapc2.technion.ac.il
|
||||
<date>v0.1, August 3 1995
|
||||
<toc>
|
||||
|
||||
<!-- Begin of document -->
|
||||
|
||||
<sect>Preface
|
||||
<p>
|
||||
|
||||
This document attempts to present an overview of the internal structure of
|
||||
the ext2 filesystem. It was written in summer 95, while I was working on the
|
||||
<tt>ext2 filesystem editor project (EXT2ED)</>.
|
||||
|
||||
In the process of constructing EXT2ED, I acquired knowledge of the various
|
||||
design aspects of the the ext2 filesystem. This document is a result of an
|
||||
effort to document this knowledge.
|
||||
|
||||
This is only the initial version of this document. It is obviously neither
|
||||
error-prone nor complete, but at least it provides a starting point.
|
||||
|
||||
In the process of learning the subject, I have used the following sources /
|
||||
tools:
|
||||
<itemize>
|
||||
<item> Experimenting with EXT2ED, as it was developed.
|
||||
<item> The ext2 kernel sources:
|
||||
<itemize>
|
||||
<item> The main ext2 include file,
|
||||
<tt>/usr/include/linux/ext2_fs.h</>
|
||||
<item> The contents of the directory <tt>/usr/src/linux/fs/ext2</>.
|
||||
<item> The VFS layer sources (only a bit).
|
||||
</itemize>
|
||||
<item> The slides: The Second Extended File System, Current State, Future
|
||||
Development, by <tt>Remy Card</>.
|
||||
<item> The slides: Optimisation in File Systems, by <tt>Stephen Tweedie</>.
|
||||
<item> The various ext2 utilities.
|
||||
</itemize>
|
||||
|
||||
<sect>Introduction
|
||||
<p>
|
||||
|
||||
The <tt>Second Extended File System (Ext2fs)</> is very popular among Linux
|
||||
users. If you use Linux, chances are that you are using the ext2 filesystem.
|
||||
|
||||
Ext2fs was designed by <tt>Remy Card</> and <tt>Wayne Davison</>. It was
|
||||
implemented by <tt>Remy Card</> and was further enhanced by <tt>Stephen
|
||||
Tweedie</> and <tt>Theodore Ts'o</>.
|
||||
|
||||
The ext2 filesystem is still under development. I will document here
|
||||
version 0.5a, which is distributed along with Linux 1.2.x. At this time of
|
||||
writing, the most recent version of Linux is 1.3.13, and the version of the
|
||||
ext2 kernel source is 0.5b. A lot of fancy enhancements are planned for the
|
||||
ext2 filesystem in Linux 1.3, so stay tuned.
|
||||
|
||||
<sect>A filesystem - Why do we need it ?
|
||||
<p>
|
||||
|
||||
I thought that before we dive into the various small details, I'll reserve a
|
||||
few minutes for the discussion of filesystems from a general point of view.
|
||||
|
||||
A <tt>filesystem</> consists of two word - <tt>file</> and <tt>system</>.
|
||||
|
||||
Everyone knows the meaning of the word <tt>file</> - A bunch of data put
|
||||
somewhere. where ? This is an important question. I, for example, usually
|
||||
throw almost everything into a single drawer, and have difficulties finding
|
||||
something later.
|
||||
|
||||
This is where the <tt>system</> comes in - Instead of just throwing the data
|
||||
to the device, we generalize and construct a <tt>system</> which will
|
||||
virtualize for us a nice and ordered structure in which we could arrange our
|
||||
data in much the same way as books are arranged in a library. The purpose of
|
||||
the filesystem, as I understand it, is to make it easy for us to update and
|
||||
maintain our data.
|
||||
|
||||
Normally, by <tt>mounting</> filesystems, we just use the nice and logical
|
||||
virtual structure. However, the disk knows nothing about that - The device
|
||||
driver views the disk as a large continuous paper in which we can write notes
|
||||
wherever we wish. It is the task of the filesystem management code to store
|
||||
bookkeeping information which will serve the kernel for showing us the nice
|
||||
and ordered virtual structure.
|
||||
|
||||
In this document, we consider one particular administrative structure - The
|
||||
Second Extended Filesystem.
|
||||
|
||||
<sect>The Linux VFS layer
|
||||
<p>
|
||||
|
||||
When Linux was first developed, it supported only one filesystem - The
|
||||
<tt>Minix</> filesystem. Today, Linux has the ability to support several
|
||||
filesystems concurrently. This was done by the introduction of another layer
|
||||
between the kernel and the filesystem code - The Virtual File System (VFS).
|
||||
|
||||
The kernel "speaks" with the VFS layer. The VFS layer passes the kernel's
|
||||
request to the proper filesystem management code. I haven't learned much of
|
||||
the VFS layer as I didn't need it for the construction of EXT2ED so that I
|
||||
can't elaborate on it. Just be aware that it exists.
|
||||
|
||||
<sect>About blocks and block groups
|
||||
<p>
|
||||
|
||||
In order to ease management, the ext2 filesystem logically divides the disk
|
||||
into small units called <tt>blocks</>. A block is the smallest unit which
|
||||
can be allocated. Each block in the filesystem can be <tt>allocated</> or
|
||||
<tt>free</>.
|
||||
<footnote>
|
||||
The Ext2fs source code refers to the concept of <tt>fragments</>, which I
|
||||
believe are supposed to be sub-block allocations. As far as I know,
|
||||
fragments are currently unsupported in Ext2fs.
|
||||
</footnote>
|
||||
The block size can be selected to be 1024, 2048 or 4096 bytes when creating
|
||||
the filesystem.
|
||||
|
||||
Ext2fs groups together a fixed number of sequential blocks into a <tt>group
|
||||
block</>. The resulting situation is that the filesystem is managed as a
|
||||
series of group blocks. This is done in order to keep related information
|
||||
physically close on the disk and to ease the management task. As a result,
|
||||
much of the filesystem management reduces to management of a single blocks
|
||||
group.
|
||||
|
||||
<sect>The view of inodes from the point of view of a blocks group
|
||||
<p>
|
||||
|
||||
Each file in the filesystem is reserved a special <tt>inode</>. I don't want
|
||||
to explain inodes now. Rather, I would like to treat it as another resource,
|
||||
much like a <tt>block</> - Each blocks group contains a limited number of
|
||||
inode, while any specific inode can be <tt>allocated</> or
|
||||
<tt>unallocated</>.
|
||||
|
||||
<sect>The group descriptors
|
||||
<p>
|
||||
|
||||
Each blocks group is accompanied by a <tt>group descriptor</>. The group
|
||||
descriptor summarizes some necessary information about the specific group
|
||||
block. Follows the definition of the group descriptor, as defined in
|
||||
/usr/include/linux/ext2_fs.h:
|
||||
|
||||
<tscreen><code>
|
||||
struct ext2_group_desc
|
||||
{
|
||||
__u32 bg_block_bitmap; /* Blocks bitmap block */
|
||||
__u32 bg_inode_bitmap; /* Inodes bitmap block */
|
||||
__u32 bg_inode_table; /* Inodes table block */
|
||||
__u16 bg_free_blocks_count; /* Free blocks count */
|
||||
__u16 bg_free_inodes_count; /* Free inodes count */
|
||||
__u16 bg_used_dirs_count; /* Directories count */
|
||||
__u16 bg_pad;
|
||||
__u32 bg_reserved[3];
|
||||
};
|
||||
</code></tscreen>
|
||||
|
||||
The last three variables: <tt>bg_free_blocks_count, bg_free_inodes_count and
|
||||
bg_used_dirs_count</> provide statistics about the use of the three
|
||||
resources in a blocks group - The <tt>blocks</>, the <tt>inodes</> and the
|
||||
<tt>directories</>. I believe that they are used by the kernel for balancing
|
||||
the load between the various blocks groups.
|
||||
|
||||
<tt>bg_block_bitmap</> contains the block number of the <tt>block allocation
|
||||
bitmap block</>. This is used to allocate / deallocate each block in the
|
||||
specific blocks group.
|
||||
|
||||
<tt>bg_inode_bitmap</> is fully analogous to the previous variable - It
|
||||
contains the block number of the <tt>inode allocation bitmap block</>, which
|
||||
is used to allocate / deallocate each specific inode in the filesystem.
|
||||
|
||||
<tt>bg_inode_table</> contains the block number of the start of the
|
||||
<tt>inode table of the current blocks group</>. The <tt>inode table</> is
|
||||
just the actual inodes which are reserved for the current block.
|
||||
|
||||
The block bitmap block, inode bitmap block and the inode table are created
|
||||
when the filesystem is created.
|
||||
|
||||
The group descriptors are placed one after the other. Together they make the
|
||||
<tt>group descriptors table</>.
|
||||
|
||||
Each blocks group contains the entire table of group descriptors in its
|
||||
second block, right after the superblock. However, only the first copy (in
|
||||
group 0) is actually used by the kernel. The other copies are there for
|
||||
backup purposes and can be of use if the main copy gets corrupted.
|
||||
|
||||
<sect>The block bitmap allocation block
|
||||
<p>
|
||||
|
||||
Each blocks group contains one special block which is actually a map of the
|
||||
entire blocks in the group, with respect to their allocation status. Each
|
||||
<tt>bit</> in the block bitmap indicated whether a specific block in the
|
||||
group is used or free.
|
||||
|
||||
The format is actually quite simple - Just view the entire block as a series
|
||||
of bits. For example,
|
||||
|
||||
Suppose the block size is 1024 bytes. As such, there is a place for
|
||||
1024*8=8192 blocks in a group block. This number is one of the fields in the
|
||||
filesystem's <tt>superblock</>, which will be explained later.
|
||||
|
||||
<itemize>
|
||||
<item> Block 0 in the blocks group is managed by bit 0 of byte 0 in the bitmap
|
||||
block.
|
||||
<item> Block 7 in the blocks group is managed by bit 7 of byte 0 in the bitmap
|
||||
block.
|
||||
<item> Block 8 in the blocks group is managed by bit 0 of byte 1 in the bitmap
|
||||
block.
|
||||
<item> Block 8191 in the blocks group is managed by bit 7 of byte 1023 in the
|
||||
bitmap block.
|
||||
</itemize>
|
||||
|
||||
A value of "<tt>1</>" in the appropriate bit signals that the block is
|
||||
allocated, while a value of "<tt>0</>" signals that the block is
|
||||
unallocated.
|
||||
|
||||
You will probably notice that typically, all the bits in a byte contain the
|
||||
same value, making the byte's value <tt>0</> or <tt>0ffh</>. This is done by
|
||||
the kernel on purpose in order to group related data in physically close
|
||||
blocks, since the physical device is usually optimized to handle such a close
|
||||
relationship.
|
||||
|
||||
<sect>The inode allocation bitmap
|
||||
<p>
|
||||
|
||||
The format of the inode allocation bitmap block is exactly like the format of
|
||||
the block allocation bitmap block. The explanation above is valid here, with
|
||||
the work <tt>block</> replaced by <tt>inode</>. Typically, there are much less
|
||||
inodes then blocks in a blocks group and thus only part of the inode bitmap
|
||||
block is used. The number of inodes in a blocks group is another variable
|
||||
which is listed in the <tt>superblock</>.
|
||||
|
||||
<sect>On the inode and the inode tables
|
||||
<p>
|
||||
|
||||
An inode is a main resource in the ext2 filesystem. It is used for various
|
||||
purposes, but the main two are:
|
||||
<itemize>
|
||||
<item> Support of files
|
||||
<item> Support of directories
|
||||
</itemize>
|
||||
|
||||
Each file, for example, will allocate one inode from the filesystem
|
||||
resources.
|
||||
|
||||
An ext2 filesystem has a total number of available inodes which is determined
|
||||
while creating the filesystem. When all the inodes are used, for example, you
|
||||
will not be able to create an additional file even though there will still
|
||||
be free blocks on the filesystem.
|
||||
|
||||
Each inode takes up 128 bytes in the filesystem. By default, <tt>mke2fs</>
|
||||
reserves an inode for each 4096 bytes of the filesystem space.
|
||||
|
||||
The inodes are placed in several tables, each of which contains the same
|
||||
number of inodes and is placed at a different blocks group. The goal is to
|
||||
place inodes and their related files in the same blocks group because of
|
||||
locality arguments.
|
||||
|
||||
The number of inodes in a blocks group is available in the superblock variable
|
||||
<tt>s_inodes_per_group</>. For example, if there are 2000 inodes per group,
|
||||
group 0 will contain the inodes 1-2000, group 2 will contain the inodes
|
||||
2001-4000, and so on.
|
||||
|
||||
Each inode table is accessed from the group descriptor of the specific
|
||||
blocks group which contains the table.
|
||||
|
||||
Follows the structure of an inode in Ext2fs:
|
||||
|
||||
<tscreen><code>
|
||||
struct ext2_inode {
|
||||
__u16 i_mode; /* File mode */
|
||||
__u16 i_uid; /* Owner Uid */
|
||||
__u32 i_size; /* Size in bytes */
|
||||
__u32 i_atime; /* Access time */
|
||||
__u32 i_ctime; /* Creation time */
|
||||
__u32 i_mtime; /* Modification time */
|
||||
__u32 i_dtime; /* Deletion Time */
|
||||
__u16 i_gid; /* Group Id */
|
||||
__u16 i_links_count; /* Links count */
|
||||
__u32 i_blocks; /* Blocks count */
|
||||
__u32 i_flags; /* File flags */
|
||||
union {
|
||||
struct {
|
||||
__u32 l_i_reserved1;
|
||||
} linux1;
|
||||
struct {
|
||||
__u32 h_i_translator;
|
||||
} hurd1;
|
||||
struct {
|
||||
__u32 m_i_reserved1;
|
||||
} masix1;
|
||||
} osd1; /* OS dependent 1 */
|
||||
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
|
||||
__u32 i_version; /* File version (for NFS) */
|
||||
__u32 i_file_acl; /* File ACL */
|
||||
__u32 i_dir_acl; /* Directory ACL */
|
||||
__u32 i_faddr; /* Fragment address */
|
||||
union {
|
||||
struct {
|
||||
__u8 l_i_frag; /* Fragment number */
|
||||
__u8 l_i_fsize; /* Fragment size */
|
||||
__u16 i_pad1;
|
||||
__u32 l_i_reserved2[2];
|
||||
} linux2;
|
||||
struct {
|
||||
__u8 h_i_frag; /* Fragment number */
|
||||
__u8 h_i_fsize; /* Fragment size */
|
||||
__u16 h_i_mode_high;
|
||||
__u16 h_i_uid_high;
|
||||
__u16 h_i_gid_high;
|
||||
__u32 h_i_author;
|
||||
} hurd2;
|
||||
struct {
|
||||
__u8 m_i_frag; /* Fragment number */
|
||||
__u8 m_i_fsize; /* Fragment size */
|
||||
__u16 m_pad1;
|
||||
__u32 m_i_reserved2[2];
|
||||
} masix2;
|
||||
} osd2; /* OS dependent 2 */
|
||||
};
|
||||
</code></tscreen>
|
||||
|
||||
<sect1>The allocated blocks
|
||||
<p>
|
||||
|
||||
The basic functionality of an inode is to group together a series of
|
||||
allocated blocks. There is no limitation on the allocated blocks - Each
|
||||
block can be allocated to each inode. Nevertheless, block allocation will
|
||||
usually be done in series to take advantage of the locality principle.
|
||||
|
||||
The inode is not always used in that way. I will now explain the allocation
|
||||
of blocks, assuming that the current inode type indeed refers to a list of
|
||||
allocated blocks.
|
||||
|
||||
It was found experimently that many of the files in the filesystem are
|
||||
actually quite small. To take advantage of this effect, the kernel provides
|
||||
storage of up to 12 block numbers in the inode itself. Those blocks are
|
||||
called <tt>direct blocks</>. The advantage is that once the kernel has the
|
||||
inode, it can directly access the file's blocks, without an additional disk
|
||||
access. Those 12 blocks are directly specified in the variables
|
||||
<tt>i_block[0] to i_block[11]</>.
|
||||
|
||||
<tt>i_block[12]</> is the <tt>indirect block</> - The block pointed by
|
||||
i_block[12] will <tt>not</> be a data block. Rather, it will just contain a
|
||||
list of direct blocks. For example, if the block size is 1024 bytes, since
|
||||
each block number is 4 bytes long, there will be place for 256 indirect
|
||||
blocks. That is, block 13 till block 268 in the file will be accessed by the
|
||||
<tt>indirect block</> method. The penalty in this case, compared to the
|
||||
direct blocks case, is that an additional access to the device is needed -
|
||||
We need <tt>two</> accesses to reach the required data block.
|
||||
|
||||
In much the same way, <tt>i_block[13]</> is the <tt>double indirect block</>
|
||||
and <tt>i_block[14]</> is the <tt>triple indirect block</>.
|
||||
|
||||
<tt>i_block[13]</> points to a block which contains pointers to indirect
|
||||
blocks. Each one of them is handled in the way described above.
|
||||
|
||||
In much the same way, the triple indirect block is just an additional level
|
||||
of indirection - It will point to a list of double indirect blocks.
|
||||
|
||||
<sect1>The i_mode variable
|
||||
<p>
|
||||
|
||||
The i_mode variable is used to determine the <tt>inode type</> and the
|
||||
associated <tt>permissions</>. It is best described by representing it as an
|
||||
octal number. Since it is a 16 bit variable, there will be 6 octal digits.
|
||||
Those are divided into two parts - The rightmost 4 digits and the leftmost 2
|
||||
digits.
|
||||
|
||||
<sect2>The rightmost 4 octal digits
|
||||
<p>
|
||||
|
||||
The rightmost 4 digits are <tt>bit options</> - Each bit has its own
|
||||
purpose.
|
||||
|
||||
The last 3 digits (Octal digits 0,1 and 2) are just the usual permissions,
|
||||
in the known form <tt>rwxrwxrwx</>. Digit 2 refers to the user, digit 1 to
|
||||
the group and digit 2 to everyone else. They are used by the kernel to grant
|
||||
or deny access to the object presented by this inode.
|
||||
<footnote>
|
||||
A <tt>smarter</> permissions control is one of the enhancements planned for
|
||||
Linux 1.3 - The ACL (Access Control Lists). Actually, from browsing of the
|
||||
kernel source, some of the ACL handling is already done.
|
||||
</footnote>
|
||||
|
||||
Bit number 9 signals that the file (I'll refer to the object presented by
|
||||
the inode as file even though it can be a special device, for example) is
|
||||
<tt>set VTX</>. I still don't know what is the meaning of "VTX".
|
||||
|
||||
Bit number 10 signals that the file is <tt>set group id</> - I don't know
|
||||
exactly the meaning of the above either.
|
||||
|
||||
Bit number 11 signals that the file is <tt>set user id</>, which means that
|
||||
the file will run with an effective user id root.
|
||||
|
||||
<sect2>The leftmost two octal digits
|
||||
<p>
|
||||
|
||||
Note the the leftmost octal digit can only be 0 or 1, since the total number
|
||||
of bits is 16.
|
||||
|
||||
Those digits, as opposed to the rightmost 4 digits, are not bit mapped
|
||||
options. They determine the type of the "file" to which the inode belongs:
|
||||
<itemize>
|
||||
<item> <tt>01</> - The file is a <tt>FIFO</>.
|
||||
<item> <tt>02</> - The file is a <tt>character device</>.
|
||||
<item> <tt>04</> - The file is a <tt>directory</>.
|
||||
<item> <tt>06</> - The file is a <tt>block device</>.
|
||||
<item> <tt>10</> - The file is a <tt>regular file</>.
|
||||
<item> <tt>12</> - The file is a <tt>symbolic link</>.
|
||||
<item> <tt>14</> - The file is a <tt>socket</>.
|
||||
</itemize>
|
||||
|
||||
<sect1>Time and date
|
||||
<p>
|
||||
|
||||
Linux records the last time in which various operations occured with the
|
||||
file. The time and date are saved in the standard C library format - The
|
||||
number of seconds which passed since 00:00:00 GMT, January 1, 1970. The
|
||||
following times are recorded:
|
||||
<itemize>
|
||||
<item> <tt>i_ctime</> - The time in which the inode was last allocated. In
|
||||
other words, the time in which the file was created.
|
||||
<item> <tt>i_mtime</> - The time in which the file was last modified.
|
||||
<item> <tt>i_atime</> - The time in which the file was last accessed.
|
||||
<item> <tt>i_dtime</> - The time in which the inode was deallocated. In
|
||||
other words, the time in which the file was deleted.
|
||||
</itemize>
|
||||
|
||||
<sect1>i_size
|
||||
<p>
|
||||
|
||||
<tt>i_size</> contains information about the size of the object presented by
|
||||
the inode. If the inode corresponds to a regular file, this is just the size
|
||||
of the file in bytes. In other cases, the interpretation of the variable is
|
||||
different.
|
||||
|
||||
<sect1>User and group id
|
||||
<p>
|
||||
|
||||
The user and group id of the file are just saved in the variables
|
||||
<tt>i_uid</> and <tt>i_gid</>.
|
||||
|
||||
<sect1>Hard links
|
||||
<p>
|
||||
|
||||
Later, when we'll discuss the implementation of directories, it will be
|
||||
explained that each <tt>directory entry</> points to an inode. It is quite
|
||||
possible that a <tt>single inode</> will be pointed to from <tt>several</>
|
||||
directories. In that case, we say that there exist <tt>hard links</> to the
|
||||
file - The file can be accessed from each of the directories.
|
||||
|
||||
The kernel keeps track of the number of hard links in the variable
|
||||
<tt>i_links_count</>. The variable is set to "1" when first allocating the
|
||||
inode, and is incremented with each additional link. Deletion of a file will
|
||||
delete the current directory entry and will decrement the number of links.
|
||||
Only when this number reaches zero, the inode will be actually deallocated.
|
||||
|
||||
The name <tt>hard link</> is used to distinguish between the alias method
|
||||
described above, to another alias method called <tt>symbolic linking</>,
|
||||
which will be described later.
|
||||
|
||||
<sect1>The Ext2fs extended flags
|
||||
<p>
|
||||
|
||||
The ext2 filesystem associates additional flags with an inode. The extended
|
||||
attributes are stored in the variable <tt>i_flags</>. <tt>i_flags</> is a 32
|
||||
bit variable. Only the 7 rightmost bits are defined. Of them, only 5 bits
|
||||
are used in version 0.5a of the filesystem. Specifically, the
|
||||
<tt>undelete</> and the <tt>compress</> features are not implemented, and
|
||||
are to be introduced in Linux 1.3 development.
|
||||
|
||||
The currently available flags are:
|
||||
<itemize>
|
||||
<item> bit 0 - Secure deletion.
|
||||
|
||||
When this bit is on, the file's blocks are zeroed when the file is
|
||||
deleted. With this bit off, they will just be left with their
|
||||
original data when the inode is deallocated.
|
||||
<item> bit 1 - Undelete.
|
||||
|
||||
This bit is not supported yet. It will be used to provide an
|
||||
<tt>undelete</> feature in future Ext2fs developments.
|
||||
<item> bit 2 - Compress file.
|
||||
|
||||
This bit is also not supported. The plan is to offer "compression on
|
||||
the fly" in future releases.
|
||||
<item> bit 3 - Synchronous updates.
|
||||
|
||||
With this bit on, the meta-data will be written synchronously to the
|
||||
disk, as if the filesystem was mounted with the "sync" mount option.
|
||||
<item> bit 4 - Immutable file.
|
||||
|
||||
When this bit is on, the file will stay as it is - Can not be
|
||||
changed, deleted, renamed, no hard links, etc, before the bit is
|
||||
cleared.
|
||||
<item> bit 5 - Append only file.
|
||||
|
||||
With this option active, data will only be appended to the file.
|
||||
<item> bit 6 - Do not dump this file.
|
||||
|
||||
I think that this bit is used by the port of dump to linux (ported by
|
||||
<tt>Remy Card</>) to check if the file should not be dumped.
|
||||
</itemize>
|
||||
|
||||
<sect1>Symbolic links
|
||||
<p>
|
||||
|
||||
The <tt>hard links</> presented above are just another pointers to the same
|
||||
inode. The important aspect is that the inode number is <tt>fixed</> when
|
||||
the link is created. This means that the implementation details of the
|
||||
filesystem are visible to the user - In a pure abstract usage of the
|
||||
filesystem, the user should not care about inodes.
|
||||
|
||||
The above causes several limitations:
|
||||
<itemize>
|
||||
<item> Hard links can be done only in the same filesystem. This is obvious,
|
||||
since a hard link is just an inode number in some directory entry,
|
||||
and the above elements are filesystem specific.
|
||||
<item> You can not "replace" the file which is pointed to by the hard link
|
||||
after the link creation. "Replacing" the file in one directory will
|
||||
still leave the original file in the other directory - The
|
||||
"replacement" will not deallocate the original inode, but rather
|
||||
allocate another inode for the new version, and the directory entry
|
||||
at the other place will just point to the old inode number.
|
||||
</itemize>
|
||||
|
||||
<tt>Symbolic link</>, on the other hand, is analyzed at <tt>run time</>. A
|
||||
symbolic link is just a <tt>pathname</> which is accessible from an inode.
|
||||
As such, it "speaks" in the language of the abstract filesystem. When the
|
||||
kernel reaches a symbolic link, it will <tt>follow it in run time</> using
|
||||
its normal way of reaching directories.
|
||||
|
||||
As such, symbolic link can be made <tt>across different filesystems</> and a
|
||||
replacement of a file with a new version will automatically be active on all
|
||||
its symbolic links.
|
||||
|
||||
The disadvantage is that hard link doesn't consume space except to a small
|
||||
directory entry. Symbolic link, on the other hand, consumes at least an
|
||||
inode, and can also consume one block.
|
||||
|
||||
When the inode is identified as a symbolic link, the kernel needs to find
|
||||
the path to which it points.
|
||||
|
||||
<sect2>Fast symbolic links
|
||||
<p>
|
||||
|
||||
When the pathname contains up to 64 bytes, it can be saved directly in the
|
||||
inode, on the <tt>i_block[0] - i_block[15]</> variables, since those are not
|
||||
needed in that case. This is called <tt>fast</> symbolic link. It is fast
|
||||
because the pathname resolution can be done using the inode itself, without
|
||||
accessing additional blocks. It is also economical, since it allocates only
|
||||
an inode. The length of the pathname is stored in the <tt>i_size</>
|
||||
variable.
|
||||
|
||||
<sect2>Slow symbolic links
|
||||
<p>
|
||||
|
||||
Starting from 65 bytes, additional block is allocated (by the use of
|
||||
<tt>i_block[0]</>) and the pathname is stored in it. It is called slow
|
||||
because the kernel needs to read additional block to resolve the pathname.
|
||||
The length is again saved in <tt>i_size</>.
|
||||
|
||||
<sect1>i_version
|
||||
<p>
|
||||
|
||||
<tt>i_version</> is used with regard to Network File System. I don't know
|
||||
its exact use.
|
||||
|
||||
<sect1>Reserved variables
|
||||
<p>
|
||||
|
||||
As far as I know, the variables which are connected to ACL and fragments
|
||||
are not currently used. They will be supported in future versions.
|
||||
|
||||
Ext2fs is being ported to other operating systems. As far as I know,
|
||||
at least in linux, the os dependent variables are also not used.
|
||||
|
||||
<sect1>Special reserved inodes
|
||||
<p>
|
||||
|
||||
The first ten inodes on the filesystem are special inodes:
|
||||
<itemize>
|
||||
<item> Inode 1 is the <tt>bad blocks inode</> - I believe that its data
|
||||
blocks contain a list of the bad blocks in the filesystem, which
|
||||
should not be allocated.
|
||||
<item> Inode 2 is the <tt>root inode</> - The inode of the root directory.
|
||||
It is the starting point for reaching a known path in the filesystem.
|
||||
<item> Inode 3 is the <tt>acl index inode</>. Access control lists are
|
||||
currently not supported by the ext2 filesystem, so I believe this
|
||||
inode is not used.
|
||||
<item> Inode 4 is the <tt>acl data inode</>. Of course, the above applies
|
||||
here too.
|
||||
<item> Inode 5 is the <tt>boot loader inode</>. I don't know its
|
||||
usage.
|
||||
<item> Inode 6 is the <tt>undelete directory inode</>. It is also a
|
||||
foundation for future enhancements, and is currently not used.
|
||||
<item> Inodes 7-10 are <tt>reserved</> and currently not used.
|
||||
</itemize>
|
||||
|
||||
<sect>Directories
|
||||
<p>
|
||||
|
||||
A directory is implemented in the same way as files are implemented (with
|
||||
the direct blocks, indirect blocks, etc) - It is just a file which is
|
||||
formatted with a special format - A list of directory entries.
|
||||
|
||||
Follows the definition of a directory entry:
|
||||
|
||||
<tscreen><code>
|
||||
struct ext2_dir_entry {
|
||||
__u32 inode; /* Inode number */
|
||||
__u16 rec_len; /* Directory entry length */
|
||||
__u16 name_len; /* Name length */
|
||||
char name[EXT2_NAME_LEN]; /* File name */
|
||||
};
|
||||
</code></tscreen>
|
||||
|
||||
Ext2fs supports file names of varying lengths, up to 255 bytes. The
|
||||
<tt>name</> field above just contains the file name. Note that it is
|
||||
<tt>not zero terminated</>; Instead, the variable <tt>name_len</> contains
|
||||
the length of the file name.
|
||||
|
||||
The variable <tt>rec_len</> is provided because the directory entries are
|
||||
padded with zeroes so that the next entry will be in an offset which is
|
||||
a multiplition of 4. The resulting directory entry size is stored in
|
||||
<tt>rec_len</>. If the directory entry is the last in the block, it is
|
||||
padded with zeroes till the end of the block, and rec_len is updated
|
||||
accordingly.
|
||||
|
||||
The <tt>inode</> variable points to the inode of the above file.
|
||||
|
||||
Deletion of directory entries is done by appending of the deleted entry
|
||||
space to the previous (or next, I am not sure) entry.
|
||||
|
||||
<sect>The superblock
|
||||
<p>
|
||||
|
||||
The <tt>superblock</> is a block which contains information which describes
|
||||
the state of the internal filesystem.
|
||||
|
||||
The superblock is located at the <tt>fixed offset 1024</> in the device. Its
|
||||
length is 1024 bytes also.
|
||||
|
||||
The superblock, like the group descriptors, is copied on each blocks group
|
||||
boundary for backup purposes. However, only the main copy is used by the
|
||||
kernel.
|
||||
|
||||
The superblock contain three types of information:
|
||||
<itemize>
|
||||
<item> Filesystem parameters which are fixed and which were determined when
|
||||
this specific filesystem was created. Some of those parameters can
|
||||
be different in different installations of the ext2 filesystem, but
|
||||
can not be changed once the filesystem was created.
|
||||
<item> Filesystem parameters which are tunable - Can always be changed.
|
||||
<item> Information about the current filesystem state.
|
||||
</itemize>
|
||||
|
||||
Follows the superblock definition:
|
||||
|
||||
<tscreen><code>
|
||||
struct ext2_super_block {
|
||||
__u32 s_inodes_count; /* Inodes count */
|
||||
__u32 s_blocks_count; /* Blocks count */
|
||||
__u32 s_r_blocks_count; /* Reserved blocks count */
|
||||
__u32 s_free_blocks_count; /* Free blocks count */
|
||||
__u32 s_free_inodes_count; /* Free inodes count */
|
||||
__u32 s_first_data_block; /* First Data Block */
|
||||
__u32 s_log_block_size; /* Block size */
|
||||
__s32 s_log_frag_size; /* Fragment size */
|
||||
__u32 s_blocks_per_group; /* # Blocks per group */
|
||||
__u32 s_frags_per_group; /* # Fragments per group */
|
||||
__u32 s_inodes_per_group; /* # Inodes per group */
|
||||
__u32 s_mtime; /* Mount time */
|
||||
__u32 s_wtime; /* Write time */
|
||||
__u16 s_mnt_count; /* Mount count */
|
||||
__s16 s_max_mnt_count; /* Maximal mount count */
|
||||
__u16 s_magic; /* Magic signature */
|
||||
__u16 s_state; /* File system state */
|
||||
__u16 s_errors; /* Behaviour when detecting errors */
|
||||
__u16 s_pad;
|
||||
__u32 s_lastcheck; /* time of last check */
|
||||
__u32 s_checkinterval; /* max. time between checks */
|
||||
__u32 s_creator_os; /* OS */
|
||||
__u32 s_rev_level; /* Revision level */
|
||||
__u16 s_def_resuid; /* Default uid for reserved blocks */
|
||||
__u16 s_def_resgid; /* Default gid for reserved blocks */
|
||||
__u32 s_reserved[235]; /* Padding to the end of the block */
|
||||
};
|
||||
</code></tscreen>
|
||||
|
||||
<sect1>superblock identification
|
||||
<p>
|
||||
|
||||
The ext2 filesystem's superblock is identified by the <tt>s_magic</> field.
|
||||
The current ext2 magic number is 0xEF53. I presume that "EF" means "Extended
|
||||
Filesystem". In versions of the ext2 filesystem prior to 0.2B, the magic
|
||||
number was 0xEF51. Those filesystems are not compatible with the current
|
||||
versions; Specifically, the group descriptors definition is different. I
|
||||
doubt if there still exists such a installation.
|
||||
|
||||
<sect1>Filesystem fixed parameters
|
||||
<p>
|
||||
|
||||
By using the word <tt>fixed</>, I mean fixed with respect to a particular
|
||||
installation. Those variables are usually not fixed with respect to
|
||||
different installations.
|
||||
|
||||
The <tt>block size</> is determined by using the <tt>s_log_block_size</>
|
||||
variable. The block size is 1024*pow (2,s_log_block_size) and should be
|
||||
between 1024 and 4096. The available options are 1024, 2048 and 4096.
|
||||
|
||||
<tt>s_inodes_count</> contains the total number of available inodes.
|
||||
|
||||
<tt>s_blocks_count</> contains the total number of available blocks.
|
||||
|
||||
<tt>s_first_data_block</> specifies in which of the <tt>device block</> the
|
||||
<tt>superblock</> is present. The superblock is always present at the fixed
|
||||
offset 1024, but the device block numbering can differ. For example, if the
|
||||
block size is 1024, the superblock will be at <tt>block 1</> with respect to
|
||||
the device. However, if the block size is 4096, offset 1024 is included in
|
||||
<tt>block 0</> of the device, and in that case <tt>s_first_data_block</>
|
||||
will contain 0. At least this is how I understood this variable.
|
||||
|
||||
<tt>s_blocks_per_group</> contains the number of blocks which are grouped
|
||||
together as a blocks group.
|
||||
|
||||
<tt>s_inodes_per_group</> contains the number of inodes available in a group
|
||||
block. I think that this is always the total number of inodes divided by the
|
||||
number of blocks groups.
|
||||
|
||||
<tt>s_creator_os</> contains a code number which specifies the operating
|
||||
system which created this specific filesystem:
|
||||
<itemize>
|
||||
<item> <tt>Linux</> :-) is specified by the value <tt>0</>.
|
||||
<item> <tt>Hurd</> is specified by the value <tt>1</>.
|
||||
<item> <tt>Masix</> is specified by the value <tt>2</>.
|
||||
</itemize>
|
||||
|
||||
<tt>s_rev_level</> contains the major version of the ext2 filesystem.
|
||||
Currently this is always <tt>0</>, as the most recent version is 0.5B. It
|
||||
will probably take some time until we reach version 1.0.
|
||||
|
||||
As far as I know, fragments (sub-block allocations) are currently not
|
||||
supported and hence a block is equal to a fragment. As a result,
|
||||
<tt>s_log_frag_size</> and <tt>s_frags_per_group</> are always equal to
|
||||
<tt>s_log_block_size</> and <tt>s_blocks_per_group</>, respectively.
|
||||
|
||||
<sect1>Ext2fs error handling
|
||||
<p>
|
||||
|
||||
The ext2 filesystem error handling is based on the following philosophy:
|
||||
<enum>
|
||||
<item> Identification of problems is done by the kernel code.
|
||||
<item> The correction task is left to an external utility, such as
|
||||
<tt>e2fsck by Theodore Ts'o</> for <tt>automatic</> analysis and
|
||||
correction, or perhaps <tt>debugfs by Theodore Ts'o</> and
|
||||
<tt>EXT2ED by myself</>, for <tt>hand</> analysis and correction.
|
||||
</enum>
|
||||
|
||||
The <tt>s_state</> variable is used by the kernel to pass the identification
|
||||
result to third party utilities:
|
||||
<itemize>
|
||||
<item> <tt>bit 0</> of s_state is reset when the partition is mounted and
|
||||
set when the partition is unmounted. Thus, a value of 0 on an
|
||||
unmounted filesystem means that the filesystem was not unmounted
|
||||
properly - The filesystem is not "clean" and probably contains
|
||||
errors.
|
||||
<item> <tt>bit 1</> of s_state is set by the kernel when it detects an
|
||||
error in the filesystem. A value of 0 doesn't mean that there isn't
|
||||
an error in the filesystem, just that the kernel didn't find any.
|
||||
</itemize>
|
||||
|
||||
The kernel behavior when an error is found is determined by the user tunable
|
||||
parameter <tt>s_errors</>:
|
||||
<itemize>
|
||||
<item> The kernel will ignore the error and continue if <tt>s_errors=1</>.
|
||||
<item> The kernel will remount the filesystem in read-only mode if
|
||||
<tt>s_errors=2</>.
|
||||
<item> A kernel panic will be issued if <tt>s_errors=3</>.
|
||||
</itemize>
|
||||
|
||||
The default behavior is to ignore the error.
|
||||
|
||||
<sect1>Additional parameters used by e2fsck
|
||||
<p>
|
||||
|
||||
Of-course, <tt>e2fsck</> will check the filesystem if errors were detected
|
||||
or if the filesystem is not clean.
|
||||
|
||||
In addition, each time the filesystem is mounted, <tt>s_mnt_count</> is
|
||||
incremented. When s_mnt_count reaches <tt>s_max_mnt_count</>, <tt>e2fsck</>
|
||||
will force a check on the filesystem even though it may be clean. It will
|
||||
then zero s_mnt_count. <tt>s_max_mnt_count</> is a tunable parameter.
|
||||
|
||||
E2fsck also records the last time in which the file system was checked in
|
||||
the <tt>s_lastcheck</> variable. The user tunable parameter
|
||||
<tt>s_checkinterval</> will contain the number of seconds which are allowed
|
||||
to pass since <tt>s_lastcheck</> until a check is reforced. A value of
|
||||
<tt>0</> disables time-based check.
|
||||
|
||||
<sect1>Additional user tunable parameters
|
||||
<p>
|
||||
|
||||
<tt>s_r_blocks_count</> contains the number of disk blocks which are
|
||||
reserved for root, the user whose id number is <tt>s_def_resuid</> and the
|
||||
group whose id number is <tt>s_deg_resgid</>. The kernel will refuse to
|
||||
allocate those last <tt>s_r_blocks_count</> if the user is not one of the
|
||||
above. This is done so that the filesystem will usually not be 100% full,
|
||||
since 100% full filesystems can affect various aspects of operation.
|
||||
|
||||
<tt>s_def_resuid</> and <tt>s_def_resgid</> contain the id of the user and
|
||||
of the group who can use the reserved blocks in addition to root.
|
||||
|
||||
<sect1>Filesystem current state
|
||||
<p>
|
||||
|
||||
<tt>s_free_blocks_count</> contains the current number of free blocks
|
||||
in the filesystem.
|
||||
|
||||
<tt>s_free_inodes_count</> contains the current number of free inodes in the
|
||||
filesystem.
|
||||
|
||||
<tt>s_mtime</> contains the time at which the system was last mounted.
|
||||
|
||||
<tt>s_wtime</> contains the last time at which something was changed in the
|
||||
filesystem.
|
||||
|
||||
<sect>Copyright
|
||||
<p>
|
||||
|
||||
This document contains source code which was taken from the Linux ext2
|
||||
kernel source code, mainly from /usr/include/linux/ext2_fs.h. Follows
|
||||
the original copyright:
|
||||
|
||||
<tscreen><verb>
|
||||
/*
|
||||
* linux/include/linux/ext2_fs.h
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994, 1995
|
||||
* Remy Card (card@masi.ibp.fr)
|
||||
* Laboratoire MASI - Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* from
|
||||
*
|
||||
* linux/include/linux/minix_fs.h
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
</verb></tscreen>
|
||||
|
||||
<sect>Acknowledgments
|
||||
<p>
|
||||
|
||||
I would like to thank the following people, who were involved in the
|
||||
design and implementation of the ext2 filesystem kernel code and support
|
||||
utilities:
|
||||
<itemize>
|
||||
<item> <tt>Remy Card</>
|
||||
|
||||
Who designed, implemented and maintains the ext2 filesystem kernel
|
||||
code, and some of the ext2 utilities. <tt>Remy Card</> is also the
|
||||
author of several helpful slides concerning the ext2 filesystem.
|
||||
Specifically, he is the author of <tt>File Management in the Linux
|
||||
Kernel</> and of <tt>The Second Extended File System - Current
|
||||
State, Future Development</>.
|
||||
|
||||
<item> <tt>Wayne Davison</>
|
||||
|
||||
Who designed the ext2 filesystem.
|
||||
<item> <tt>Stephen Tweedie</>
|
||||
|
||||
Who helped designing the ext2 filesystem kernel code and wrote the
|
||||
slides <tt>Optimizations in File Systems</>.
|
||||
<item> <tt>Theodore Ts'o</>
|
||||
|
||||
Who is the author of several ext2 utilities and of the ext2 library
|
||||
<tt>libext2fs</> (which I didn't use, simply because I didn't know
|
||||
it exists when I started to work on my project).
|
||||
</itemize>
|
||||
|
||||
Lastly, I would like to thank, of-course, <tt>Linus Torvalds</> and the
|
||||
<tt>Linux community</> for providing all of us with such a great operating
|
||||
system.
|
||||
|
||||
Please contact me in a case of an error report, suggestions, or just about
|
||||
anything concerning this document.
|
||||
|
||||
Enjoy,
|
||||
|
||||
Gadi Oxman <tgud@tochnapc2.technion.ac.il>
|
||||
|
||||
Haifa, August 95
|
||||
</article>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,72 @@
|
|||
.\" -*- nroff -*-
|
||||
.TH EXT2ED 8 "August 1995" "Version 0.1"
|
||||
.SH NAME
|
||||
ext2ed \- ext2 file system editor
|
||||
.SH SYNOPSIS
|
||||
.B ext2ed
|
||||
.SH DESCRIPTION
|
||||
.B ext2ed
|
||||
in an
|
||||
.B editor
|
||||
for the
|
||||
.B second extended filesystem.
|
||||
Its aim is to show you the various internal filesystem structures in an
|
||||
intuitive form so that you would be able to easily understand and modify
|
||||
them.
|
||||
.SH DOCUMENTATION
|
||||
The documentation is not available in man page format. Instead, I have
|
||||
written three articles which are related to ext2ed:
|
||||
|
||||
The first article is
|
||||
.B The user's guide.
|
||||
This article explains how to use ext2ed.
|
||||
|
||||
The second article is
|
||||
.B The Ext2fs overview.
|
||||
This article gives an overview of internal structure of the ext2 filesystem.
|
||||
You need to understand the internal layout in order to effectively edit
|
||||
your filesystem.
|
||||
|
||||
The third article is
|
||||
.B EXT2ED - Design and implementation.
|
||||
This article explains how I constructed ext2ed. You may want to have a look
|
||||
in it if you plan to view or modify the source code.
|
||||
|
||||
.SH WARNING
|
||||
|
||||
.B
|
||||
Do not use ext2ed on a mounted filesystem.
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
.I /usr/bin/ext2ed
|
||||
The program itself.
|
||||
.TP
|
||||
.I /var/lib/ext2ed/ext2ed.conf
|
||||
ext2ed's configuration file.
|
||||
.TP
|
||||
.I /var/lib/ext2ed/ext2.descriptors
|
||||
Definition of the various objects for the ext2 filesystem.
|
||||
.TP
|
||||
.I /var/lib/ext2ed/ext2ed.log
|
||||
Log file of actual changes made to the filesystem.
|
||||
.TP
|
||||
.I /usr/man/man8/ext2ed.8
|
||||
The manual page.
|
||||
.TP
|
||||
.I /usr/doc/ext2ed/user-guide-0.1.ps
|
||||
The user's guide.
|
||||
.TP
|
||||
.I /usr/doc/ext2ed/Ext2fs-overview-0.1.ps
|
||||
Technical overview of the ext2 filesystem.
|
||||
.TP
|
||||
.I /usr/doc/ext2ed/ext2ed-design-0.1.ps
|
||||
EXT2ED design notes.
|
||||
|
||||
.SH BUGS
|
||||
Filesystems bigger than 2 GB aren't yet supported.
|
||||
.SH AUTHOR
|
||||
Gadi Oxman <tgud@tochnapc2.technion.ac.il>
|
||||
.SH SEE ALSO
|
||||
.BR e2fsck (8),
|
||||
.BR debugfs (8)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,407 @@
|
|||
Extended 2 filesystem structure definitions for ext2ed.
|
||||
|
||||
Most of this file is just copied from the ext2 main include file.
|
||||
|
||||
My parser is very primitive - It only searches for the struct keywords,
|
||||
and uses the variables in there. The rest of the file is just ignored.
|
||||
|
||||
You will find at the end a few additional types which are not aviable in
|
||||
the original include file, such as the types "file" and "dir". They have
|
||||
no variables, but are necessary due to the way ext2ed binds C commands
|
||||
to specific types.
|
||||
|
||||
Gadi Oxman, 7/95
|
||||
|
||||
Here is the original copyright:
|
||||
|
||||
/*
|
||||
* linux/include/linux/ext2_fs.h
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr)
|
||||
* Laboratoire MASI - Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* from
|
||||
*
|
||||
* linux/include/linux/minix_fs.h
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* ACL structures
|
||||
*/
|
||||
struct ext2_acl_header /* Header of Access Control Lists */
|
||||
{
|
||||
unsigned long aclh_size;
|
||||
unsigned long aclh_file_count;
|
||||
unsigned long aclh_acle_count;
|
||||
unsigned long aclh_first_acle;
|
||||
};
|
||||
|
||||
struct ext2_acl_entry /* Access Control List Entry */
|
||||
{
|
||||
unsigned long acle_size;
|
||||
unsigned short acle_perms; /* Access permissions */
|
||||
unsigned short acle_type; /* Type of entry */
|
||||
unsigned short acle_tag; /* User or group identity */
|
||||
unsigned short acle_pad1;
|
||||
unsigned long acle_next; /* Pointer on next entry for the */
|
||||
/* same inode or on next free entry */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of a blocks group descriptor
|
||||
*/
|
||||
|
||||
struct ext2_group_desc
|
||||
{
|
||||
unsigned long bg_block_bitmap; /* Blocks bitmap block */
|
||||
unsigned long bg_inode_bitmap; /* Inodes bitmap block */
|
||||
unsigned long bg_inode_table; /* Inodes table block */
|
||||
unsigned short bg_free_blocks_count; /* Free blocks count */
|
||||
unsigned short bg_free_inodes_count; /* Free inodes count */
|
||||
unsigned short bg_used_dirs_count; /* Directories count */
|
||||
unsigned short bg_pad;
|
||||
unsigned long bg_reserved[0];
|
||||
unsigned long bg_reserved[1];
|
||||
unsigned long bg_reserved[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of an inode on the disk
|
||||
*/
|
||||
struct ext2_inode {
|
||||
unsigned short i_mode; /* File mode */
|
||||
unsigned short i_uid; /* Owner Uid */
|
||||
unsigned long i_size; /* Size in bytes */
|
||||
unsigned long i_atime; /* Access time */
|
||||
unsigned long i_ctime; /* Creation time */
|
||||
unsigned long i_mtime; /* Modification time */
|
||||
unsigned long i_dtime; /* Deletion Time */
|
||||
unsigned short i_gid; /* Group Id */
|
||||
unsigned short i_links_count; /* Links count */
|
||||
unsigned long i_blocks; /* Blocks count */
|
||||
unsigned long i_flags; /* File flags */
|
||||
unsigned long l_i_reserved1;
|
||||
unsigned long i_block[0]; /* Pointers to blocks */
|
||||
unsigned long i_block[1]; /* Pointers to blocks */
|
||||
unsigned long i_block[2]; /* Pointers to blocks */
|
||||
unsigned long i_block[3]; /* Pointers to blocks */
|
||||
unsigned long i_block[4]; /* Pointers to blocks */
|
||||
unsigned long i_block[5]; /* Pointers to blocks */
|
||||
unsigned long i_block[6]; /* Pointers to blocks */
|
||||
unsigned long i_block[7]; /* Pointers to blocks */
|
||||
unsigned long i_block[8]; /* Pointers to blocks */
|
||||
unsigned long i_block[9]; /* Pointers to blocks */
|
||||
unsigned long i_block[10]; /* Pointers to blocks */
|
||||
unsigned long i_block[11]; /* Pointers to blocks */
|
||||
unsigned long i_block[12]; /* Pointers to blocks */
|
||||
unsigned long i_block[13]; /* Pointers to blocks */
|
||||
unsigned long i_block[14]; /* Pointers to blocks */
|
||||
unsigned long i_version; /* File version (for NFS) */
|
||||
unsigned long i_file_acl; /* File ACL */
|
||||
unsigned long i_dir_acl; /* Directory ACL */
|
||||
unsigned long i_faddr; /* Fragment address */
|
||||
unsigned char l_i_frag; /* Fragment number */
|
||||
unsigned char l_i_fsize; /* Fragment size */
|
||||
unsigned short i_pad1;
|
||||
unsigned long l_i_reserved2[0];
|
||||
unsigned long l_i_reserved2[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of the super block
|
||||
*/
|
||||
struct ext2_super_block {
|
||||
unsigned long s_inodes_count; /* Inodes count */
|
||||
unsigned long s_blocks_count; /* Blocks count */
|
||||
unsigned long s_r_blocks_count; /* Reserved blocks count */
|
||||
unsigned long s_free_blocks_count; /* Free blocks count */
|
||||
unsigned long s_free_inodes_count; /* Free inodes count */
|
||||
unsigned long s_first_data_block; /* First Data Block */
|
||||
unsigned long s_log_block_size; /* Block size */
|
||||
long s_log_frag_size; /* Fragment size */
|
||||
unsigned long s_blocks_per_group; /* # Blocks per group */
|
||||
unsigned long s_frags_per_group; /* # Fragments per group */
|
||||
unsigned long s_inodes_per_group; /* # Inodes per group */
|
||||
unsigned long s_mtime; /* Mount time */
|
||||
unsigned long s_wtime; /* Write time */
|
||||
unsigned short s_mnt_count; /* Mount count */
|
||||
short s_max_mnt_count; /* Maximal mount count */
|
||||
unsigned short s_magic; /* Magic signature */
|
||||
unsigned short s_state; /* File system state */
|
||||
unsigned short s_errors; /* Behaviour when detecting errors */
|
||||
unsigned short s_pad;
|
||||
unsigned long s_lastcheck; /* time of last check */
|
||||
unsigned long s_checkinterval; /* max. time between checks */
|
||||
unsigned long s_creator_os; /* OS */
|
||||
unsigned long s_rev_level; /* Revision level */
|
||||
unsigned short s_def_resuid;
|
||||
unsigned short s_deg_resgid;
|
||||
|
||||
unsigned long s_reserved[0]; /* Padding to the end of the block */
|
||||
unsigned long s_reserved[1];
|
||||
unsigned long s_reserved[2];
|
||||
unsigned long s_reserved[3];
|
||||
unsigned long s_reserved[4];
|
||||
unsigned long s_reserved[5];
|
||||
unsigned long s_reserved[6];
|
||||
unsigned long s_reserved[7];
|
||||
unsigned long s_reserved[8];
|
||||
unsigned long s_reserved[9];
|
||||
unsigned long s_reserved[10];
|
||||
unsigned long s_reserved[11];
|
||||
unsigned long s_reserved[12];
|
||||
unsigned long s_reserved[13];
|
||||
unsigned long s_reserved[14];
|
||||
unsigned long s_reserved[15];
|
||||
unsigned long s_reserved[16];
|
||||
unsigned long s_reserved[17];
|
||||
unsigned long s_reserved[18];
|
||||
unsigned long s_reserved[19];
|
||||
unsigned long s_reserved[20];
|
||||
unsigned long s_reserved[21];
|
||||
unsigned long s_reserved[22];
|
||||
unsigned long s_reserved[23];
|
||||
unsigned long s_reserved[24];
|
||||
unsigned long s_reserved[25];
|
||||
unsigned long s_reserved[26];
|
||||
unsigned long s_reserved[27];
|
||||
unsigned long s_reserved[28];
|
||||
unsigned long s_reserved[29];
|
||||
unsigned long s_reserved[30];
|
||||
unsigned long s_reserved[31];
|
||||
unsigned long s_reserved[32];
|
||||
unsigned long s_reserved[33];
|
||||
unsigned long s_reserved[34];
|
||||
unsigned long s_reserved[35];
|
||||
unsigned long s_reserved[36];
|
||||
unsigned long s_reserved[37];
|
||||
unsigned long s_reserved[38];
|
||||
unsigned long s_reserved[39];
|
||||
unsigned long s_reserved[40];
|
||||
unsigned long s_reserved[41];
|
||||
unsigned long s_reserved[42];
|
||||
unsigned long s_reserved[43];
|
||||
unsigned long s_reserved[44];
|
||||
unsigned long s_reserved[45];
|
||||
unsigned long s_reserved[46];
|
||||
unsigned long s_reserved[47];
|
||||
unsigned long s_reserved[48];
|
||||
unsigned long s_reserved[49];
|
||||
unsigned long s_reserved[50];
|
||||
unsigned long s_reserved[51];
|
||||
unsigned long s_reserved[52];
|
||||
unsigned long s_reserved[53];
|
||||
unsigned long s_reserved[54];
|
||||
unsigned long s_reserved[55];
|
||||
unsigned long s_reserved[56];
|
||||
unsigned long s_reserved[57];
|
||||
unsigned long s_reserved[58];
|
||||
unsigned long s_reserved[59];
|
||||
unsigned long s_reserved[60];
|
||||
unsigned long s_reserved[61];
|
||||
unsigned long s_reserved[62];
|
||||
unsigned long s_reserved[63];
|
||||
unsigned long s_reserved[64];
|
||||
unsigned long s_reserved[65];
|
||||
unsigned long s_reserved[66];
|
||||
unsigned long s_reserved[67];
|
||||
unsigned long s_reserved[68];
|
||||
unsigned long s_reserved[69];
|
||||
unsigned long s_reserved[70];
|
||||
unsigned long s_reserved[71];
|
||||
unsigned long s_reserved[72];
|
||||
unsigned long s_reserved[73];
|
||||
unsigned long s_reserved[74];
|
||||
unsigned long s_reserved[75];
|
||||
unsigned long s_reserved[76];
|
||||
unsigned long s_reserved[77];
|
||||
unsigned long s_reserved[78];
|
||||
unsigned long s_reserved[79];
|
||||
unsigned long s_reserved[80];
|
||||
unsigned long s_reserved[81];
|
||||
unsigned long s_reserved[82];
|
||||
unsigned long s_reserved[83];
|
||||
unsigned long s_reserved[84];
|
||||
unsigned long s_reserved[85];
|
||||
unsigned long s_reserved[86];
|
||||
unsigned long s_reserved[87];
|
||||
unsigned long s_reserved[88];
|
||||
unsigned long s_reserved[89];
|
||||
unsigned long s_reserved[90];
|
||||
unsigned long s_reserved[91];
|
||||
unsigned long s_reserved[92];
|
||||
unsigned long s_reserved[93];
|
||||
unsigned long s_reserved[94];
|
||||
unsigned long s_reserved[95];
|
||||
unsigned long s_reserved[96];
|
||||
unsigned long s_reserved[97];
|
||||
unsigned long s_reserved[98];
|
||||
unsigned long s_reserved[99];
|
||||
unsigned long s_reserved[100];
|
||||
unsigned long s_reserved[101];
|
||||
unsigned long s_reserved[102];
|
||||
unsigned long s_reserved[103];
|
||||
unsigned long s_reserved[104];
|
||||
unsigned long s_reserved[105];
|
||||
unsigned long s_reserved[106];
|
||||
unsigned long s_reserved[107];
|
||||
unsigned long s_reserved[108];
|
||||
unsigned long s_reserved[109];
|
||||
unsigned long s_reserved[110];
|
||||
unsigned long s_reserved[111];
|
||||
unsigned long s_reserved[112];
|
||||
unsigned long s_reserved[113];
|
||||
unsigned long s_reserved[114];
|
||||
unsigned long s_reserved[115];
|
||||
unsigned long s_reserved[116];
|
||||
unsigned long s_reserved[117];
|
||||
unsigned long s_reserved[118];
|
||||
unsigned long s_reserved[119];
|
||||
unsigned long s_reserved[120];
|
||||
unsigned long s_reserved[121];
|
||||
unsigned long s_reserved[122];
|
||||
unsigned long s_reserved[123];
|
||||
unsigned long s_reserved[124];
|
||||
unsigned long s_reserved[125];
|
||||
unsigned long s_reserved[126];
|
||||
unsigned long s_reserved[127];
|
||||
unsigned long s_reserved[128];
|
||||
unsigned long s_reserved[129];
|
||||
unsigned long s_reserved[130];
|
||||
unsigned long s_reserved[131];
|
||||
unsigned long s_reserved[132];
|
||||
unsigned long s_reserved[133];
|
||||
unsigned long s_reserved[134];
|
||||
unsigned long s_reserved[135];
|
||||
unsigned long s_reserved[136];
|
||||
unsigned long s_reserved[137];
|
||||
unsigned long s_reserved[138];
|
||||
unsigned long s_reserved[139];
|
||||
unsigned long s_reserved[140];
|
||||
unsigned long s_reserved[141];
|
||||
unsigned long s_reserved[142];
|
||||
unsigned long s_reserved[143];
|
||||
unsigned long s_reserved[144];
|
||||
unsigned long s_reserved[145];
|
||||
unsigned long s_reserved[146];
|
||||
unsigned long s_reserved[147];
|
||||
unsigned long s_reserved[148];
|
||||
unsigned long s_reserved[149];
|
||||
unsigned long s_reserved[150];
|
||||
unsigned long s_reserved[151];
|
||||
unsigned long s_reserved[152];
|
||||
unsigned long s_reserved[153];
|
||||
unsigned long s_reserved[154];
|
||||
unsigned long s_reserved[155];
|
||||
unsigned long s_reserved[156];
|
||||
unsigned long s_reserved[157];
|
||||
unsigned long s_reserved[158];
|
||||
unsigned long s_reserved[159];
|
||||
unsigned long s_reserved[160];
|
||||
unsigned long s_reserved[161];
|
||||
unsigned long s_reserved[162];
|
||||
unsigned long s_reserved[163];
|
||||
unsigned long s_reserved[164];
|
||||
unsigned long s_reserved[165];
|
||||
unsigned long s_reserved[166];
|
||||
unsigned long s_reserved[167];
|
||||
unsigned long s_reserved[168];
|
||||
unsigned long s_reserved[169];
|
||||
unsigned long s_reserved[170];
|
||||
unsigned long s_reserved[171];
|
||||
unsigned long s_reserved[172];
|
||||
unsigned long s_reserved[173];
|
||||
unsigned long s_reserved[174];
|
||||
unsigned long s_reserved[175];
|
||||
unsigned long s_reserved[176];
|
||||
unsigned long s_reserved[177];
|
||||
unsigned long s_reserved[178];
|
||||
unsigned long s_reserved[179];
|
||||
unsigned long s_reserved[180];
|
||||
unsigned long s_reserved[181];
|
||||
unsigned long s_reserved[182];
|
||||
unsigned long s_reserved[183];
|
||||
unsigned long s_reserved[184];
|
||||
unsigned long s_reserved[185];
|
||||
unsigned long s_reserved[186];
|
||||
unsigned long s_reserved[187];
|
||||
unsigned long s_reserved[188];
|
||||
unsigned long s_reserved[189];
|
||||
unsigned long s_reserved[190];
|
||||
unsigned long s_reserved[191];
|
||||
unsigned long s_reserved[192];
|
||||
unsigned long s_reserved[193];
|
||||
unsigned long s_reserved[194];
|
||||
unsigned long s_reserved[195];
|
||||
unsigned long s_reserved[196];
|
||||
unsigned long s_reserved[197];
|
||||
unsigned long s_reserved[198];
|
||||
unsigned long s_reserved[199];
|
||||
unsigned long s_reserved[200];
|
||||
unsigned long s_reserved[201];
|
||||
unsigned long s_reserved[202];
|
||||
unsigned long s_reserved[203];
|
||||
unsigned long s_reserved[204];
|
||||
unsigned long s_reserved[205];
|
||||
unsigned long s_reserved[206];
|
||||
unsigned long s_reserved[207];
|
||||
unsigned long s_reserved[208];
|
||||
unsigned long s_reserved[209];
|
||||
unsigned long s_reserved[210];
|
||||
unsigned long s_reserved[211];
|
||||
unsigned long s_reserved[212];
|
||||
unsigned long s_reserved[213];
|
||||
unsigned long s_reserved[214];
|
||||
unsigned long s_reserved[215];
|
||||
unsigned long s_reserved[216];
|
||||
unsigned long s_reserved[217];
|
||||
unsigned long s_reserved[218];
|
||||
unsigned long s_reserved[219];
|
||||
unsigned long s_reserved[220];
|
||||
unsigned long s_reserved[221];
|
||||
unsigned long s_reserved[222];
|
||||
unsigned long s_reserved[223];
|
||||
unsigned long s_reserved[224];
|
||||
unsigned long s_reserved[225];
|
||||
unsigned long s_reserved[226];
|
||||
unsigned long s_reserved[227];
|
||||
unsigned long s_reserved[228];
|
||||
unsigned long s_reserved[229];
|
||||
unsigned long s_reserved[230];
|
||||
unsigned long s_reserved[231];
|
||||
unsigned long s_reserved[232];
|
||||
unsigned long s_reserved[233];
|
||||
unsigned long s_reserved[234];
|
||||
};
|
||||
|
||||
The following is actually not used, due to the variable length of the
|
||||
name field. EXT2ED handles directories through the type "dir" below.
|
||||
|
||||
/*
|
||||
* Structure of a directory entry
|
||||
*/
|
||||
|
||||
/* struct ext2_dir_entry { */
|
||||
/*
|
||||
unsigned long inode; /* Inode number */
|
||||
unsigned short rec_len; /* Directory entry length */
|
||||
unsigned short name_len; /* Name length */
|
||||
char name[EXT2_NAME_LEN]; /* File name */
|
||||
};
|
||||
*/
|
||||
|
||||
struct file {
|
||||
};
|
||||
|
||||
struct dir {
|
||||
};
|
||||
|
||||
struct block_bitmap {
|
||||
};
|
||||
|
||||
struct inode_bitmap {
|
||||
};
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/ext2_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
--------------------------------------
|
||||
Extended-2 filesystem General commands
|
||||
--------------------------------------
|
||||
|
||||
The commands here will be registered when we are editing an ext2 filesystem
|
||||
|
||||
First written on: July 28 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
void type_ext2___super (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
We are moving to the superblock - Just use setoffset and settype. The offset was gathered in the
|
||||
initialization phase (but is constant - 1024).
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
char buffer [80];
|
||||
|
||||
super_info.copy_num=0;
|
||||
sprintf (buffer,"setoffset %ld",file_system_info.super_block_offset);dispatch (buffer);
|
||||
sprintf (buffer,"settype ext2_super_block");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2___cd (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
A global cd command - The path should start with /.
|
||||
|
||||
We implement it through dispatching to our primitive functions.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
char temp [80],buffer [80],*ptr;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - No argument specified\n");refresh_command_win ();return;
|
||||
}
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
if (buffer [0] != '/') {
|
||||
wprintw (command_win,"Error - Use a full pathname (begin with '/')\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
/* Note the various dispatches below - They should be intuitive if you know the ext2 filesystem structure */
|
||||
|
||||
dispatch ("super");dispatch ("group");dispatch ("inode");dispatch ("next");dispatch ("dir");
|
||||
if (buffer [1] != 0) {
|
||||
sprintf (temp,"cd %s",buffer+1);dispatch (temp);
|
||||
}
|
||||
}
|
||||
|
||||
void type_ext2___group (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
We go to the group descriptors.
|
||||
First, we go to the first group descriptor in the main copy.
|
||||
Then, we use the group's entry command to pass to another group.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
long group_num=0;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
group_num=atol (buffer);
|
||||
}
|
||||
|
||||
group_info.copy_num=0;group_info.group_num=0;
|
||||
sprintf (buffer,"setoffset %ld",file_system_info.first_group_desc_offset);dispatch (buffer);
|
||||
sprintf (buffer,"settype ext2_group_desc");dispatch (buffer);
|
||||
sprintf (buffer,"entry %ld",group_num);dispatch (buffer);
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
##############################################################################
|
||||
# ext2ed.conf #
|
||||
# #
|
||||
# Configuration file for the extended 2 file system disk editor. #
|
||||
##############################################################################
|
||||
|
||||
# Ext2Descriptors is the location of the ext2 filesystem structure
|
||||
# definitions.
|
||||
|
||||
|
||||
Ext2Descriptors /var/lib/ext2ed/ext2.descriptors
|
||||
|
||||
|
||||
# Using AlternateDescriptors you can declare additional structures. Those
|
||||
# structures can contain only variables. Linking functions to the objects is
|
||||
# possible only through source code additions.
|
||||
|
||||
|
||||
AlternateDescriptors
|
||||
|
||||
|
||||
# LogFile is the location of the log file. Actual changes to the filesystem
|
||||
# are logged there. See also LogChanges.
|
||||
|
||||
|
||||
LogFile /var/lib/ext2ed/ext2ed.log
|
||||
|
||||
|
||||
# The following selects the default behavior when changes are made to the
|
||||
# filesystem. When on, each change will be logged - Both the previous data
|
||||
# and the new written data.
|
||||
|
||||
|
||||
LogChanges on
|
||||
|
||||
|
||||
# AllowChanges off will not allow ext2ed to do any changes to the
|
||||
# filesystem - The "enablewrite" command will not work. When on, enablewrite
|
||||
# will still have to be issued to allow write access.
|
||||
|
||||
|
||||
AllowChanges on
|
||||
|
||||
|
||||
# With this option you can choose whether ext2ed will allow read-only mode on
|
||||
# a mounted filesystem. Read-Write mode is never allowed on a mounted
|
||||
# filesystem.
|
||||
|
||||
|
||||
AllowMountedRead on
|
||||
|
||||
|
||||
# When ForceExt2 is set to on, the filesystem is assumed to be ext2
|
||||
# filesystem, despite the possibly corrupt superblock magic number reading.
|
||||
# All the ext2 specific commands will be aviable despite the possible
|
||||
# autodetection failture.
|
||||
|
||||
ForceExt2 off
|
||||
|
||||
|
||||
# Normally, the various filesystem parameters such as the block size and the
|
||||
# total number of blocks are gathered from the ext2 filesystem itself.
|
||||
# However, on a corrupt filesystem, ext2ed is unable to get the right
|
||||
# parameters. In this case, they will be taken from here. See also
|
||||
# ForceDefault.
|
||||
|
||||
|
||||
DefaultBlockSize 1024
|
||||
DefaultTotalBlocks 2097151 # ~2 GB total size
|
||||
DefaultBlocksInGroup 8192
|
||||
|
||||
# With ForceDefault on, you can force the use of the default parameters
|
||||
# above. This is not recommended, as ext2ed will fallback by default to those
|
||||
# parameters if it can't figure up the parameters from the filesystem itself.
|
||||
|
||||
|
||||
ForceDefault off
|
||||
|
||||
|
|
@ -0,0 +1,438 @@
|
|||
|
||||
/*
|
||||
|
||||
/usr/src/ext2ed/ext2ed.h
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
--------------------------------------
|
||||
Include file for the ext2 disk editor.
|
||||
--------------------------------------
|
||||
|
||||
This file contains declarations which are needed by all the files in ext2ed.
|
||||
|
||||
First written on: April 9 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#ifndef EXT2ED_EDITOR_H
|
||||
#define EXT2ED_EDITOR_H
|
||||
|
||||
/*
|
||||
|
||||
-----------------------
|
||||
User definable options
|
||||
-----------------------
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VAR_DIR
|
||||
#define VAR_DIR "/var/lib/ext2ed" /* The configuration file will be searched here */
|
||||
#endif
|
||||
|
||||
#define DEBUG /* Activate self-sanity checks */
|
||||
|
||||
#include <linux/ext2_fs.h> /* Main kernel ext2 include file */
|
||||
#include <linux/stat.h>
|
||||
|
||||
#ifdef OLD_NCURSES /* The ncurses interface */
|
||||
#include <ncurses/ncurses.h>
|
||||
#else
|
||||
#include <ncurses/curses.h>
|
||||
#endif
|
||||
|
||||
#define MAX_FIELDS 400
|
||||
|
||||
#define MAX_COMMAND_LINE 81
|
||||
#define MAX_COMMANDS_NUM 30 /* Maximum number of commands of one type */
|
||||
#define REMEMBER_COUNT 30 /* Object memory size */
|
||||
|
||||
/*
|
||||
The user screen consists of four parts:
|
||||
|
||||
1. Title window (title_win).
|
||||
2. Show (status) window (show_win).
|
||||
3. Main show pad (show_pad).
|
||||
4. Command window (command_win).
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
The show pad is mapped to the space left between the other three windows.
|
||||
|
||||
If you wondered why ext2ed grabs so memory, the answer is probably below - I wanted to treat
|
||||
the virtual display as infinite. Decrease the following for more realistic memory consumption.
|
||||
|
||||
*/
|
||||
|
||||
#define SHOW_PAD_LINES 3000
|
||||
#define SHOW_PAD_COLS (COLS > 140 ? COLS : 140)
|
||||
|
||||
#define COMMAND_WIN_LINES 6 /* Change this to your preferences */
|
||||
#define TITLE_WIN_LINES 3
|
||||
#define SHOW_WIN_LINES 3
|
||||
|
||||
#define HEX 1
|
||||
#define TEXT 2
|
||||
|
||||
#ifndef EXT2_PRE_02B_MAGIC
|
||||
#define EXT2_PRE_02B_MAGIC 0xEF51
|
||||
#endif
|
||||
|
||||
|
||||
typedef void (*PF) (char *); /* Used to point to the dispatched functions */
|
||||
|
||||
struct struct_commands { /* Holds commands of an object */
|
||||
int last_command;
|
||||
char *names [MAX_COMMANDS_NUM];
|
||||
char *descriptions [MAX_COMMANDS_NUM];
|
||||
PF callback [MAX_COMMANDS_NUM];
|
||||
};
|
||||
|
||||
struct struct_descriptor { /* Describes an object */
|
||||
unsigned long length;
|
||||
unsigned char name [60];
|
||||
unsigned short fields_num;
|
||||
unsigned char field_names [MAX_FIELDS][80];
|
||||
unsigned short field_lengths [MAX_FIELDS];
|
||||
unsigned short field_positions [MAX_FIELDS];
|
||||
struct struct_commands type_commands;
|
||||
struct struct_descriptor *prev,*next;
|
||||
};
|
||||
|
||||
struct struct_type_data { /* The object's data is usually here */
|
||||
long offset_in_block;
|
||||
|
||||
union union_type_data { /* Format it in various ways */
|
||||
char buffer [EXT2_MAX_BLOCK_SIZE];
|
||||
struct ext2_acl_header t_ext2_acl_header;
|
||||
struct ext2_acl_entry t_ext2_acl_entry;
|
||||
struct ext2_group_desc t_ext2_group_desc;
|
||||
struct ext2_inode t_ext2_inode;
|
||||
struct ext2_super_block t_ext2_super_block;
|
||||
struct ext2_dir_entry t_ext2_dir_entry;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct struct_file_system_info { /* Important information about the filesystem */
|
||||
unsigned long long file_system_size;
|
||||
unsigned long super_block_offset;
|
||||
unsigned long first_group_desc_offset;
|
||||
unsigned long groups_count;
|
||||
unsigned long inodes_per_block;
|
||||
unsigned long blocks_per_group; /* The name is misleading; beware */
|
||||
unsigned long no_blocks_in_group;
|
||||
unsigned short block_size;
|
||||
struct ext2_super_block super_block;
|
||||
};
|
||||
|
||||
struct struct_file_info { /* Used to handle files and directories */
|
||||
|
||||
struct ext2_inode *inode_ptr;
|
||||
|
||||
long inode_offset;
|
||||
long global_block_num,global_block_offset;
|
||||
long block_num,blocks_count;
|
||||
long file_offset,file_length;
|
||||
long level;
|
||||
unsigned char buffer [EXT2_MAX_BLOCK_SIZE];
|
||||
long offset_in_block;
|
||||
|
||||
int display;
|
||||
/* The following is used if the file is a directory */
|
||||
|
||||
long dir_entry_num,dir_entries_count;
|
||||
long dir_entry_offset;
|
||||
};
|
||||
|
||||
struct struct_super_info { /* Used to handle the superblock */
|
||||
unsigned long copy_num;
|
||||
};
|
||||
|
||||
struct struct_group_info { /* Used to handle the group descriptors */
|
||||
unsigned long copy_num;
|
||||
unsigned long group_num;
|
||||
};
|
||||
|
||||
struct struct_block_bitmap_info { /* Used in blockbitmap_com.c */
|
||||
unsigned long entry_num;
|
||||
unsigned long group_num;
|
||||
};
|
||||
|
||||
struct struct_inode_bitmap_info { /* Used in inodebitmap_com.c */
|
||||
unsigned long entry_num;
|
||||
unsigned long group_num;
|
||||
};
|
||||
|
||||
struct struct_remember_lifo { /* Implements the objects circular memory */
|
||||
long entries_count;
|
||||
|
||||
long offset [REMEMBER_COUNT];
|
||||
struct struct_descriptor *type [REMEMBER_COUNT];
|
||||
char name [REMEMBER_COUNT][80];
|
||||
};
|
||||
|
||||
struct struct_pad_info { /* Used to zoom into the pad window */
|
||||
int display_lines,display_cols;
|
||||
int line,col;
|
||||
int max_line,max_col;
|
||||
int disable_output;
|
||||
};
|
||||
|
||||
/* Global variables (defined mostly in main.c) */
|
||||
|
||||
/* Configurable variables (Through configuration file) */
|
||||
|
||||
extern char AlternateDescriptors [200];
|
||||
extern char Ext2Descriptors [200];
|
||||
extern char LogFile [200];
|
||||
extern int LogChanges;
|
||||
extern int AllowChanges;
|
||||
extern int AllowMountedRead;
|
||||
extern int ForceExt2;
|
||||
extern int DefaultBlockSize;
|
||||
extern unsigned long DefaultTotalBlocks;
|
||||
extern unsigned long DefaultBlocksInGroup;
|
||||
extern int ForceDefault;
|
||||
|
||||
extern char device_name [80];
|
||||
extern char last_command_line [80];
|
||||
extern FILE *device_handle;
|
||||
extern long device_offset;
|
||||
extern int mounted;
|
||||
|
||||
extern short block_size;
|
||||
extern struct struct_commands general_commands;
|
||||
extern struct struct_commands ext2_commands;
|
||||
extern struct struct_descriptor *first_type;
|
||||
extern struct struct_descriptor *last_type;
|
||||
extern struct struct_descriptor *current_type;
|
||||
extern struct struct_type_data type_data;
|
||||
extern struct struct_file_system_info file_system_info;
|
||||
extern struct struct_file_info file_info,first_file_info;
|
||||
extern struct struct_group_info group_info;
|
||||
extern struct struct_super_info super_info;
|
||||
extern struct struct_block_bitmap_info block_bitmap_info;
|
||||
extern struct struct_inode_bitmap_info inode_bitmap_info;
|
||||
extern struct struct_remember_lifo remember_lifo;
|
||||
extern struct struct_pad_info show_pad_info;
|
||||
extern int write_access;
|
||||
|
||||
extern int redraw_request;
|
||||
extern char lines_s [80];
|
||||
extern char cols_s [80];
|
||||
|
||||
|
||||
/* init.c */
|
||||
|
||||
extern int init (void);
|
||||
extern void prepare_to_close (void);
|
||||
extern int set_struct_descriptors (char *file_name);
|
||||
extern void free_struct_descriptors (void);
|
||||
extern struct struct_descriptor *add_new_descriptor (char *name);
|
||||
extern void add_new_variable (struct struct_descriptor *descriptor,char *v_type,char *v_name);
|
||||
extern void fill_type_commands (struct struct_descriptor *ptr);
|
||||
extern void add_user_command (struct struct_commands *ptr,char *name,char *description,PF callback);
|
||||
extern void free_user_commands (struct struct_commands *ptr);
|
||||
extern int set_file_system_info (void);
|
||||
extern int process_configuration_file (void);
|
||||
extern void add_general_commands (void);
|
||||
extern void add_ext2_general_commands (void);
|
||||
extern void check_mounted (char *name);
|
||||
|
||||
int get_next_option (FILE *fp,char *option,char *value);
|
||||
void init_readline (void);
|
||||
void init_signals (void);
|
||||
void signal_SIGWINCH_handler (int sig_num);
|
||||
void signal_SIGTERM_handler (int sig_num);
|
||||
void signal_SIGSEGV_handler (int sig_num);
|
||||
|
||||
/* general_com.c */
|
||||
|
||||
/* General commands which are aviable always */
|
||||
|
||||
extern void help (char *command_line);
|
||||
extern void set (char *command_line);
|
||||
extern void set_device (char *command_line);
|
||||
extern void set_offset (char *command_line);
|
||||
extern void set_type (char *command_line);
|
||||
extern void show (char *command_line);
|
||||
extern void pgup (char *command_line);
|
||||
extern void pgdn (char *command_line);
|
||||
extern void redraw (char *command_line);
|
||||
extern void remember (char *command_line);
|
||||
extern void recall (char *command_line);
|
||||
extern void cd (char *command_line);
|
||||
extern void enable_write (char *command_line);
|
||||
extern void disable_write (char *command_line);
|
||||
extern void write_data (char *command_line);
|
||||
extern void next (char *command_line);
|
||||
extern void prev (char *command_line);
|
||||
|
||||
void hex_set (char *command_line);
|
||||
void detailed_help (char *text);
|
||||
|
||||
|
||||
/* ext2_com.c */
|
||||
|
||||
/* Extended2 filesystem genereal commands - Aviable only when editing an
|
||||
ext2 filesystem */
|
||||
|
||||
extern void type_ext2___super (char *command_line);
|
||||
extern void type_ext2___group (char *command_line);
|
||||
extern void type_ext2___cd (char *command_line);
|
||||
|
||||
|
||||
/* main.c */
|
||||
|
||||
extern int version_major,version_minor;
|
||||
extern char revision_date [80];
|
||||
extern char email_address [80];
|
||||
|
||||
#ifdef DEBUG
|
||||
extern void internal_error (char *description,char *source_name,char *function_name);
|
||||
#endif
|
||||
|
||||
void parser (void);
|
||||
extern int dispatch (char *command_line);
|
||||
char *parse_word (char *source,char *dest);
|
||||
char *complete_command (char *text,int state);
|
||||
char *dupstr (char *src);
|
||||
|
||||
|
||||
|
||||
/* disk.c */
|
||||
|
||||
extern int load_type_data (void);
|
||||
extern int write_type_data (void);
|
||||
extern int low_read (unsigned char *buffer,unsigned long length,unsigned long offset);
|
||||
extern int low_write (unsigned char *buffer,unsigned long length,unsigned long offset);
|
||||
extern int log_changes (unsigned char *buffer,unsigned long length,unsigned long offset);
|
||||
|
||||
/* file_com.c */
|
||||
|
||||
extern int init_file_info (void);
|
||||
extern void type_file___show (char *command_line);
|
||||
extern void type_file___inode (char *command_line);
|
||||
extern void type_file___display (char *command_line);
|
||||
extern void type_file___prev (char *command_line);
|
||||
extern void type_file___next (char *command_line);
|
||||
extern void type_file___offset (char *command_line);
|
||||
extern void type_file___prevblock (char *command_line);
|
||||
extern void type_file___nextblock (char *command_line);
|
||||
extern void type_file___block (char *command_line);
|
||||
extern void type_file___remember (char *command_line);
|
||||
extern void type_file___set (char *command_line);
|
||||
extern void type_file___writedata (char *command_line);
|
||||
|
||||
extern long file_block_to_global_block (long file_block,struct struct_file_info *file_info_ptr);
|
||||
extern long return_indirect (long table_block,long block_num);
|
||||
extern long return_dindirect (long table_block,long block_num);
|
||||
extern long return_tindirect (long table_block,long block_num);
|
||||
|
||||
void file_show_hex (void);
|
||||
void file_show_text (void);
|
||||
void show_status (void);
|
||||
|
||||
/* inode_com.c */
|
||||
|
||||
extern void type_ext2_inode___next (char *command_line);
|
||||
extern void type_ext2_inode___prev (char *command_line);
|
||||
extern void type_ext2_inode___show (char *command_line);
|
||||
extern void type_ext2_inode___group (char *command_line);
|
||||
extern void type_ext2_inode___entry (char *command_line);
|
||||
extern void type_ext2_inode___file (char *command_line);
|
||||
extern void type_ext2_inode___dir (char *command_line);
|
||||
|
||||
extern long inode_offset_to_group_num (long inode_offset);
|
||||
extern long int inode_offset_to_inode_num (long inode_offset);
|
||||
extern long int inode_num_to_inode_offset (long inode_num);
|
||||
|
||||
/* dir_com.c */
|
||||
|
||||
extern int init_dir_info (struct struct_file_info *info);
|
||||
extern void type_dir___show (char *command_line);
|
||||
extern void type_dir___inode (char *command_line);
|
||||
extern void type_dir___pgdn (char *command_line);
|
||||
extern void type_dir___pgup (char *command_line);
|
||||
extern void type_dir___prev (char *command_line);
|
||||
extern void type_dir___next (char *command_line);
|
||||
extern void type_dir___followinode (char *command_line);
|
||||
extern void type_dir___remember (char *command_line);
|
||||
extern void type_dir___cd (char *command_line);
|
||||
extern void type_dir___entry (char *command_line);
|
||||
extern void type_dir___writedata (char *command_line);
|
||||
extern void type_dir___set (char *command_line);
|
||||
|
||||
#define HEX 1
|
||||
#define TEXT 2
|
||||
|
||||
#define ABORT 0
|
||||
#define CONTINUE 1
|
||||
#define FOUND 2
|
||||
|
||||
struct struct_file_info search_dir_entries (int (*action) (struct struct_file_info *info),int *status);
|
||||
int action_count (struct struct_file_info *info);
|
||||
void show_dir_status (void);
|
||||
long count_dir_entries (void);
|
||||
int action_name (struct struct_file_info *info);
|
||||
int action_entry_num (struct struct_file_info *info);
|
||||
int action_show (struct struct_file_info *info);
|
||||
|
||||
/* super_com.c */
|
||||
|
||||
extern void type_ext2_super_block___show (char *command_line);
|
||||
extern void type_ext2_super_block___gocopy (char *command_line);
|
||||
extern void type_ext2_super_block___setactivecopy (char *command_line);
|
||||
|
||||
/* group_com.c */
|
||||
|
||||
extern void type_ext2_group_desc___next (char *command_line);
|
||||
extern void type_ext2_group_desc___prev (char *command_line);
|
||||
extern void type_ext2_group_desc___entry (char *command_line);
|
||||
extern void type_ext2_group_desc___show (char *command_line);
|
||||
extern void type_ext2_group_desc___inode (char *command_line);
|
||||
extern void type_ext2_group_desc___gocopy (char *command_line);
|
||||
extern void type_ext2_group_desc___blockbitmap (char *command_line);
|
||||
extern void type_ext2_group_desc___inodebitmap (char *command_line);
|
||||
extern void type_ext2_group_desc___setactivecopy (char *command_line);
|
||||
|
||||
/* blockbitmap_com.c */
|
||||
|
||||
extern void type_ext2_block_bitmap___show (char *command_line);
|
||||
extern void type_ext2_block_bitmap___entry (char *command_line);
|
||||
extern void type_ext2_block_bitmap___next (char *command_line);
|
||||
extern void type_ext2_block_bitmap___prev (char *command_line);
|
||||
extern void type_ext2_block_bitmap___allocate (char *command_line);
|
||||
extern void type_ext2_block_bitmap___deallocate (char *command_line);
|
||||
void allocate_block (long entry_num);
|
||||
void deallocate_block (long entry_num);
|
||||
|
||||
/* inodebitmap_bom.c */
|
||||
|
||||
extern void type_ext2_inode_bitmap___show (char *command_line);
|
||||
extern void type_ext2_inode_bitmap___entry (char *command_line);
|
||||
extern void type_ext2_inode_bitmap___next (char *command_line);
|
||||
extern void type_ext2_inode_bitmap___prev (char *command_line);
|
||||
extern void type_ext2_inode_bitmap___allocate (char *command_line);
|
||||
extern void type_ext2_inode_bitmap___deallocate (char *command_line);
|
||||
void allocate_inode (long entry_num);
|
||||
void deallocate_inode (long entry_num);
|
||||
|
||||
/* win.c */
|
||||
|
||||
extern WINDOW *title_win,*show_win,*command_win,*show_pad;
|
||||
|
||||
extern void init_windows (void);
|
||||
extern void refresh_title_win (void);
|
||||
extern void refresh_show_win (void);
|
||||
extern void refresh_show_pad (void);
|
||||
extern void refresh_command_win (void);
|
||||
extern void show_info (void);
|
||||
extern void redraw_all (void);
|
||||
extern void close_windows (void);
|
||||
|
||||
#endif /* EXT2ED_EDITOR_H */
|
|
@ -0,0 +1,564 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/file_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
----------------------------
|
||||
Commands which handle a file
|
||||
----------------------------
|
||||
|
||||
First written on: April 18 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
int init_file_info (void)
|
||||
|
||||
{
|
||||
struct ext2_inode *ptr;
|
||||
|
||||
ptr=&type_data.u.t_ext2_inode;
|
||||
|
||||
file_info.inode_ptr=ptr;
|
||||
file_info.inode_offset=device_offset;
|
||||
|
||||
file_info.global_block_num=ptr->i_block [0];
|
||||
file_info.global_block_offset=ptr->i_block [0]*file_system_info.block_size;
|
||||
file_info.block_num=0;
|
||||
file_info.blocks_count=(ptr->i_size+file_system_info.block_size-1)/file_system_info.block_size;
|
||||
file_info.file_offset=0;
|
||||
file_info.file_length=ptr->i_size;
|
||||
file_info.level=0;
|
||||
file_info.offset_in_block=0;
|
||||
|
||||
file_info.display=HEX;
|
||||
|
||||
low_read (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
void type_file___inode (char *command_line)
|
||||
|
||||
{
|
||||
dispatch ("settype ext2_inode");
|
||||
}
|
||||
|
||||
void type_file___show (char *command_line)
|
||||
|
||||
{
|
||||
if (file_info.display==HEX)
|
||||
file_show_hex ();
|
||||
if (file_info.display==TEXT)
|
||||
file_show_text ();
|
||||
}
|
||||
|
||||
void type_file___nextblock (char *command_line)
|
||||
|
||||
{
|
||||
long block_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
block_offset*=atol (buffer);
|
||||
}
|
||||
|
||||
if (file_info.block_num+block_offset >= file_info.blocks_count) {
|
||||
wprintw (command_win,"Error - Block offset out of range\n");wrefresh (command_win);
|
||||
return;
|
||||
}
|
||||
|
||||
file_info.block_num+=block_offset;
|
||||
file_info.global_block_num=file_block_to_global_block (file_info.block_num,&file_info);
|
||||
file_info.global_block_offset=file_info.global_block_num*file_system_info.block_size;
|
||||
file_info.file_offset=file_info.block_num*file_system_info.block_size;
|
||||
|
||||
low_read (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
|
||||
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_file___next (char *command_line)
|
||||
|
||||
{
|
||||
int offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
offset*=atol (buffer);
|
||||
}
|
||||
|
||||
if (file_info.offset_in_block+offset < file_system_info.block_size) {
|
||||
file_info.offset_in_block+=offset;
|
||||
sprintf (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Offset out of block\n");refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
void type_file___offset (char *command_line)
|
||||
|
||||
{
|
||||
unsigned long offset;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
offset=atol (buffer);
|
||||
}
|
||||
else {
|
||||
wprintw (command_win,"Error - Argument not specified\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset < file_system_info.block_size) {
|
||||
file_info.offset_in_block=offset;
|
||||
sprintf (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Offset out of block\n");refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
void type_file___prev (char *command_line)
|
||||
|
||||
{
|
||||
int offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
offset*=atol (buffer);
|
||||
}
|
||||
|
||||
if (file_info.offset_in_block-offset >= 0) {
|
||||
file_info.offset_in_block-=offset;
|
||||
sprintf (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Offset out of block\n");refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
void type_file___prevblock (char *command_line)
|
||||
|
||||
{
|
||||
long block_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
block_offset*=atol (buffer);
|
||||
}
|
||||
|
||||
if (file_info.block_num-block_offset < 0) {
|
||||
wprintw (command_win,"Error - Block offset out of range\n");wrefresh (command_win);
|
||||
return;
|
||||
}
|
||||
|
||||
file_info.block_num-=block_offset;
|
||||
file_info.global_block_num=file_block_to_global_block (file_info.block_num,&file_info);
|
||||
file_info.global_block_offset=file_info.global_block_num*file_system_info.block_size;
|
||||
file_info.file_offset=file_info.block_num*file_system_info.block_size;
|
||||
|
||||
low_read (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
|
||||
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_file___block (char *command_line)
|
||||
|
||||
{
|
||||
long block_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Invalid arguments\n");wrefresh (command_win);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (ptr,buffer);
|
||||
block_offset=atol (buffer);
|
||||
|
||||
if (block_offset < 0 || block_offset >= file_info.blocks_count) {
|
||||
wprintw (command_win,"Error - Block offset out of range\n");wrefresh (command_win);
|
||||
return;
|
||||
}
|
||||
|
||||
file_info.block_num=block_offset;
|
||||
file_info.global_block_num=file_block_to_global_block (file_info.block_num,&file_info);
|
||||
file_info.global_block_offset=file_info.global_block_num*file_system_info.block_size;
|
||||
file_info.file_offset=file_info.block_num*file_system_info.block_size;
|
||||
|
||||
low_read (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
|
||||
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_file___display (char *command_line)
|
||||
|
||||
{
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0)
|
||||
strcpy (buffer,"hex");
|
||||
else
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
if (strcasecmp (buffer,"hex")==0) {
|
||||
wprintw (command_win,"Display set to hex\n");wrefresh (command_win);
|
||||
file_info.display=HEX;
|
||||
sprintf (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else if (strcasecmp (buffer,"text")==0) {
|
||||
wprintw (command_win,"Display set to text\n");wrefresh (command_win);
|
||||
file_info.display=TEXT;
|
||||
sprintf (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Invalid arguments\n");wrefresh (command_win);
|
||||
}
|
||||
}
|
||||
|
||||
void file_show_hex (void)
|
||||
|
||||
{
|
||||
long offset=0,l,i;
|
||||
unsigned char *ch_ptr;
|
||||
|
||||
/* device_offset and type_data points to the inode */
|
||||
|
||||
show_pad_info.line=0;
|
||||
|
||||
wmove (show_pad,0,0);
|
||||
ch_ptr=file_info.buffer;
|
||||
for (l=0;l<file_system_info.block_size/16;l++) {
|
||||
if (file_info.file_offset+offset>file_info.file_length-1) break;
|
||||
wprintw (show_pad,"%08ld : ",offset);
|
||||
for (i=0;i<16;i++) {
|
||||
|
||||
if (file_info.file_offset+offset+i>file_info.file_length-1) {
|
||||
wprintw (show_pad," ");
|
||||
}
|
||||
|
||||
else {
|
||||
if (file_info.offset_in_block==offset+i)
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
|
||||
if (ch_ptr [i]>=' ' && ch_ptr [i]<='z')
|
||||
wprintw (show_pad,"%c",ch_ptr [i]);
|
||||
else
|
||||
wprintw (show_pad,".");
|
||||
|
||||
if (file_info.offset_in_block==offset+i)
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
wprintw (show_pad," ");
|
||||
for (i=0;i<16;i++) {
|
||||
if (file_info.file_offset+offset+i>file_info.file_length-1) break;
|
||||
if (file_info.offset_in_block==offset+i)
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
|
||||
wprintw (show_pad,"%02x",ch_ptr [i]);
|
||||
|
||||
if (file_info.offset_in_block==offset+i) {
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
show_pad_info.line=l-l % show_pad_info.display_lines;
|
||||
}
|
||||
|
||||
wprintw (show_pad," ");
|
||||
|
||||
}
|
||||
|
||||
wprintw (show_pad,"\n");
|
||||
offset+=i;
|
||||
ch_ptr+=i;
|
||||
}
|
||||
|
||||
show_pad_info.max_line=l-1;
|
||||
|
||||
refresh_show_pad ();
|
||||
|
||||
show_status ();
|
||||
}
|
||||
|
||||
void file_show_text (void)
|
||||
|
||||
{
|
||||
long offset=0,last_offset,l=0,cols=0;
|
||||
unsigned char *ch_ptr;
|
||||
|
||||
/* device_offset and type_data points to the inode */
|
||||
|
||||
show_pad_info.line=0;
|
||||
wmove (show_pad,0,0);
|
||||
ch_ptr=file_info.buffer;
|
||||
|
||||
last_offset=file_system_info.block_size-1;
|
||||
|
||||
if (file_info.file_offset+last_offset > file_info.file_length-1)
|
||||
last_offset=file_info.file_length-1-file_info.file_offset;
|
||||
|
||||
while ( (offset <= last_offset) && l<SHOW_PAD_LINES) {
|
||||
|
||||
if (cols==SHOW_PAD_COLS-1) {
|
||||
wprintw (show_pad,"\n");
|
||||
l++;cols=0;
|
||||
}
|
||||
|
||||
|
||||
if (file_info.offset_in_block==offset)
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
|
||||
if (*ch_ptr >= ' ' && *ch_ptr <= 'z')
|
||||
wprintw (show_pad,"%c",*ch_ptr);
|
||||
|
||||
|
||||
else {
|
||||
if (*ch_ptr == 0xa) {
|
||||
wprintw (show_pad,"\n");
|
||||
l++;cols=0;
|
||||
}
|
||||
|
||||
else if (*ch_ptr == 0x9)
|
||||
wprintw (show_pad," ");
|
||||
|
||||
else
|
||||
wprintw (show_pad,".");
|
||||
}
|
||||
|
||||
if (file_info.offset_in_block==offset) {
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
show_pad_info.line=l-l % show_pad_info.display_lines;
|
||||
}
|
||||
|
||||
|
||||
offset++;cols++;ch_ptr++;
|
||||
}
|
||||
|
||||
wprintw (show_pad,"\n");
|
||||
show_pad_info.max_line=l;
|
||||
|
||||
refresh_show_pad ();
|
||||
|
||||
show_status ();
|
||||
}
|
||||
|
||||
void show_status (void)
|
||||
|
||||
{
|
||||
long inode_num;
|
||||
|
||||
werase (show_win);wmove (show_win,0,0);
|
||||
wprintw (show_win,"File contents. Block %ld. ",file_info.global_block_num);
|
||||
wprintw (show_win,"File block %ld of %ld. ",file_info.block_num,file_info.blocks_count-1);
|
||||
wprintw (show_win,"File Offset %ld of %ld.",file_info.file_offset,file_info.file_length-1);
|
||||
|
||||
wmove (show_win,1,0);
|
||||
inode_num=inode_offset_to_inode_num (file_info.inode_offset);
|
||||
wprintw (show_win,"File inode %ld. Indirection level %ld.",inode_num,file_info.level);
|
||||
|
||||
refresh_show_win ();
|
||||
}
|
||||
|
||||
void type_file___remember (char *command_line)
|
||||
|
||||
{
|
||||
int found=0;
|
||||
long entry_num;
|
||||
char *ptr,buffer [80];
|
||||
struct struct_descriptor *descriptor_ptr;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Argument not specified\n");wrefresh (command_win);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
entry_num=remember_lifo.entries_count++;
|
||||
if (entry_num>REMEMBER_COUNT-1) {
|
||||
entry_num=0;
|
||||
remember_lifo.entries_count--;
|
||||
}
|
||||
|
||||
descriptor_ptr=first_type;
|
||||
while (descriptor_ptr!=NULL && !found) {
|
||||
if (strcmp (descriptor_ptr->name,"ext2_inode")==0)
|
||||
found=1;
|
||||
else
|
||||
descriptor_ptr=descriptor_ptr->next;
|
||||
}
|
||||
|
||||
|
||||
remember_lifo.offset [entry_num]=device_offset;
|
||||
remember_lifo.type [entry_num]=descriptor_ptr;
|
||||
strcpy (remember_lifo.name [entry_num],buffer);
|
||||
|
||||
wprintw (command_win,"Object %s in Offset %ld remembered as %s\n",descriptor_ptr->name,device_offset,buffer);
|
||||
wrefresh (command_win);
|
||||
}
|
||||
|
||||
void type_file___set (char *command_line)
|
||||
|
||||
{
|
||||
unsigned char tmp;
|
||||
char *ptr,buffer [80],*ch_ptr;
|
||||
int mode=HEX;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Argument not specified\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
if (strcasecmp (buffer,"text")==0) {
|
||||
mode=TEXT;
|
||||
strcpy (buffer,ptr);
|
||||
}
|
||||
|
||||
else if (strcasecmp (buffer,"hex")==0) {
|
||||
mode=HEX;
|
||||
ptr=parse_word (ptr,buffer);
|
||||
}
|
||||
|
||||
if (*buffer==0) {
|
||||
wprintw (command_win,"Error - Data not specified\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
if (mode==HEX) {
|
||||
do {
|
||||
tmp=(unsigned char) strtol (buffer,NULL,16);
|
||||
file_info.buffer [file_info.offset_in_block]=tmp;
|
||||
file_info.offset_in_block++;
|
||||
ptr=parse_word (ptr,buffer);
|
||||
if (file_info.offset_in_block==file_system_info.block_size) {
|
||||
if (*ptr) {
|
||||
wprintw (command_win,"Error - Ending offset outside block, only partial string changed\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
file_info.offset_in_block--;
|
||||
}
|
||||
} while (*buffer) ;
|
||||
}
|
||||
|
||||
else {
|
||||
ch_ptr=buffer;
|
||||
while (*ch_ptr) {
|
||||
tmp=(unsigned char) *ch_ptr++;
|
||||
file_info.buffer [file_info.offset_in_block]=tmp;
|
||||
file_info.offset_in_block++;
|
||||
if (file_info.offset_in_block==file_system_info.block_size) {
|
||||
if (*ch_ptr) {
|
||||
wprintw (command_win,"Error - Ending offset outside block, only partial string changed\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
file_info.offset_in_block--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_file___writedata (char *command_line)
|
||||
|
||||
{
|
||||
low_write (file_info.buffer,file_system_info.block_size,file_info.global_block_offset);
|
||||
return;
|
||||
}
|
||||
|
||||
long file_block_to_global_block (long file_block,struct struct_file_info *file_info_ptr)
|
||||
|
||||
{
|
||||
long last_direct,last_indirect,last_dindirect;
|
||||
|
||||
last_direct=EXT2_NDIR_BLOCKS-1;
|
||||
last_indirect=last_direct+file_system_info.block_size/4;
|
||||
last_dindirect=last_indirect+(file_system_info.block_size/4)*(file_system_info.block_size/4);
|
||||
|
||||
if (file_block <= last_direct) {
|
||||
file_info_ptr->level=0;
|
||||
return (file_info_ptr->inode_ptr->i_block [file_block]);
|
||||
}
|
||||
|
||||
if (file_block <= last_indirect) {
|
||||
file_info_ptr->level=1;
|
||||
file_block=file_block-last_direct-1;
|
||||
return (return_indirect (file_info_ptr->inode_ptr->i_block [EXT2_IND_BLOCK],file_block));
|
||||
}
|
||||
|
||||
if (file_block <= last_dindirect) {
|
||||
file_info_ptr->level=2;
|
||||
file_block=file_block-last_indirect-1;
|
||||
return (return_dindirect (file_info_ptr->inode_ptr->i_block [EXT2_DIND_BLOCK],file_block));
|
||||
}
|
||||
|
||||
file_info_ptr->level=3;
|
||||
file_block=file_block-last_dindirect-1;
|
||||
return (return_tindirect (file_info_ptr->inode_ptr->i_block [EXT2_TIND_BLOCK],file_block));
|
||||
}
|
||||
|
||||
long return_indirect (long table_block,long block_num)
|
||||
|
||||
{
|
||||
long block_table [EXT2_MAX_BLOCK_SIZE/4];
|
||||
|
||||
low_read ((char *) block_table,file_system_info.block_size,table_block*file_system_info.block_size);
|
||||
return (block_table [block_num]);
|
||||
}
|
||||
|
||||
long return_dindirect (long table_block,long block_num)
|
||||
|
||||
{
|
||||
long f_indirect;
|
||||
|
||||
f_indirect=block_num/(file_system_info.block_size/4);
|
||||
f_indirect=return_indirect (table_block,f_indirect);
|
||||
return (return_indirect (f_indirect,block_num%(file_system_info.block_size/4)));
|
||||
}
|
||||
|
||||
long return_tindirect (long table_block,long block_num)
|
||||
|
||||
{
|
||||
long s_indirect;
|
||||
|
||||
s_indirect=block_num/((file_system_info.block_size/4)*(file_system_info.block_size/4));
|
||||
s_indirect=return_indirect (table_block,s_indirect);
|
||||
return (return_dindirect (s_indirect,block_num%((file_system_info.block_size/4)*(file_system_info.block_size/4))));
|
||||
}
|
|
@ -0,0 +1,748 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/general_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
---------------------
|
||||
General user commands
|
||||
---------------------
|
||||
|
||||
First written on: April 9 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
void help (char *command_line)
|
||||
|
||||
{
|
||||
int i,max_line=0;
|
||||
char argument [80],*ptr;
|
||||
|
||||
werase (show_pad);wmove (show_pad,0,0);
|
||||
|
||||
ptr=parse_word (command_line,argument);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,argument);
|
||||
if (*argument!=0) {
|
||||
detailed_help (argument);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_type!=NULL) {
|
||||
|
||||
wprintw (show_pad,"Type %s specific commands:\n",current_type->name);max_line++;
|
||||
|
||||
if (current_type->type_commands.last_command==-1) {
|
||||
wprintw (show_pad,"\nnone\n");max_line+=2;
|
||||
}
|
||||
else
|
||||
for (i=0;i<=current_type->type_commands.last_command;i++) {
|
||||
if (i%5==0) {
|
||||
wprintw (show_pad,"\n");max_line++;
|
||||
}
|
||||
wprintw (show_pad,"%-13s",current_type->type_commands.names [i]);
|
||||
if (i%5!=4)
|
||||
wprintw (show_pad,"; ");
|
||||
}
|
||||
|
||||
wprintw (show_pad,"\n\n");max_line+=2;
|
||||
}
|
||||
|
||||
if (ext2_commands.last_command != -1) {
|
||||
wprintw (show_pad,"ext2 filesystem general commands: \n");max_line++;
|
||||
for (i=0;i<=ext2_commands.last_command;i++) {
|
||||
if (i%5==0) {
|
||||
wprintw (show_pad,"\n");max_line++;
|
||||
}
|
||||
wprintw (show_pad,"%-13s",ext2_commands.names [i]);
|
||||
if (i%5!=4)
|
||||
wprintw (show_pad,"; ");
|
||||
|
||||
}
|
||||
wprintw (show_pad,"\n\n");max_line+=2;
|
||||
}
|
||||
|
||||
wprintw (show_pad,"General commands: \n");
|
||||
|
||||
for (i=0;i<=general_commands.last_command;i++) {
|
||||
if (i%5==0) {
|
||||
wprintw (show_pad,"\n");max_line++;
|
||||
}
|
||||
wprintw (show_pad,"%-13s",general_commands.names [i]);
|
||||
if (i%5!=4)
|
||||
wprintw (show_pad,"; ");
|
||||
}
|
||||
|
||||
wprintw (show_pad,"\n\n");max_line+=2;
|
||||
|
||||
wprintw (show_pad,"EXT2ED ver %d.%d (%s)\n",version_major,version_minor,revision_date);
|
||||
wprintw (show_pad,"Copyright (C) 1995 Gadi Oxman\n");
|
||||
wprintw (show_pad,"EXT2ED is hereby placed under the terms of the GNU General Public License.\n\n");
|
||||
wprintw (show_pad,"EXT2ED was programmed as a student project in the software laboratory\n");
|
||||
wprintw (show_pad,"of the faculty of electrical engineering in the\n");
|
||||
wprintw (show_pad,"Technion - Israel Institute of Technology\n");
|
||||
wprintw (show_pad,"with the guide of Avner Lottem and Dr. Ilana David.\n");
|
||||
|
||||
max_line+=6;
|
||||
|
||||
wprintw (show_pad,"\n\n");max_line+=2;
|
||||
|
||||
wprintw (show_pad,"Please feel free to mail me at (currently) %s\n",email_address);
|
||||
wprintw (show_pad,"with any commet, suggestion, and of-course, bug report concerning EXT2ED.\n");
|
||||
|
||||
max_line+=2;
|
||||
|
||||
show_pad_info.line=0;show_pad_info.max_line=max_line;
|
||||
|
||||
werase (show_win);wmove (show_win,0,0);
|
||||
wprintw (show_win,"EXT2ED help");
|
||||
|
||||
refresh_show_win ();
|
||||
refresh_show_pad ();
|
||||
}
|
||||
|
||||
void detailed_help (char *text)
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
if (current_type != NULL)
|
||||
for (i=0;i<=current_type->type_commands.last_command;i++) {
|
||||
if (strcmp (current_type->type_commands.names [i],text)==0) {
|
||||
wprintw (show_pad,"%s - %s\n",text,current_type->type_commands.descriptions [i]);
|
||||
refresh_show_pad ();return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0;i<=ext2_commands.last_command;i++) {
|
||||
if (strcmp (ext2_commands.names [i],text)==0) {
|
||||
wprintw (show_pad,"%s - %s\n",text,ext2_commands.descriptions [i]);
|
||||
refresh_show_pad ();return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0;i<=general_commands.last_command;i++) {
|
||||
if (strcmp (general_commands.names [i],text)==0) {
|
||||
wprintw (show_pad,"%s - %s\n",text,general_commands.descriptions [i]);
|
||||
refresh_show_pad ();return;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp ("quit",text)==0) {
|
||||
wprintw (show_pad,"quit - Exists EXT2ED");
|
||||
refresh_show_pad ();return;
|
||||
}
|
||||
|
||||
wprintw (show_pad,"Error - Command %s not aviable now\n",text);
|
||||
refresh_show_pad ();return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void set_device (char *command_line)
|
||||
|
||||
{
|
||||
char *ptr,new_device [80];
|
||||
|
||||
ptr=parse_word (command_line,new_device);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Device name not specified\n");
|
||||
refresh_command_win ();return;
|
||||
}
|
||||
parse_word (ptr,new_device);
|
||||
check_mounted (new_device);
|
||||
if (mounted && !AllowMountedRead) {
|
||||
wprintw (command_win,"Error - Filesystem is mounted, aborting\n");
|
||||
wprintw (command_win,"You may wish to use the AllowMountedRead on configuration option\n");
|
||||
refresh_command_win ();return;
|
||||
}
|
||||
|
||||
if (mounted && AllowMountedRead) {
|
||||
wprintw (command_win,"Warning - Filesystem is mounted. Displayed data may be unreliable.\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
|
||||
if (device_handle!=NULL)
|
||||
fclose (device_handle);
|
||||
|
||||
if ( (device_handle=fopen (new_device,"rb"))==NULL) {
|
||||
wprintw (command_win,"Error - Can not open device %s\n",new_device);refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
strcpy (device_name,new_device);
|
||||
write_access=0; /* Write access disabled */
|
||||
current_type=NULL; /* There is no type now */
|
||||
remember_lifo.entries_count=0; /* Empty Object memory */
|
||||
free_user_commands (&ext2_commands); /* Free filesystem specific objects */
|
||||
free_struct_descriptors ();
|
||||
if (!set_file_system_info ()) { /* Error while getting info --> abort */
|
||||
free_user_commands (&ext2_commands);
|
||||
free_struct_descriptors ();
|
||||
fclose (device_handle);
|
||||
device_handle=NULL; /* Notice that our device is still not set up */
|
||||
device_offset=-1;
|
||||
return;
|
||||
}
|
||||
if (*AlternateDescriptors) /* Check if user defined objects exist */
|
||||
set_struct_descriptors (AlternateDescriptors);
|
||||
dispatch ("setoffset 0");
|
||||
dispatch ("help"); /* Show help screen */
|
||||
wprintw (command_win,"Device changed to %s",device_name);refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
void set_offset (char *command_line)
|
||||
|
||||
{
|
||||
long mult=1;
|
||||
long new_offset;
|
||||
char *ptr,new_offset_buffer [80];
|
||||
|
||||
if (device_handle==NULL) {
|
||||
wprintw (command_win,"Error - No device opened\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (command_line,new_offset_buffer);
|
||||
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - No argument specified\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (ptr,new_offset_buffer);
|
||||
|
||||
if (strcmp (new_offset_buffer,"block")==0) {
|
||||
mult=file_system_info.block_size;
|
||||
ptr=parse_word (ptr,new_offset_buffer);
|
||||
}
|
||||
|
||||
if (strcmp (new_offset_buffer,"type")==0) {
|
||||
if (current_type==NULL) {
|
||||
wprintw (command_win,"Error - No type set\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
mult=current_type->length;
|
||||
ptr=parse_word (ptr,new_offset_buffer);
|
||||
}
|
||||
|
||||
if (*new_offset_buffer==0) {
|
||||
wprintw (command_win,"Error - No offset specified\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_offset_buffer [0]=='+') {
|
||||
if (device_offset==-1) {
|
||||
wprintw (command_win,"Error - Select a fixed offset first\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
new_offset=device_offset+atol (new_offset_buffer+1)*mult;
|
||||
}
|
||||
|
||||
else if (new_offset_buffer [0]=='-') {
|
||||
if (device_offset==-1) {
|
||||
wprintw (command_win,"Error - Select a fixed offset first\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
new_offset=device_offset-atol (new_offset_buffer+1)*mult;
|
||||
if (new_offset<0) new_offset=0;
|
||||
}
|
||||
|
||||
else
|
||||
new_offset=atol (new_offset_buffer)*mult;
|
||||
|
||||
if ( (fseek (device_handle,new_offset,SEEK_SET))==-1) {
|
||||
wprintw (command_win,"Error - Failed to seek to offset %ld in device %s\n",new_offset,device_name);
|
||||
refresh_command_win ();
|
||||
return;
|
||||
};
|
||||
device_offset=new_offset;
|
||||
wprintw (command_win,"Device offset changed to %ld\n",device_offset);refresh_command_win ();
|
||||
load_type_data ();
|
||||
type_data.offset_in_block=0;
|
||||
}
|
||||
|
||||
void set (char *command_line)
|
||||
|
||||
{
|
||||
unsigned short *int_ptr;
|
||||
unsigned char *char_ptr;
|
||||
unsigned long *long_ptr,offset=0;
|
||||
int i,found=0;
|
||||
char *ptr,buffer [80],variable [80],value [80];
|
||||
|
||||
if (device_handle==NULL) {
|
||||
wprintw (command_win,"Error - No device opened\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_type==NULL) {
|
||||
hex_set (command_line);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (ptr==NULL || *ptr==0) {
|
||||
wprintw (command_win,"Error - Missing arguments\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
parse_word (ptr,buffer);
|
||||
ptr=strchr (buffer,'=');
|
||||
if (ptr==NULL) {
|
||||
wprintw (command_win,"Error - Bad syntax\n");refresh_command_win ();return;
|
||||
}
|
||||
strncpy (variable,buffer,ptr-buffer);variable [ptr-buffer]=0;
|
||||
strcpy (value,++ptr);
|
||||
|
||||
if (current_type==NULL) {
|
||||
wprintw (command_win,"Sorry, not yet supported\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
for (i=0;i<current_type->fields_num && !found;i++) {
|
||||
if (strcmp (current_type->field_names [i],variable)==0) {
|
||||
found=1;
|
||||
ptr=type_data.u.buffer+offset;
|
||||
switch (current_type->field_lengths [i]) {
|
||||
case 1:
|
||||
char_ptr=(unsigned char *) ptr;
|
||||
*char_ptr=(char) atoi (value);
|
||||
wprintw (command_win,"Variable %s set to %u\n",variable,*char_ptr);refresh_command_win ();
|
||||
break;
|
||||
case 2:
|
||||
int_ptr=(unsigned short *) ptr;
|
||||
*int_ptr=atoi (value);
|
||||
wprintw (command_win,"Variable %s set to %u\n",variable,*int_ptr);refresh_command_win ();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
long_ptr=(unsigned long *) ptr;
|
||||
*long_ptr=atol (value);
|
||||
wprintw (command_win,"Variable %s set to %lu\n",variable,*long_ptr);refresh_command_win ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset+=current_type->field_lengths [i];
|
||||
}
|
||||
if (found)
|
||||
dispatch ("show");
|
||||
else {
|
||||
wprintw (command_win,"Error - Variable %s not found\n",variable);
|
||||
refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
void hex_set (char *command_line)
|
||||
|
||||
{
|
||||
unsigned char tmp;
|
||||
char *ptr,buffer [80],*ch_ptr;
|
||||
int mode=HEX;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Argument not specified\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
if (strcasecmp (buffer,"text")==0) {
|
||||
mode=TEXT;
|
||||
strcpy (buffer,ptr);
|
||||
}
|
||||
|
||||
else if (strcasecmp (buffer,"hex")==0) {
|
||||
mode=HEX;
|
||||
ptr=parse_word (ptr,buffer);
|
||||
}
|
||||
|
||||
if (*buffer==0) {
|
||||
wprintw (command_win,"Error - Data not specified\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
if (mode==HEX) {
|
||||
do {
|
||||
tmp=(unsigned char) strtol (buffer,NULL,16);
|
||||
type_data.u.buffer [type_data.offset_in_block]=tmp;
|
||||
type_data.offset_in_block++;
|
||||
ptr=parse_word (ptr,buffer);
|
||||
if (type_data.offset_in_block==file_system_info.block_size) {
|
||||
if (*ptr) {
|
||||
wprintw (command_win,"Error - Ending offset outside block, only partial string changed\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
type_data.offset_in_block--;
|
||||
}
|
||||
} while (*buffer) ;
|
||||
}
|
||||
|
||||
else {
|
||||
ch_ptr=buffer;
|
||||
while (*ch_ptr) {
|
||||
tmp=(unsigned char) *ch_ptr++;
|
||||
type_data.u.buffer [type_data.offset_in_block]=tmp;
|
||||
type_data.offset_in_block++;
|
||||
if (type_data.offset_in_block==file_system_info.block_size) {
|
||||
if (*ch_ptr) {
|
||||
wprintw (command_win,"Error - Ending offset outside block, only partial string changed\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
type_data.offset_in_block--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void set_type (char *command_line)
|
||||
|
||||
{
|
||||
struct struct_descriptor *descriptor_ptr;
|
||||
char *ptr,buffer [80],tmp_buffer [80];
|
||||
short found=0;
|
||||
|
||||
if (!load_type_data ())
|
||||
return;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
parse_word (ptr,buffer);
|
||||
|
||||
if (strcmp (buffer,"none")==0 || strcmp (buffer,"hex")==0) {
|
||||
wprintw (command_win,"Data will be shown as hex dump\n");refresh_command_win ();
|
||||
current_type=NULL;
|
||||
sprintf (tmp_buffer,"show");dispatch (tmp_buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
descriptor_ptr=first_type;
|
||||
while (descriptor_ptr!=NULL && !found) {
|
||||
if (strcmp (descriptor_ptr->name,buffer)==0)
|
||||
found=1;
|
||||
else
|
||||
descriptor_ptr=descriptor_ptr->next;
|
||||
}
|
||||
if (found) {
|
||||
wprintw (command_win,"Structure type set to %s\n",buffer);refresh_command_win ();
|
||||
current_type=descriptor_ptr;
|
||||
sprintf (tmp_buffer,"show");dispatch (tmp_buffer);
|
||||
}
|
||||
else {
|
||||
wprintw (command_win,"Error - %s is not a valid type\n",buffer);refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void show (char *command_line)
|
||||
|
||||
{
|
||||
unsigned int i,l,temp_int;
|
||||
unsigned long offset=0,temp_long;
|
||||
unsigned char temp_char,*ch_ptr;
|
||||
void *ptr;
|
||||
|
||||
if (device_handle==NULL)
|
||||
return;
|
||||
|
||||
show_pad_info.line=0;
|
||||
|
||||
if (current_type==NULL) {
|
||||
wmove (show_pad,0,0);
|
||||
ch_ptr=type_data.u.buffer;
|
||||
for (l=0;l<file_system_info.block_size/16;l++) {
|
||||
wprintw (show_pad,"%08ld : ",offset);
|
||||
for (i=0;i<16;i++) {
|
||||
if (type_data.offset_in_block==offset+i)
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
|
||||
if (ch_ptr [i]>=' ' && ch_ptr [i]<='z')
|
||||
wprintw (show_pad,"%c",ch_ptr [i]);
|
||||
else
|
||||
wprintw (show_pad,".");
|
||||
if (type_data.offset_in_block==offset+i)
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
}
|
||||
wprintw (show_pad," ");
|
||||
for (i=0;i<16;i++) {
|
||||
if (type_data.offset_in_block==offset+i)
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
|
||||
wprintw (show_pad,"%02x",ch_ptr [i]);
|
||||
|
||||
if (type_data.offset_in_block==offset+i) {
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
show_pad_info.line=l-l % show_pad_info.display_lines;
|
||||
}
|
||||
|
||||
wprintw (show_pad," ");
|
||||
}
|
||||
wprintw (show_pad,"\n");
|
||||
offset+=16;
|
||||
ch_ptr+=16;
|
||||
}
|
||||
show_pad_info.max_line=l-1;show_pad_info.max_col=COLS-1;
|
||||
refresh_show_pad ();show_info ();
|
||||
}
|
||||
else {
|
||||
wmove (show_pad,0,0);l=0;
|
||||
for (i=0;i<current_type->fields_num;i++) {
|
||||
wprintw (show_pad,"%-20s = ",current_type->field_names [i]);
|
||||
ptr=type_data.u.buffer+offset;
|
||||
switch (current_type->field_lengths [i]) {
|
||||
case 1:
|
||||
temp_char=*((unsigned char *) ptr);
|
||||
wprintw (show_pad,"%3u (0x%02x",temp_char,temp_char);
|
||||
if (temp_char>=' ' && temp_char<='z')
|
||||
wprintw (show_pad," , %c)\n",temp_char);
|
||||
else
|
||||
wprintw (show_pad,")\n");
|
||||
|
||||
offset ++;l++;
|
||||
break;
|
||||
case 2:
|
||||
temp_int=*((unsigned short *) ptr);
|
||||
wprintw (show_pad,"%u (0x%x)\n",temp_int,temp_int);
|
||||
offset +=2;l++;
|
||||
break;
|
||||
case 4:
|
||||
temp_long=*((unsigned long *) ptr);
|
||||
wprintw (show_pad,"%lu\n",temp_long);
|
||||
offset +=4;l++;
|
||||
break;
|
||||
}
|
||||
/* offset+=current_type->field_lengths [i]; */
|
||||
}
|
||||
current_type->length=offset;
|
||||
show_pad_info.max_line=l-1;
|
||||
refresh_show_pad ();show_info ();
|
||||
}
|
||||
}
|
||||
|
||||
void next (char *command_line)
|
||||
|
||||
{
|
||||
long offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
offset*=atol (buffer);
|
||||
}
|
||||
|
||||
if (current_type!=NULL) {
|
||||
sprintf (buffer,"setoffset type +%ld",offset);
|
||||
dispatch (buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type_data.offset_in_block+offset < file_system_info.block_size) {
|
||||
type_data.offset_in_block+=offset;
|
||||
sprintf (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Offset out of block\n");refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
void prev (char *command_line)
|
||||
|
||||
{
|
||||
long offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
offset*=atol (buffer);
|
||||
}
|
||||
|
||||
if (current_type!=NULL) {
|
||||
sprintf (buffer,"setoffset type -%ld",offset);
|
||||
dispatch (buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type_data.offset_in_block-offset >= 0) {
|
||||
type_data.offset_in_block-=offset;
|
||||
sprintf (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Offset out of block\n");refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
void pgdn (char *commnad_line)
|
||||
|
||||
{
|
||||
show_pad_info.line+=show_pad_info.display_lines;
|
||||
refresh_show_pad ();refresh_show_win ();
|
||||
}
|
||||
|
||||
void pgup (char *command_line)
|
||||
|
||||
{
|
||||
show_pad_info.line-=show_pad_info.display_lines;
|
||||
refresh_show_pad ();refresh_show_win ();
|
||||
}
|
||||
|
||||
void redraw (char *command_line)
|
||||
|
||||
{
|
||||
redraw_all ();
|
||||
dispatch ("show");
|
||||
}
|
||||
|
||||
void remember (char *command_line)
|
||||
|
||||
{
|
||||
long entry_num;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
if (device_handle==NULL) {
|
||||
wprintw (command_win,"Error - No device opened\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Argument not specified\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
entry_num=remember_lifo.entries_count++;
|
||||
if (entry_num>REMEMBER_COUNT-1) {
|
||||
entry_num=0;
|
||||
remember_lifo.entries_count--;
|
||||
}
|
||||
|
||||
remember_lifo.offset [entry_num]=device_offset;
|
||||
remember_lifo.type [entry_num]=current_type;
|
||||
strcpy (remember_lifo.name [entry_num],buffer);
|
||||
|
||||
if (current_type!=NULL)
|
||||
wprintw (command_win,"Object %s in Offset %ld remembered as %s\n",current_type->name,device_offset,buffer);
|
||||
else
|
||||
wprintw (command_win,"Offset %ld remembered as %s\n",device_offset,buffer);
|
||||
|
||||
refresh_command_win ();
|
||||
}
|
||||
|
||||
void recall (char *command_line)
|
||||
|
||||
{
|
||||
char *ptr,buffer [80];
|
||||
long entry_num;
|
||||
|
||||
if (device_handle==NULL) {
|
||||
wprintw (command_win,"Error - No device opened\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - Argument not specified\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
|
||||
for (entry_num=remember_lifo.entries_count-1;entry_num>=0;entry_num--) {
|
||||
if (strcmp (remember_lifo.name [entry_num],buffer)==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry_num==-1) {
|
||||
wprintw (command_win,"Error - Can not recall %s\n",buffer);refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf (buffer,"setoffset %ld",remember_lifo.offset [entry_num]);dispatch (buffer);
|
||||
if (remember_lifo.type [entry_num] != NULL) {
|
||||
sprintf (buffer,"settype %s",remember_lifo.type [entry_num]->name);dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
sprintf (buffer,"settype none");dispatch (buffer);
|
||||
}
|
||||
|
||||
wprintw (command_win,"Object %s in Offset %ld recalled\n",current_type->name,device_offset);
|
||||
refresh_command_win ();
|
||||
}
|
||||
|
||||
void enable_write (char *command_line)
|
||||
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (device_handle==NULL) {
|
||||
wprintw (command_win,"Error - No device opened\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AllowChanges) {
|
||||
wprintw (command_win,"Sorry, write access is not allowed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
wprintw (command_win,"Error - Filesystem is mounted\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (fp=fopen (device_name,"r+b"))==NULL) {
|
||||
wprintw (command_win,"Error - Can not open device %s for reading and writing\n",device_name);refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
fclose (device_handle);
|
||||
device_handle=fp;write_access=1;
|
||||
wprintw (command_win,"Write access enabled - Be careful\n");refresh_command_win ();
|
||||
}
|
||||
|
||||
void disable_write (char *command_line)
|
||||
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if (device_handle==NULL) {
|
||||
wprintw (command_win,"Error - No device opened\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (fp=fopen (device_name,"rb"))==NULL) {
|
||||
wprintw (command_win,"Error - Can not open device %s\n",device_name);refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
fclose (device_handle);
|
||||
device_handle=fp;write_access=0;
|
||||
wprintw (command_win,"Write access disabled\n");refresh_command_win ();
|
||||
}
|
||||
|
||||
void write_data (char *command_line)
|
||||
|
||||
{
|
||||
write_type_data ();
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/group_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
General user commands
|
||||
|
||||
First written on: April 17 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
void type_ext2_group_desc___next (char *command_line)
|
||||
|
||||
{
|
||||
long entry_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
entry_offset=atol (buffer);
|
||||
}
|
||||
|
||||
sprintf (buffer,"entry %ld",group_info.group_num+entry_offset);
|
||||
dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_group_desc___prev (char *command_line)
|
||||
|
||||
{
|
||||
long entry_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
entry_offset=atol (buffer);
|
||||
}
|
||||
|
||||
sprintf (buffer,"entry %ld",group_info.group_num-entry_offset);
|
||||
dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_group_desc___entry (char *command_line)
|
||||
|
||||
{
|
||||
long group_num;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - No argument specified\n");refresh_command_win ();return;
|
||||
}
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
group_num=atol (buffer);
|
||||
|
||||
if (group_num < 0 || group_num >= file_system_info.groups_count) {
|
||||
wprintw (command_win,"Error - Entry number out of bounds\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
device_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
|
||||
|
||||
sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
group_info.group_num=group_num;
|
||||
}
|
||||
|
||||
|
||||
void type_ext2_group_desc___gocopy (char *command_line)
|
||||
|
||||
{
|
||||
unsigned long copy_num,offset;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - No argument specified\n");refresh_command_win ();return;
|
||||
}
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
copy_num=atol (buffer);
|
||||
|
||||
offset=file_system_info.first_group_desc_offset+copy_num*file_system_info.super_block.s_blocks_per_group*file_system_info.block_size;
|
||||
|
||||
if (offset > file_system_info.file_system_size) {
|
||||
wprintw (command_win,"Error - Copy number out of bounds\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
group_info.copy_num=copy_num;
|
||||
device_offset=offset+group_info.group_num*sizeof (struct ext2_group_desc);
|
||||
|
||||
sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
|
||||
void type_ext2_group_desc___show (char *command_line)
|
||||
|
||||
{
|
||||
long group_num,temp;
|
||||
|
||||
temp=(device_offset-file_system_info.first_group_desc_offset) % (file_system_info.super_block.s_blocks_per_group*file_system_info.block_size);
|
||||
group_num=temp/sizeof (struct ext2_group_desc);
|
||||
|
||||
show (command_line);
|
||||
|
||||
wmove (show_win,1,0);wprintw (show_win,"\n");wmove (show_win,2,0);
|
||||
wprintw (show_win,"Group %ld of %ld ",group_num,file_system_info.groups_count-1);
|
||||
wprintw (show_win,"in copy %ld ",group_info.copy_num);
|
||||
if (group_info.copy_num==0) wprintw (show_win,"(Main copy)");
|
||||
wprintw (show_win,"\n");refresh_show_win ();
|
||||
|
||||
if (group_num==0) {
|
||||
wprintw (command_win,"Reached first group descriptor\n");
|
||||
wrefresh (command_win);
|
||||
}
|
||||
|
||||
if (group_num==file_system_info.groups_count-1) {
|
||||
wprintw (command_win,"Reached last group descriptor\n");
|
||||
wrefresh (command_win);
|
||||
}
|
||||
}
|
||||
|
||||
void type_ext2_group_desc___inode (char *command_line)
|
||||
|
||||
{
|
||||
long inode_offset;
|
||||
char buffer [80];
|
||||
|
||||
inode_offset=type_data.u.t_ext2_group_desc.bg_inode_table;
|
||||
sprintf (buffer,"setoffset block %ld",inode_offset);dispatch (buffer);
|
||||
sprintf (buffer,"settype ext2_inode");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_group_desc___blockbitmap (char *command_line)
|
||||
|
||||
{
|
||||
long block_bitmap_offset;
|
||||
char buffer [80];
|
||||
|
||||
block_bitmap_info.entry_num=0;
|
||||
block_bitmap_info.group_num=group_info.group_num;
|
||||
|
||||
block_bitmap_offset=type_data.u.t_ext2_group_desc.bg_block_bitmap;
|
||||
sprintf (buffer,"setoffset block %ld",block_bitmap_offset);dispatch (buffer);
|
||||
sprintf (buffer,"settype block_bitmap");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_group_desc___inodebitmap (char *command_line)
|
||||
|
||||
{
|
||||
long inode_bitmap_offset;
|
||||
char buffer [80];
|
||||
|
||||
inode_bitmap_info.entry_num=0;
|
||||
inode_bitmap_info.group_num=group_info.group_num;
|
||||
|
||||
inode_bitmap_offset=type_data.u.t_ext2_group_desc.bg_inode_bitmap;
|
||||
sprintf (buffer,"setoffset block %ld",inode_bitmap_offset);dispatch (buffer);
|
||||
sprintf (buffer,"settype inode_bitmap");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_group_desc___setactivecopy (char *command_line)
|
||||
|
||||
{
|
||||
struct ext2_group_desc gd;
|
||||
|
||||
gd=type_data.u.t_ext2_group_desc;
|
||||
dispatch ("gocopy 0");
|
||||
type_data.u.t_ext2_group_desc=gd;
|
||||
dispatch ("show");
|
||||
}
|
|
@ -0,0 +1,607 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/init.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
--------------------------------
|
||||
Various initialization routines.
|
||||
--------------------------------
|
||||
|
||||
First written on: April 9 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <readline.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
char lines_s [80],cols_s [80];
|
||||
|
||||
void signal_handler (void);
|
||||
|
||||
void prepare_to_close (void)
|
||||
|
||||
{
|
||||
close_windows ();
|
||||
if (device_handle!=NULL)
|
||||
fclose (device_handle);
|
||||
free_user_commands (&general_commands);
|
||||
free_user_commands (&ext2_commands);
|
||||
free_struct_descriptors ();
|
||||
}
|
||||
|
||||
int init (void)
|
||||
|
||||
{
|
||||
printf ("Initializing ...\n");
|
||||
|
||||
if (!process_configuration_file ()) {
|
||||
fprintf (stderr,"Error - Unable to complete configuration. Quitting.\n");
|
||||
return (0);
|
||||
};
|
||||
|
||||
general_commands.last_command=-1; /* No commands whatsoever meanwhile */
|
||||
ext2_commands.last_command=-1;
|
||||
add_general_commands (); /* Add the general commands, aviable always */
|
||||
device_handle=NULL; /* Notice that our device is still not set up */
|
||||
device_offset=-1;
|
||||
current_type=NULL; /* No filesystem specific types yet */
|
||||
|
||||
remember_lifo.entries_count=0; /* Object memory is empty */
|
||||
|
||||
init_windows (); /* Initialize the NCURSES interface */
|
||||
init_readline (); /* Initialize the READLINE interface */
|
||||
init_signals (); /* Initialize the signal handlers */
|
||||
write_access=0; /* Write access disabled */
|
||||
|
||||
strcpy (last_command_line,"help"); /* Show the help screen to the user */
|
||||
dispatch ("help");
|
||||
return (1); /* Success */
|
||||
}
|
||||
|
||||
void add_general_commands (void)
|
||||
|
||||
{
|
||||
add_user_command (&general_commands,"help","EXT2ED help system",help);
|
||||
add_user_command (&general_commands,"set","Changes a variable in the current object",set);
|
||||
add_user_command (&general_commands,"setdevice","Selects the filesystem block device (e.g. /dev/hda1)",set_device);
|
||||
add_user_command (&general_commands,"setoffset","Moves asynchronicly in the filesystem",set_offset);
|
||||
add_user_command (&general_commands,"settype","Tells EXT2ED how to interpert the current object",set_type);
|
||||
add_user_command (&general_commands,"show","Displays the current object",show);
|
||||
add_user_command (&general_commands,"pgup","Scrolls data one page up",pgup);
|
||||
add_user_command (&general_commands,"pgdn","Scrolls data one page down",pgdn);
|
||||
add_user_command (&general_commands,"redraw","Redisplay the screen",redraw);
|
||||
add_user_command (&general_commands,"remember","Saves the current position and data information",remember);
|
||||
add_user_command (&general_commands,"recall","Gets back to the saved object position",recall);
|
||||
add_user_command (&general_commands,"enablewrite","Enters Read/Write mode - Allows changing the filesystem",enable_write);
|
||||
add_user_command (&general_commands,"disablewrite","Enters read only mode",disable_write);
|
||||
add_user_command (&general_commands,"writedata","Write data back to disk",write_data);
|
||||
add_user_command (&general_commands,"next","Moves to the next byte in hex mode",next);
|
||||
add_user_command (&general_commands,"prev","Moves to the previous byte in hex mode",prev);
|
||||
}
|
||||
|
||||
void add_ext2_general_commands (void)
|
||||
|
||||
{
|
||||
add_user_command (&ext2_commands,"super","Moves to the superblock of the filesystem",type_ext2___super);
|
||||
add_user_command (&ext2_commands,"group","Moves to the first group descriptor",type_ext2___group);
|
||||
add_user_command (&ext2_commands,"cd","Moves to the directory specified",type_ext2___cd);
|
||||
}
|
||||
|
||||
int set_struct_descriptors (char *file_name)
|
||||
|
||||
{
|
||||
FILE *fp;
|
||||
char current_line [500],current_word [50],*ch;
|
||||
char variable_name [50],variable_type [20];
|
||||
struct struct_descriptor *current_descriptor;
|
||||
|
||||
if ( (fp=fopen (file_name,"rt"))==NULL) {
|
||||
wprintw (command_win,"Error - Failed to open descriptors file %s\n",file_name);
|
||||
refresh_command_win (); return (0);
|
||||
};
|
||||
|
||||
while (!feof (fp)) {
|
||||
fgets (current_line,500,fp);
|
||||
if (feof (fp)) break;
|
||||
ch=parse_word (current_line,current_word);
|
||||
if (strcmp (current_word,"struct")==0) {
|
||||
ch=parse_word (ch,current_word);
|
||||
current_descriptor=add_new_descriptor (current_word);
|
||||
|
||||
while (strchr (current_line,'{')==NULL) {
|
||||
fgets (current_line,500,fp);
|
||||
if (feof (fp)) break;
|
||||
};
|
||||
if (feof (fp)) break;
|
||||
|
||||
fgets (current_line,500,fp);
|
||||
|
||||
while (strchr (current_line,'}')==NULL) {
|
||||
while (strchr (current_line,';')==NULL) {
|
||||
fgets (current_line,500,fp);
|
||||
if (strchr (current_line,'}')!=NULL) break;
|
||||
};
|
||||
if (strchr (current_line,'}') !=NULL) break;
|
||||
ch=parse_word (current_line,variable_type);
|
||||
ch=parse_word (ch,variable_name);
|
||||
while (variable_name [strlen (variable_name)-1]!=';') {
|
||||
strcpy (variable_type,variable_name);
|
||||
ch=parse_word (ch,variable_name);
|
||||
};
|
||||
variable_name [strlen (variable_name)-1]=0;
|
||||
add_new_variable (current_descriptor,variable_type,variable_name);
|
||||
fgets (current_line,500,fp);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fclose (fp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void free_struct_descriptors (void)
|
||||
|
||||
{
|
||||
struct struct_descriptor *ptr,*next;
|
||||
|
||||
ptr=first_type;
|
||||
while (ptr!=NULL) {
|
||||
next=ptr->next;
|
||||
free_user_commands (&ptr->type_commands);
|
||||
free (ptr);
|
||||
ptr=next;
|
||||
}
|
||||
first_type=last_type=current_type=NULL;
|
||||
}
|
||||
|
||||
void free_user_commands (struct struct_commands *ptr)
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<=ptr->last_command;i++) {
|
||||
free (ptr->names [i]);
|
||||
free (ptr->descriptions [i]);
|
||||
}
|
||||
|
||||
ptr->last_command=-1;
|
||||
}
|
||||
|
||||
struct struct_descriptor *add_new_descriptor (char *name)
|
||||
|
||||
{
|
||||
struct struct_descriptor *ptr;
|
||||
|
||||
if (first_type==NULL) {
|
||||
first_type=last_type=ptr=(struct struct_descriptor *) malloc (sizeof (struct struct_descriptor));
|
||||
if (ptr==NULL) {
|
||||
printf ("Error - Can not allocate memory - Quitting\n");
|
||||
exit (1);
|
||||
}
|
||||
ptr->prev=ptr->next=NULL;
|
||||
strcpy (ptr->name,name);
|
||||
ptr->length=0;
|
||||
ptr->fields_num=0;
|
||||
ptr->type_commands.last_command=-1;
|
||||
fill_type_commands (ptr);
|
||||
}
|
||||
else {
|
||||
ptr=(struct struct_descriptor *) malloc (sizeof (struct struct_descriptor));
|
||||
if (ptr==NULL) {
|
||||
printf ("Error - Can not allocate memory - Quitting\n");
|
||||
exit (1);
|
||||
}
|
||||
ptr->prev=last_type;last_type->next=ptr;last_type=ptr;
|
||||
strcpy (ptr->name,name);
|
||||
ptr->length=0;
|
||||
ptr->fields_num=0;
|
||||
ptr->type_commands.last_command=-1;
|
||||
fill_type_commands (ptr);
|
||||
}
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
void add_new_variable (struct struct_descriptor *ptr,char *v_type,char *v_name)
|
||||
|
||||
{
|
||||
short len=1;
|
||||
|
||||
strcpy (ptr->field_names [ptr->fields_num],v_name);
|
||||
ptr->field_positions [ptr->fields_num]=ptr->length;
|
||||
|
||||
if (strcasecmp (v_type,"long")==0) len=4;
|
||||
if (strcasecmp (v_type,"__u32")==0) len=4;
|
||||
if (strcasecmp (v_type,"__s32")==0) len=4;
|
||||
|
||||
if (strcasecmp (v_type,"__u16")==0) len=2;
|
||||
if (strcasecmp (v_type,"__s16")==0) len=2;
|
||||
if (strcasecmp (v_type,"short")==0) len=2;
|
||||
if (strcasecmp (v_type,"int")==0) len=2;
|
||||
|
||||
if (strcasecmp (v_type,"__u8")==0) len=1;
|
||||
if (strcasecmp (v_type,"__s8")==0) len=1;
|
||||
if (strcasecmp (v_type,"char")==0) len=1;
|
||||
|
||||
ptr->field_lengths [ptr->fields_num]=len;
|
||||
|
||||
ptr->length+=len;
|
||||
ptr->fields_num++;
|
||||
}
|
||||
|
||||
void fill_type_commands (struct struct_descriptor *ptr)
|
||||
|
||||
/*
|
||||
|
||||
Set specific type user commands.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
|
||||
if (strcmp ((ptr->name),"file")==0) {
|
||||
add_user_command (&ptr->type_commands,"show","Shows file data",type_file___show);
|
||||
add_user_command (&ptr->type_commands,"inode","Returns to the inode of the current file",type_file___inode);
|
||||
add_user_command (&ptr->type_commands,"display","Specifies data format - text or hex",type_file___display);
|
||||
add_user_command (&ptr->type_commands,"next","Pass to next byte",type_file___next);
|
||||
add_user_command (&ptr->type_commands,"prev","Pass to the previous byte",type_file___prev);
|
||||
add_user_command (&ptr->type_commands,"offset","Pass to a specified byte in the current block",type_file___offset);
|
||||
add_user_command (&ptr->type_commands,"nextblock","Pass to next file block",type_file___nextblock);
|
||||
add_user_command (&ptr->type_commands,"prevblock","Pass to the previous file block",type_file___prevblock);
|
||||
add_user_command (&ptr->type_commands,"block","Specify which file block to edit",type_file___block);
|
||||
add_user_command (&ptr->type_commands,"remember","Saves the file\'s inode position for later reference",type_file___remember);
|
||||
add_user_command (&ptr->type_commands,"set","Sets the current byte",type_file___set);
|
||||
add_user_command (&ptr->type_commands,"writedata","Writes the current block to the disk",type_file___writedata);
|
||||
}
|
||||
|
||||
if (strcmp ((ptr->name),"ext2_inode")==0) {
|
||||
add_user_command (&ptr->type_commands,"show","Shows inode data",type_ext2_inode___show);
|
||||
add_user_command (&ptr->type_commands,"next","Move to next inode in current block group",type_ext2_inode___next);
|
||||
add_user_command (&ptr->type_commands,"prev","Move to next inode in current block group",type_ext2_inode___prev);
|
||||
add_user_command (&ptr->type_commands,"group","Move to the group descriptors of the current inode table",type_ext2_inode___group);
|
||||
add_user_command (&ptr->type_commands,"entry","Move to a specified entry in the current inode table",type_ext2_inode___entry);
|
||||
add_user_command (&ptr->type_commands,"file","Display file data of the current inode",type_ext2_inode___file);
|
||||
add_user_command (&ptr->type_commands,"dir","Display directory data of the current inode",type_ext2_inode___dir);
|
||||
}
|
||||
|
||||
if (strcmp ((ptr->name),"dir")==0) {
|
||||
add_user_command (&ptr->type_commands,"show","Shows current directory data",type_dir___show);
|
||||
add_user_command (&ptr->type_commands,"inode","Returns to the inode of the current directory",type_dir___inode);
|
||||
add_user_command (&ptr->type_commands,"next","Pass to the next directory entry",type_dir___next);
|
||||
add_user_command (&ptr->type_commands,"prev","Pass to the previous directory entry",type_dir___prev);
|
||||
add_user_command (&ptr->type_commands,"followinode","Follows the inode specified in this directory entry",type_dir___followinode);
|
||||
add_user_command (&ptr->type_commands,"remember","Remember the inode of the current directory entry",type_dir___remember);
|
||||
add_user_command (&ptr->type_commands,"cd","Changes directory relative to the current directory",type_dir___cd);
|
||||
add_user_command (&ptr->type_commands,"entry","Moves to a specified entry in the current directory",type_dir___entry);
|
||||
add_user_command (&ptr->type_commands,"writedata","Writes the current entry to the disk",type_dir___writedata);
|
||||
add_user_command (&ptr->type_commands,"set","Changes a variable in the current directory entry",type_dir___set);
|
||||
}
|
||||
|
||||
if (strcmp ((ptr->name),"ext2_super_block")==0) {
|
||||
add_user_command (&ptr->type_commands,"show","Displays the super block data",type_ext2_super_block___show);
|
||||
add_user_command (&ptr->type_commands,"gocopy","Move to another backup copy of the superblock",type_ext2_super_block___gocopy);
|
||||
add_user_command (&ptr->type_commands,"setactivecopy","Copies the current superblock to the main superblock",type_ext2_super_block___setactivecopy);
|
||||
}
|
||||
|
||||
if (strcmp ((ptr->name),"ext2_group_desc")==0) {
|
||||
add_user_command (&ptr->type_commands,"next","Pass to the next block group decriptor",type_ext2_group_desc___next);
|
||||
add_user_command (&ptr->type_commands,"prev","Pass to the previous group descriptor",type_ext2_group_desc___prev);
|
||||
add_user_command (&ptr->type_commands,"entry","Pass to a specific group descriptor",type_ext2_group_desc___entry);
|
||||
add_user_command (&ptr->type_commands,"show","Shows the current group descriptor",type_ext2_group_desc___show);
|
||||
add_user_command (&ptr->type_commands,"inode","Pass to the inode table of the current group block",type_ext2_group_desc___inode);
|
||||
add_user_command (&ptr->type_commands,"gocopy","Move to another backup copy of the group descriptor",type_ext2_group_desc___gocopy);
|
||||
add_user_command (&ptr->type_commands,"blockbitmap","Show the block allocation bitmap of the current group block",type_ext2_group_desc___blockbitmap);
|
||||
add_user_command (&ptr->type_commands,"inodebitmap","Show the inode allocation bitmap of the current group block",type_ext2_group_desc___inodebitmap);
|
||||
add_user_command (&ptr->type_commands,"setactivecopy","Copies the current group descriptor to the main table",type_ext2_super_block___setactivecopy);
|
||||
}
|
||||
|
||||
if (strcmp ((ptr->name),"block_bitmap")==0) {
|
||||
add_user_command (&ptr->type_commands,"show","Displays the block allocation bitmap",type_ext2_block_bitmap___show);
|
||||
add_user_command (&ptr->type_commands,"entry","Moves to a specific bit",type_ext2_block_bitmap___entry);
|
||||
add_user_command (&ptr->type_commands,"next","Moves to the next bit",type_ext2_block_bitmap___next);
|
||||
add_user_command (&ptr->type_commands,"prev","Moves to the previous bit",type_ext2_block_bitmap___prev);
|
||||
add_user_command (&ptr->type_commands,"allocate","Allocates the current block",type_ext2_block_bitmap___allocate);
|
||||
add_user_command (&ptr->type_commands,"deallocate","Deallocates the current block",type_ext2_block_bitmap___deallocate);
|
||||
}
|
||||
|
||||
if (strcmp ((ptr->name),"inode_bitmap")==0) {
|
||||
add_user_command (&ptr->type_commands,"show","Displays the inode allocation bitmap",type_ext2_inode_bitmap___show);
|
||||
add_user_command (&ptr->type_commands,"entry","Moves to a specific bit",type_ext2_inode_bitmap___entry);
|
||||
add_user_command (&ptr->type_commands,"next","Moves to the next bit",type_ext2_inode_bitmap___next);
|
||||
add_user_command (&ptr->type_commands,"prev","Moves to the previous bit",type_ext2_inode_bitmap___prev);
|
||||
add_user_command (&ptr->type_commands,"allocate","Allocates the current inode",type_ext2_inode_bitmap___allocate);
|
||||
add_user_command (&ptr->type_commands,"deallocate","Deallocates the current inode",type_ext2_inode_bitmap___deallocate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void add_user_command (struct struct_commands *ptr,char *name,char *description,PF callback)
|
||||
|
||||
{
|
||||
int num;
|
||||
|
||||
num=ptr->last_command;
|
||||
if (num+1==MAX_COMMANDS_NUM) {
|
||||
printf ("Internal Error - Can't add command %s\n",name);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr->last_command=++num;
|
||||
|
||||
ptr->names [num]=(char *) malloc (strlen (name)+1);
|
||||
strcpy (ptr->names [num],name);
|
||||
|
||||
if (*description!=0) {
|
||||
ptr->descriptions [num]=(char *) malloc (strlen (description)+1);
|
||||
strcpy (ptr->descriptions [num],description);
|
||||
}
|
||||
|
||||
ptr->callback [num]=callback;
|
||||
}
|
||||
|
||||
int set_file_system_info (void)
|
||||
|
||||
{
|
||||
int ext2_detected=0;
|
||||
struct ext2_super_block *sb;
|
||||
|
||||
file_system_info.super_block_offset=1024;
|
||||
file_system_info.file_system_size=DefaultTotalBlocks*DefaultBlockSize;
|
||||
|
||||
low_read ((char *) &file_system_info.super_block,sizeof (struct ext2_super_block),file_system_info.super_block_offset);
|
||||
|
||||
sb=&file_system_info.super_block;
|
||||
|
||||
if (sb->s_magic == EXT2_SUPER_MAGIC)
|
||||
ext2_detected=1;
|
||||
|
||||
if (ext2_detected)
|
||||
wprintw (command_win,"Detected extended 2 file system on device %s\n",device_name);
|
||||
else
|
||||
wprintw (command_win,"Warning - Extended 2 filesystem not detected on device %s\n",device_name);
|
||||
|
||||
if (!ext2_detected && !ForceExt2)
|
||||
wprintw (command_win,"You may wish to use the configuration option ForceExt2 on\n");
|
||||
|
||||
if (ForceExt2 && !ext2_detected)
|
||||
wprintw (command_win,"Forcing extended 2 filesystem\n");
|
||||
|
||||
if (ForceDefault || !ext2_detected)
|
||||
wprintw (command_win,"Forcing default parameters\n");
|
||||
|
||||
refresh_command_win ();
|
||||
|
||||
if (ext2_detected || ForceExt2) {
|
||||
add_ext2_general_commands ();
|
||||
if (!set_struct_descriptors (Ext2Descriptors))
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!ForceDefault && ext2_detected) {
|
||||
|
||||
file_system_info.block_size=EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size;
|
||||
if (file_system_info.block_size == EXT2_MIN_BLOCK_SIZE)
|
||||
file_system_info.first_group_desc_offset=2*EXT2_MIN_BLOCK_SIZE;
|
||||
else
|
||||
file_system_info.first_group_desc_offset=file_system_info.block_size;
|
||||
file_system_info.groups_count=( sb->s_blocks_count-sb->s_first_data_block+sb->s_blocks_per_group-1) /
|
||||
sb->s_blocks_per_group;
|
||||
|
||||
file_system_info.inodes_per_block=file_system_info.block_size/sizeof (struct ext2_inode);
|
||||
file_system_info.blocks_per_group=sb->s_inodes_per_group/file_system_info.inodes_per_block;
|
||||
file_system_info.no_blocks_in_group=sb->s_blocks_per_group;
|
||||
file_system_info.file_system_size=(sb->s_blocks_count-1)*file_system_info.block_size;
|
||||
}
|
||||
|
||||
else {
|
||||
file_system_info.file_system_size=DefaultTotalBlocks*DefaultBlockSize;
|
||||
file_system_info.block_size=DefaultBlockSize;
|
||||
file_system_info.no_blocks_in_group=DefaultBlocksInGroup;
|
||||
}
|
||||
|
||||
if (file_system_info.file_system_size > 2147483647) {
|
||||
wprintw (command_win,"Sorry, filesystems bigger than 2 GB are currently not supported\n");
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
void init_readline (void)
|
||||
|
||||
{
|
||||
rl_completion_entry_function=(Function *) complete_command;
|
||||
}
|
||||
|
||||
void init_signals (void)
|
||||
|
||||
{
|
||||
signal (SIGWINCH,(SignalHandler) signal_SIGWINCH_handler); /* Catch SIGWINCH */
|
||||
signal (SIGTERM,(SignalHandler) signal_SIGTERM_handler);
|
||||
signal (SIGSEGV,(SignalHandler) signal_SIGSEGV_handler);
|
||||
|
||||
}
|
||||
|
||||
void signal_SIGWINCH_handler (int sig_num)
|
||||
|
||||
{
|
||||
redraw_request=1; /* We will handle it in main.c */
|
||||
}
|
||||
|
||||
void signal_SIGTERM_handler (int sig_num)
|
||||
|
||||
{
|
||||
prepare_to_close ();
|
||||
printf ("Terminated due to signal %d\n",sig_num);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void signal_SIGSEGV_handler (int sig_num)
|
||||
|
||||
{
|
||||
prepare_to_close ();
|
||||
printf ("Killed by signal %d !\n",sig_num);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
int process_configuration_file (void)
|
||||
|
||||
{
|
||||
char buffer [300];
|
||||
char option [80],value [80];
|
||||
FILE *fp;
|
||||
|
||||
strcpy (buffer,VAR_DIR);
|
||||
strcat (buffer,"/ext2ed.conf");
|
||||
|
||||
if ((fp=fopen (buffer,"rt"))==NULL) {
|
||||
fprintf (stderr,"Error - Unable to open configuration file %s\n",buffer);
|
||||
return (0);
|
||||
}
|
||||
|
||||
while (get_next_option (fp,option,value)) {
|
||||
if (strcasecmp (option,"Ext2Descriptors")==0) {
|
||||
strcpy (Ext2Descriptors,value);
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"AlternateDescriptors")==0) {
|
||||
strcpy (AlternateDescriptors,value);
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"LogFile")==0) {
|
||||
strcpy (LogFile,value);
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"LogChanges")==0) {
|
||||
if (strcasecmp (value,"on")==0)
|
||||
LogChanges = 1;
|
||||
else if (strcasecmp (value,"off")==0)
|
||||
LogChanges = 0;
|
||||
else {
|
||||
fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
|
||||
fclose (fp);return (0);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"AllowChanges")==0) {
|
||||
if (strcasecmp (value,"on")==0)
|
||||
AllowChanges = 1;
|
||||
else if (strcasecmp (value,"off")==0)
|
||||
AllowChanges = 0;
|
||||
else {
|
||||
fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
|
||||
fclose (fp);return (0);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"AllowMountedRead")==0) {
|
||||
if (strcasecmp (value,"on")==0)
|
||||
AllowMountedRead = 1;
|
||||
else if (strcasecmp (value,"off")==0)
|
||||
AllowMountedRead = 0;
|
||||
else {
|
||||
fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
|
||||
fclose (fp);return (0);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"ForceExt2")==0) {
|
||||
if (strcasecmp (value,"on")==0)
|
||||
ForceExt2 = 1;
|
||||
else if (strcasecmp (value,"off")==0)
|
||||
ForceExt2 = 0;
|
||||
else {
|
||||
fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
|
||||
fclose (fp);return (0);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"DefaultBlockSize")==0) {
|
||||
DefaultBlockSize = atoi (value);
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"DefaultTotalBlocks")==0) {
|
||||
DefaultTotalBlocks = strtoul (value,NULL,10);
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"DefaultBlocksInGroup")==0) {
|
||||
DefaultBlocksInGroup = strtoul (value,NULL,10);
|
||||
}
|
||||
|
||||
else if (strcasecmp (option,"ForceDefault")==0) {
|
||||
if (strcasecmp (value,"on")==0)
|
||||
ForceDefault = 1;
|
||||
else if (strcasecmp (value,"off")==0)
|
||||
ForceDefault = 0;
|
||||
else {
|
||||
fprintf (stderr,"Error - Illegal value: %s %s\n",option,value);
|
||||
fclose (fp);return (0);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
fprintf (stderr,"Error - Unknown option: %s\n",option);
|
||||
fclose (fp);return (0);
|
||||
}
|
||||
}
|
||||
|
||||
printf ("Configuration completed\n");
|
||||
fclose (fp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
int get_next_option (FILE *fp,char *option,char *value)
|
||||
|
||||
{
|
||||
char *ptr;
|
||||
char buffer [600];
|
||||
|
||||
if (feof (fp)) return (0);
|
||||
do{
|
||||
if (feof (fp)) return (0);
|
||||
fgets (buffer,500,fp);
|
||||
} while (buffer [0]=='#' || buffer [0]=='\n');
|
||||
|
||||
ptr=parse_word (buffer,option);
|
||||
ptr=parse_word (ptr,value);
|
||||
return (1);
|
||||
}
|
||||
|
||||
void check_mounted (char *name)
|
||||
|
||||
{
|
||||
FILE *fp;
|
||||
char *ptr;
|
||||
char current_line [500],current_word [200];
|
||||
|
||||
mounted=0;
|
||||
|
||||
if ( (fp=fopen ("/etc/mtab","rt"))==NULL) {
|
||||
wprintw (command_win,"Error - Failed to open /etc/mtab. Assuming filesystem is mounted.\n");
|
||||
refresh_command_win ();mounted=1;return;
|
||||
};
|
||||
|
||||
while (!feof (fp)) {
|
||||
fgets (current_line,500,fp);
|
||||
if (feof (fp)) break;
|
||||
ptr=parse_word (current_line,current_word);
|
||||
if (strcasecmp (current_word,name)==0) {
|
||||
mounted=1;fclose (fp);return;
|
||||
}
|
||||
};
|
||||
|
||||
fclose (fp);
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/inode_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
Commands relevant to ext2_inode type.
|
||||
|
||||
First written on: April 9 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
void type_ext2_inode___prev (char *command_line)
|
||||
|
||||
{
|
||||
|
||||
char *ptr,buffer [80];
|
||||
|
||||
long group_num,group_offset,entry_num,block_num,first_entry,last_entry;
|
||||
long inode_num,mult=1;
|
||||
struct ext2_group_desc desc;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
mult=atol (buffer);
|
||||
}
|
||||
|
||||
block_num=device_offset/file_system_info.block_size;
|
||||
|
||||
group_num=inode_offset_to_group_num (device_offset);
|
||||
group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
|
||||
|
||||
low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
|
||||
|
||||
entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
|
||||
|
||||
first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
|
||||
inode_num=0;
|
||||
|
||||
if (entry_num-mult+1>0) {
|
||||
device_offset-=sizeof (struct ext2_inode)*mult;
|
||||
entry_num-=mult;
|
||||
|
||||
sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Entry out of limits\n");refresh_command_win ();
|
||||
}
|
||||
|
||||
if (entry_num==0) {
|
||||
wprintw (command_win,"Reached first inode in current group descriptor\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
void type_ext2_inode___next (char *command_line)
|
||||
|
||||
{
|
||||
|
||||
char *ptr,buffer [80];
|
||||
|
||||
long group_num,group_offset,entry_num,block_num,first_entry,last_entry;
|
||||
long inode_num,mult=1;
|
||||
struct ext2_group_desc desc;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
mult=atol (buffer);
|
||||
}
|
||||
|
||||
|
||||
block_num=device_offset/file_system_info.block_size;
|
||||
|
||||
group_num=inode_offset_to_group_num (device_offset);
|
||||
group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
|
||||
|
||||
low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
|
||||
|
||||
entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
|
||||
|
||||
first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
|
||||
inode_num=0;
|
||||
|
||||
if (entry_num+mult-1<last_entry) {
|
||||
device_offset+=sizeof (struct ext2_inode)*mult;
|
||||
entry_num+=mult;
|
||||
|
||||
sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
else {
|
||||
wprintw (command_win,"Error - Entry out of limits\n");refresh_command_win ();
|
||||
}
|
||||
|
||||
if (entry_num==last_entry) {
|
||||
wprintw (command_win,"Reached last inode in current group descriptor\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void type_ext2_inode___show (char *command_line)
|
||||
|
||||
{
|
||||
struct ext2_inode *inode_ptr;
|
||||
|
||||
unsigned short temp;
|
||||
int i;
|
||||
|
||||
long group_num,group_offset,entry_num,block_num,first_entry,last_entry,inode_num;
|
||||
struct ext2_group_desc desc;
|
||||
|
||||
block_num=device_offset/file_system_info.block_size;
|
||||
|
||||
group_num=inode_offset_to_group_num (device_offset);
|
||||
group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
|
||||
|
||||
low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
|
||||
|
||||
entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
|
||||
first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
|
||||
inode_num=group_num*file_system_info.super_block.s_inodes_per_group+1;
|
||||
inode_num+=entry_num;
|
||||
|
||||
inode_ptr=&type_data.u.t_ext2_inode;
|
||||
|
||||
show (command_line);
|
||||
|
||||
wmove (show_pad,0,40);wprintw (show_pad,"octal = %06o ",inode_ptr->i_mode);
|
||||
for (i=6;i>=0;i-=3) {
|
||||
temp=inode_ptr->i_mode & 0x1ff;
|
||||
temp=temp >> i;
|
||||
if (temp & 4)
|
||||
wprintw (show_pad,"r");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
if (temp & 2)
|
||||
wprintw (show_pad,"w");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
if (temp & 1)
|
||||
wprintw (show_pad,"x");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
}
|
||||
wmove (show_pad,3,40);wprintw (show_pad,"%s",ctime ((time_t *) &type_data.u.t_ext2_inode.i_atime));
|
||||
wmove (show_pad,4,40);wprintw (show_pad,"%s",ctime ((time_t *) &type_data.u.t_ext2_inode.i_ctime));
|
||||
wmove (show_pad,5,40);wprintw (show_pad,"%s",ctime ((time_t *) &type_data.u.t_ext2_inode.i_mtime));
|
||||
wmove (show_pad,6,40);wprintw (show_pad,"%s",ctime ((time_t *) &type_data.u.t_ext2_inode.i_dtime));
|
||||
|
||||
wmove (show_pad,10,40);
|
||||
temp=inode_ptr->i_flags;
|
||||
|
||||
if (temp & EXT2_SECRM_FL)
|
||||
wprintw (show_pad,"s");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
|
||||
if (temp & EXT2_UNRM_FL)
|
||||
wprintw (show_pad,"u");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
if (temp & EXT2_COMPR_FL)
|
||||
wprintw (show_pad,"c");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
if (temp & EXT2_SYNC_FL)
|
||||
wprintw (show_pad,"S");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
if (temp & EXT2_IMMUTABLE_FL)
|
||||
wprintw (show_pad,"i");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
if (temp & EXT2_APPEND_FL)
|
||||
wprintw (show_pad,"a");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
if (temp & EXT2_NODUMP_FL)
|
||||
wprintw (show_pad,"d");
|
||||
else
|
||||
wprintw (show_pad,"-");
|
||||
|
||||
refresh_show_pad ();
|
||||
|
||||
wmove (show_win,1,0);
|
||||
|
||||
wprintw (show_win,"Inode %ld of %ld. Entry %ld of %ld in group descriptor %ld.\n"
|
||||
,inode_num,file_system_info.super_block.s_inodes_count,entry_num,last_entry,group_num);
|
||||
|
||||
wprintw (show_win,"Inode type: ");
|
||||
|
||||
if (inode_num < EXT2_FIRST_INO) {
|
||||
switch (inode_num) {
|
||||
case EXT2_BAD_INO:
|
||||
wprintw (show_win,"Bad blocks inode - ");
|
||||
break;
|
||||
case EXT2_ROOT_INO:
|
||||
wprintw (show_win,"Root inode - ");
|
||||
break;
|
||||
case EXT2_ACL_IDX_INO:
|
||||
wprintw (show_win,"ACL index inode - ");
|
||||
break;
|
||||
case EXT2_ACL_DATA_INO:
|
||||
wprintw (show_win,"ACL data inode - ");
|
||||
break;
|
||||
case EXT2_BOOT_LOADER_INO:
|
||||
wprintw (show_win,"Boot loader inode - ");
|
||||
break;
|
||||
case EXT2_UNDEL_DIR_INO:
|
||||
wprintw (show_win,"Undelete directory inode - ");
|
||||
break;
|
||||
default:
|
||||
wprintw (show_win,"Reserved inode - ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (type_data.u.t_ext2_inode.i_mode==0)
|
||||
wprintw (show_win,"Free. ");
|
||||
|
||||
if (S_ISREG (type_data.u.t_ext2_inode.i_mode))
|
||||
wprintw (show_win,"File. ");
|
||||
|
||||
if (S_ISDIR (type_data.u.t_ext2_inode.i_mode))
|
||||
wprintw (show_win,"Directory. ");
|
||||
|
||||
if (S_ISLNK (type_data.u.t_ext2_inode.i_mode)) {
|
||||
wprintw (show_win,"Symbolic link. ");
|
||||
wmove (show_pad,12,40);
|
||||
|
||||
if (inode_ptr->i_size <= 60)
|
||||
wprintw (show_pad,"-> %s",(char *) &type_data.u.t_ext2_inode.i_block [0]);
|
||||
else
|
||||
wprintw (show_pad,"Slow symbolic link\n");
|
||||
refresh_show_pad ();
|
||||
}
|
||||
|
||||
if (S_ISCHR (type_data.u.t_ext2_inode.i_mode))
|
||||
wprintw (show_win,"Character device.");
|
||||
|
||||
if (S_ISBLK (type_data.u.t_ext2_inode.i_mode))
|
||||
wprintw (show_win,"Block device. ");
|
||||
|
||||
wprintw (show_win,"\n");refresh_show_win ();
|
||||
|
||||
if (entry_num==last_entry) {
|
||||
wprintw (command_win,"Reached last inode in current group descriptor\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
|
||||
if (entry_num==first_entry) {
|
||||
wprintw (command_win,"Reached first inode in current group descriptor\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void type_ext2_inode___entry (char *command_line)
|
||||
|
||||
{
|
||||
char *ptr,buffer [80];
|
||||
|
||||
long group_num,group_offset,entry_num,block_num,wanted_entry;
|
||||
struct ext2_group_desc desc;
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) return;
|
||||
ptr=parse_word (ptr,buffer);
|
||||
wanted_entry=atol (buffer);
|
||||
|
||||
block_num=device_offset/file_system_info.block_size;
|
||||
|
||||
group_num=inode_offset_to_group_num (device_offset);
|
||||
group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
|
||||
|
||||
low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
|
||||
|
||||
entry_num=(device_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
|
||||
|
||||
if (wanted_entry > entry_num) {
|
||||
sprintf (buffer,"next %ld",wanted_entry-entry_num);
|
||||
dispatch (buffer);
|
||||
}
|
||||
|
||||
else if (wanted_entry < entry_num) {
|
||||
sprintf (buffer,"prev %ld",entry_num-wanted_entry);
|
||||
dispatch (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void type_ext2_inode___group (char *command_line)
|
||||
|
||||
{
|
||||
char buffer [80];
|
||||
|
||||
long group_num,group_offset;
|
||||
|
||||
group_num=inode_offset_to_group_num (device_offset);
|
||||
group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
|
||||
|
||||
sprintf (buffer,"setoffset %ld",group_offset);dispatch (buffer);
|
||||
sprintf (buffer,"settype ext2_group_desc");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_inode___file (char *command_line)
|
||||
|
||||
{
|
||||
char buffer [80];
|
||||
|
||||
if (!S_ISREG (type_data.u.t_ext2_inode.i_mode)) {
|
||||
wprintw (command_win,"Error - Inode type is not file\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!init_file_info ()) {
|
||||
wprintw (command_win,"Error - Unable to show file\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf (buffer,"settype file");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_inode___dir (char *command_line)
|
||||
|
||||
{
|
||||
char buffer [80];
|
||||
|
||||
if (!S_ISDIR (type_data.u.t_ext2_inode.i_mode)) {
|
||||
wprintw (command_win,"Error - Inode type is not directory\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
/* It is very important to init first_file_info first, as search_dir_entries relies on it */
|
||||
|
||||
if (!init_dir_info (&first_file_info)) {
|
||||
wprintw (command_win,"Error - Unable to show directory\n");refresh_command_win ();
|
||||
return;
|
||||
}
|
||||
|
||||
file_info=first_file_info;
|
||||
|
||||
sprintf (buffer,"settype dir");dispatch (buffer);
|
||||
}
|
||||
|
||||
long inode_offset_to_group_num (long inode_offset)
|
||||
|
||||
{
|
||||
int found=0;
|
||||
struct ext2_group_desc desc;
|
||||
|
||||
long block_num,group_offset,group_num;
|
||||
|
||||
block_num=inode_offset/file_system_info.block_size;
|
||||
|
||||
group_offset=file_system_info.first_group_desc_offset;
|
||||
group_num=(group_offset-file_system_info.first_group_desc_offset)/sizeof (struct ext2_group_desc);
|
||||
|
||||
while (!found && group_num>=0 && group_num<file_system_info.groups_count) {
|
||||
low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
|
||||
if (block_num>=desc.bg_inode_table && block_num<desc.bg_inode_table+file_system_info.blocks_per_group)
|
||||
found=1;
|
||||
else
|
||||
group_offset+=sizeof (struct ext2_group_desc);
|
||||
group_num=(group_offset-file_system_info.first_group_desc_offset)/sizeof (struct ext2_group_desc);
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return (-1);
|
||||
|
||||
return (group_num);
|
||||
}
|
||||
|
||||
|
||||
|
||||
long int inode_offset_to_inode_num (long inode_offset)
|
||||
|
||||
{
|
||||
long group_num,group_offset,entry_num,block_num,first_entry,last_entry,inode_num;
|
||||
struct ext2_group_desc desc;
|
||||
|
||||
block_num=inode_offset/file_system_info.block_size;
|
||||
|
||||
group_num=inode_offset_to_group_num (inode_offset);
|
||||
group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
|
||||
|
||||
low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
|
||||
|
||||
entry_num=(inode_offset-desc.bg_inode_table*file_system_info.block_size)/sizeof (struct ext2_inode);
|
||||
first_entry=0;last_entry=file_system_info.super_block.s_inodes_per_group-1;
|
||||
inode_num=group_num*file_system_info.super_block.s_inodes_per_group+1;
|
||||
inode_num+=entry_num;
|
||||
|
||||
return (inode_num);
|
||||
}
|
||||
|
||||
long int inode_num_to_inode_offset (long inode_num)
|
||||
|
||||
{
|
||||
long group_num,group_offset,inode_offset,inode_entry;
|
||||
struct ext2_group_desc desc;
|
||||
|
||||
inode_num--;
|
||||
|
||||
group_num=inode_num/file_system_info.super_block.s_inodes_per_group;
|
||||
inode_entry=inode_num%file_system_info.super_block.s_inodes_per_group;
|
||||
group_offset=file_system_info.first_group_desc_offset+group_num*sizeof (struct ext2_group_desc);
|
||||
low_read ((char *) &desc,sizeof (struct ext2_group_desc),group_offset);
|
||||
|
||||
inode_offset=desc.bg_inode_table*file_system_info.block_size+inode_entry*sizeof (struct ext2_inode);
|
||||
|
||||
return (inode_offset);
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/inodebitmap_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
-------------------------
|
||||
Handles the inode bitmap.
|
||||
-------------------------
|
||||
|
||||
Please refer to the documentation in blockbitmap_com.c - Those two files are almost equal.
|
||||
|
||||
First written on: July 25 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
|
||||
void type_ext2_inode_bitmap___entry (char *command_line)
|
||||
|
||||
{
|
||||
unsigned long entry_num;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - No argument specified\n");refresh_command_win ();return;
|
||||
}
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
entry_num=atol (buffer);
|
||||
|
||||
if (entry_num >= file_system_info.super_block.s_inodes_per_group) {
|
||||
wprintw (command_win,"Error - Entry number out of bounds\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
inode_bitmap_info.entry_num=entry_num;
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_inode_bitmap___next (char *command_line)
|
||||
|
||||
{
|
||||
long entry_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
entry_offset=atol (buffer);
|
||||
}
|
||||
|
||||
sprintf (buffer,"entry %ld",inode_bitmap_info.entry_num+entry_offset);
|
||||
dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_inode_bitmap___prev (char *command_line)
|
||||
|
||||
{
|
||||
long entry_offset=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
entry_offset=atol (buffer);
|
||||
}
|
||||
|
||||
sprintf (buffer,"entry %ld",inode_bitmap_info.entry_num-entry_offset);
|
||||
dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_inode_bitmap___allocate (char *command_line)
|
||||
|
||||
{
|
||||
long entry_num,num=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
num=atol (buffer);
|
||||
}
|
||||
|
||||
entry_num=inode_bitmap_info.entry_num;
|
||||
if (num > file_system_info.super_block.s_inodes_per_group-entry_num) {
|
||||
wprintw (command_win,"Error - There aren't that much inodes in the group\n");
|
||||
refresh_command_win ();return;
|
||||
}
|
||||
|
||||
while (num) {
|
||||
allocate_inode (entry_num);
|
||||
num--;entry_num++;
|
||||
}
|
||||
|
||||
dispatch ("show");
|
||||
}
|
||||
|
||||
void type_ext2_inode_bitmap___deallocate (char *command_line)
|
||||
|
||||
{
|
||||
long entry_num,num=1;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr!=0) {
|
||||
ptr=parse_word (ptr,buffer);
|
||||
num=atol (buffer);
|
||||
}
|
||||
|
||||
entry_num=inode_bitmap_info.entry_num;
|
||||
if (num > file_system_info.super_block.s_inodes_per_group-entry_num) {
|
||||
wprintw (command_win,"Error - There aren't that much inodes in the group\n");
|
||||
refresh_command_win ();return;
|
||||
}
|
||||
|
||||
while (num) {
|
||||
deallocate_inode (entry_num);
|
||||
num--;entry_num++;
|
||||
}
|
||||
|
||||
dispatch ("show");
|
||||
}
|
||||
|
||||
|
||||
void allocate_inode (long entry_num)
|
||||
|
||||
{
|
||||
unsigned char bit_mask=1;
|
||||
int byte_offset,j;
|
||||
|
||||
byte_offset=entry_num/8;
|
||||
for (j=0;j<entry_num%8;j++)
|
||||
bit_mask*=2;
|
||||
type_data.u.buffer [byte_offset] |= bit_mask;
|
||||
}
|
||||
|
||||
void deallocate_inode (long entry_num)
|
||||
|
||||
{
|
||||
unsigned char bit_mask=1;
|
||||
int byte_offset,j;
|
||||
|
||||
byte_offset=entry_num/8;
|
||||
for (j=0;j<entry_num%8;j++)
|
||||
bit_mask*=2;
|
||||
bit_mask^=0xff;
|
||||
|
||||
type_data.u.buffer [byte_offset] &= bit_mask;
|
||||
}
|
||||
|
||||
void type_ext2_inode_bitmap___show (char *command_line)
|
||||
|
||||
{
|
||||
int i,j;
|
||||
unsigned char *ptr;
|
||||
unsigned long inode_num,entry_num;
|
||||
|
||||
ptr=type_data.u.buffer;
|
||||
show_pad_info.line=0;show_pad_info.max_line=-1;
|
||||
|
||||
wmove (show_pad,0,0);
|
||||
for (i=0,entry_num=0;i<file_system_info.super_block.s_inodes_per_group/8;i++,ptr++) {
|
||||
for (j=1;j<=128;j*=2) {
|
||||
if (entry_num==inode_bitmap_info.entry_num) {
|
||||
wattrset (show_pad,A_REVERSE);
|
||||
show_pad_info.line=show_pad_info.max_line-show_pad_info.display_lines/2;
|
||||
}
|
||||
|
||||
if ((*ptr) & j)
|
||||
wprintw (show_pad,"1");
|
||||
else
|
||||
wprintw (show_pad,"0");
|
||||
|
||||
if (entry_num==inode_bitmap_info.entry_num)
|
||||
wattrset (show_pad,A_NORMAL);
|
||||
|
||||
entry_num++;
|
||||
}
|
||||
wprintw (show_pad," ");
|
||||
if (i%8==7) {
|
||||
wprintw (show_pad,"\n");
|
||||
show_pad_info.max_line++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i%8!=7) {
|
||||
wprintw (show_pad,"\n");
|
||||
show_pad_info.max_line++;
|
||||
}
|
||||
|
||||
refresh_show_pad ();
|
||||
show_info ();
|
||||
wmove (show_win,1,0);wprintw (show_win,"Inode bitmap of block group %ld\n",inode_bitmap_info.group_num);
|
||||
|
||||
inode_num=1+inode_bitmap_info.entry_num+inode_bitmap_info.group_num*file_system_info.super_block.s_inodes_per_group;
|
||||
wprintw (show_win,"Status of inode %ld - ",inode_num);
|
||||
ptr=type_data.u.buffer+inode_bitmap_info.entry_num/8;
|
||||
j=1;
|
||||
for (i=inode_bitmap_info.entry_num % 8;i>0;i--)
|
||||
j*=2;
|
||||
if ((*ptr) & j)
|
||||
wprintw (show_win,"Allocated\n");
|
||||
else
|
||||
wprintw (show_win,"Free\n");
|
||||
refresh_show_win ();
|
||||
}
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/main.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
------------
|
||||
Main program
|
||||
------------
|
||||
|
||||
This file mostly contains:
|
||||
|
||||
1. A list of global variables used through the entire program.
|
||||
2. The parser, which asks the command line from the user.
|
||||
3. The dispatcher, which analyzes the command line and calls the appropriate handler function.
|
||||
4. A command pattern matcher which is used along with the readline completion feature.
|
||||
5. A function which tells the user that an internal error has occured.
|
||||
|
||||
First written on: March 30 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <readline.h>
|
||||
#include <history.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
/* Global variables */
|
||||
|
||||
/*
|
||||
|
||||
Configuration file options
|
||||
|
||||
The following variables will be set by init.c to the values selected in the user configuration file.
|
||||
They are initialized below to some logical defaults.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
char Ext2Descriptors [200]="ext2.descriptors"; /* The location of the ext2 filesystem object definition */
|
||||
char AlternateDescriptors [200]=""; /* We allow the user to define additional structures */
|
||||
char LogFile [200]="ext2ed.log"; /* The location of the log file - Each write will be logged there */
|
||||
int LogChanges=1; /* 1 enables logging, 0 diables logging */
|
||||
int AllowChanges=0; /* When set, the enablewrite command will fail */
|
||||
int AllowMountedRead=0; /* Behavior when trying to open a mounted filesystem read-only */
|
||||
int ForceExt2=0; /* When set, ext2 autodetection is overridden */
|
||||
int DefaultBlockSize=1024;
|
||||
unsigned long DefaultTotalBlocks=2097151;
|
||||
unsigned long DefaultBlocksInGroup=8192; /* The default values are used when an ext2 filesystem is not */
|
||||
int ForceDefault=0; /* detected, or ForceDefault is set */
|
||||
|
||||
char last_command_line [80]; /* A simple one command cache, in addition to the readline history */
|
||||
|
||||
char device_name [80]; /* The location of the filesystem */
|
||||
FILE *device_handle=NULL; /* This is passed to the fopen / fread ... commands */
|
||||
long device_offset; /* The current position in the filesystem */
|
||||
/* Note that we have a 2 GB limitation */
|
||||
|
||||
int mounted=0; /* This is set when we find that the filesystem is mounted */
|
||||
|
||||
struct struct_commands general_commands,ext2_commands; /* Used to define the general and ext2 commands */
|
||||
struct struct_descriptor *first_type,*last_type,*current_type; /* Used to access the double linked list */
|
||||
struct struct_type_data type_data; /* The current data is sometimes stored here */
|
||||
struct struct_file_system_info file_system_info; /* Essential information on the filesystem */
|
||||
struct struct_file_info file_info,first_file_info; /* Used by file_com.c to access files */
|
||||
struct struct_group_info group_info; /* Used by group_com.c */
|
||||
struct struct_super_info super_info; /* Used by super_com.c */
|
||||
struct struct_remember_lifo remember_lifo; /* A circular memory of objects */
|
||||
struct struct_block_bitmap_info block_bitmap_info; /* Used by blockbitmap_com.c */
|
||||
struct struct_inode_bitmap_info inode_bitmap_info; /* Used by inodebitmap_com.c */
|
||||
|
||||
int redraw_request=0; /* Is set by a signal handler to handle terminal */
|
||||
/* screen size change. */
|
||||
int version_major=0,version_minor=1;
|
||||
char revision_date [80]="August 22 1995";
|
||||
char email_address [80]="tgud@tochnapc2.technion.ac.il";
|
||||
|
||||
int main (void)
|
||||
|
||||
/* We just call the parser to get commands from the user. We quit when parser returns. */
|
||||
|
||||
{
|
||||
if (!init ()) return (0); /* Perform some initial initialization */
|
||||
/* Quit if failed */
|
||||
|
||||
parser (); /* Get and parse user commands */
|
||||
|
||||
prepare_to_close (); /* Do some cleanup */
|
||||
printf ("Quitting ...\n");
|
||||
return (1); /* And quit */
|
||||
}
|
||||
|
||||
|
||||
void parser (void)
|
||||
|
||||
/*
|
||||
|
||||
This function asks the user for a command and calls the dispatcher function, dispatch, to analyze it.
|
||||
We use the readline library function readline to read the command, hence all the usual readline keys
|
||||
are available.
|
||||
The new command is saved both in the readline's history and in our tiny one-command cache, so that
|
||||
only the enter key is needed to retype it.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
char *ptr,command_line [80];
|
||||
int quit=0;
|
||||
|
||||
while (!quit) {
|
||||
|
||||
if (redraw_request) { /* Terminal screen size has changed */
|
||||
dispatch ("redraw");dispatch ("show");redraw_request=0;
|
||||
}
|
||||
|
||||
wmove (command_win,0,0);wclrtoeol (command_win);refresh_command_win ();
|
||||
|
||||
mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0); /* At last ! I spent ** days ** on this one */
|
||||
|
||||
/* The ncurses library optimizes cursor movement by */
|
||||
/* keeping track of the cursor position. However, by */
|
||||
/* using the readline library I'm breaking its */
|
||||
/* assumptions. The double -1 arguments tell ncurses */
|
||||
/* to disable cursor movement optimization this time. */
|
||||
echo ();
|
||||
ptr=readline ("ext2ed > "); /* Read the user's command line. */
|
||||
noecho ();
|
||||
|
||||
strcpy (command_line,ptr); /* Readline allocated the buffer - Copy the string */
|
||||
free (ptr); /* and free the allocated buffer */
|
||||
|
||||
if (*command_line != 0)
|
||||
add_history (command_line); /* Add the non-empty command to the command histroy */
|
||||
|
||||
if (*command_line==0) /* If only enter was pressed, recall the last command */
|
||||
strcpy (command_line,last_command_line);
|
||||
|
||||
/* Emulate readline's actions for ncurses */
|
||||
|
||||
mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0); /* Again, needed for correct integration of the */
|
||||
/* ncurses and readline libraries */
|
||||
|
||||
werase (command_win);
|
||||
wprintw (command_win,"ext2ed > ");wprintw (command_win,command_line);
|
||||
wprintw (command_win,"\n");refresh_command_win ();
|
||||
|
||||
strcpy (last_command_line,command_line); /* Save this command in our tiny cache */
|
||||
|
||||
quit=dispatch (command_line); /* And call dispatch to do the actual job */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int dispatch (char *command_line)
|
||||
|
||||
/*
|
||||
|
||||
This is a very important function. Its task is to recieve a command name and link it to a C function.
|
||||
There are three type of commands:
|
||||
|
||||
1. General commands - Always available and accessed through general_commands.
|
||||
2. Ext2 specific commands - Available when editing an ext2 filesystem, accessed through ext2_commands.
|
||||
3. Type specific commands - Those are changing according to the current type. The global
|
||||
variable current_type points to the current object definition (of type struct_descriptor).
|
||||
In it, the struct_commands entry contains the type specific commands links.
|
||||
|
||||
Overriding is an important feature - Much like in C++ : The same command name can dispatch to different
|
||||
functions. The overriding priority is 3,2,1; That is - A type specific command will always override a
|
||||
general command. This is used through the program to allow fine tuned operation.
|
||||
|
||||
When an handling function is found, it is called along with the command line that was passed to us. The handling
|
||||
function is then free to interpert the arguments in its own style.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int i,found=0;
|
||||
|
||||
char command [80];
|
||||
|
||||
parse_word (command_line,command);
|
||||
|
||||
if (strcasecmp (command,"quit")==0) return (1);
|
||||
|
||||
/* 1. Search for type specific commands FIRST - Allows overriding of a general command */
|
||||
|
||||
if (current_type != NULL)
|
||||
for (i=0;i<=current_type->type_commands.last_command && !found;i++) {
|
||||
if (strcasecmp (command,current_type->type_commands.names [i])==0) {
|
||||
(*current_type->type_commands.callback [i]) (command_line);
|
||||
found=1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. Now search for ext2 filesystem general commands */
|
||||
|
||||
if (!found)
|
||||
for (i=0;i<=ext2_commands.last_command && !found;i++) {
|
||||
if (strcasecmp (command,ext2_commands.names [i])==0) {
|
||||
(*ext2_commands.callback [i]) (command_line);
|
||||
found=1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 3. If not found, search the general commands */
|
||||
|
||||
if (!found)
|
||||
for (i=0;i<=general_commands.last_command && !found;i++) {
|
||||
if (strcasecmp (command,general_commands.names [i])==0) {
|
||||
(*general_commands.callback [i]) (command_line);
|
||||
found=1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 4. If not found, issue an error message and return */
|
||||
|
||||
if (!found) {
|
||||
wprintw (command_win,"Error: Unknown command\n");
|
||||
refresh_command_win ();
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *parse_word (char *source,char *dest)
|
||||
|
||||
/*
|
||||
|
||||
This function copies the next word in source to the variable dest, ignoring whitespaces.
|
||||
It returns a pointer to the next word in source.
|
||||
It is used to split the command line into command and arguments.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
char ch,*source_ptr,*target_ptr;
|
||||
|
||||
if (*source==0) {
|
||||
*dest=0;
|
||||
return (source);
|
||||
};
|
||||
|
||||
source_ptr=source;target_ptr=dest;
|
||||
do {
|
||||
ch=*source_ptr++;
|
||||
} while (! (ch>' ' && ch<='z') && ch!=0);
|
||||
|
||||
while (ch>' ' && ch<='z') {
|
||||
*target_ptr++=ch;
|
||||
ch=*source_ptr++;
|
||||
}
|
||||
|
||||
*target_ptr=0;
|
||||
|
||||
source_ptr--;
|
||||
do {
|
||||
ch=*source_ptr++;
|
||||
} while (! (ch>' ' && ch<='z') && ch!=0);
|
||||
|
||||
return (--source_ptr);
|
||||
}
|
||||
|
||||
char *complete_command (char *text,int state)
|
||||
|
||||
/*
|
||||
|
||||
text is the partial command entered by the user; We assume that it is a part of a command - I didn't write code
|
||||
for smarter completion.
|
||||
|
||||
The state variable is an index which tells us how many possible completions we already returned to readline.
|
||||
|
||||
We return only one possible completion or (char *) NULL if there are no more completions. This
|
||||
function will be called by readline over and over until we tell it to stop.
|
||||
|
||||
While scanning for possible completions, we use the same priority definition which was used in dispatch.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
int state_index=-1;
|
||||
int i,len;
|
||||
|
||||
len=strlen (text);
|
||||
|
||||
/* Is the command type specific ? */
|
||||
|
||||
if (current_type != NULL)
|
||||
for (i=0;i<=current_type->type_commands.last_command;i++) {
|
||||
if (strncmp (current_type->type_commands.names [i],text,len)==0) {
|
||||
state_index++;
|
||||
if (state==state_index) {
|
||||
return (dupstr (current_type->type_commands.names [i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No, pehaps ext2 specific command then ? */
|
||||
|
||||
for (i=0;i<=ext2_commands.last_command;i++) {
|
||||
if (strncmp (ext2_commands.names [i],text,len)==0) {
|
||||
state_index++;
|
||||
if (state==state_index)
|
||||
return (dupstr (ext2_commands.names [i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check for a general command */
|
||||
|
||||
for (i=0;i<=general_commands.last_command;i++) {
|
||||
if (strncmp (general_commands.names [i],text,len)==0) {
|
||||
state_index++;
|
||||
if (state==state_index)
|
||||
return (dupstr (general_commands.names [i]));
|
||||
}
|
||||
}
|
||||
|
||||
/* quit is handled differently */
|
||||
|
||||
if (strncmp ("quit",text,len)==0) {
|
||||
state_index++;
|
||||
if (state==state_index)
|
||||
return (dupstr ("quit"));
|
||||
}
|
||||
|
||||
/* No more completions */
|
||||
|
||||
return ((char *) NULL);
|
||||
}
|
||||
|
||||
char *dupstr (char *src)
|
||||
|
||||
/*
|
||||
|
||||
Nothing special - Just allocates enough space and copy the string.
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
ptr=(char *) malloc (strlen (src)+1);
|
||||
strcpy (ptr,src);
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
void internal_error (char *description,char *source_name,char *function_name)
|
||||
|
||||
/*
|
||||
|
||||
This function reports an internal error. It is almost not used. One place in which I do check for internal
|
||||
errors is disk.c.
|
||||
|
||||
We just report the error, and try to continue ...
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
wprintw (command_win,"Internal error - Found by source: %s.c , function: %s\n",source_name,function_name);
|
||||
wprintw (command_win,"\t%s\n",description);
|
||||
wprintw (command_win,"Press enter to (hopefully) continue\n");
|
||||
refresh_command_win ();getch ();werase (command_win);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/super_com.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
----------------------
|
||||
Handles the superblock
|
||||
----------------------
|
||||
|
||||
First written on: April 9 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
void type_ext2_super_block___show (char *command_line)
|
||||
|
||||
{
|
||||
struct ext2_super_block *super;
|
||||
super=&type_data.u.t_ext2_super_block;
|
||||
|
||||
show (command_line);
|
||||
|
||||
if (super->s_blocks_count != 0) {
|
||||
wmove (show_pad,2,40);wprintw (show_pad,"%2.2f%%",100*(float) super->s_r_blocks_count/ (float) super->s_blocks_count);
|
||||
wmove (show_pad,3,40);wprintw (show_pad,"%2.2f%%",100*(float) super->s_free_blocks_count/ (float) super->s_blocks_count);
|
||||
}
|
||||
|
||||
if (super->s_inodes_count != 0) {
|
||||
wmove (show_pad,4,40);wprintw (show_pad,"%2.2f%%",100*(float) super->s_free_inodes_count/ (float) super->s_inodes_count);
|
||||
}
|
||||
|
||||
wmove (show_pad,6,40);
|
||||
switch (super->s_log_block_size) {
|
||||
case 0: wprintw (show_pad,"1024 bytes");break;
|
||||
case 1: wprintw (show_pad,"2048 bytes");break;
|
||||
case 2: wprintw (show_pad,"4096 bytes");break;
|
||||
}
|
||||
wmove (show_pad,11,40);wprintw (show_pad,"%s",ctime ((time_t *) &type_data.u.t_ext2_super_block.s_mtime));
|
||||
wmove (show_pad,12,40);wprintw (show_pad,"%s",ctime ((time_t *) &type_data.u.t_ext2_super_block.s_wtime));
|
||||
wmove (show_pad,19,40);wprintw (show_pad,"%s",ctime ((time_t *) &type_data.u.t_ext2_super_block.s_lastcheck));
|
||||
wmove (show_pad,15,40);
|
||||
|
||||
switch (type_data.u.t_ext2_super_block.s_magic) {
|
||||
case EXT2_SUPER_MAGIC:
|
||||
wprintw (show_pad,"ext2 >= 0.2B");
|
||||
break;
|
||||
case EXT2_PRE_02B_MAGIC:
|
||||
wprintw (show_pad,"ext2 < 0.2B (not supported)");
|
||||
break;
|
||||
default:
|
||||
wprintw (show_pad,"Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
wmove (show_pad,16,40);
|
||||
if (type_data.u.t_ext2_super_block.s_state & 0x1)
|
||||
wprintw (show_pad,"clean ");
|
||||
else
|
||||
wprintw (show_pad,"not clean ");
|
||||
|
||||
if (type_data.u.t_ext2_super_block.s_state & 0x2)
|
||||
wprintw (show_pad,"with errors ");
|
||||
else
|
||||
wprintw (show_pad,"with no errors");
|
||||
|
||||
wmove (show_pad,17,40);
|
||||
|
||||
switch (type_data.u.t_ext2_super_block.s_errors) {
|
||||
case EXT2_ERRORS_CONTINUE:
|
||||
wprintw (show_pad,"Continue");
|
||||
break;
|
||||
case EXT2_ERRORS_RO:
|
||||
wprintw (show_pad,"Remount read only");
|
||||
break;
|
||||
case EXT2_ERRORS_PANIC:
|
||||
wprintw (show_pad,"Issue kernel panic");
|
||||
break;
|
||||
default:
|
||||
wprintw (show_pad,"Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
wmove (show_pad,21,40);
|
||||
|
||||
switch (type_data.u.t_ext2_super_block.s_creator_os) {
|
||||
|
||||
case EXT2_OS_LINUX:
|
||||
wprintw (show_pad,"Linux :-)");
|
||||
break;
|
||||
|
||||
case EXT2_OS_HURD:
|
||||
wprintw (show_pad,"Hurd");
|
||||
break;
|
||||
|
||||
case EXT2_OS_MASIX:
|
||||
wprintw (show_pad,"Masix");
|
||||
break;
|
||||
|
||||
default:
|
||||
wprintw (show_pad,"Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
refresh_show_pad ();
|
||||
|
||||
wmove (show_win,1,0);wprintw (show_win,"\n");wmove (show_win,2,0);
|
||||
wprintw (show_win,"Superblock copy %ld ",super_info.copy_num);
|
||||
if (super_info.copy_num==0)
|
||||
wprintw (show_win,"(main copy)");
|
||||
wprintw (show_win,"\n");
|
||||
refresh_show_win ();
|
||||
}
|
||||
|
||||
void type_ext2_super_block___gocopy (char *command_line)
|
||||
|
||||
{
|
||||
unsigned long copy_num,offset;
|
||||
char *ptr,buffer [80];
|
||||
|
||||
ptr=parse_word (command_line,buffer);
|
||||
if (*ptr==0) {
|
||||
wprintw (command_win,"Error - No argument specified\n");refresh_command_win ();return;
|
||||
}
|
||||
ptr=parse_word (ptr,buffer);
|
||||
|
||||
copy_num=atol (buffer);
|
||||
|
||||
offset=file_system_info.super_block_offset+copy_num*file_system_info.no_blocks_in_group*file_system_info.block_size;
|
||||
|
||||
if (offset > file_system_info.file_system_size) {
|
||||
wprintw (command_win,"Error - Copy number out of bounds\n");refresh_command_win ();return;
|
||||
}
|
||||
|
||||
super_info.copy_num=copy_num;
|
||||
device_offset=offset;
|
||||
|
||||
sprintf (buffer,"setoffset %ld",device_offset);dispatch (buffer);
|
||||
strcpy (buffer,"show");dispatch (buffer);
|
||||
}
|
||||
|
||||
void type_ext2_super_block___setactivecopy (char *command_line)
|
||||
|
||||
{
|
||||
struct ext2_super_block sb;
|
||||
|
||||
sb=type_data.u.t_ext2_super_block;
|
||||
dispatch ("gocopy 0");
|
||||
type_data.u.t_ext2_super_block=sb;
|
||||
dispatch ("show");
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
|
||||
/usr/src/ext2ed/win.c
|
||||
|
||||
A part of the extended file system 2 disk editor.
|
||||
|
||||
--------------------------------------------------------
|
||||
Window management - Interfacing with the ncurses library
|
||||
--------------------------------------------------------
|
||||
|
||||
First written on: April 17 1995
|
||||
|
||||
Copyright (C) 1995 Gadi Oxman
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2ed.h"
|
||||
|
||||
struct struct_pad_info show_pad_info;
|
||||
WINDOW *title_win,*show_win,*command_win,*show_pad;
|
||||
|
||||
void init_windows (void)
|
||||
|
||||
{
|
||||
char title_string [80];
|
||||
|
||||
initscr ();
|
||||
|
||||
if (LINES<TITLE_WIN_LINES+SHOW_WIN_LINES+COMMAND_WIN_LINES+3) {
|
||||
printf ("Sorry, your terminal screen is too small\n");
|
||||
printf ("Error - Can not initialize windows\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
title_win=newwin (TITLE_WIN_LINES,COLS,0,0);
|
||||
show_win=newwin (SHOW_WIN_LINES,COLS,TITLE_WIN_LINES,0);
|
||||
show_pad=newpad (SHOW_PAD_LINES,SHOW_PAD_COLS);
|
||||
command_win=newwin (COMMAND_WIN_LINES,COLS,LINES-COMMAND_WIN_LINES,0);
|
||||
|
||||
if (title_win==NULL || show_win==NULL || show_pad==NULL || command_win==NULL) {
|
||||
printf ("Error - Not enough memory - Can not initialize windows\n");exit (1);
|
||||
}
|
||||
|
||||
box (title_win,0,0);
|
||||
sprintf (title_string,"EXT2ED - Extended-2 File System editor ver %d.%d (%s)",version_major,version_minor,revision_date);
|
||||
wmove (title_win,TITLE_WIN_LINES/2,(COLS-strlen (title_string))/2);
|
||||
wprintw (title_win,title_string);
|
||||
|
||||
#ifdef OLD_NCURSES
|
||||
wattrset (show_win,A_NORMAL);werase (show_win);
|
||||
#else
|
||||
wbkgdset (show_win,A_REVERSE);werase (show_win);
|
||||
#endif
|
||||
show_pad_info.line=0;show_pad_info.col=0;
|
||||
show_pad_info.display_lines=LINES-TITLE_WIN_LINES-SHOW_WIN_LINES-COMMAND_WIN_LINES-2;
|
||||
show_pad_info.display_cols=COLS;
|
||||
show_pad_info.max_line=show_pad_info.display_lines-1;show_pad_info.max_col=show_pad_info.display_cols-1;
|
||||
show_pad_info.disable_output=0;
|
||||
|
||||
scrollok (command_win,TRUE);
|
||||
|
||||
refresh_title_win ();refresh_show_win ();refresh_show_pad ();refresh_command_win ();
|
||||
}
|
||||
|
||||
void refresh_title_win (void)
|
||||
|
||||
{
|
||||
wrefresh (title_win);
|
||||
}
|
||||
|
||||
void refresh_show_win (void)
|
||||
|
||||
{
|
||||
int current_page,total_pages;
|
||||
|
||||
current_page=show_pad_info.line/show_pad_info.display_lines+1;
|
||||
if (show_pad_info.line%show_pad_info.display_lines)
|
||||
current_page++;
|
||||
total_pages=show_pad_info.max_line/show_pad_info.display_lines+1;
|
||||
|
||||
wmove (show_win,2,COLS-18);
|
||||
wprintw (show_win,"Page %d of %d\n",current_page,total_pages);
|
||||
|
||||
wmove (show_win,2,COLS-18);
|
||||
wrefresh (show_win);
|
||||
}
|
||||
|
||||
|
||||
void refresh_show_pad (void)
|
||||
|
||||
{
|
||||
int left,top,right,bottom,i;
|
||||
|
||||
if (show_pad_info.disable_output)
|
||||
return;
|
||||
|
||||
if (show_pad_info.max_line < show_pad_info.display_lines-1) {
|
||||
for (i=show_pad_info.max_line+1;i<show_pad_info.display_lines;i++) {
|
||||
wmove (show_pad,i,0);wprintw (show_pad,"\n");
|
||||
}
|
||||
}
|
||||
left=0;right=show_pad_info.display_cols-1;
|
||||
top=TITLE_WIN_LINES+SHOW_WIN_LINES+1;bottom=top+show_pad_info.display_lines-1;
|
||||
|
||||
if (show_pad_info.line > show_pad_info.max_line-show_pad_info.display_lines+1)
|
||||
show_pad_info.line=show_pad_info.max_line-show_pad_info.display_lines+1;
|
||||
|
||||
if (show_pad_info.line < 0)
|
||||
show_pad_info.line=0;
|
||||
|
||||
#ifdef OLD_NCURSES
|
||||
prefresh (show_pad,show_pad_info.line,show_pad_info.col,top,left,show_pad_info.display_lines-1,show_pad_info.display_cols-1);
|
||||
#else
|
||||
prefresh (show_pad,show_pad_info.line,show_pad_info.col,top,left,top+show_pad_info.display_lines-1,left+show_pad_info.display_cols-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void refresh_command_win (void)
|
||||
|
||||
{
|
||||
wrefresh (command_win);
|
||||
}
|
||||
|
||||
void close_windows (void)
|
||||
|
||||
{
|
||||
echo ();
|
||||
|
||||
delwin (title_win);
|
||||
delwin (command_win);
|
||||
delwin (show_win);
|
||||
delwin (show_pad);
|
||||
|
||||
endwin ();
|
||||
}
|
||||
|
||||
void show_info (void)
|
||||
|
||||
{
|
||||
int block_num,block_offset;
|
||||
|
||||
block_num=device_offset/file_system_info.block_size;
|
||||
block_offset=device_offset%file_system_info.block_size;
|
||||
|
||||
wmove (show_win,0,0);
|
||||
wprintw (show_win,"Offset %-3ld in block %ld. ",block_offset,block_num);
|
||||
if (current_type != NULL)
|
||||
wprintw (show_win,"Type: %s\n",current_type->name);
|
||||
else
|
||||
wprintw (show_win,"Type: %s\n","none");
|
||||
|
||||
refresh_show_win ();
|
||||
}
|
||||
|
||||
|
||||
void redraw_all (void)
|
||||
|
||||
{
|
||||
close_windows ();
|
||||
init_windows ();
|
||||
|
||||
wmove (command_win,0,0);
|
||||
mvcur (-1,-1,LINES-COMMAND_WIN_LINES,0);
|
||||
|
||||
}
|
Loading…
Reference in New Issue