Check in ext2ed version 0.1

bitmap-optimize
Theodore Ts'o 2002-05-11 13:00:22 -04:00
parent 7de6577cd9
commit 583a1ce5d1
23 changed files with 10438 additions and 0 deletions

346
ext2ed/COPYRIGHT Normal file
View File

@ -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.

78
ext2ed/Makefile Normal file
View File

@ -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)

101
ext2ed/README Normal file
View File

@ -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

265
ext2ed/blockbitmap_com.c Normal file
View File

@ -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 ();
}

675
ext2ed/dir_com.c Normal file
View File

@ -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;
}

238
ext2ed/disk.c Normal file
View File

@ -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 *) &current_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);
}

View File

@ -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 &lt;tgud@tochnapc2.technion.ac.il&gt;
Haifa, August 95
</article>

File diff suppressed because it is too large Load Diff

72
ext2ed/doc/ext2ed.8 Normal file
View File

@ -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

407
ext2ed/ext2.descriptors Normal file
View File

@ -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 {
};

97
ext2ed/ext2_com.c Normal file
View File

@ -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);
}

79
ext2ed/ext2ed.conf Normal file
View File

@ -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

438
ext2ed/ext2ed.h Normal file
View File

@ -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 */

564
ext2ed/file_com.c Normal file
View File

@ -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))));
}

748
ext2ed/general_com.c Normal file
View File

@ -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 ();
}

182
ext2ed/group_com.c Normal file
View File

@ -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");
}

607
ext2ed/init.c Normal file
View File

@ -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;
}

436
ext2ed/inode_com.c Normal file
View File

@ -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);
}

214
ext2ed/inodebitmap_com.c Normal file
View File

@ -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 ();
}

374
ext2ed/main.c Normal file
View File

@ -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

159
ext2ed/super_com.c Normal file
View File

@ -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");
}

169
ext2ed/win.c Normal file
View File

@ -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);
}