summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Ulrich Niedermann <hun@n-dimensional.de>2007-12-14 16:08:25 +0100
committerHans Ulrich Niedermann <hun@n-dimensional.de>2007-12-14 16:08:25 +0100
commit6749719af90afe9544db14bdd8e2742926f1439c (patch)
tree9bb8edef05f9625be2ccd9bce5cb245af63effc4
downloade2tools-6749719af90afe9544db14bdd8e2742926f1439c.tar.gz
e2tools-6749719af90afe9544db14bdd8e2742926f1439c.tar.xz
e2tools-6749719af90afe9544db14bdd8e2742926f1439c.zip
Upstream's 0.0.16v0.0.16upstream
-rw-r--r--AUTHORS1
-rw-r--r--COPYING336
-rw-r--r--ChangeLog183
-rw-r--r--INSTALL182
-rw-r--r--Makefile.am29
-rw-r--r--Makefile.in346
-rw-r--r--NEWS0
-rw-r--r--README282
-rw-r--r--TODO8
-rw-r--r--aclocal.m4137
-rwxr-xr-xconfigure2185
-rw-r--r--configure.in31
-rw-r--r--copy.c1202
-rw-r--r--e2tools.c78
-rw-r--r--e2tools.h138
-rw-r--r--e2tools.spec52
-rw-r--r--elist.c198
-rw-r--r--elist.h39
-rwxr-xr-xinstall-sh251
-rw-r--r--ln.c388
-rw-r--r--ls.c1055
-rwxr-xr-xmissing190
-rw-r--r--mkdir.c587
-rwxr-xr-xmkinstalldirs40
-rw-r--r--mv.c554
-rw-r--r--progress.c198
-rw-r--r--read.c368
-rw-r--r--rm.c413
-rw-r--r--tail.c440
-rw-r--r--util.c320
-rw-r--r--write.c377
31 files changed, 10608 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..4f27749
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Keith W Sheffield (sheff@pobox.com)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..30eb861
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,336 @@
+ 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.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..d3d4c89
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,183 @@
+2004-04-06 Keith W. Sheffield <sheff@pobox.com>
+
+ * README: Added some basic user documentation.
+
+ * mkdir.c (e2mkdir): Updated the usage string and modified to
+ always use the default user and group information.
+
+ * write.c (put_file): Added a default file stat parameter.
+
+ * copy.c (copy): Corrected usage when -d is to a local directory.
+ Updated the usage string. Modified to pass the default file stat
+ to put_file().
+
+ * rm.c (e2rm): Corrected getopt and usage strings.
+
+ * elist.c (elist_delete): Modified to correctly update the
+ previous and next nodes in the list.
+
+ * ls.c: Modified to print "No files found!" for empty directories,
+ corrected the directory name display, and fixed REGEX_OPT masking.
+
+2003-07-12 Keith W. Sheffield <sheff@pobox.com>
+
+ * Makefile.am (install-exec-hook): using $(LN_S)
+
+ * tail.c (do_tail): fixed a bug when no arguments are given
+
+2003-07-10 Keith W. Sheffield <sheff@pobox.com>
+
+ * configure.in: initial version
+
+ * Makefile.am: initial version
+
+2002-08-08 Keith W. Sheffield <sheff@pobox.com>
+
+ * e2tools.c: Added a new feature suggested by Ralf Spenneberg:
+ e2tail. It can operate in follow mode or just dump N lines mode.
+
+ * read.c (retrieve_data): Split out the copy loop into its own
+ function read_to_eof() which can jump to an offset if needed.
+
+2002-07-08 Keith W. Sheffield <sheff@pobox.com>
+
+ * mkdir.c (create_dir): fixed a bug in the error reporting that
+ was truncating the full file name.
+
+ * copy.c: Corrected the destination directory name for verbose and
+ error output.
+
+2002-06-30 Keith W. Sheffield <sheff@pobox.com>
+
+ * ln.c (create_hard_link): Testing file type before linking to
+ directory.
+
+2002-06-26 Keith W. Sheffield <sheff@pobox.com>
+
+ * write.c (store_data): Added call to update_progress
+ (put_file): Called ext2fs_flush() before returning
+
+ * copy.c: Corrected copying from stdin and added a call to
+ initialize the file copy progress information.
+
+
+2002-06-05 Keith W. Sheffield <sheff@pobox.com>
+
+ * ls.c (long_disp): Increased file size field width.
+ (do_list_dir): Added -f and -D options. Allow for multiple file
+ specifications.
+
+ * elist.c: Added a new function: elist_delete
+
+2002-06-03 Keith W. Sheffield <sheff@pobox.com>
+
+ * ls.c (do_list_dir): Added -t -c -r -a -i options and modular
+ display and sort functions.
+ (list_dir_proc): Removed display code and just adds inode and
+ filename information to a linked list.
+
+ * elist.c: Added a new function: elist_sort
+
+2002-05-31 Keith W. Sheffield <sheff@pobox.com>
+
+ * ls.c: Added regular expression support.
+
+ * rm.c: Added code to handle regular expressions and recursive
+ directory removal.
+
+ * util.c: Added routines to check if a file is a shell regular
+ expression and one to create a standard regular expression and
+ compile it.
+
+2002-05-21 Keith W. Sheffield <sheff@pobox.com>
+
+ * copy.c (find_link): Fixed the list ordered search bug.
+
+2002-05-06 Keith W. Sheffield <sheff@pobox.com>
+
+ * copy.c (open_destination): Fixed a bug where if the destination
+ filespec was just localpath:, the file would not be copied to the
+ root directory.
+
+2002-05-02 Keith W. Sheffield <sheff@pobox.com>
+
+ * copy.c (open_destination): Fixed a bug that was causing a file
+ to be copied to the home directory if the destination file already
+ existed.
+
+2002-04-10 Keith W. Sheffield <sheff@pobox.com>
+
+ * e2tools.c (main): new feature: e2rm command
+
+ * e2tools.h: new feature: e2rm() function
+
+ * copy.c: Added the ability to set the file attributes for a
+ directory from defaults or the values from an existing directory.
+
+ * util.c: Added function init_stat_buf
+
+ * mkdir.c: Added a parameter to contain the default file
+ attributes for a directory.
+
+2002-03-21 Keith W. Sheffield <sheff@pobox.com>
+
+ * mv.c (do_swap): new feature: in-place file name swap
+
+ * ln.c (do_ln): Removed code that retrieved the directory name,
+ directory inode number, and base filename and replaced it with a
+ function call to get_file_parts().
+
+2002-03-20 Keith W. Sheffield <sheff@pobox.com>
+
+ * ln.c (do_ln): separated the ln/mv operations into two separate
+ functions. b
+
+2002-03-07 Keith W. Sheffield <sheff@pobox.com>
+
+ * write.c (put_file): Added ability to store the original file's
+ owner, group, access, modification, and create times.
+
+ * copy.c (copy): Copying hard links to ext2fs correctly, verbose
+ works
+
+
+2002-03-06 Keith W. Sheffield <sheff@pobox.com>
+
+ * ln.c (do_ln): Modified to perform a file rename/move
+
+ * e2tools.c (main): Added a call to do_ln to implement e2mv
+
+ * util.c (rm_file): checked for return of ext2fs_unlink
+
+2002-03-05 Keith W. Sheffield <sheff@pobox.com>
+
+ * e2tools.c (main): Added a call to do_ln
+
+ * write.c (put_file): Fixed a bug with reading from stdin.
+
+ * ls.c (do_list_dir): Removed setting optind for SCO
+
+ * mkdir.c (e2mkdir): Removed setting optind for SCO
+
+2002-02-27 Keith W. Sheffield <sheff@pobox.com>
+
+ * write.c (put_file): Added parameter to pass back the output
+ file's inode number.
+
+ * copy.c (copy): Added a directory check for file names being read
+ in from stdin and copied to an ext2fs.
+
+2002-02-26 Keith W. Sheffield <sheff@pobox.com>
+
+ * Makefile: added definitions to auto-checkout and added new
+ program e2mkdir.
+
+ * e2tools.c (main): added a call to e2mkdir
+
+ * mkdir.c: Added a new function e2mkdir
+
+ * e2tools.h: Added a section for external prototypes.
+
+ * copy.c (copy): removed unnecessary printf.
+
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..ca4a2bc
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,29 @@
+INCLUDES = -I@includedir@
+
+.c.o:
+ $(COMPILE) -c $<
+
+bin_PROGRAMS = e2cp
+e2cp_SOURCES = copy.c \
+ e2tools.c e2tools.h \
+ elist.c elist.h \
+ ln.c \
+ ls.c \
+ mkdir.c \
+ mv.c \
+ progress.c \
+ read.c \
+ rm.c \
+ tail.c \
+ util.c \
+ write.c
+e2cp_LDADD = -L@libdir@ -lext2fs -lcom_err
+EXTRA_DIST = README TODO e2tools.spec
+
+install-exec-hook:
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2ln
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2ls
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2mkdir
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2mv
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2rm
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2tail
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..d2b552d
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,346 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = .
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+CC = @CC@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+INCLUDES = -I@includedir@
+
+bin_PROGRAMS = e2cp
+e2cp_SOURCES = copy.c e2tools.c e2tools.h elist.c elist.h ln.c ls.c mkdir.c mv.c progress.c read.c rm.c tail.c util.c write.c
+
+e2cp_LDADD = -L@libdir@ -lext2fs -lcom_err
+EXTRA_DIST = README TODO e2tools.spec
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_CLEAN_FILES =
+PROGRAMS = $(bin_PROGRAMS)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+e2cp_OBJECTS = copy.o e2tools.o elist.o ln.o ls.o mkdir.o mv.o \
+progress.o read.o rm.o tail.o util.o write.o
+e2cp_DEPENDENCIES =
+e2cp_LDFLAGS =
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \
+Makefile.in NEWS TODO aclocal.m4 configure configure.in install-sh \
+missing mkinstalldirs
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+SOURCES = $(e2cp_SOURCES)
+OBJECTS = $(e2cp_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in
+ cd $(srcdir) && $(ACLOCAL)
+
+config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+$(srcdir)/configure: @MAINTAINER_MODE_TRUE@$(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES)
+ cd $(srcdir) && $(AUTOCONF)
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ if test -f $$p; then \
+ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \
+ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ list='$(bin_PROGRAMS)'; for p in $$list; do \
+ rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
+ done
+
+.s.o:
+ $(COMPILE) -c $<
+
+.S.o:
+ $(COMPILE) -c $<
+
+mostlyclean-compile:
+ -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+ -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+e2cp: $(e2cp_OBJECTS) $(e2cp_DEPENDENCIES)
+ @rm -f e2cp
+ $(LINK) $(e2cp_LDFLAGS) $(e2cp_OBJECTS) $(e2cp_LDADD) $(LIBS)
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ here=`pwd` && cd $(srcdir) \
+ && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS)'; \
+ unique=`for i in $$list; do echo $$i; done | \
+ awk ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+ || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ -rm -rf $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz
+ mkdir $(distdir)/=build
+ mkdir $(distdir)/=inst
+ dc_install_base=`cd $(distdir)/=inst && pwd`; \
+ cd $(distdir)/=build \
+ && ../configure --srcdir=.. --prefix=$$dc_install_base \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) dist
+ -rm -rf $(distdir)
+ @banner="$(distdir).tar.gz is ready for distribution"; \
+ dashes=`echo "$$banner" | sed s/./=/g`; \
+ echo "$$dashes"; \
+ echo "$$banner"; \
+ echo "$$dashes"
+dist: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+dist-all: distdir
+ -chmod -R a+r $(distdir)
+ GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir)
+ -rm -rf $(distdir)
+distdir: $(DISTFILES)
+ -rm -rf $(distdir)
+ mkdir $(distdir)
+ -chmod 777 $(distdir)
+ @for file in $(DISTFILES); do \
+ d=$(srcdir); \
+ if test -d $$d/$$file; then \
+ cp -pr $$d/$$file $(distdir)/$$file; \
+ else \
+ test -f $(distdir)/$$file \
+ || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $$d/$$file $(distdir)/$$file || :; \
+ fi; \
+ done
+copy.o: copy.c e2tools.h elist.h
+e2tools.o: e2tools.c e2tools.h
+elist.o: elist.c elist.h
+ln.o: ln.c e2tools.h
+ls.o: ls.c e2tools.h elist.h
+mkdir.o: mkdir.c e2tools.h
+mv.o: mv.c e2tools.h
+progress.o: progress.c
+read.o: read.c e2tools.h
+rm.o: rm.c e2tools.h
+tail.o: tail.c e2tools.h
+util.o: util.c e2tools.h
+write.o: write.c e2tools.h
+
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-binPROGRAMS
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-hook
+install-exec: install-exec-am
+
+install-data-am:
+install-data: install-data-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-binPROGRAMS
+uninstall: uninstall-am
+all-am: Makefile $(PROGRAMS)
+all-redirect: all-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+ $(mkinstalldirs) $(DESTDIR)$(bindir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+ -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am: clean-binPROGRAMS clean-compile clean-tags clean-generic \
+ mostlyclean-am
+
+clean: clean-am
+
+distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \
+ distclean-generic clean-am
+
+distclean: distclean-am
+ -rm -f config.status
+
+maintainer-clean-am: maintainer-clean-binPROGRAMS \
+ maintainer-clean-compile maintainer-clean-tags \
+ maintainer-clean-generic distclean-am
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+ -rm -f config.status
+
+.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \
+maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+.c.o:
+ $(COMPILE) -c $<
+
+install-exec-hook:
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2ln
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2ls
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2mkdir
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2mv
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2rm
+ $(LN_S) -f e2cp $(DESTDIR)$(bindir)/e2tail
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..333bf00
--- /dev/null
+++ b/README
@@ -0,0 +1,282 @@
+E2tools is a simple set of GPL'ed utilities to read, write, and
+manipulate files in an ext2/ext3 filesystem. These utilities access a
+filesystem directly using the ext2fs library. I wrote these tools in order
+to copy files into a linux filesystem on a machine that does not have ext2
+support. Of course, they can also be used on a linux machine to read/write
+to disk images or floppies without having to mount them or have root
+access.
+
+Supported functionality:
+
+copy files: e2cp
+move files: e2mv
+remove files: e2rm
+create directory: e2mkdir
+create hard links: e2ln
+list files/directories: e2ls
+output the last part of a file: e2tail
+
+Requirements:
+
+e2fsprogs-1.27 or later - http://e2fsprogs.sourceforge.net/
+gcc - e2fsprogs will not compile with some proprietary compilers (ie SCO's)
+
+If you have questions, comments, patches, or feature requests, just email
+them to me. I will do my best to respond in a timely manner.
+
+Keith Sheffield <sheff@pobox.com>
+
+
+Quickstart Documentation
+------------------------
+
+In general, to specify a directory or file on an ext2 filesystem for the
+e2tools utilities, use the following form:
+
+ filesystem:directory_path
+
+The filesystem can be an unmounted partition or a regular file that's been
+formatted to contain an ext2 filesystem. In general, if a command takes
+multiple file names on the command line, if the first one contains an ext2
+file specification, the rest of the files are assumed to be on the same
+filesystem until another one is explicitly stated:
+
+/tmp/boot.img:/tmp/file1 /tmp/file2 /tmp/file3 /tmp/boot2.img:/tmp/file4
+
+Files 1-3 are on /tmp/boot.img and the last file is on /tmp/boot2.img
+
+
+e2cp
+-----
+
+This program copies files to/from an e2fs filesystem from/to the machine's
+native filesystem.
+
+Usage:
+
+e2cp [-0apv][-P mode][-O uid][-G gid][-d dest_dir][-s src_dir][file1..N dest]
+
+-0 Input lines terminated by a null character
+-a Absolute directory names - create directories instead of just copying
+ into the destination. Only valid for copying into an ext2fs filesystem
+-d Destination of files to be copied. May be in the ext2fs filesystem or
+ the host filesystem.
+-G Set the default group to gid.
+-O Set the default file owner to uid.
+-p Preserve host file attributes (permissions, times, etc.) when copying
+ files.
+-P Set the file permissions (ie 755, 666).
+-s The source of the files to be copied.
+-v Be verbose.
+
+A - by itself means to use standard input/output
+
+Examples:
+
+Copy a file and use the default permission and ownership of the current user:
+
+e2cp README.txt /tmp/boot.img:/tmp
+
+Do the same thing, but keep permissions & ownership:
+
+e2cp -p README.txt /tmp/boot.img:/tmp
+
+Dump a file to standard out:
+
+e2cp /tmp/boot.img:/tmp/README.txt - | wc
+
+Get a file from standard input and put it on an unmounted partition:
+
+tar cf - /data/logs|gzip| e2cp - /dev/hdb1:/backup/logs.tar.gz
+
+Copy the files from one directory and put them under another directory on
+an unmounted partition, keeping the original paths, permissions & ownership:
+
+find /data -type f |tee filelist | e2cp -apv -d /dev/hdb1:/mirror
+
+Copy files from a directory on an unmounted partition to a local directory
+(Note: this does not recreate the directories in the local filesystem,
+yet). The list of files are read from standard input:
+
+e2cp -pv -s /dev/hdb1:/mirror -d /data2 < filelist
+
+Copy a file to a file system and make the group and ownership root
+
+e2cp -G 0 -O 0 myfile /tmp/boot.img/boot/rootfile
+
+
+e2mv
+----
+
+This program moves or renames files on an ext2fs filesystem.
+
+Usage:
+
+e2mv [-vfs] source1 [... sourceN] destination
+
+-f Force the operation to remove any existing files
+-s Swap names of the two files
+-v Be verbose
+
+Note: The source files must be explicitly stated. It does not use regular
+expressions, yet.
+
+Examples:
+
+Rename a file:
+
+e2cp -v /tmp/boot.img:/boot/grub/grub.conf /boot/grub/grub.conf.old
+
+If /boot/grub/grub.conf.old already exists and is not a directory, this
+will fail. Use -f to force removal.
+
+Move a file to a different directory (/data/processed):
+
+e2cp -v /dev/hdb1:/data/input0.txt /data/processed
+
+To swap the names of two files:
+
+e2cp -vs /tmp/boot.img:/boot/grub/grub.conf /boot/grub/grub.conf.bk
+
+To swap two files and use a new name for the first one:
+
+e2cp -vs boot.img:/boot/grub/grub.conf /boot/grub/grub.c2 /boot/grub/grub.c1
+
+/boot/grub/grub.conf is now /boot/grub/grub.c1
+/boot/grub/grub.c2 is now /boot/grub/grub.conf
+
+
+e2rm
+----
+
+This program removes files and directories on an ext2 filesystem.
+
+Usage:
+
+e2rm [-vr] filesystem:filepath ...fileN
+
+-r Recursively delete files if a directory name is givne
+-v Be verbose
+
+Note: This program expects to have a full ext2 file specification for each
+argument.
+
+Examples:
+
+Remove a file
+
+e2rm -v boot.img:/boot/grub/grub.c1 /boot/grub/grub.c2
+
+Remove a directory and all the files
+
+e2rm -r boot.img:/boot/grub
+
+
+e2mkdir
+-------
+
+This program creates a directory on an ext2 filesystem. It behaves similar
+to 'mkdir -p'.
+
+
+Usage:
+
+e2mkdir [-G gid][-O uid][-P mode][-v] filesystem:directory...dirN
+
+-G Set the default group to gid.
+-O Set the default file owner to uid.
+-P Set the file permissions (ie 755, 666).
+-v Be verbose.
+
+Note: This program expects to have a full ext2 file specification for each
+argument.
+
+Examples:
+
+This creates the directory /boot/grub with on boot.img with the current
+user and group ids:
+
+e2mkdir boot.img:/boot/grub
+
+To override the default ownership and permissions:
+
+e2mkdir -O 100 -P 700 /dev/hdb1:/data/backup
+
+e2ln
+----
+
+This program is used to create hard links on an ext2 filesystem.
+
+Usage:
+
+e2ln [-vsf] source destination
+
+-f Force the operation to remove any existing files
+-s Create a symlink
+-v Be verbose
+
+Note: creating symlinks is not operational at this time.
+
+Examples:
+
+This will remove /data/process_status if it exists and isn't already a hard
+link to /data/info/status.
+
+e2ln -vf /dev/hdb1:/data/info/status /data/process_status
+
+
+e2ls
+----
+
+This program is used to list files and directories on an ext2 filesystem.
+
+Usage:
+
+e2ls [-acDfilrt][-d dir] file_specification
+
+-a Show hidden directories
+-c Sort by creation time (must include -t when using -l)
+-d dir Open the ext2 filesystem specified by dir
+-D Show deleted files bracketed with ><.
+-f No sorting of the file list
+-i Show the inodes (very useful for the -l option)
+-l Long listing
+-r Reverse the sort order
+-t Sort by time
+
+Note: Files deleted via e2rm sometimes will show up even without the -D
+option. It is being investigated.
+
+Examples:
+
+e2ls -a boot.img:.
+e2ls -l /dev/hdb1:/data
+
+
+e2tail
+------
+
+This program implements a basic version of the tail command.
+
+Usage:
+
+e2tail [-n num_lines][-fF][-s sleep_interval] file
+
+-n The number of lines to display
+-f Output appended data as the file grows. This is inode dependent, so if
+ the file is renamed, it will keep checking it.
+-F Output appended data as the file grows. This is file name dependent,
+ so if the file is renamed, it will check on any new files with the same
+ name as the original. This is useful for watching log files that may
+ be rotated out occasionally. This was requested by a person in the
+ computer security field for monitoring 'honeypot' type machines.
+-s The number of seconds to sleep before checking if the file has grown
+ while in 'follow' mode. The default is 1.
+
+
+Examples:
+
+Check /var/log/messages on /dev/sdc1 every 10 seconds
+
+e2tail -s 10 -F /dev/sdc1:/var/log/messages
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..f4e3a63
--- /dev/null
+++ b/TODO
@@ -0,0 +1,8 @@
+Create user documentation
+htree and extended attribute support
+automated test suite
+Add e2rm with regular expressions
+Make copy aware of symbolic links
+Add comments
+Add e2mknod
+Add e2test
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..bd342b7
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,137 @@
+dnl aclocal.m4 generated automatically by aclocal 1.2d
+
+dnl Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+dnl This Makefile.in is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# Do all the work for Automake. This macro actually does too much --
+# some checks are only needed if your package does certain things.
+# But this isn't really a big deal.
+
+# serial 1
+
+dnl Usage:
+dnl AM_INIT_AUTOMAKE(package,version, [no-define])
+
+AC_DEFUN(AM_INIT_AUTOMAKE,
+[AC_REQUIRE([AC_PROG_INSTALL])
+PACKAGE=[$1]
+AC_SUBST(PACKAGE)
+VERSION=[$2]
+AC_SUBST(VERSION)
+dnl test to see if srcdir already configured
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+fi
+ifelse([$3],,
+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package]))
+AC_REQUIRE([AM_SANITY_CHECK])
+AC_REQUIRE([AC_ARG_PROGRAM])
+dnl FIXME This is truly gross.
+missing_dir=`cd $ac_aux_dir && pwd`
+AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
+AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
+AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
+AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
+AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
+AC_REQUIRE([AC_PROG_MAKE_SET])])
+
+#
+# Check to make sure that the build environment is sane.
+#
+
+AC_DEFUN(AM_SANITY_CHECK,
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+ if test "[$]*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftestfile`
+ fi
+ if test "[$]*" != "X $srcdir/configure conftestfile" \
+ && test "[$]*" != "X conftestfile $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "[$]2" = conftestfile
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+rm -f conftest*
+AC_MSG_RESULT(yes)])
+
+dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY)
+dnl The program must properly implement --version.
+AC_DEFUN(AM_MISSING_PROG,
+[AC_MSG_CHECKING(for working $2)
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if ($2 --version) < /dev/null > /dev/null 2>&1; then
+ $1=$2
+ AC_MSG_RESULT(found)
+else
+ $1="$3/missing $2"
+ AC_MSG_RESULT(missing)
+fi
+AC_SUBST($1)])
+
+# Add --enable-maintainer-mode option to configure.
+# From Jim Meyering
+
+# serial 1
+
+AC_DEFUN(AM_MAINTAINER_MODE,
+[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode is disabled by default
+ AC_ARG_ENABLE(maintainer-mode,
+[ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ USE_MAINTAINER_MODE=$enableval,
+ USE_MAINTAINER_MODE=no)
+ AC_MSG_RESULT($USE_MAINTAINER_MODE)
+ AM_CONDITIONAL(MAINTAINER_MODE, test $USE_MAINTAINER_MODE = yes)
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST(MAINT)dnl
+]
+)
+
+# Define a conditional.
+
+AC_DEFUN(AM_CONDITIONAL,
+[AC_SUBST($1_TRUE)
+AC_SUBST($1_FALSE)
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi])
+
diff --git a/configure b/configure
new file mode 100755
index 0000000..9e50cb0
--- /dev/null
+++ b/configure
@@ -0,0 +1,2185 @@
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=e2tools.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:559: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
+echo "configure:612: checking whether build environment is sane" >&5
+# Just in case
+sleep 1
+echo timestamp > conftestfile
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftestfile`
+ fi
+ if test "$*" != "X $srcdir/configure conftestfile" \
+ && test "$*" != "X conftestfile $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ { echo "configure: error: ls -t appears to fail. Make sure there is not a broken
+alias in your environment" 1>&2; exit 1; }
+ fi
+
+ test "$2" = conftestfile
+ )
+then
+ # Ok.
+ :
+else
+ { echo "configure: error: newly created file is older than distributed files!
+Check your system clock" 1>&2; exit 1; }
+fi
+rm -f conftest*
+echo "$ac_t""yes" 1>&6
+if test "$program_transform_name" = s,x,x,; then
+ program_transform_name=
+else
+ # Double any \ or $. echo might interpret backslashes.
+ cat <<\EOF_SED > conftestsed
+s,\\,\\\\,g; s,\$,$$,g
+EOF_SED
+ program_transform_name="`echo $program_transform_name|sed -f conftestsed`"
+ rm -f conftestsed
+fi
+test "$program_prefix" != NONE &&
+ program_transform_name="s,^,${program_prefix},; $program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s,\$\$,${program_suffix},; $program_transform_name"
+
+# sed with no file args requires a program.
+test "$program_transform_name" = "" && program_transform_name="s,x,x,"
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:669: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+PACKAGE=e2tools
+
+VERSION=0.0.16
+
+if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then
+ { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; }
+fi
+cat >> confdefs.h <<EOF
+#define PACKAGE "$PACKAGE"
+EOF
+
+cat >> confdefs.h <<EOF
+#define VERSION "$VERSION"
+EOF
+
+
+
+missing_dir=`cd $ac_aux_dir && pwd`
+echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
+echo "configure:715: checking for working aclocal" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (aclocal --version) < /dev/null > /dev/null 2>&1; then
+ ACLOCAL=aclocal
+ echo "$ac_t""found" 1>&6
+else
+ ACLOCAL="$missing_dir/missing aclocal"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
+echo "configure:728: checking for working autoconf" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (autoconf --version) < /dev/null > /dev/null 2>&1; then
+ AUTOCONF=autoconf
+ echo "$ac_t""found" 1>&6
+else
+ AUTOCONF="$missing_dir/missing autoconf"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working automake""... $ac_c" 1>&6
+echo "configure:741: checking for working automake" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (automake --version) < /dev/null > /dev/null 2>&1; then
+ AUTOMAKE=automake
+ echo "$ac_t""found" 1>&6
+else
+ AUTOMAKE="$missing_dir/missing automake"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
+echo "configure:754: checking for working autoheader" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (autoheader --version) < /dev/null > /dev/null 2>&1; then
+ AUTOHEADER=autoheader
+ echo "$ac_t""found" 1>&6
+else
+ AUTOHEADER="$missing_dir/missing autoheader"
+ echo "$ac_t""missing" 1>&6
+fi
+
+echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
+echo "configure:767: checking for working makeinfo" >&5
+# Run test in a subshell; some versions of sh will print an error if
+# an executable is not found, even if stderr is redirected.
+# Redirect stdin to placate older versions of autoconf. Sigh.
+if (makeinfo --version) < /dev/null > /dev/null 2>&1; then
+ MAKEINFO=makeinfo
+ echo "$ac_t""found" 1>&6
+else
+ MAKEINFO="$missing_dir/missing makeinfo"
+ echo "$ac_t""missing" 1>&6
+fi
+
+
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:784: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:814: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:865: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
+ esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:897: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 908 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:939: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:944: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:953: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:972: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1015: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1068: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+ rm -f conftestdata
+ ac_cv_prog_LN_S="ln -s"
+else
+ ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+ echo "$ac_t""yes" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1089: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
+echo "configure:1116: checking whether to enable maintainer-specific portions of Makefiles" >&5
+ # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then
+ enableval="$enable_maintainer_mode"
+ USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ echo "$ac_t""$USE_MAINTAINER_MODE" 1>&6
+
+
+if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1142: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1157 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1163: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1174 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1180: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1191 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1197: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1222: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1227 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1235: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1252 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1270 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1291 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1302: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in errno.h fcntl.h sys/time.h unistd.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1329: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1334 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1339: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for working const""... $ac_c" 1>&6
+echo "configure:1367: checking for working const" >&5
+if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1372 "configure"
+#include "confdefs.h"
+
+int main() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero = {0,0};
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if { (eval echo configure:1421: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_c_const" 1>&6
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+echo $ac_n "checking for mode_t""... $ac_c" 1>&6
+echo "configure:1442: checking for mode_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1447 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_mode_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_mode_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_mode_t" 1>&6
+if test $ac_cv_type_mode_t = no; then
+ cat >> confdefs.h <<\EOF
+#define mode_t int
+EOF
+
+fi
+
+echo $ac_n "checking for off_t""... $ac_c" 1>&6
+echo "configure:1475: checking for off_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1480 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_off_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_off_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_off_t" 1>&6
+if test $ac_cv_type_off_t = no; then
+ cat >> confdefs.h <<\EOF
+#define off_t long
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1508: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1513 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1522: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
+echo "configure:1543: checking whether struct tm is in sys/time.h or time.h" >&5
+if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1548 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <time.h>
+int main() {
+struct tm *tp; tp->tm_sec;
+; return 0; }
+EOF
+if { (eval echo configure:1556: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_struct_tm=time.h
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_struct_tm" 1>&6
+if test $ac_cv_struct_tm = sys/time.h; then
+ cat >> confdefs.h <<\EOF
+#define TM_IN_SYS_TIME 1
+EOF
+
+fi
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments. Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
+echo "configure:1580: checking for working alloca.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1585 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if { (eval echo configure:1592: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_header_alloca_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
+if test $ac_cv_header_alloca_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&6
+echo "configure:1613: checking for alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1618 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# ifdef _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+int main() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if { (eval echo configure:1646: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ ac_cv_func_alloca_works=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_func_alloca_works=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
+if test $ac_cv_func_alloca_works = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca_works = no; then
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+ # that cause trouble. Some versions do not even contain alloca or
+ # contain a buggy version. If you still want to use their alloca,
+ # use ar to extract alloca.o from them instead of compiling alloca.c.
+ ALLOCA=alloca.${ac_objext}
+ cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
+echo "configure:1678: checking whether alloca needs Cray hooks" >&5
+if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1683 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "webecray" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_os_cray=yes
+else
+ rm -rf conftest*
+ ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_os_cray" 1>&6
+if test $ac_cv_os_cray = yes; then
+for ac_func in _getb67 GETB67 getb67; do
+ echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1708: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1713 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1736: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<EOF
+#define CRAY_STACKSEG_END $ac_func
+EOF
+
+ break
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+done
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
+echo "configure:1763: checking stack direction for C alloca" >&5
+if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_stack_direction=0
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1771 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+ exit (find_stack_direction() < 0);
+}
+EOF
+if { (eval echo configure:1790: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_c_stack_direction=1
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_c_stack_direction=-1
+fi
+rm -fr conftest*
+fi
+
+fi
+
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+echo $ac_n "checking whether utime accepts a null argument""... $ac_c" 1>&6
+echo "configure:1812: checking whether utime accepts a null argument" >&5
+if eval "test \"`echo '$''{'ac_cv_func_utime_null'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ rm -f conftestdata; > conftestdata
+# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong.
+if test "$cross_compiling" = yes; then
+ ac_cv_func_utime_null=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1822 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+main() {
+struct stat s, t;
+exit(!(stat ("conftestdata", &s) == 0 && utime("conftestdata", (long *)0) == 0
+&& stat("conftestdata", &t) == 0 && t.st_mtime >= s.st_mtime
+&& t.st_mtime - s.st_mtime < 120));
+}
+EOF
+if { (eval echo configure:1833: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+ ac_cv_func_utime_null=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_func_utime_null=no
+fi
+rm -fr conftest*
+fi
+
+rm -f core core.* *.core
+fi
+
+echo "$ac_t""$ac_cv_func_utime_null" 1>&6
+if test $ac_cv_func_utime_null = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_UTIME_NULL 1
+EOF
+
+fi
+
+for ac_func in gettimeofday regcomp strdup strtol
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1859: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1864 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1887: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+cat > conftest.defs <<\EOF
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
+s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
+s%\[%\\&%g
+s%\]%\\&%g
+s%\$%$$%g
+EOF
+DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
+rm -f conftest.defs
+
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@PACKAGE@%$PACKAGE%g
+s%@VERSION@%$VERSION%g
+s%@ACLOCAL@%$ACLOCAL%g
+s%@AUTOCONF@%$AUTOCONF%g
+s%@AUTOMAKE@%$AUTOMAKE%g
+s%@AUTOHEADER@%$AUTOHEADER%g
+s%@MAKEINFO@%$MAKEINFO%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CC@%$CC%g
+s%@LN_S@%$LN_S%g
+s%@MAINTAINER_MODE_TRUE@%$MAINTAINER_MODE_TRUE%g
+s%@MAINTAINER_MODE_FALSE@%$MAINTAINER_MODE_FALSE%g
+s%@MAINT@%$MAINT%g
+s%@CPP@%$CPP%g
+s%@ALLOCA@%$ALLOCA%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..366a0bf
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,31 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(e2tools.c)
+AM_INIT_AUTOMAKE(e2tools, 0.0.16)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AM_MAINTAINER_MODE
+
+dnl Checks for libraries.
+
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(errno.h fcntl.h sys/time.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_MODE_T
+AC_TYPE_OFF_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+dnl Checks for library functions.
+AC_FUNC_ALLOCA
+AC_FUNC_UTIME_NULL
+AC_CHECK_FUNCS(gettimeofday regcomp strdup strtol)
+
+AC_OUTPUT(Makefile)
diff --git a/copy.c b/copy.c
new file mode 100644
index 0000000..40522f4
--- /dev/null
+++ b/copy.c
@@ -0,0 +1,1202 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/copy.c,v 0.16 2004/04/07 01:15:20 ksheff Exp $ */
+/*
+ * copy.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ */
+
+#ifndef COPY_C
+#define COPY_C
+#endif
+
+/* Description */
+/*
+ * This module contains functions used to copy files to and from an ext2fs
+ * filesystem
+ *
+ */
+/*
+ * $Log: copy.c,v $
+ * Revision 0.16 2004/04/07 01:15:20 ksheff
+ * Modified to pass the default file stat to put_file() so the user may alter
+ * the owner, group, or permissions of a file copied to an ext2fs file system.
+ *
+ * Revision 0.15 2004/04/07 00:13:38 ksheff
+ * Corrected behavior when the argument to -d is a local filesystem.
+ *
+ * Revision 0.14 2004/04/06 23:26:37 ksheff
+ * Updated the usage string.
+ *
+ * Revision 0.13 2002/07/09 06:43:19 ksheff
+ * compensated for blank dest_dir.
+ *
+ * Revision 0.12 2002/07/09 06:31:41 ksheff
+ * Forgot to remove debugging printfs.
+ *
+ * Revision 0.11 2002/07/09 02:36:51 ksheff
+ * Verbose was not always reporting the correct output destination - fixed.
+ *
+ * Revision 0.10 2002/06/26 11:13:46 ksheff
+ * Added a call to init_progress() before any copy operation if the verbose
+ * flag is set.
+ *
+ * Revision 0.9 2002/06/19 00:52:00 ksheff
+ * Fixed read from stdin to filesystem.
+ *
+ * Revision 0.8 2002/05/22 03:00:39 ksheff
+ * Fixed the search order bug in find_link().
+ *
+ * Revision 0.7 2002/05/06 06:37:50 ksheff
+ * Fixed a bug where if the destination filespec was just localpath:, the file
+ * would not be copied to the root directory.
+ *
+ * Revision 0.6 2002/05/02 07:15:49 ksheff
+ * Fixed a bug that was causing a file to be copied to the home directory if
+ * the destination file already existed.
+ *
+ * Revision 0.5 2002/04/10 09:29:40 ksheff
+ * Added the ability to set or keep the ownership, group, and permissions for
+ * directories being created.
+ *
+ * Revision 0.4 2002/03/07 07:16:16 ksheff
+ * Modified to copy hard links to an ext2fs system correctly.
+ *
+ * Revision 0.3 2002/02/27 13:34:16 ksheff
+ * Added a directory check for file names read from stdin and copied to an
+ * ext2fs.
+ *
+ * Revision 0.2 2002/02/27 05:05:45 ksheff
+ * Removed unnecessary printf
+ *
+ * Revision 0.1 2002/02/27 04:46:46 ksheff
+ * initial revision
+ *
+ */
+
+/* Feature Test Switches */
+/* Headers */
+
+#include "e2tools.h"
+#include "elist.h"
+
+/* Macros */
+#define USAGE "Usage: e2cp [-0apv][-P mode][-O uid][-G gid][-d dest_dir][-s src_dir][file1...N dest]\n"
+#define BUF_SIZE 8192
+
+#ifdef isspace
+#define ISSPACE(c) isspace(c)
+#else
+#define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' \
+ || (c) == '\f' || (c) == '\v')
+#endif
+
+/* Structures and Unions */
+typedef enum {NONE, HOST_FS, EXT2_FS} FS_CAT_T;
+typedef struct
+{
+ dev_t dev_no;
+ ino_t ino_no;
+ ext2_ino_t new_ino;
+} INODE_XREF_T;
+
+/* Local Variables */
+
+elist_t *link_list = NULL;
+static char cur_out_dir[BUF_SIZE];
+
+/* External Prototypes */
+
+extern void init_progress(char *file, struct stat *sbuf);
+
+/* Local Prototypes */
+
+long
+copy(int argc, char *argv[]);
+long
+open_destination(char **dest_dir, char **cur_filesys, ext2_filsys *fs,
+ ext2_ino_t *root, ext2_ino_t *cwd, char *outfile,
+ int *absolute, FS_CAT_T *dst_cat, int *allow_non_dir,
+ struct stat *def_stat);
+long
+copy_files(int num_files, char **cur_file_names, char *dest_dir, char *dest_fs,
+ ext2_filsys *fs, ext2_ino_t *root, ext2_ino_t orig_cwd,
+ char *outpath, char *out_file, int max_file_len,
+ FS_CAT_T src_category, FS_CAT_T dst_category, int absolute,
+ int keep, int file_to_file, int verbose, struct stat *def_stat);
+static char *
+diag_output_name(char *odir, int file_to_file, char *ofile);
+
+long
+dir_changed(char *newdir, ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ ext2_ino_t *newcwd, struct stat *def_stat, char *dest_dir);
+int
+read_line(char *inbuf);
+int
+read_string(char *inbuf);
+
+int
+my_strcmp(const void *n1, const void *n2);
+
+INODE_XREF_T *
+find_link(struct stat *sbuf);
+long
+add_link(struct stat *sbuf, ext2_ino_t newfile);
+static long
+cp_to_ext2fs(ext2_filsys fs, ext2_ino_t cwd, char *in_file, char *out_file,
+ struct stat *statbuf, int keep, struct stat *def_stat);
+
+
+/* Name: copy()
+ *
+ * Description:
+ *
+ * This function will copy one or more files from a host filesystem to a
+ * ext2fs filesystem and vice versa. The files to be copied are presented
+ * as command line arguments or are read from standard input. The files are
+ * in the form:
+ *
+ * host filesystem: /this/is/a/file
+ * ext2fs filesystem: filesystem_path:/this/is/another/file
+ *
+ * The - character represents stdin/stdout. The meaning will vary depending if
+ * it used as a source of destination.
+ *
+ * Where filesystem_path represents where the ext2fs is located in the
+ * host or local filesystem. This can be a regular file containing a
+ * or block device formatted with ext2fs tools.
+ *
+ * The parameters are:
+ *
+ * -0 Input lines terminated by a null character
+ * -a Absolute directory names - create directories instead of just
+ * copying into the destination. Only valid for copying into an
+ * ext2fs filesystem
+ * -d Destination of files to be copied. May be in the ext2fs filesystem
+ * or the host filesystem
+ * -p Preserve host file attributes (permissions, times, etc.) when
+ * copying files.
+ * -s The source of the files to be copied.
+ * -v Be verbose.
+ *
+ *
+ * Algorithm:
+ *
+ * Parse the command line for flags and special parameters
+ * If there are any parameters left, they are the files to be copied
+ * If no -s or -d parameters have been processed
+ * Retrieve the last parameter which is the destination
+ * If the destination is a ext2fs file specificiation
+ * Open the filesystem with write capability
+ * Test to make sure that is a directory and not a file
+ * Sort the names of the files to be copied.
+ * For each file
+ * If it is an ext2fs file specification
+ * Check to see if it is the same as the last ext2fs spec
+ * If not, close the prior ext2fs and open the new one
+ * If the source and destination files are of the same type
+ * Print a warning message and continue
+ * Copy the file
+ * Otherwise, no parameters are left, file list is on stdin
+ * For each line of input
+ * If the -0 is not given, strip whitespace off the end
+ * If the -a option is given
+ * determine the dirname of the file
+ * Compare the directory to the last directory processed
+ * If different
+ * Make a new directory
+ * Copy the file
+ * Close any open ext2fs filesystems
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * int argc; The number of arguments
+ * char *argv[]; The command line arguments
+ *
+ * Return Values:
+ *
+ * 0 - everything copied successfully
+ * the error code of what went wrong
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/20/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 02/27/02 K. Sheffield Added directory check for file names being
+ * read from stdin and copied to an ext2fs.
+ *
+ * 03/06/02 K. Sheffield Copying hard links to ext2fs correctly
+ */
+long
+copy(int argc, char *argv[])
+{
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ ext2_ino_t orig_cwd;
+ ext2_ino_t cwd;
+ char tmpbuf[BUF_SIZE];
+ char outpath[BUF_SIZE];
+ char *last_filesys = NULL;
+ char *cur_filesys = NULL;
+ int retval;
+ int c;
+ char *src_dir = NULL;
+ char *dest_dir = NULL;
+ char *in_file = NULL;
+ char *out_file = NULL;
+ int max_out_len;
+ int keep = 0;
+ int absolute = 0;
+ int verbose = 0;
+ FS_CAT_T src_category = NONE;
+ FS_CAT_T dst_category = NONE;
+ char **cur_file_name;
+ int (*read_input)(char *buf) = read_line;
+ int errcnt = 0;
+ int num_files;
+ char *ptr;
+ int non_directory = 0;
+ struct stat statbuf;
+ struct stat def_stat;
+ INODE_XREF_T *xref;
+ int tmp_val;
+
+ init_stat_buf(&def_stat);
+
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt(argc, argv, "0ad:G:O:pP:s:v")) != EOF)
+ {
+ switch (c)
+ {
+ case '0':
+ read_input = read_string;
+ break;
+ case 'a':
+ absolute = 1;
+ break;
+ case 'd':
+ dest_dir = optarg;
+ break;
+ case 'G':
+ def_stat.st_gid = atoi(optarg);
+ def_stat.st_ino = 1;
+ break;
+ case 'O':
+ def_stat.st_uid = atoi(optarg);
+ def_stat.st_ino = 1;
+ break;
+ case 'P':
+ def_stat.st_mode = strtol(optarg, NULL, 8);
+ def_stat.st_ino = 1;
+ break;
+ case 'p':
+ keep = 1;
+ def_stat.st_ino = 1;
+ break;
+ case 's':
+ src_dir = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ errcnt++;
+ break;
+ }
+ }
+
+ if (errcnt)
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+
+ /* if the source directory has been specified, go to it */
+ if (src_dir != NULL)
+ {
+ /* check to see if the destination directory is an ext2fs */
+ if (NULL != (ptr = strchr(src_dir, ':')))
+ {
+ *ptr++ = '\0';
+ cur_filesys = src_dir;
+ src_dir = ptr;
+ src_category = EXT2_FS;
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 0)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+ orig_cwd = root;
+ cwd = root;
+
+ if ((*src_dir != '\0' &&
+ strcmp(src_dir, ".") != 0 &&
+ strcmp(src_dir, "/") != 0) &&
+ (retval = change_cwd(fs, root, &cwd, src_dir)))
+ {
+ fprintf(stderr, "Error changing to input directory %s\n",
+ src_dir);
+ return(-1);
+ }
+
+ src_category = EXT2_FS;
+ }
+ else
+ { /* deal with a normal host directory */
+ if (chdir(src_dir))
+ {
+ perror(src_dir);
+ fprintf(stderr, "Error changing to input directory %s\n",
+ src_dir);
+ return(-1);
+ }
+ src_category = HOST_FS;
+ }
+ /* get rid of any trailing /'s */
+ tmp_val = strlen(src_dir) - 1;
+ if (src_dir[tmp_val] == '/')
+ src_dir[tmp_val] = '\0';
+
+ }
+
+ /* open the destination directory */
+ if (dest_dir != NULL)
+ {
+ non_directory = 0;
+ if ((retval = open_destination(&dest_dir, &cur_filesys, &fs, &root,
+ &cwd, outpath, &absolute, &dst_category,
+ &non_directory, &def_stat)))
+ {
+ fprintf(stderr, "Error opening destination %s:%s\n", cur_filesys,
+ dest_dir);
+ if (fs)
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ orig_cwd = cwd;
+ max_out_len = strlen(outpath);
+ out_file = outpath + max_out_len;
+ if (max_out_len > 0)
+ {
+ max_out_len++;
+ *out_file++ = '/';
+ }
+
+ max_out_len = BUF_SIZE - max_out_len - 1;
+ }
+
+ if (src_category != NONE && src_category == dst_category)
+ {
+ fputs("The source and destination must be native and ext2fs\n", stderr);
+ if (fs)
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* copy any remaining files */
+ if (argc > optind)
+ {
+ num_files = argc - optind;
+ if (dest_dir == NULL)
+ {
+ dest_dir = argv[optind + (--num_files)];
+ if (num_files < 1)
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+ non_directory = (num_files == 1);
+ if ((retval = open_destination(&dest_dir, &cur_filesys, &fs, &root,
+ &cwd, outpath, &absolute,
+ &dst_category, &non_directory,
+ &def_stat)))
+ {
+ fprintf(stderr, "Error opening destination %s:%s\n", cur_filesys,
+ dest_dir);
+ if (fs)
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ orig_cwd = cwd;
+ max_out_len = strlen(outpath);
+ out_file = outpath + max_out_len;
+ if (max_out_len > 0 && non_directory == 0)
+ {
+ max_out_len++;
+ *out_file++ = '/';
+ }
+ max_out_len = BUF_SIZE - max_out_len - 1;
+ } /* src_dir & dest_dir == NULL? */
+
+ if (num_files > 1 && dest_dir != NULL)
+ qsort(argv+optind, num_files, sizeof(char *), my_strcmp);
+
+ cur_file_name = argv + optind;
+
+ if ((retval = copy_files(num_files, cur_file_name, dest_dir, cur_filesys,
+ &fs, &root, orig_cwd, outpath, out_file,
+ max_out_len, src_category, dst_category,
+ absolute, keep, non_directory, verbose,
+ &def_stat)))
+ {
+ fputs("Error encountered copying files\n", stderr);
+ if (fs)
+ ext2fs_close(fs);
+ return(-1);
+ }
+ }
+ else
+ {
+ /******************************************************************/
+ /* read from standard input */
+ /******************************************************************/
+
+ if (src_dir == NULL && dest_dir == NULL)
+ {
+ fputs("No input source or destination selected\n", stderr);
+ if (fs)
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ if (dest_dir == NULL && dst_category == NONE)
+ {
+ dest_dir = outpath;
+ out_file = outpath;
+ max_out_len = BUF_SIZE - 1;
+ }
+
+ if (dst_category == EXT2_FS)
+ {
+ strncpy(cur_out_dir, (dest_dir) ? dest_dir : ".", BUF_SIZE);
+ cur_out_dir[BUF_SIZE-1] = '\0';
+ }
+
+ while (-1 != (c = (read_input)(tmpbuf)))
+ {
+ if (c < 1)
+ continue;
+
+ in_file = tmpbuf;
+
+ if (verbose)
+ init_progress(in_file, &statbuf);
+
+ if (dst_category == EXT2_FS)
+ {
+ if (stat(in_file, &statbuf) != 0)
+ {
+ perror(in_file);
+ continue;
+ }
+
+ if (S_ISDIR(statbuf.st_mode))
+ {
+ if (absolute &&
+ (retval = dir_changed(in_file, fs, root,
+ orig_cwd, &cwd,
+ (keep)?&statbuf:&def_stat,
+ dest_dir)))
+ {
+ fprintf(stderr,"Error creating output directory %s\n",
+ dest_dir);
+ if (fs)
+ ext2fs_close(fs);
+ return(-1);
+ }
+ continue;
+ }
+
+ /* can't handle anything other than regular files right now */
+ if (!S_ISREG(statbuf.st_mode))
+ continue;
+
+
+ if (NULL != (ptr = strrchr(in_file, '/')))
+ {
+ *ptr = '\0';
+
+ if (absolute &&
+ (retval = dir_changed(in_file, fs, root, orig_cwd,
+ &cwd, &def_stat, dest_dir)))
+ {
+ fprintf(stderr,"Error creating output directory %s\n",
+ dest_dir);
+ if (fs)
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ *ptr = '/';
+ out_file = ptr + 1;
+ } /* partial path included ? */
+ else
+ {
+ cwd = orig_cwd;
+ out_file = in_file;
+ }
+
+ if (statbuf.st_nlink > 1)
+ {
+ if (NULL != (xref = find_link(&statbuf)))
+ {
+ if ((retval = create_hard_link(fs, cwd, xref->new_ino,
+ out_file, E2T_FORCE)))
+ {
+ fprintf(stderr, "Error creating link for %s/%s\n",
+ cur_out_dir, out_file);
+ if (fs)
+ ext2fs_close(fs);
+ elist_free(link_list, free);
+ return(1);
+ }
+ if (verbose)
+ fprintf(stderr, "Copied %s to %s:%s\n", in_file,
+ cur_filesys, cur_out_dir);
+ continue;
+ }
+ }
+ if ((retval = cp_to_ext2fs(fs, cwd, in_file, out_file,
+ &statbuf, keep, &def_stat)))
+ {
+ fprintf(stderr, "Error copying file %s to %s:%s\n",
+ in_file, cur_filesys, dest_dir);
+ if (fs)
+ ext2fs_close(fs);
+ return retval;
+ }
+ if (verbose)
+ fprintf(stderr, "Copied %s to %s:%s\n", in_file, cur_filesys,
+ cur_out_dir);
+
+ }
+ else
+ { /* copy to the local file system */
+
+ /* get the basename of the file */
+ if (NULL != (ptr = strrchr(in_file, '/')))
+ ++ptr;
+ else
+ ptr = in_file;
+
+ if (dest_dir != NULL)
+ {
+ /* create output file name */
+ strncpy(out_file, ptr, max_out_len);
+ outpath[BUF_SIZE-1] = '\0';
+ }
+
+ if ((retval = get_file(fs, root, cwd, in_file,
+ (dest_dir == NULL) ? NULL:outpath, keep)))
+ {
+ fprintf(stderr, "Error copying file %s to %s\n",
+ in_file, outpath);
+ if (fs)
+ ext2fs_close(fs);
+ return retval;
+ }
+
+ if (verbose)
+ fprintf(stderr, "Copied %s:%s/%s to %s\n", cur_filesys,
+ src_dir, in_file,
+ (dest_dir == NULL) ? outpath : dest_dir);
+ }
+
+ }
+ }
+
+ if (fs)
+ ext2fs_close(fs);
+
+ return(0);
+} /* end of copy */
+
+long
+open_destination(char **dest_dir, char **cur_filesys, ext2_filsys *fs,
+ ext2_ino_t *root, ext2_ino_t *cwd, char *outfile,
+ int *absolute, FS_CAT_T *dst_cat, int *allow_non_dir,
+ struct stat *def_stat)
+{
+ char *ptr;
+ struct stat statbuf;
+ char *dptr;
+ int retval;
+ ext2_ino_t inode;
+ int new_dir = 1;
+
+ if (dest_dir == NULL || cur_filesys == NULL || fs == NULL || root == NULL ||
+ cwd == NULL || outfile == NULL)
+ {
+ fputs("Invalid parameters\n", stderr);
+ return(-1);
+ }
+
+ dptr = *dest_dir;
+ *outfile = '\0';
+
+ /* check to see if the destination directory is an ext2fs */
+ if (NULL != (ptr = strchr(dptr, ':')))
+ {
+ if (*fs != NULL)
+ {
+ fputs("An Ext2fs filesystem is already open!", stderr);
+ return(-1);
+ }
+
+ *ptr++ = '\0';
+ *cur_filesys = dptr;
+ dptr = ptr;
+ *dst_cat = EXT2_FS;
+ if ((retval = open_filesystem(*cur_filesys, fs, root, 1)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+
+ *cwd = *root;
+
+ if ((*dptr != '\0' &&
+ strcmp(dptr, ".") != 0 &&
+ strcmp(dptr, "/") != 0))
+ {
+
+ if (*allow_non_dir == 1)
+ {
+ ptr = NULL;
+ new_dir = 0;
+ /* check to see if it exists */
+ if ((retval = ext2fs_namei(*fs, *root, *cwd, dptr, &inode)) ||
+ (retval = ext2fs_check_directory(*fs, inode)))
+ {
+ if ((retval != EXT2_ET_FILE_NOT_FOUND) &&
+ (retval != EXT2_ET_NO_DIRECTORY))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return(retval);
+ }
+
+ /* ok, so it doesn't exist or isn't a directory
+ *...let's see if it's parent does
+ */
+ if (NULL != (ptr = strrchr(dptr, '/')))
+ {
+ *ptr = '\0';
+ if (ptr[1] == '\0')
+ *allow_non_dir = 0;
+ new_dir = 1;
+
+ if ((retval = ext2fs_namei(*fs, *root, *cwd, dptr,
+ &inode)))
+ {
+ if (retval != EXT2_ET_FILE_NOT_FOUND)
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return(retval);
+ }
+ /* it doesn't exist either */
+ }
+ else
+ {
+ if ((retval = ext2fs_check_directory(*fs, inode)))
+ {
+ /* ok, it exists, but it's not a directory... */
+ fprintf(stderr, "%s\n", error_message(retval));
+ return(retval);
+ }
+ *cwd = inode;
+ new_dir = 0;
+ }
+ }
+ }
+ else
+ {
+ /* ok, the directory exists */
+ *cwd = inode;
+ *allow_non_dir = 0;
+ }
+ }
+
+ if (new_dir == 1 &&
+ (retval = create_dir(*fs, *root, cwd, dptr, def_stat)))
+ {
+ fprintf(stderr, "Error creating output directory %s\n",
+ dptr);
+ return(-1);
+ }
+ /* see if we need to copy the file into the output path */
+ if (*allow_non_dir == 1)
+ {
+ strncpy(outfile, (ptr != NULL) ? ++ptr : dptr, BUF_SIZE);
+ outfile[BUF_SIZE-1] = '\0';
+ }
+ }
+ else
+ {
+ if (*allow_non_dir == 1)
+ {
+ *allow_non_dir = 0;
+ dptr = NULL;
+ }
+ }
+ }
+ else
+ { /* deal with a normal host directory */
+ *absolute = 0;
+ if (strcmp(dptr, "-") == 0)
+ dptr = NULL;
+ else
+ {
+ strncpy(outfile, dptr, BUF_SIZE);
+ outfile[BUF_SIZE-1] = '\0';
+
+ if (0 > stat(outfile, &statbuf) ||
+ !S_ISDIR(statbuf.st_mode))
+ {
+ if (*allow_non_dir == 0)
+ {
+ fprintf(stderr, "%s is not a directory!\n", outfile);
+ return(-1);
+ }
+ }
+ else
+ *allow_non_dir = 0;
+ }
+
+ *dst_cat = HOST_FS;
+ }
+ *dest_dir = dptr;
+ return(0);
+}
+
+long
+copy_files(int num_files, char **cur_file_names, char *dest_dir, char *dest_fs,
+ ext2_filsys *fs, ext2_ino_t *root, ext2_ino_t orig_cwd,
+ char *outpath, char *out_file, int max_file_len,
+ FS_CAT_T src_category, FS_CAT_T dst_category, int absolute,
+ int keep, int file_to_file, int verbose, struct stat *def_stat)
+{
+ char *in_file;
+ char *dst_file;
+ char *ptr;
+ char *last_filesys = NULL;
+ char *cur_filesys = dest_fs;
+ ext2_ino_t cwd = orig_cwd;
+ int retval;
+ int i;
+ struct stat statbuf;
+ INODE_XREF_T *xref;
+
+ strncpy(cur_out_dir, (dest_dir) ? dest_dir : ".", BUF_SIZE);
+ cur_out_dir[BUF_SIZE-1] = '\0';
+
+ for(i=0;i<num_files;i++)
+ {
+ in_file = *cur_file_names++;
+
+ if (verbose)
+ init_progress(in_file, &statbuf);
+ /* dealing with a filesystem or a regular file */
+ if (NULL != (ptr = strchr(in_file, ':')))
+ {
+ if (dst_category == EXT2_FS)
+ {
+ fputs("Already copying to an ext2fs!\n", stderr);
+ return(-1);
+ }
+ if (src_category == EXT2_FS)
+ {
+ fputs("The source is already an ext2fs!\n", stderr);
+ return(-1);
+ }
+
+ /* separate the filesystem name from the file name */
+ *ptr++ = '\0';
+ cur_filesys = in_file;
+ in_file = ptr;
+
+ if (dest_dir != NULL)
+ {
+ if (!file_to_file)
+ {
+ /* get the basename of the file */
+ if (NULL != (ptr = strrchr(in_file, '/')))
+ ++ptr;
+ else
+ ptr = in_file;
+
+ /* create output file name */
+ strncpy(out_file, ptr, max_file_len);
+ outpath[BUF_SIZE-1] = '\0';
+ }
+ }
+
+ /* check to see if the filesystem has changed */
+ if (last_filesys == NULL ||
+ strcmp(last_filesys, cur_filesys) != 0)
+ {
+ if (last_filesys != NULL &&
+ (retval = ext2fs_close(*fs)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+
+ if ((retval = open_filesystem(cur_filesys, fs, root, 0)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ fprintf(stderr, "Error opening fileystem %s\n",
+ cur_filesys);
+ return retval;
+ }
+ cwd = *root;
+ last_filesys = cur_filesys;
+ } /* end of filesystem change? */
+
+ if ((retval = get_file(*fs, *root, cwd, in_file,
+ (dest_dir == NULL) ? NULL:outpath, keep)))
+ {
+ fprintf(stderr, "Error copying file %s to %s\n",
+ in_file, outpath);
+ return retval;
+ }
+ } /* end of do we have a filesystem spec? */
+ else
+ {
+ if (dst_category == HOST_FS)
+ {
+ fputs("Already copying to a native filesystem!\n",
+ stderr);
+ continue;
+ }
+
+
+ memset(&statbuf, 0, sizeof(statbuf));
+ if (strcmp(in_file, "-") == 0)
+ {
+ statbuf.st_mode = S_IFREG;
+ in_file = NULL;
+ }
+
+ if (in_file != NULL && stat(in_file, &statbuf) != 0)
+ {
+ perror(in_file);
+ continue;
+ }
+
+ /* can't handle anything other than regular files right now */
+ if (!S_ISREG(statbuf.st_mode))
+ continue;
+
+ if (file_to_file)
+ dst_file = outpath;
+ else
+ dst_file = in_file;
+
+ if (NULL != (ptr = strrchr(dst_file, '/')))
+ {
+ *ptr = '\0';
+
+ if (absolute)
+ {
+ if ((retval = dir_changed(dst_file, *fs, *root, orig_cwd,
+ &cwd, def_stat, dest_dir)))
+ {
+ fprintf(stderr,"Error creating output directory %s\n",
+ dst_file);
+ return(-1);
+ }
+ }
+ *ptr = '/';
+ out_file = ptr + 1;
+ }
+ else
+ {
+ cwd = orig_cwd;
+ out_file = dst_file;
+ }
+
+ if (statbuf.st_nlink > 1)
+ {
+ if (NULL != (xref = find_link(&statbuf)))
+ {
+ if ((retval = create_hard_link(*fs, cwd, xref->new_ino,
+ out_file, E2T_FORCE)))
+ {
+ fprintf(stderr, "Error creating link for %s/%s\n",
+ cur_out_dir, out_file);
+ elist_free(link_list, free);
+ return(1);
+ }
+
+ if (verbose)
+ fprintf(stderr, "Copied %s to %s:%s\n", in_file,
+ cur_filesys, diag_output_name(cur_out_dir,
+ file_to_file,
+ outpath));
+
+ continue;
+ }
+ }
+
+ if ((retval = cp_to_ext2fs(*fs, cwd, in_file, out_file, &statbuf,
+ keep, def_stat)))
+ {
+ fprintf(stderr, "Error copying file %s to %s:%s\n",
+ (in_file) ? in_file : "<stdin>" , cur_filesys,
+ diag_output_name(cur_out_dir, file_to_file, outpath));
+ return retval;
+ }
+ if (verbose)
+ fprintf(stderr, "Copied %s to %s:%s\n",
+ (in_file) ? in_file : "<stdin>", cur_filesys,
+ diag_output_name(cur_out_dir, file_to_file, outpath));
+ }
+ }
+
+ return(0);
+}
+
+static char *
+diag_output_name(char *odir, int file_to_file, char *ofile)
+{
+ static char tmpstr[BUF_SIZE];
+ if (file_to_file)
+ {
+ snprintf(tmpstr, BUF_SIZE, "%s/%s", odir, ofile);
+ tmpstr[BUF_SIZE-1] = '\0';
+ return(tmpstr);
+ }
+ else
+ return(odir);
+}
+
+
+long
+dir_changed(char *newdir, ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ ext2_ino_t *newcwd, struct stat *def_stat, char *dest_dir)
+{
+ static char last_cwd[BUF_SIZE];
+ static int first = 1;
+ long retval;
+
+
+ if (first || strcmp(last_cwd, newdir))
+ {
+ first = 0;
+
+ *newcwd = cwd;
+ if ((*newdir != '\0' &&
+ strcmp(newdir, ".") != 0) &&
+ (retval = create_dir(fs, root, newcwd, newdir, def_stat)))
+ {
+ fprintf(stderr,"Error creating output "
+ "directory %s\n", newdir);
+ return(-1);
+ }
+ strncpy(last_cwd, newdir, BUF_SIZE);
+ last_cwd[BUF_SIZE-1] = '\0';
+
+ if (*newdir == '/' || dest_dir == NULL || *dest_dir == '\0')
+ strncpy(cur_out_dir, newdir, BUF_SIZE);
+ else
+ snprintf(cur_out_dir, BUF_SIZE, "%s/%s", dest_dir, newdir);
+
+ cur_out_dir[BUF_SIZE-1] = '\0';
+ }
+ return(0);
+}
+
+
+int
+read_line(char *inbuf)
+{
+ char *ptr;
+ char c;
+
+ *inbuf = '\0';
+
+ if (NULL == fgets(inbuf, BUF_SIZE, stdin))
+ {
+ if (ferror(stdin))
+ perror("read_line");
+ return(-1);
+ }
+
+ ptr = inbuf + strlen(inbuf);
+ ptr--;
+
+ while (ptr >= inbuf)
+ {
+ c = *ptr;
+ if (!ISSPACE(c))
+ break;
+ ptr--;
+ }
+ ptr++;
+ *ptr = '\0';
+ return(strlen(inbuf));
+}
+
+int
+read_string(char *inbuf)
+{
+ char *ptr;
+ char *boundary;
+ int c;
+ int cnt;
+
+ boundary = inbuf + BUF_SIZE - 1;
+ ptr = inbuf;
+ *ptr = '\0';
+ while ((c = getchar()) != EOF && c != '\0')
+ {
+ if (ptr < boundary)
+ *ptr++ = c;
+ else
+ break;
+ }
+
+ if (c == EOF)
+ {
+ if (ferror(stdin))
+ {
+ perror("read_string");
+ return(-1);
+ }
+ else if (feof(stdin))
+ return(-1);
+ }
+ *ptr = '\0';
+ return(strlen(inbuf));
+}
+
+int
+my_strcmp(const void *n1, const void *n2)
+{
+ char *s1 = *((char **)n1);
+ char *s2 = *((char **)n2);
+
+ return(strcmp(s1, s2));
+}
+
+INODE_XREF_T *
+find_link(struct stat *sbuf)
+{
+ elist_t *n;
+ INODE_XREF_T *xref;
+
+ n = link_list;
+
+ while (n != NULL)
+ {
+ if ((xref = n->data) != NULL)
+ {
+ if (xref->dev_no > sbuf->st_dev)
+ return(NULL);
+ else if (xref->dev_no == sbuf->st_dev)
+ {
+ if (xref->ino_no > sbuf->st_ino)
+ return(NULL);
+ else if (xref->ino_no == sbuf->st_ino)
+ return(xref);
+ }
+ }
+ n = n->next;
+ }
+
+ return(NULL);
+}
+
+long
+add_link(struct stat *sbuf, ext2_ino_t newfile)
+{
+ INODE_XREF_T *xref;
+ INODE_XREF_T *x_node;
+ elist_t *n;
+
+ if (NULL == (xref = malloc(sizeof(INODE_XREF_T))))
+ {
+ perror("malloc");
+ return(1);
+ }
+
+ xref->dev_no = sbuf->st_dev;
+ xref->ino_no = sbuf->st_ino;
+ xref->new_ino = newfile;
+
+ if (link_list == NULL)
+ {
+ if (NULL == (link_list = elist_new()))
+ {
+ perror("elist_new");
+ free(xref);
+ return(1);
+ }
+ }
+
+ n = link_list->next;
+ while (n != NULL)
+ {
+ if (NULL != (x_node = n->data))
+ {
+ if (x_node->dev_no > xref->dev_no ||
+ (x_node->dev_no == xref->dev_no &&
+ x_node->ino_no > xref->ino_no))
+ {
+ if (NULL == elist_insert(n, xref))
+ {
+ perror("elist_insert");
+ free(xref);
+ return(1);
+ }
+ return(0);
+ }
+ }
+ n = n->next;
+ }
+
+ if (NULL == elist_append(link_list, xref))
+ {
+ perror("elist_append");
+ free(xref);
+ return(1);
+ }
+ return(0);
+}
+
+static long
+cp_to_ext2fs(ext2_filsys fs, ext2_ino_t cwd, char *in_file, char *out_file,
+ struct stat *statbuf, int keep, struct stat *def_stat)
+{
+ long retval;
+ ext2_ino_t out_file_ino;
+
+ if ((retval = put_file(fs, cwd, in_file, out_file,
+ &out_file_ino, keep, def_stat)))
+ {
+ elist_free(link_list, free);
+ return retval;
+ }
+ if (statbuf->st_nlink > 1)
+ {
+ if ((retval = add_link(statbuf, out_file_ino)))
+ {
+ fprintf(stderr, "Error adding link info for %s to list\n",
+ out_file);
+ elist_free(link_list, free);
+ return retval;
+ }
+ }
+ return(0);
+}
diff --git a/e2tools.c b/e2tools.c
new file mode 100644
index 0000000..abb61c5
--- /dev/null
+++ b/e2tools.c
@@ -0,0 +1,78 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/e2tools.c,v 0.7 2002/08/08 07:55:03 ksheff Exp $ */
+/*
+ * e2tools.c
+ */
+
+#ifndef E2TOOLS_C
+#define E2TOOLS_C
+#endif
+
+/* Description */
+/*
+ *
+ *
+ */
+/*
+ * $Log: e2tools.c,v $
+ * Revision 0.7 2002/08/08 07:55:03 ksheff
+ * Added e2tail
+ *
+ * Revision 0.6 2002/04/10 10:43:09 ksheff
+ * Added e2rm
+ *
+ * Revision 0.5 2002/03/21 04:38:14 ksheff
+ * Created a separate do_mv function instead of overloading do_ln.
+ *
+ * Revision 0.4 2002/03/07 07:17:24 ksheff
+ * Added ability to move files on an ext2fs.
+ *
+ * Revision 0.3 2002/03/05 14:02:30 ksheff
+ * Added a call to do_ln() if the user wants to invoke the ln program.
+ *
+ * Revision 0.2 2002/02/27 05:26:22 ksheff
+ * Added a call to e2mkdir if the user wants to invoke the mkdir program.
+ *
+ * Revision 0.1 2002/02/27 04:47:21 ksheff
+ * initial revision
+ *
+ */
+
+/* Feature Test Switches */
+/* Headers */
+
+#include "e2tools.h"
+
+int
+main(int argc, char *argv[])
+{
+ char *ptr;
+
+ if (NULL != (ptr = strrchr(argv[0], '/')))
+ ptr++;
+ else
+ ptr = argv[0];
+
+ initialize_ext2_error_table();
+
+ if (strcmp(ptr, "e2ls") == 0)
+ exit(do_list_dir(argc, argv));
+ else if (strcmp(ptr, "e2cp") == 0)
+ exit(copy(argc, argv));
+ else if (strcmp(ptr, "e2mkdir") == 0)
+ exit(e2mkdir(argc, argv));
+ else if (strcmp(ptr, "e2ln") == 0)
+ exit(do_ln(argc, argv));
+ else if (strcmp(ptr, "e2mv") == 0)
+ exit(do_mv(argc, argv));
+ else if (strcmp(ptr, "e2rm") == 0)
+ exit(e2rm(argc, argv));
+ else if (strcmp(ptr, "e2tail") == 0)
+ exit(do_tail(argc, argv));
+ else
+ {
+ fprintf(stderr, "Not implemented\n");
+ exit(1);
+ }
+ return(0);
+}
+
diff --git a/e2tools.h b/e2tools.h
new file mode 100644
index 0000000..285f776
--- /dev/null
+++ b/e2tools.h
@@ -0,0 +1,138 @@
+#ifndef E2TOOLS_H
+#define E2TOOLS_H
+
+/* $Header: /home/ksheff/src/e2tools/RCS/e2tools.h,v 0.7 2004/04/07 01:15:55 ksheff Exp $ */
+
+/* Copyright 2002 Keith W. Sheffield */
+
+/* Description */
+/*
+ * $Log: e2tools.h,v $
+ * Revision 0.7 2004/04/07 01:15:55 ksheff
+ * Added the parameter struct stat *def_stat to put_file().
+ *
+ * Revision 0.6 2002/08/08 07:57:04 ksheff
+ * Added new routine do_tail() from tail.c
+ * Added new routine read_to_eof() from read.c
+ * Made retrieve_data() from read.c a public routine
+ *
+ * Revision 0.5 2002/04/10 10:43:27 ksheff
+ * Added e2rm().
+ *
+ * Revision 0.4 2002/04/10 09:33:26 ksheff
+ * Modified prototypes for functions involved with setting directory
+ * attributes.
+ *
+ * Revision 0.3 2002/03/21 09:05:16 ksheff
+ * Added function prototypes from mv.c and altered do_ln() slightly.
+ *
+ * Revision 0.2 2002/03/07 07:26:02 ksheff
+ * Added function prototypes and defined the macros E2T_FORCE and E2T_DO_MV
+ *
+ * Revision 0.1 2002/02/27 04:47:44 ksheff
+ * initial revision
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <utime.h>
+/*
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#endif
+*/
+
+#ifdef HAVE_OPTRESET
+extern int optreset; /* defined by BSD, but not others */
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+
+#define E2T_FORCE 1
+#define E2T_DO_MV 2
+
+#ifndef COPY_C
+extern long copy(int argc, char *argv[]);
+extern int my_strcmp(const void *n1, const void *n2);
+#endif
+
+#ifdef LN_C
+extern long do_ln(int argc, char *argv[]);
+
+extern long create_hard_link(ext2_filsys fs, ext2_ino_t cwd, ext2_ino_t
+ new_file_ino, char *newfile, int ln_flags);
+#endif
+
+#ifndef LS_C
+extern long do_list_dir(int argc, char *argv[]);
+#endif
+
+#ifndef MKDIR_C
+extern long e2mkdir(int argc, char *argv[]);
+extern long create_dir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd,
+ char *dirname, struct stat *def_stat);
+#endif
+
+#ifdef MV_C
+extern long do_mv(int argc, char *argv[]);
+extern long get_file_parts(ext2_filsys fs, ext2_ino_t root, char *pathname,
+ ext2_ino_t *dir_ino, char **dir_name,
+ char **base_name);
+
+#endif
+
+
+#ifndef READ_C
+extern long get_file(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ char *infile, char *outfile, int keep);
+extern long retrieve_data(ext2_filsys fs, ext2_ino_t src, int dest_fd,
+ char *dest_name, int keep, ext2_off_t offset,
+ ext2_off_t *ret_pos);
+extern long read_to_eof(ext2_file_t infile, int dest_fd, ext2_off_t offset,
+ ext2_off_t *ret_pos);
+#endif
+
+#ifndef RM_C
+extern long e2rm(int argc, char *argv[]);
+#endif
+
+#ifndef TAIL_C
+extern long do_tail(int argc, char *argv[]);
+#endif
+
+#ifndef UTIL_C
+extern mode_t ext2_mode_xlate(__u16 lmode);
+extern __u16 host_mode_xlate(mode_t hmode);
+extern long open_filesystem(char *name, ext2_filsys *fs, ext2_ino_t *root, int
+ rw_mode);
+extern long read_inode(ext2_filsys fs, ext2_ino_t file, struct ext2_inode
+ *inode);
+extern long write_inode(ext2_filsys fs, ext2_ino_t file, struct ext2_inode
+ *inode);
+extern long rm_file(ext2_filsys fs, ext2_ino_t cwd, char *outfile, ext2_ino_t
+ delfile);
+extern long delete_file(ext2_filsys fs, ext2_ino_t inode);
+extern void init_stat_buf(struct stat *buf);
+#endif
+
+#ifndef WRITE_C
+extern long
+put_file(ext2_filsys fs, ext2_ino_t cwd, char *infile, char *outfile,
+ ext2_ino_t *outfile_ino, int keep, struct stat *def_stat);
+#endif
+
+#endif
+
+
diff --git a/e2tools.spec b/e2tools.spec
new file mode 100644
index 0000000..00d5971
--- /dev/null
+++ b/e2tools.spec
@@ -0,0 +1,52 @@
+Summary: Tools to access files on an unmounted ext2 filesystem
+Name: e2tools
+Version: 0.0.16
+Release: 1
+Copyright: GPL
+Group: Applications/filesystems
+Source0: http://ksheff.net/sw/e2tools/%{name}-%{version}.tar.gz
+Patch1: e2tools.diff
+BuildRoot: /var/tmp/%{name}-root
+Prefix: /usr
+Packager: Keith W. Sheffield <sheff@pobox.com>
+Requires: e2fsprogs > 1.25
+BuildRequires: e2fsprogs-devel > 1.25
+
+%description
+E2tools is a simple set of GPL'ed utilities to read, write, and manipulate
+files in an ext2/ext3 filesystem. I wrote these tools in order to copy files
+into a linux filesystem on a machine that does not have ext2 support. Of
+course, they can also be used on a linux machine to read/write to disk images
+or floppies without having to mount them.
+
+
+%prep
+%setup
+
+chmod 755 configure
+autoconf
+
+%build
+./configure --prefix=$RPM_BUILD_ROOT/usr
+make
+%install
+rm -rf $RPM_BUILD_ROOT
+make install
+mv -f $RPM_BUILD_ROOT/usr/bin $RPM_BUILD_ROOT/usr/sbin
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%attr(755,root,root) /usr/sbin/
+%doc README TODO COPYING ChangeLog
+
+%changelog
+* Tue Apr 06 2004 Keith Sheffield
+- Updated version due to bug fix release.
+* Wed Jul 09 2003 Keith Sheffield
+- autoconfiscated the build system
+* Thu Aug 08 2002 Ralf Spenneberg <ralf@spenneberg.de>
+- first release
+
diff --git a/elist.c b/elist.c
new file mode 100644
index 0000000..e83ef7d
--- /dev/null
+++ b/elist.c
@@ -0,0 +1,198 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/elist.c,v 0.6 2004/04/06 19:34:44 ksheff Exp $ */
+/*
+ * elist.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ */
+
+#ifndef ELIST_C
+#define ELIST_C
+#endif
+
+/* Description */
+/*
+ *
+ *
+ */
+/*
+ * $Log: elist.c,v $
+ * Revision 0.6 2004/04/06 19:34:44 ksheff
+ * Corrected elist_delete to update the previous node if it exists.
+ *
+ * Revision 0.5 2002/06/05 22:05:01 ksheff
+ * Added elist_delete.
+ *
+ * Revision 0.4 2002/06/03 23:02:01 ksheff
+ * Added the function elist_sort().
+ *
+ * Revision 0.3 2002/04/23 01:49:48 ksheff
+ * Added a define for NULL if it doesn't exist.
+ *
+ * Revision 0.2 2002/03/07 07:33:28 ksheff
+ * silenced compiler warnings for calloc return value.
+ *
+ * Revision 0.1 2002/03/07 07:24:35 ksheff
+ * initial revision
+ *
+ */
+
+/* Feature Test Switches */
+/* Headers */
+#include <memory.h>
+#include "elist.h"
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+elist_t *
+elist_new()
+{
+ elist_t *list;
+
+ list = (elist_t *) calloc(sizeof(elist_t), 1);
+ return list;
+}
+
+elist_t *
+elist_delete(elist_t *l, void (*data_free)(void *))
+{
+ elist_t *n;
+
+ if (l)
+ {
+ n = l->next;
+ if (n)
+ n->prev = l->prev;
+ if (l->prev)
+ l->prev->next = n;
+ if (data_free && l->data)
+ (*data_free)(l->data);
+ free(l);
+ l = n;
+ }
+ return(l);
+}
+
+void
+elist_free(elist_t *l, void (*data_free)(void *))
+{
+ elist_t *n;
+
+ if (l)
+ {
+ do
+ {
+ l = elist_delete(l, data_free);
+ } while (l);
+ }
+}
+
+elist_t *
+elist_append(elist_t *l, void *data)
+{
+ elist_t *n;
+ elist_t *t;
+
+ if (NULL == (n = elist_new()))
+ return(NULL);
+
+ n->data = data;
+
+ if (l)
+ {
+ t = l;
+ while (t->next != NULL) t = t->next;
+ t->next = n;
+ n->prev = t;
+ }
+ else
+ l = n;
+
+ return(l);
+}
+
+elist_t *
+elist_insert(elist_t *l, void *data)
+{
+ elist_t *n;
+
+ if (NULL == (n = elist_new()))
+ return(NULL);
+ n->data = data;
+
+ if (l)
+ {
+ n->prev = l->prev;
+ l->prev = n;
+ n->next = l;
+ if (n->prev)
+ n->prev->next = n;
+ }
+ l = n;
+
+ return(l);
+}
+
+void elist_sort(elist_t *l, int (sort_func)(void *, void *), int reverse)
+{
+ int c=0;
+ elist_t *tl;
+ void **data;
+ void **dptr;
+
+ if (l != NULL && sort_func != NULL)
+ {
+ /* count the number of nodes */
+ tl = l;
+ while (tl != NULL)
+ {
+ c++;
+ tl = tl->next;
+ }
+
+ /* if there are more than 1 nodes, allocate a lookup table */
+ if (c > 1 && (NULL != (data = (void **) malloc(c*sizeof(void*)))))
+ {
+ /* fill in the lookup table */
+ tl = l;
+ dptr = data;
+ while (tl != NULL)
+ {
+ *dptr++ = tl->data;
+ tl = tl->next;
+ }
+
+ qsort(data, c, sizeof(dptr), sort_func);
+
+ /* now fill in the data pointers in the linked list with the
+ * data nodes in the correct order
+ */
+ tl = l;
+ if (reverse)
+ {
+ dptr = data + c - 1;
+ while (tl != NULL)
+ {
+ tl->data = *dptr--;
+ tl = tl->next;
+ }
+ }
+ else
+ {
+ dptr = data;
+ while (tl != NULL)
+ {
+ tl->data = *dptr++;
+ tl = tl->next;
+ }
+ }
+ free(data);
+ }
+ }
+}
+
+
+
diff --git a/elist.h b/elist.h
new file mode 100644
index 0000000..ea046d7
--- /dev/null
+++ b/elist.h
@@ -0,0 +1,39 @@
+#ifndef ELIST_H
+#define ELIST_H
+
+/* $Header: /home/ksheff/src/e2tools/RCS/elist.h,v 0.3 2002/06/05 22:04:13 ksheff Exp $ */
+
+/* Copyright 2002 Keith W. Sheffield */
+
+/*
+ * $Log: elist.h,v $
+ * Revision 0.3 2002/06/05 22:04:13 ksheff
+ * Added elist_delete.
+ *
+ * Revision 0.2 2002/06/03 21:02:39 ksheff
+ * Added elist_sort() definition.
+ *
+ * Revision 0.1 2002/03/07 07:24:50 ksheff
+ * initial revision
+ *
+ */
+
+
+typedef struct _elist_t
+{
+ struct _elist_t *prev;
+ struct _elist_t *next;
+ void *data;
+} elist_t;
+
+#ifndef ELIST_C
+extern elist_t * elist_new();
+extern elist_t *elist_delete(elist_t *l, void (*data_free)(void *));
+extern void elist_free(elist_t *l, void (*data_free)(void *));
+extern elist_t * elist_append(elist_t *l, void *data);
+extern elist_t * elist_insert(elist_t *l, void *data);
+extern void
+elist_sort(elist_t *l, int (sort_func)(void *, void *), int reverse);
+#endif
+
+#endif
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/ln.c b/ln.c
new file mode 100644
index 0000000..e5bda69
--- /dev/null
+++ b/ln.c
@@ -0,0 +1,388 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/ln.c,v 0.3 2002/06/30 05:54:02 ksheff Exp $ */
+/*
+ * ln.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ */
+
+#ifndef LN_C
+#define LN_C
+#endif
+
+/* Description */
+/*
+ * Module to create links
+ *
+ */
+/*
+ * $Log: ln.c,v $
+ * Revision 0.3 2002/06/30 05:54:02 ksheff
+ * Modified create_hard_link() to check file type before linking to current
+ * directory. This was not being done before and it was causing problems if a
+ * non regular file was renamed.
+ *
+ * Revision 0.2 2002/03/21 09:04:40 ksheff
+ * Split the mv operation into its own module.
+ *
+ * Revision 0.1 2002/03/07 07:23:41 ksheff
+ * initial revision.
+ *
+ */
+
+/* Feature Test Switches */
+/* Headers */
+#include "e2tools.h"
+
+/* Macros */
+#define USAGE "Usage: e2ln [-vfs] source destination\n"
+
+/* Local Prototypes */
+long
+do_ln(int argc, char *argv[]);
+
+long
+create_hard_link(ext2_filsys fs, ext2_ino_t cwd, ext2_ino_t new_file_ino,
+ char *newfile, int ln_flags);
+
+/* Name: do_ln()
+ *
+ * Description:
+ *
+ * This function reads the command line arguments and creates a link
+ * in an ext2fs file system
+ *
+ * Algorithm:
+ *
+ * Read any command line switches
+ * Get the source file specification
+ * Open the file system
+ * Get the directory and basename of the source file
+ * Determine the inode number for the source file
+ * If the destination file is not given or if it's a .
+ * use the current directory and the basename of the source file
+ * Otherwise
+ * Get the directory and basename of the destination file
+ * Create the link
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * int argc; The number of arguments
+ * char *argv[]; The command line arguments
+ *
+ * Return Values:
+ *
+ * 0 - the link was created successfully
+ * an error occurred.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 03/05/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 03/06/02 K. Sheffield Modified to perform file moves
+ * 03/20/02 K. Sheffield Moved the mv operation to a separate file
+ */
+long
+do_ln(int argc, char *argv[])
+{
+ int verbose=0;
+ int force=0;
+ int symlink=0;
+ int num_files;
+ int errcnt=0;
+ char *cur_filesys = NULL;
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ ext2_ino_t srcd;
+ ext2_ino_t destd;
+ ext2_ino_t source_file;
+ char *src_dir;
+ char *dest_dir;
+ char *src_name;
+ char *dest_name;
+ long retval;
+ int c;
+
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt(argc, argv, "vfs")) != EOF)
+ {
+ switch (c)
+ {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'f':
+ force = E2T_FORCE;
+ break;
+ case 's':
+ symlink = 1;
+ break;
+ default:
+ errcnt++;
+ break;
+ }
+ }
+
+ if (errcnt || argc == optind)
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+
+ if (symlink)
+ {
+ fputs("Not implemented yet\n", stderr);
+ return(1);
+ }
+
+ cur_filesys = argv[optind++];
+ if (NULL == (src_dir = strchr(cur_filesys, ':')))
+ {
+ fprintf(stderr, "Invalid file specification: %s\n", cur_filesys);
+ return(1);
+ }
+ *src_dir++ = '\0';
+
+ if (*src_dir == '\0')
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
+ {
+ fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys);
+ return retval;
+ }
+
+ /* move to the source directory */
+
+ if (get_file_parts(fs, root, src_dir, &srcd, &src_dir, &src_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* get the inode number for the source file */
+ if ((retval = ext2fs_namei(fs, srcd, srcd, src_name, &source_file)))
+ {
+ fprintf(stderr, "%s: source file %s\n",error_message(retval), src_name);
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ /* get the destination directory */
+ destd = root;
+ if (argc == optind || strcmp(dest_dir = argv[optind], ".") == 0)
+ dest_name = src_name;
+ else
+ {
+ if (get_file_parts(fs, root, dest_dir, &destd, &dest_dir,
+ &dest_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+ }
+
+ /* now create the link */
+ if ((retval = create_hard_link(fs, destd, source_file, dest_name, force)))
+ {
+ fprintf(stderr, "Error linking %s/%s as %s/%s\n",
+ ((src_dir == NULL) ? "." : src_dir), src_name,
+ ((dest_dir == NULL) ? "." : dest_dir), dest_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if (verbose)
+ fprintf(stderr, "linked %s/%s as %s/%s\n",
+ ((src_dir == NULL) ? "." : src_dir), src_name,
+ ((dest_dir == NULL) ? "." : dest_dir), dest_name);
+
+ ext2fs_close(fs);
+ return(0);
+
+} /* end of do_ln */
+
+/* Name: create_hard_link()
+ *
+ * Description:
+ *
+ * This function creates a hard link to an existing file
+ *
+ * Algorithm:
+ *
+ * Check input parameters
+ * Check to see if the new file name already exists
+ * Make sure the new file is not an existing directory
+ * If the file exists, remove it if the del_current flag is set
+ * Add the new file name and it's inode to the current directory.
+ * Get the inode structure for the current inode number
+ * update the number of links
+ * Write the inode structure back out to the file system.
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current file system
+ * ext2_ino_t cwd; The current working directory
+ * ext2_ino_t new_file_ino; The inode number of the new file
+ * char *newfile; The name of the new file
+ * int ln_flags; Flags affecting hard_link action
+ *
+ * Return Values:
+ *
+ * 0 - the new file link was created successfully
+ * any other value indicates an error
+ *
+ * Author: Keith W. Sheffield
+ * Date: 03/05/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 06/30/02 K.Sheffield Directory link flag is now based on the
+ * type of file being linked. This was
+ * causing problems if a directory was
+ * renamed.
+ */
+long
+create_hard_link(ext2_filsys fs, ext2_ino_t cwd, ext2_ino_t new_file_ino,
+ char *newfile, int ln_flags)
+{
+ ext2_ino_t curr_ino;
+ struct ext2_inode inode;
+ long retval;
+ int dir_flag;
+
+ if (fs == NULL || newfile == NULL)
+ {
+ fputs("Invalid input parameter. Exiting create_hard_link() with -1\n",
+ stderr);
+ return (-1);
+ }
+
+ /* check to see if the file name already exists in the current directory */
+ if ((retval = ext2fs_namei(fs, cwd, cwd, newfile, &curr_ino)))
+ {
+ if (retval != EXT2_ET_FILE_NOT_FOUND)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+
+ }
+ /* file name exists, let's see if is a directory */
+ else if ((retval = ext2fs_check_directory(fs, curr_ino)))
+ {
+ if (retval != EXT2_ET_NO_DIRECTORY)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+
+ /* delete the existing file if needed */
+ if ((ln_flags & E2T_FORCE) &&
+ (curr_ino != new_file_ino))
+ {
+ if ((retval = rm_file(fs, cwd, newfile, curr_ino)))
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "ln: %s: File exists\n", newfile);
+ return(1);
+ }
+ }
+ else
+ {
+ /* if we get here, then it's an existing directory */
+ fprintf(stderr, "%s is a directory!\n", newfile);
+ return(1);
+ }
+
+ /* read the inode associated with the file */
+ if ((retval = read_inode(fs, new_file_ino, &inode)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return (retval);
+ }
+
+ /* determine how to link into the directory based on the type of file */
+ switch(inode.i_mode & LINUX_S_IFMT)
+ {
+ case LINUX_S_IFREG:
+ dir_flag = EXT2_FT_REG_FILE;
+ break;
+ case LINUX_S_IFLNK:
+ dir_flag = EXT2_FT_SYMLINK;
+ break;
+ case LINUX_S_IFDIR:
+ dir_flag = EXT2_FT_DIR;
+ break;
+ case LINUX_S_IFSOCK:
+ dir_flag = EXT2_FT_SOCK;
+ break;
+ case LINUX_S_IFBLK:
+ dir_flag = EXT2_FT_BLKDEV;
+ break;
+ case LINUX_S_IFCHR:
+ dir_flag = EXT2_FT_CHRDEV;
+ break;
+ case LINUX_S_IFIFO:
+ dir_flag = EXT2_FT_FIFO;
+ break;
+ default:
+ dir_flag = EXT2_FT_UNKNOWN;
+ break;
+ }
+
+
+ if ((retval = ext2fs_link(fs, cwd, newfile, new_file_ino, dir_flag)))
+ {
+ /* check to see if we ran out of space in the directory */
+ if (retval == EXT2_ET_DIR_NO_SPACE)
+ {
+ /* try resizing the directory and try again */
+ if (0 == (retval = ext2fs_expand_dir(fs, cwd)))
+ retval = ext2fs_link(fs, cwd, newfile, new_file_ino, dir_flag);
+ }
+ if (retval)
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+ }
+
+
+ /* update the inode stat information */
+ if ((ln_flags & E2T_DO_MV) == 0)
+ {
+ inode.i_links_count++;
+ if ((retval = write_inode(fs, new_file_ino, &inode)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return (retval);
+ }
+ }
+
+ return(0);
+
+} /* end of create_hard_link */
+
diff --git a/ls.c b/ls.c
new file mode 100644
index 0000000..2d093b7
--- /dev/null
+++ b/ls.c
@@ -0,0 +1,1055 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/ls.c,v 0.8 2004/04/07 03:30:49 ksheff Exp $ */
+/*
+ * ls.c --- list directories
+ *
+ * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ * Modified by Keith W. Sheffield <shefff@pobox.com> for inclusion with e2tools
+ */
+/*
+ * $Log: ls.c,v $
+ * Revision 0.8 2004/04/07 03:30:49 ksheff
+ * Updated usage string.
+ *
+ * Revision 0.7 2004/04/07 02:41:50 ksheff
+ * Modified to bracket files with an inode number of 0 with >< characters.
+ *
+ * Revision 0.6 2004/04/06 20:27:26 ksheff
+ * Modified to print "No files found!" for empty directories, corrected the
+ * directory name display, and fixed REGEX_OPT masking.
+ *
+ * Revision 0.5 2002/06/05 23:14:11 ksheff
+ * Fixed short display with respect to displaying the contents of multiple
+ * directories.
+ *
+ * Revision 0.4 2002/06/05 23:07:34 ksheff
+ * Allowed for multiple directory and file specifications. Added the -f
+ * option for no sorting.
+ *
+ * Revision 0.3 2002/06/03 23:00:51 ksheff
+ * Removed display code from directory iterator. A list of displayable files
+ * is now generated. This list can be sorted and displayed in a variety of
+ * ways. The -a, -c, -i, -r, and -t options are now accepted.
+ *
+ * Revision 0.2 2002/03/05 12:12:52 ksheff
+ * Removed setting optind for SCO.
+ *
+ * Revision 0.1 2002/02/27 04:46:21 ksheff
+ * initial revision
+ *
+ */
+
+
+#include "e2tools.h"
+#include "elist.h"
+#include <regex.h>
+
+/*
+ * list directory
+ */
+
+#define LONG_OPT 0x0001
+#define DELETED_OPT 0x0002
+#define REGEX_OPT 0x0004
+#define REVERSE_OPT 0x0008
+#define HIDDEN_OPT 0x0010
+#define CREATE_OPT 0x0020
+#define INODE_OPT 0x0040
+
+#define DIRECTORY_TYPE -1
+#define NORMAL_TYPE 0
+
+struct list_dir_struct
+{
+ int options;
+ regex_t *reg;
+ elist_t *files;
+};
+
+typedef struct list_file_struct
+{
+
+ char *name;
+ struct ext2_inode inode;
+ ext2_ino_t dir;
+ ext2_ino_t inode_num;
+ int entry;
+ long type;
+} ls_file_t;
+
+static const char *monstr[] =
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+static ext2_filsys fs;
+static int max_name_len = 0;
+
+static int
+list_dir_proc(ext2_ino_t dir, int entry, struct ext2_dir_entry *dirent,
+ int offset, int blocksize, char *buf, void *private);
+void
+free_ls_file_t(void *f);
+long
+do_list_dir(int argc, char *argv[]);
+void
+long_disp(ls_file_t *info, int *col, int options);
+void
+short_disp(ls_file_t *info, int *col, int options);
+int
+no_sort(void *n1, void *n2);
+int
+name_sort(void *n1, void *n2);
+int
+inode_sort(void *n1, void *n2);
+int
+mod_time_sort(void *n1, void *n2);
+int
+creat_time_sort(void *n1, void *n2);
+long
+add_ls_file(char *name, int namelen, ext2_ino_t dir, ext2_ino_t ino,
+ int entry, int type, struct list_dir_struct *ls);
+elist_t *
+remove_ls_dups(elist_t *list);
+
+/* Name: list_dir_proc()
+ *
+ * Description:
+ *
+ *
+ * Algorithm:
+ *
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ *
+ * Return Values:
+ *
+ *
+ * Author: Theodore Ts'o
+ * Date: 1997
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 02/27/02 K.Sheffield Modified for use with e2tools
+ */
+static int
+list_dir_proc(ext2_ino_t dir, int entry, struct ext2_dir_entry *dirent,
+ int offset, int blocksize, char *buf, void *private)
+{
+ struct ext2_inode inode;
+ char name[EXT2_NAME_LEN];
+ struct list_dir_struct *ls = (struct list_dir_struct *) private;
+ int thislen;
+
+ thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN) ?
+ (dirent->name_len & 0xFF) : EXT2_NAME_LEN;
+ strncpy(name, dirent->name, thislen);
+ name[thislen] = '\0';
+
+ /* skip hidden files unless we ask for them */
+ if (0 == (ls->options & HIDDEN_OPT) &&
+ name[0] == '.')
+ return(0);
+
+ if ((ls->options & REGEX_OPT) &&
+ regexec(ls->reg, name, 0, NULL, 0))
+ return(0);
+
+ return(add_ls_file(name, thislen, dir, dirent->inode, entry, NORMAL_TYPE,
+ ls));
+
+}
+
+/* Name: add_ls_file()
+ *
+ * Description:
+ *
+ *
+ * Algorithm:
+ *
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ *
+ * Return Values:
+ *
+ *
+ * Author: K.Sheffield
+ * Date: 02/27/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ */
+long
+add_ls_file(char *name, int namelen, ext2_ino_t dir, ext2_ino_t ino,
+ int entry, int type, struct list_dir_struct *ls)
+{
+ ls_file_t *file_info;
+ elist_t *flist;
+
+ if (NULL == (file_info = calloc(sizeof(ls_file_t),1)))
+ {
+ perror("list_dir");
+ return(0);
+ }
+
+ file_info->dir = dir;
+
+ if (entry == DIRENT_DELETED_FILE)
+ file_info->inode_num = 0;
+ else
+ file_info->inode_num = ino;
+
+ file_info->entry = entry;
+ file_info->type = type;
+
+ if (file_info->inode_num)
+ {
+ if (read_inode(fs, file_info->inode_num, &file_info->inode))
+ {
+ free(file_info);
+ return 0;
+ }
+ }
+
+ if (name)
+ file_info->name = strdup(name);
+
+ if (NULL == (flist = elist_insert(ls->files, file_info)))
+ {
+ perror("list_dir");
+ free_ls_file_t(file_info);
+ return 0;
+ }
+ ls->files = flist;
+
+ if (max_name_len < namelen)
+ max_name_len = namelen;
+
+ return 0;
+}
+
+/* Name: free_ls_file_t()
+ *
+ * Description:
+ *
+ * This function is used to free an ls_file_t structure.
+ *
+ * Algorithm:
+ *
+ * Free the file's name if it is not NULL
+ * Free the ls_file_t structure
+ * Check to make sure the ls_file_t structure is not NULL
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * void *f; The structure to free
+ *
+ * Return Values:
+ *
+ * none
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/03/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+void free_ls_file_t(void *f)
+{
+ ls_file_t *n = (ls_file_t *) f;
+
+ if (n != NULL)
+ {
+ if (n->name != NULL)
+ free(n->name);
+ free(n);
+ }
+} /* end of free_ls_file_t */
+
+/* Name: do_list_dir()
+ *
+ * Description:
+ *
+ *
+ * Algorithm:
+ *
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ *
+ * Return Values:
+ *
+ *
+ * Author: Theodore Ts'o
+ * Date: 1997
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 02/27/02 K.Sheffield Modified for use with e2tools
+ * 04/06/04 K.Sheffield Modified to print "No Files Found!" for
+ * each empty directory. Corrected masking
+ * out REGEX_OPT.
+ */
+
+long
+do_list_dir(int argc, char *argv[])
+{
+ ext2_ino_t root;
+ ext2_ino_t cwd;
+ ext2_ino_t inode=0;
+ int retval;
+ int c;
+ int flags;
+ struct list_dir_struct ls;
+ char *fs_name;
+ char *last_fs_name;
+ char *path = NULL;
+ char *dup_path = NULL;
+ char *dir_name;
+ char *base_name;
+ int (*file_sort)(void *n1, void *n2) = name_sort;
+ void (*file_disp)(ls_file_t *n, int *col, int options) = short_disp;
+ elist_t *files=NULL;
+ int col=0;
+ ls_file_t *cur_file;
+ long last_type = 1;
+
+ memset(&ls, 0, sizeof(ls));
+
+ last_fs_name = NULL;
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt (argc, argv, "acDd:filrt")) != EOF)
+ {
+ switch (c)
+ {
+ case 'a':
+ ls.options |= HIDDEN_OPT;
+ break;
+ case 'c':
+ ls.options |= CREATE_OPT;
+ break;
+ case 'l':
+ file_disp = long_disp;
+ break;
+ case 'D':
+ ls.options |= DELETED_OPT;
+ break;
+ case 'd':
+ fs_name = optarg;
+ if (NULL != (path = strchr(fs_name, ':')))
+ *path++ = '\0';
+ if ((retval = open_filesystem(fs_name, &fs, &root, 0)))
+ {
+ fputs(error_message(retval), stderr);
+ return(1);
+ }
+ last_fs_name = fs_name;
+ break;
+ case 'f':
+ file_sort = no_sort;
+ break;
+ case 't':
+ file_sort = mod_time_sort;
+ break;
+ case 'r':
+ ls.options |= REVERSE_OPT;
+ break;
+ case 'i':
+ file_sort = inode_sort;
+ ls.options |= INODE_OPT;
+ break;
+ }
+ }
+
+ if (argc <= optind)
+ {
+ fputs("Usage: e2ls [-acDfilrt][-d dir] file\n", stderr);
+ return(1);
+ }
+
+ if (ls.options & CREATE_OPT &&
+ (file_sort == mod_time_sort || file_disp != long_disp))
+ file_sort = creat_time_sort;
+
+ /* sort the remaining command line arguments */
+ qsort(argv+optind, argc-optind, sizeof(char *), my_strcmp);
+
+ for(c=optind;c<argc;c++)
+ {
+ fs_name = argv[c];
+
+ if (NULL != (path = strchr(fs_name, ':')))
+ *path++ = '\0';
+ else if (last_fs_name != NULL)
+ {
+ path = fs_name;
+ fs_name = last_fs_name;
+ }
+
+ /* keep a copy of the file path for later because get_file_parts() is
+ * destructive.
+ */
+
+ if (dup_path)
+ {
+ free(dup_path);
+ dup_path = NULL;
+ }
+
+ if (path)
+ dup_path = strdup(path);
+
+ if (last_fs_name == NULL || strcmp(last_fs_name, fs_name))
+ {
+ if (last_fs_name != NULL)
+ ext2fs_close(fs);
+
+ if ((retval = open_filesystem(fs_name, &fs, &root, 0)))
+ {
+ fputs(error_message(retval), stderr);
+ return(1);
+ }
+ last_fs_name = fs_name;
+ }
+
+ dir_name = NULL;
+ cwd = root;
+ ls.options &= (~REGEX_OPT);
+
+ if (path != NULL && *path != '\0')
+ {
+ if (get_file_parts(fs, root, path, &cwd, &dir_name, &base_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ if (is_file_regexp(base_name))
+ {
+ if (NULL == (ls.reg = (regex_t *) make_regexp(base_name)))
+ {
+ fprintf(stderr,
+ "Error creating regular expression for %s\n",
+ base_name);
+ return(1);
+ }
+ ls.options |= REGEX_OPT;
+ inode = cwd;
+
+ }
+ /* check to see if the file name exists in the current directory
+ */
+ else if ((retval = ext2fs_namei(fs, cwd, cwd, base_name, &inode)))
+ {
+ fputs(error_message(retval), stderr);
+ ext2fs_close(fs);
+ return(1);
+ }
+ }
+ else
+ inode = root;
+
+ if(!dir_name)
+ dir_name = ".";
+
+ if (!inode)
+ continue;
+
+ flags = DIRENT_FLAG_INCLUDE_EMPTY;
+ if (ls.options & DELETED_OPT)
+ flags |= DIRENT_FLAG_INCLUDE_REMOVED;
+
+ if (retval = ext2fs_check_directory(fs, inode))
+ {
+ if (retval != EXT2_ET_NO_DIRECTORY)
+ {
+ fputs(error_message(retval), stderr);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if(add_ls_file(dir_name, 0, cwd, 0, 0, DIRECTORY_TYPE, &ls))
+ {
+ fputs(error_message(retval), stderr);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if(add_ls_file(base_name, strlen(base_name), cwd, inode, 0,
+ NORMAL_TYPE, &ls))
+ {
+ fputs(error_message(retval), stderr);
+ ext2fs_close(fs);
+ return(1);
+ }
+ }
+ else
+ {
+ if (ls.options & REGEX_OPT || path == NULL || *path == '\0')
+ path = dir_name;
+ else if (dup_path)
+ path = dup_path;
+
+
+ // if(add_ls_file((ls.options & REGEX_OPT) ? dir_name : path, 0, inode, 0,
+ if(add_ls_file(path, 0, inode, 0, 0, DIRECTORY_TYPE, &ls))
+ {
+ fputs(error_message(retval), stderr);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ retval = ext2fs_dir_iterate2(fs, inode, flags, 0, list_dir_proc,
+ &ls);
+ if (retval)
+ {
+ fputs(error_message(retval), stderr);
+ ext2fs_close(fs);
+ return(1);
+ }
+ }
+ }
+
+
+ elist_sort(ls.files, file_sort, ls.options & REVERSE_OPT);
+
+ ls.files = files = remove_ls_dups(ls.files);
+
+ if (files == NULL)
+ printf("No files found!");
+ else
+ {
+ while(files != NULL)
+ {
+ cur_file = (ls_file_t *)files->data;
+ if (cur_file->type == DIRECTORY_TYPE)
+ {
+ if (col > 0)
+ {
+ putchar('\n');
+ col = 0;
+ }
+ if (last_type == DIRECTORY_TYPE)
+ printf("No files found!\n");
+
+ printf("%s:", cur_file->name);
+ }
+ else
+ {
+ if (last_type == DIRECTORY_TYPE)
+ putchar('\n');
+ (file_disp)(cur_file, &col, ls.options);
+ }
+
+ last_type = cur_file->type;
+
+ files = files->next;
+ }
+ if (last_type == DIRECTORY_TYPE)
+ printf("No files found!");
+ }
+
+ putchar('\n');
+
+ elist_free(ls.files, free_ls_file_t);
+
+ ext2fs_close(fs);
+ return(0);
+}
+
+/* Name: long_disp()
+ *
+ * Description:
+ *
+ * This function displays a file's information for a long listing
+ *
+ * Algorithm:
+ *
+ * Generate the time string for the modification time
+ * Display the file's permission bits, owner, group, mod time, and name
+ *
+ * Global Variables:
+ *
+ * none
+ *
+ * Arguments:
+ *
+ * ls_file_t *info; The structure containing the file information
+ * int *col; The current column - unused
+ * int options; Options to ls
+ *
+ * Return Values:
+ *
+ * None
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/03/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 06/06/02 K.Sheffield Increased file size width
+ * 04/06/04 K.Sheffield Modified to show entries with an inode of 0
+ * as deleted.
+ */
+void long_disp(ls_file_t *info, int *col, int options)
+{
+ char lbr, rbr;
+ char datestr[80];
+ time_t modtime;
+ struct tm *tm_p;
+
+
+ if (info->entry == DIRENT_DELETED_FILE ||
+ info->inode_num == 0)
+ {
+ lbr = '>';
+ rbr = '<';
+ }
+ else
+ {
+ lbr = rbr = ' ';
+ }
+
+
+ if (info->inode_num)
+ {
+ if (options & CREATE_OPT)
+ modtime = info->inode.i_ctime;
+ else
+ modtime = info->inode.i_mtime;
+ tm_p = localtime(&modtime);
+ sprintf(datestr, "%2d-%s-%4d %02d:%02d",
+ tm_p->tm_mday, monstr[tm_p->tm_mon],
+ 1900 + tm_p->tm_year, tm_p->tm_hour,
+ tm_p->tm_min);
+ }
+ else
+ strcpy(datestr, " ");
+
+ printf("%c%6u%c %6o %5d %5d ", lbr, info->inode_num, rbr,
+ info->inode.i_mode, info->inode.i_uid, info->inode.i_gid);
+ if (LINUX_S_ISDIR(info->inode.i_mode))
+ printf("%7d", info->inode.i_size);
+ else
+ printf("%7lld", info->inode.i_size |
+ ((__u64)info->inode.i_size_high << 32));
+ printf(" %s %s\n", datestr, info->name);
+
+} /* end of long_disp */
+
+
+/* Name: short_disp()
+ *
+ * Description:
+ *
+ * This function displays a file's information for a long listing
+ *
+ * Algorithm:
+ *
+ * Display the file's name at the appropriate column.
+ *
+ * Global Variables:
+ *
+ * none
+ *
+ * Arguments:
+ *
+ * ls_file_t *info; The structure containing the file information
+ * int *col; The current column
+ * int options; Options to ls
+ *
+ * Return Values:
+ *
+ * None
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/03/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 04/06/04 K.Sheffield Modified to show entries with an inode of 0
+ * as deleted.
+ */
+void short_disp(ls_file_t *info, int *col, int options)
+{
+ char lbr, rbr;
+ char tmp[300];
+ int thislen;
+ static max_col_size = 0;
+
+ if (max_col_size == 0)
+ {
+ max_col_size = 80/(max_name_len + 2 + ((options & INODE_OPT) ? 8 : 0));
+ if (max_col_size == 0)
+ max_col_size = -1;
+ else
+ max_col_size = 80/max_col_size;
+ }
+
+
+ if (info->entry == DIRENT_DELETED_FILE ||
+ info->inode_num == 0)
+ {
+ lbr = '>';
+ rbr = '<';
+ }
+ else
+ {
+ lbr = 0;
+ rbr = ' ';
+ }
+
+ if (lbr == 0)
+ {
+ if (options & INODE_OPT)
+ sprintf(tmp, "%7d %s%c", info->inode_num, info->name, rbr);
+ else
+ sprintf(tmp, "%s%c", info->name, rbr);
+ }
+ else
+ {
+ if (options & INODE_OPT)
+ sprintf(tmp, "%7d %c%s%c", info->inode_num, lbr, info->name, rbr);
+ else
+ sprintf(tmp, "%c%s%c", lbr, info->name, rbr);
+ }
+
+ thislen = strlen(tmp);
+
+ if (*col + thislen > 80)
+ {
+ putchar('\n');
+ *col = 0;
+ }
+ thislen = max_col_size - thislen;
+ if (thislen < 0)
+ thislen = 0;
+
+ printf("%s%*.*s", tmp, thislen, thislen, "");
+ *col += max_col_size;
+}
+
+/* Name: no_sort()
+ *
+ * Description:
+ *
+ * This function sorts two ls_file_t structures by the file name
+ *
+ * Algorithm:
+ *
+ * Assign two ls_file_t pointers from the input void pointers
+ * Return the result of the comparison of the directories & type
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * void *n1; The first node being compared
+ * void *n2; The second node being compared
+ *
+ * Return Values:
+ *
+ * >0 - n1 > n2
+ * =0 - n1 == n2
+ * <0 - n1 < n2
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/03/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+int no_sort(void *n1, void *n2)
+{
+ ls_file_t *f1 = *((ls_file_t **) n1);
+ ls_file_t *f2 = *((ls_file_t **) n2);
+ int retval;
+
+ return((retval = (f1->dir - f2->dir)) ? retval : (f1->type - f2->type));
+
+} /* end of name_sort */
+
+/* Name: name_sort()
+ *
+ * Description:
+ *
+ * This function sorts two ls_file_t structures by the file name
+ *
+ * Algorithm:
+ *
+ * Assign two ls_file_t pointers from the input void pointers
+ * Return the result of the comparison of the names
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * void *n1; The first node being compared
+ * void *n2; The second node being compared
+ *
+ * Return Values:
+ *
+ * >0 - n1 > n2
+ * =0 - n1 == n2
+ * <0 - n1 < n2
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/03/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+int name_sort(void *n1, void *n2)
+{
+ ls_file_t *f1 = *((ls_file_t **) n1);
+ ls_file_t *f2 = *((ls_file_t **) n2);
+ int retval;
+
+ return((retval = (f1->dir - f2->dir)) ? retval :
+ ((retval = (f1->type - f2->type)) ? retval :
+ strcmp(f1->name, f2->name)));
+} /* end of name_sort */
+
+/* Name: inode_sort()
+ *
+ * Description:
+ *
+ * This function sorts two ls_file_t structures by the file inode number
+ *
+ * Algorithm:
+ *
+ * Assign two ls_file_t pointers from the input void pointers
+ * Return the result of the comparison of the inode numbers
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * void *n1; The first node being compared
+ * void *n2; The second node being compared
+ *
+ * Return Values:
+ *
+ * >0 - n1 > n2
+ * =0 - n1 == n2
+ * <0 - n1 < n2
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/03/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+int inode_sort(void *n1, void *n2)
+{
+ ls_file_t *f1 = *((ls_file_t **) n1);
+ ls_file_t *f2 = *((ls_file_t **) n2);
+ int retval;
+
+ return((retval = (f1->dir - f2->dir)) ? retval :
+ ((retval = (f1->type - f2->type)) ? retval :
+ (f1->inode_num - f2->inode_num)));
+} /* end of inode_sort */
+
+/* Name: mod_time_sort()
+ *
+ * Description:
+ *
+ * This function sorts two ls_file_t structures by the file modification time
+ *
+ * Algorithm:
+ *
+ * Assign two ls_file_t pointers from the input void pointers
+ * Return the result of the comparison of the modification time
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * void *n1; The first node being compared
+ * void *n2; The second node being compared
+ *
+ * Return Values:
+ *
+ * >0 - n1 > n2
+ * =0 - n1 == n2
+ * <0 - n1 < n2
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/03/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+int mod_time_sort(void *n1, void *n2)
+{
+ ls_file_t *f1 = *((ls_file_t **) n1);
+ ls_file_t *f2 = *((ls_file_t **) n2);
+ int retval;
+
+ return((retval = (f1->dir - f2->dir)) ? retval :
+ ((retval = (f1->type - f2->type)) ? retval :
+ (f2->inode.i_mtime - f1->inode.i_mtime)));
+
+} /* end of mod_time_sort */
+
+/* Name: creat_time_sort()
+ *
+ * Description:
+ *
+ * This function sorts two ls_file_t structures by the file creation time
+ *
+ * Algorithm:
+ *
+ * Assign two ls_file_t pointers from the input void pointers
+ * Return the result of the comparison of the creation time
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * void *n1; The first node being compared
+ * void *n2; The second node being compared
+ *
+ * Return Values:
+ *
+ * >0 - n1 > n2
+ * =0 - n1 == n2
+ * <0 - n1 < n2
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/03/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+int creat_time_sort(void *n1, void *n2)
+{
+ ls_file_t *f1 = *((ls_file_t **) n1);
+ ls_file_t *f2 = *((ls_file_t **) n2);
+ int retval;
+
+ return((retval = (f1->dir - f2->dir)) ? retval :
+ ((retval = (f1->type - f2->type)) ? retval :
+ (f2->inode.i_ctime - f1->inode.i_ctime)));
+} /* end of creat_time_sort */
+
+/* Name: remove_ls_dups()
+ *
+ * Description:
+ *
+ * This function will remove the first directory node if it is the only one
+ * found. It will also remove bogus entries.
+ *
+ * Algorithm:
+ *
+ * For each node in the linked list
+ * If the current node has no data
+ * Remove it from the linked list
+ * If the current entry is a DIRECTORY_TYPE
+ * Increment the number of directories.
+ * Return the starting node in the linked list
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * elist *list; The linked list to process
+ *
+ * Return Values:
+ *
+ * The starting node in the linked list.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/05/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 04/06/04 K.Sheffield Modified to just remove the first directory
+ * node if it is the only one found.
+ *
+ */
+elist_t * remove_ls_dups(elist_t *list)
+{
+ elist_t *start = list;
+ elist_t *next;
+ ls_file_t *cd;
+ ls_file_t *nd;
+ int cnt=0;
+
+ while(list != NULL)
+ {
+ cd = (ls_file_t *) list->data;
+ if (cd == NULL)
+ {
+ /* remove any empty nodes */
+ if (list == start)
+ start = list->next;
+ list = elist_delete(list, free_ls_file_t);
+ continue;
+ }
+ else if (cd->type == DIRECTORY_TYPE)
+ {
+ cnt++;
+ }
+ list = list->next;
+ }
+
+ /* if there is only one directory entry, delete it */
+ if (cnt == 1)
+ start = elist_delete(start, free_ls_file_t);
+
+ return(start);
+
+} /* end of remove_ls_dups */
diff --git a/missing b/missing
new file mode 100755
index 0000000..7789652
--- /dev/null
+++ b/missing
@@ -0,0 +1,190 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing - GNU libit 0.0"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acinclude.m4' or \`configure.in'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`configure.in'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`acconfig.h' or \`configure.in'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is missing on your system. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and you do not seem to have it handy on your
+ system. You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequirements for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/mkdir.c b/mkdir.c
new file mode 100644
index 0000000..edb791c
--- /dev/null
+++ b/mkdir.c
@@ -0,0 +1,587 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/mkdir.c,v 0.8 2004/04/07 03:19:32 ksheff Exp $ */
+/*
+ * mkdir.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ * Derived from debugfs.c Copyright (C) 1993 Theodore Ts'o <tytso@mit.edu>
+ * and modified by Robert Sanders <gt8134b@prism.gatech.edu>
+ * as well as portions of the ext2fs library (C) 1993-1995 Theodore Ts'o
+ */
+
+#ifndef MKDIR_C
+#define MKDIR_C
+#endif
+
+/* Description */
+/*
+ * This file contains the functions used to create a directory in an ext2fs
+ * filesystem.
+ *
+ */
+/*
+ * $Log: mkdir.c,v $
+ * Revision 0.8 2004/04/07 03:19:32 ksheff
+ * Modified to always apply the default user and group information.
+ *
+ * Revision 0.7 2004/04/07 02:55:44 ksheff
+ * Updated usage string.
+ *
+ * Revision 0.6 2002/07/09 02:15:23 ksheff
+ * Fixed a error reporting bug that was not displaying the full file name.
+ *
+ * Revision 0.5 2002/04/10 09:30:28 ksheff
+ * Added the ability to set the mode, owner, group, etc. for a directory.
+ *
+ * Revision 0.4 2002/03/05 13:42:12 ksheff
+ * Fixed minor indentation.
+ *
+ * Revision 0.3 2002/03/05 12:14:10 ksheff
+ * Removed setting optind for SCO.
+ *
+ * Revision 0.2 2002/02/27 05:34:43 ksheff
+ * Added the function e2mkdir which is run by a user to create directories in
+ * an ext2fs filesystem.
+ *
+ * Revision 0.1 2002/02/27 04:48:30 ksheff
+ * initial revision
+ *
+ */
+
+/* Headers */
+#include "e2tools.h"
+
+/* Local Prototypes */
+long
+e2mkdir(int argc, char *argv[]);
+
+long
+create_dir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd,
+ char *dirname, struct stat *def_stat);
+long
+create_subdir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd,
+ char *dirname, struct stat *def_stat);
+/* Name: e2mkdir()
+ *
+ * Description:
+ *
+ * This function extracts the command line parameters and creates
+ * directories based on user input
+ *
+ * Algorithm:
+ *
+ * Extract any command line switches
+ * Sort the remaining arguments
+ * For each argument
+ * Open a new filesystem if needed
+ * Create the directory
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * int argc; The number of arguments
+ * char *argv[]; the command line arguments
+ *
+ * Return Values:
+ *
+ * 0 - the directories were created successfully
+ * otherwise, an error code is returned
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/26/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 03/05/02 K. Sheffield Removed setting optind for SCO
+ * 04/10/02 K.Sheffield Added a default directory permission
+ * 04/06/04 K.Sheffield Modified to apply the default user and
+ * group.
+ */
+long
+e2mkdir(int argc, char *argv[])
+{
+ int verbose=0;
+ int num_files;
+ int errcnt=0;
+ char *last_filesys = NULL;
+ char *cur_filesys = NULL;
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ ext2_ino_t cwd;
+ char **cur_opt;
+ char *filespec;
+ int i;
+ char *ptr;
+ int c;
+ long retval;
+ struct stat def_stat;
+
+ init_stat_buf(&def_stat);
+ def_stat.st_ino = 1;
+
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt(argc, argv, "G:O:P:v")) != EOF)
+ {
+ switch (c)
+ {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'G':
+ def_stat.st_gid = atoi(optarg);
+ break;
+ case 'O':
+ def_stat.st_uid = atoi(optarg);
+ break;
+ case 'P':
+ def_stat.st_mode = strtol(optarg, NULL, 8);
+ break;
+ default:
+ errcnt++;
+ break;
+ }
+ }
+
+ if (errcnt || argc == optind)
+ {
+ fputs("Usage: e2mkdir [-G gid][-O uid][-P mode][-v] filesystem:directory...\n", stderr);
+ return(1);
+ }
+
+ num_files = argc - optind;
+
+ cur_opt = argv + optind;
+ if (num_files > 1 )
+ qsort(cur_opt, num_files, sizeof(char *), my_strcmp);
+
+ for(i=0;i<num_files;i++)
+ {
+ filespec = *cur_opt++;
+
+ /* dealing with a filesystem or a regular file */
+ if (NULL != (ptr = strchr(filespec, ':')))
+ {
+ /* separate the filesystem name from the file name */
+ *ptr++ = '\0';
+ cur_filesys = filespec;
+ filespec = ptr;
+
+ /* check to see if the filesystem has changed */
+ if (last_filesys == NULL ||
+ strcmp(last_filesys, cur_filesys) != 0)
+ {
+ if (last_filesys != NULL &&
+ (retval = ext2fs_close(fs)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ fprintf(stderr, "Error opening fileystem %s\n",
+ cur_filesys);
+ return retval;
+ }
+ cwd = root;
+ last_filesys = cur_filesys;
+ } /* end of filesystem change? */
+ if ((retval = create_dir(fs, root, &cwd, filespec, &def_stat)))
+ {
+ fprintf(stderr, "Error creating %s:%s\n", cur_filesys, filespec);
+ return(-1);
+ }
+ cwd = root; /* reset the current directory */
+ if (verbose)
+ printf("Created directory %s:%s\n", cur_filesys, filespec);
+ }
+ else if (verbose)
+ {
+ printf("%s is not a valid e2fs filesystem specification. skipping\n",
+ filespec);
+ }
+ }
+ if (fs != NULL &&
+ (retval = ext2fs_close(fs)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+ return(0);
+
+} /* end of e2mkdir */
+
+/* Name: create_dir()
+ *
+ * Description:
+ *
+ * This function will create a directory in the given ext2fs file system.
+ * It will re-create all the parent directories if necessary (similar
+ * to mkdir -p). The current working directory is then set to this new
+ * directory.
+ *
+ * Algorithm:
+ *
+ * Check the input parameters
+ * Check to see if the directory name contains a /
+ * If it exists
+ * Break the entire path into specific directory names
+ * For each section of the path
+ * Check to see if the name exists in the current directory
+ * If it doesn't
+ * Call create_subdir for that section of the path
+ * Otherwise
+ * If it is a symbolic link, follow it
+ * Read the inode structure for the current section of the path
+ * If it is not a directory
+ * Print an error message and return an error.
+ * Otherwise
+ * Call create_subdir for that section of the path
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current file system
+ * ext2_ino_t root; The inode number of the root directory
+ * ext2_ino_t *cwd; Pointer to the inode number of the current
+ * directory
+ * char *dirname; The directory to create
+ * struct stat *def_stat; Default directory status, owner, group, etc.
+ *
+ * Return Values:
+ *
+ * 0 - the directory was created successfully
+ * error code of what went wrong
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/18/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 04/10/02 K.Sheffield Added a default directory permission
+ * 07/08/02 K.Sheffield Fixed bugs in error reporting
+ */
+long
+create_dir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd,
+ char *dirname, struct stat *def_stat)
+{
+ char *ptr; /* working pointer to /'s */
+ ext2_ino_t parent; /* the parent directory inode number*/
+ ext2_ino_t child; /* the inode number of the new directory */
+ struct ext2_inode inode; /* inode of file/directory dirname */
+ char *name; /* basename of the new directory */
+ long retval; /* function return value */
+ char *buf;
+ int len;
+ char c;
+ char *dname; /* name of the sub directory */
+
+ /* make sure we have valid parameters */
+ if (fs == NULL || cwd == NULL || dirname == NULL || *dirname == '\0')
+ {
+ fputs("create_dir: invalid parameter\n", stderr);
+ return(-1);
+ }
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ /* check to see if there are any sub directories or absolute paths given
+ */
+ if (NULL != (ptr = strchr(dirname, '/')))
+ {
+
+ dname = dirname;
+ /* if the directory name starts with / the starting parent directory
+ * is the root directory.
+ */
+ if (*dirname == '/')
+ {
+ parent = root;
+ dname++;
+ }
+ else
+ parent = *cwd;
+
+ /* allocate memory for the lookups */
+ if ((retval = ext2fs_get_mem(fs->blocksize, (void **) &buf)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+
+ c = *dname;
+ ptr = dname;
+ while (c != '\0')
+ {
+ len = 0;
+ /* skip ahead to the next / character */
+ while ((c = *ptr) != '/' && c != '\0')
+ {
+ len++;
+ ptr++;
+ }
+
+ if (c == '/')
+ *ptr++ = '\0';
+
+ /* multiple /'s in a row or trailing / */
+ if (len == 0)
+ {
+ /* restore /'s */
+ if (dname > dirname)
+ *--dname = '/';
+
+ dname = ptr;
+ continue;
+ }
+
+ /* check to see if this file is in the parent directory */
+ if ((retval = ext2fs_lookup(fs, parent, dname, len, buf, &child)))
+ {
+ if (retval == EXT2_ET_FILE_NOT_FOUND)
+ {
+ /* ok, it's not there, so just create it */
+ if ((retval = create_subdir(fs, root, &parent, dname,
+ def_stat)))
+ {
+ fprintf(stderr,
+ "create_dir: error creating directory %s/%s:%d\n",
+ dirname, dname, retval);
+ ext2fs_free_mem((void **) &buf);
+ return(retval);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ ext2fs_free_mem((void **) &buf);
+ return retval;
+ }
+ }
+ else
+ {
+ /* ok, so the name exists...follow it if it's a symlink
+ * otherwise, it's a directory so set the parent directory to
+ * the child inode number
+ */
+ if ((retval = ext2fs_follow_link(fs, root, parent, child,
+ &parent)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ ext2fs_free_mem((void **) &buf);
+ return retval;
+ }
+
+ /* now check to see if it's a directory */
+ if ((retval = ext2fs_read_inode(fs, parent, &inode)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ ext2fs_free_mem((void **) &buf);
+ return retval;
+ }
+
+ /* not a directory? something's wrong */
+ if (!LINUX_S_ISDIR(inode.i_mode))
+ {
+ fprintf(stderr, "create_dir: %s/%s is not a directory: %o\n",
+ dirname, dname, inode.i_mode);
+ ext2fs_free_mem((void **) &buf);
+ return(-1);
+ }
+ }
+
+ /* restore /'s */
+ if (dname > dirname)
+ *--dname = '/';
+ dname = ptr;
+ }
+ ext2fs_free_mem((void **) &buf);
+ *cwd = parent;
+ }
+ else
+ {
+ if ((retval = create_subdir(fs, root, cwd, dirname, def_stat)))
+ {
+ fprintf(stderr,
+ "create_dir: error creating directory %s:%d\n",
+ dirname, retval);
+ return(retval);
+ }
+ }
+ return(0);
+} /* end of create_dir */
+
+/* Name: create_subdir()
+ *
+ * Description:
+ *
+ * This function will create a sub directory in the given ext2fs file system.
+ * The current working directory is then set to this new directory.
+ *
+ * Algorithm:
+ *
+ * Find a new inode number to use
+ * Create the directory
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current file system
+ * ext2_ino_t root; The inode number of the root directory
+ * ext2_ino_t *cwd; Pointer to the inode number of the current
+ * or parent directory
+ * char *dirname; The directory to create
+ * struct stat *def_stat; Default directory status, owner, group, etc.
+ *
+ * Return Values:
+ *
+ * 0 - the directory was created successfully
+ * error code of what went wrong
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/18/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 04/10/02 K.Sheffield Added a default directory permission
+ *
+ */
+long create_subdir(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd,
+ char *dirname, struct stat *def_stat)
+{
+ ext2_ino_t parent; /* the parent directory inode number*/
+ ext2_ino_t child; /* the inode number of the new directory */
+ long retval; /* function return value */
+ struct ext2_inode inode;
+
+ parent = *cwd;
+
+ if ((retval = ext2fs_namei(fs, root, parent, dirname, &child)))
+ {
+ if (retval != EXT2_ET_FILE_NOT_FOUND)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+ }
+ /* file name exists, let's see if is a directory */
+ else if ((retval = ext2fs_check_directory(fs, child)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return(retval);
+ }
+ else
+ {
+ /* if we get here, then it's an existing directory */
+ *cwd = child;
+ return(0);
+ }
+
+ /* ok, the directory doesn't exist
+ /* get a new inode number */
+ if ((retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &child)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+
+ /* now create the directory */
+ if ((retval = ext2fs_mkdir(fs, parent, child, dirname)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+
+ *cwd = child;
+ if (def_stat != NULL && def_stat->st_ino != 0)
+ {
+ if ((retval = read_inode(fs, child, &inode)))
+ return(retval);
+
+ if (def_stat->st_mode != 0)
+ inode.i_mode = LINUX_S_IFDIR | host_mode_xlate(def_stat->st_mode);
+
+ inode.i_uid = def_stat->st_uid;
+ inode.i_gid = def_stat->st_gid;
+ inode.i_atime = def_stat->st_atime;
+ inode.i_ctime = def_stat->st_ctime;
+ inode.i_mtime = def_stat->st_mtime;
+
+ if ((retval = write_inode(fs, child, &inode)))
+ return(retval);
+ }
+
+ return(0);
+} /* end of create_subdir */
+
+/* Name: change_cwd()
+ *
+ * Description:
+ *
+ * This function changes the current working directory
+ *
+ * Algorithm:
+ *
+ * Look up the inode number for the input string
+ * check to see if it's a directory
+ * Assign it as the current working directory if it is.
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current filesystem
+ * ext_ino_t root; The root directory
+ * ext_ino_t *cwd; The current working directory
+ * char *dirname; The name of the directory we want to change to
+ *
+ * Return Values:
+ *
+ * 0 - changed to the directory successfully
+ * the error code of what went wrong
+ *
+ * Author: Keith W Sheffield
+ * Date: 02/21/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+long
+change_cwd(ext2_filsys fs, ext2_ino_t root, ext2_ino_t *cwd, char *dirname)
+{
+ ext2_ino_t inode;
+ long retval;
+
+ if ((retval = ext2fs_namei(fs, root, *cwd, dirname, &inode)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+ else if ((retval = ext2fs_check_directory(fs, inode)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+ *cwd = inode;
+ return(0);
+} /* end of change_cwd */
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 0000000..4f58503
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,40 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/mv.c b/mv.c
new file mode 100644
index 0000000..a9ee0c6
--- /dev/null
+++ b/mv.c
@@ -0,0 +1,554 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/mv.c,v 0.1 2002/03/21 09:03:25 ksheff Exp $ */
+/*
+ * mv.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ */
+
+
+#ifndef MV_C
+#define MV_C
+#endif
+
+/* Description */
+/*
+ * Module to move/rename files
+ *
+ */
+/*
+ * $Log: mv.c,v $
+ * Revision 0.1 2002/03/21 09:03:25 ksheff
+ * initial revision.
+ *
+ */
+
+/* Feature Test Switches */
+/* Headers */
+#include "e2tools.h"
+
+/* Macros */
+#define USAGE "Usage: e2mv [-vfs] source1 [... sourceN] destination\n"
+
+/* Local Prototypes */
+static long
+do_swap(int force, int verbose, int curidx, int argc, char **argv);
+
+/* Name: do_mv()
+ *
+ * Description:
+ *
+ * This function reads the command line arguments and moves or renames files
+ * in an ext2fs file system
+ *
+ * Algorithm:
+ *
+ * Read any command line switches
+ * Get the first source file specification
+ * If we are performing a file swap, call do_swap()
+ * Open the file system
+ * Get the destination and determine if it is a directory
+ * If not, then get the destination's directory and basename
+ * Also check that the number of source files are no more than one
+ * For each source file
+ * Get the directory and basename of the source file
+ * Determine the inode number for the source file
+ * Create the link
+ * Unlink the original source file.
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * int argc; The number of arguments
+ * char *argv[]; The command line arguments
+ *
+ * Return Values:
+ *
+ * 0 - the file was move successfully
+ * an error occurred.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 03/20/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ */
+long
+do_mv(int argc, char *argv[])
+{
+ int verbose=0;
+ int force=0;
+ int swap_files=0;
+ int num_files;
+ int errcnt=0;
+ char *cur_filesys = NULL;
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ ext2_ino_t srcd;
+ ext2_ino_t destd;
+ ext2_ino_t source_file;
+ char *src_dir;
+ char *dest_dir;
+ char *src_name;
+ char *dest_name;
+ char *result_name;
+ long retval;
+ int c;
+ int curidx;
+
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt(argc, argv, "vfs")) != EOF)
+ {
+ switch (c)
+ {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'f':
+ force = E2T_FORCE;
+ break;
+ case 's':
+ swap_files = 1;
+ break;
+ default:
+ errcnt++;
+ break;
+ }
+ }
+
+ curidx = optind;
+
+ force |= E2T_DO_MV;
+
+ if (errcnt || argc < curidx+2)
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+
+ if (swap_files)
+ return(do_swap(force, verbose, curidx, argc, argv));
+
+ cur_filesys = argv[curidx++];
+ if (NULL == (src_dir = strchr(cur_filesys, ':')))
+ {
+ fprintf(stderr, "Invalid file specification: %s\n", cur_filesys);
+ return(1);
+ }
+ *src_dir++ = '\0';
+
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
+ {
+ fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys);
+ return retval;
+ }
+
+
+ /* get the destination directory */
+ dest_name = NULL;
+ if (strcmp(dest_dir = argv[argc-1], ".") != 0)
+ {
+ /* check to see if the file name already exists in the current
+ * directory and also see if it is a directory.
+ */
+ if ((retval = ext2fs_namei(fs, root, root, dest_dir, &destd)) ||
+ (retval = ext2fs_check_directory(fs, destd)))
+ {
+ if (retval != EXT2_ET_FILE_NOT_FOUND &&
+ retval != EXT2_ET_NO_DIRECTORY)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ /* ok, so it's either not there or it's not a directory, so
+ * get the real destination directory and file name.
+ */
+ if (curidx+1 < argc)
+ {
+ fprintf(stderr, "%s must be a directory!\n", dest_dir);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if (get_file_parts(fs, root, dest_dir, &destd, &dest_dir,
+ &dest_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+ }
+ else /* we have a directory!!! */
+ dest_name = NULL;
+ }
+ else
+ {
+ destd = root;
+ dest_name = NULL;
+ }
+
+ do
+ {
+ /* move to the source directory */
+ if (get_file_parts(fs, root, src_dir, &srcd, &src_dir, &src_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* get the inode number for the source file */
+ if ((retval = ext2fs_namei(fs, srcd, srcd, src_name, &source_file)))
+ {
+ fprintf(stderr, "%s: source file %s\n",error_message(retval),
+ src_name);
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ result_name = (dest_name) ? dest_name : src_name;
+
+ /* now create the link */
+ if ((retval = create_hard_link(fs, destd, source_file, result_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((src_dir == NULL) ? "." : src_dir), src_name,
+ ((dest_dir == NULL) ? "." : dest_dir), result_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if ((retval = ext2fs_unlink(fs, srcd, src_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", src_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ if (verbose)
+ fprintf(stderr, "moved %s/%s as %s/%s\n",
+ ((src_dir == NULL) ? "." : src_dir), src_name,
+ ((dest_dir == NULL) ? "." : dest_dir), result_name);
+ src_dir = argv[curidx++];
+ }
+ while (curidx < argc);
+
+ ext2fs_close(fs);
+ return(0);
+
+} /* end of do_mv */
+
+/* Name: get_file_parts()
+ *
+ * Description:
+ *
+ * This function returns each of the following file 'parts': directory name,
+ * base name, inode number of the directory
+ *
+ * Algorithm:
+ *
+ * Use the root directory as the current working directory
+ * Find the last / in the full pathname
+ * If none are found, set the basename to the full pathname,
+ * and the directory to NULL
+ * Otherwise,
+ * Separate the basename from the directory
+ * Change the working directory
+ * Set the return pointers.
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; the filesystem being used
+ * ext2_ino_t root; the root directory of the filesystem
+ * char *pathname; the full pathname of the file
+ * ext2_ino_t *dir_ino; The inode number of the directory
+ * char **dir_name; the directory the file is in
+ * char **base_name; The basename of the file
+ *
+ * Return Values:
+ *
+ * 0 - retrieved the information ok
+ * otherwise the error code of what went wrong
+ *
+ * Author: Keith W. Sheffield
+ * Date: 03/21/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+long
+get_file_parts(ext2_filsys fs, ext2_ino_t root, char *pathname,
+ ext2_ino_t *dir_ino, char **dir_name, char **base_name)
+{
+ char *fname;
+ long retval;
+
+ /* move to the source directory */
+ *dir_name = pathname;
+ *dir_ino = root;
+ if (NULL == (fname = strrchr(pathname, '/')))
+ {
+ fname = pathname;
+ *dir_name = NULL;
+ }
+ else
+ {
+ *fname++ = '\0';
+ if ((*pathname != '\0' && strcmp(pathname, ".") != 0) &&
+ (retval = change_cwd(fs, root, dir_ino, pathname)))
+ {
+ fprintf(stderr, "Error changing to directory %s\n",
+ pathname);
+ return(retval);
+ }
+ }
+
+ *base_name = fname;
+ return(0);
+} /* end of get_file_parts */
+
+
+/* Name: do_swap()
+ *
+ * Description:
+ *
+ * This function swaps the names of two files and optionally assigns the
+ * first file a new name:
+ *
+ * file1 file2 file3
+ *
+ * After the operation, file1 will reference the file that was originally file2, and file3 will reference the what used to be file1.
+ *
+ * Algorithm:
+ *
+ * check input parameters
+ * Get the directory and inode numbers for the first two files
+ * If a third file exists
+ * Get the directory info for the file
+ * Rename the first file to the third
+ * Rename the 2nd file to the first
+ * Otherwise
+ * Remove the first file from its directory
+ * Rename the 2nd file to the first
+ * Add the first file back as the 2nd file.
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * int force; Flag indicating if existing files are to be removed
+ * int verbose; Flag to print lots of output
+ * int curidx; The current index in the command line args
+ * int argc; The total number of arguments
+ * char **argv; Pointer to an array of argument strings.
+ *
+ * Return Values:
+ *
+ * 0 - the operation was successful
+ * otherwise the error code of what went wrong.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 03/21/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+
+static long
+do_swap(int force, int verbose, int curidx, int argc, char **argv)
+{
+ char *cur_filesys = NULL;
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ ext2_ino_t file1_dirno;
+ ext2_ino_t file2_dirno;
+ ext2_ino_t file3_dirno;
+ ext2_ino_t file1_no;
+ ext2_ino_t file2_no;
+ char *file1_dir;
+ char *file2_dir;
+ char *file3_dir;
+ char *file1_name;
+ char *file2_name;
+ char *file3_name;
+ long retval;
+
+ if (curidx + 2 > argc)
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+
+ cur_filesys = argv[curidx++];
+ if (NULL == (file1_dir = strchr(cur_filesys, ':')))
+ {
+ fprintf(stderr, "Invalid file specification: %s\n", cur_filesys);
+ return(1);
+ }
+ *file1_dir++ = '\0';
+
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
+ {
+ fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys);
+ return retval;
+ }
+
+ /* move to the file 1 directory */
+ if (get_file_parts(fs, root, file1_dir, &file1_dirno, &file1_dir,
+ &file1_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* get the inode number for the file 1 file */
+ if ((retval = ext2fs_namei(fs, file1_dirno, file1_dirno, file1_name,
+ &file1_no)))
+ {
+ fprintf(stderr, "%s: file 1 file %s\n",error_message(retval),
+ file1_name);
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+
+ /* move to the file 2 directory */
+ if (get_file_parts(fs, root, argv[curidx++], &file2_dirno, &file2_dir,
+ &file2_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* get the inode number for the file 2 file */
+ if ((retval = ext2fs_namei(fs, file2_dirno, file2_dirno, file2_name,
+ &file2_no)))
+ {
+ fprintf(stderr, "%s: file 2 file %s\n",error_message(retval),
+ file2_name);
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ if (curidx < argc)
+ {
+ /* move to the file 3 directory */
+ if (get_file_parts(fs, root, argv[curidx++], &file3_dirno, &file3_dir,
+ &file3_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* now move the first file to the 3rd */
+ if ((retval = create_hard_link(fs, file3_dirno, file1_no, file3_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name,
+ ((file3_dir == NULL) ? "." : file3_dir), file3_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if ((retval = ext2fs_unlink(fs, file1_dirno, file1_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", file1_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+
+ /* now move the 2nd file to the 1st */
+ if ((retval = create_hard_link(fs, file1_dirno, file2_no, file1_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name,
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if ((retval = ext2fs_unlink(fs, file2_dirno, file2_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", file2_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ if (verbose)
+ fprintf(stderr, "renamed file %s/%s as %s/%s\n"
+ "renamed file %s/%s as %s/%s\n",
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name,
+ ((file3_dir == NULL) ? "." : file3_dir), file3_name,
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name,
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name);
+ }
+ else
+ {
+ /* now remove the first file */
+ if ((retval = ext2fs_unlink(fs, file1_dirno, file1_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", file1_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ /* now move the 2nd file to the 1st */
+ if ((retval = create_hard_link(fs, file1_dirno, file2_no, file1_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name,
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if ((retval = ext2fs_unlink(fs, file2_dirno, file2_name, 0, 0)))
+ {
+ fprintf(stderr, "%s - %s\n", file2_name, error_message(retval));
+ ext2fs_close(fs);
+ return(retval);
+ }
+
+ if ((retval = create_hard_link(fs, file2_dirno, file1_no, file2_name,
+ force)))
+ {
+ fprintf(stderr, "Error renaming %s/%s as %s/%s\n",
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name,
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name);
+ ext2fs_close(fs);
+ return(1);
+ }
+
+ if (verbose)
+ fprintf(stderr, "swapped files %s/%s <-> %s/%s\n",
+ ((file1_dir == NULL) ? "." : file1_dir), file1_name,
+ ((file2_dir == NULL) ? "." : file2_dir), file2_name);
+
+ }
+
+ ext2fs_close(fs);
+ return(0);
+
+} /* end of do_swap */
diff --git a/progress.c b/progress.c
new file mode 100644
index 0000000..ac44cac
--- /dev/null
+++ b/progress.c
@@ -0,0 +1,198 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/progress.c,v 0.1 2002/06/26 11:17:28 ksheff Exp $ */
+/*
+ * progress.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ */
+
+#ifndef PROGRESS_C
+#define PROGRESS_C
+#endif
+
+/* Description */
+/*
+ *
+ *
+ */
+/*
+ * $Log: progress.c,v $
+ * Revision 0.1 2002/06/26 11:17:28 ksheff
+ * Initial revision
+ *
+ */
+
+/* Feature Test Switches */
+/* System Headers */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+/* Macros */
+#define PROG_FILE_SIZE 50
+#define PROG_CLEAR \
+" \r"
+/* Local Variables */
+
+static char prog_file[PROG_FILE_SIZE+1];
+static struct stat *prog_sbuf = NULL;
+static long prog_start;
+static long prog_time;
+
+/* Name: init_progress()
+ *
+ * Description:
+ *
+ * This function initializes the progress status variables for a particular
+ * file operation
+ * .
+ *
+ * Algorithm:
+ *
+ * Determine the size of the file name
+ * Copy the last PROG_FILE_SIZE characters of the filename
+ * Copy the pointer to the file statistics structure
+ *
+ * Global Variables:
+ *
+ * char prog_file[PROG_FILE_SIZE+1]; The file being operated on
+ * struct stat *prog_sbuf; prog_file's information
+ * long prog_start; The initial start time
+ * long prog_time; The last update time
+ *
+ * Arguments:
+ *
+ * char *file; The file to watch
+ * struct stat *sbuf; The file's information
+ *
+ * Return Values:
+ *
+ * None
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/26/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+void init_progress(char *file, struct stat *sbuf)
+{
+ int len;
+ struct timeval tv;
+
+ if (file != NULL && sbuf != NULL)
+ {
+ if (strcmp(file, "-") == 0)
+ file = "<stdin>";
+
+ len = strlen(file);
+ if (len > PROG_FILE_SIZE)
+ {
+ file += (len - PROG_FILE_SIZE);
+ len = PROG_FILE_SIZE;
+ }
+ memset(prog_file, ' ', PROG_FILE_SIZE);
+ memcpy(prog_file, file, len);
+ prog_file[PROG_FILE_SIZE] = '\0';
+ prog_sbuf = sbuf;
+ gettimeofday(&tv, NULL);
+ prog_start = prog_time = tv.tv_sec;
+ }
+ else
+ {
+ prog_file[0] = '\0';
+ prog_sbuf = NULL;
+ prog_start = prog_time = 0;
+ }
+
+} /* end of init_progress */
+
+/* Name: update_progress()
+ *
+ * Description:
+ *
+ * This function updates the current file progress display.
+ *
+ * Algorithm:
+ *
+ * Get the system time in seconds.
+ * If different from the last update
+ * Save the system time
+ * Display the file name, current byte total, and total file size
+ *
+ * Global Variables:
+ *
+ * char prog_file[PROG_FILE_SIZE+1]; The file being operated on
+ * struct stat *prog_sbuf; prog_file's information
+ * long prog_time; The last update time
+ *
+ * Arguments:
+ *
+ * unsigned long num_bytes; The number of bytes transferred
+ *
+ * Return Values:
+ *
+ * None
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/26/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+void update_progress(unsigned long num_bytes)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ if (prog_sbuf != NULL && prog_time != tv.tv_sec)
+ {
+ prog_time = tv.tv_sec;
+ fprintf(stderr, "%s %10d / %10d\r", prog_file, num_bytes,
+ prog_sbuf->st_size);
+ fflush(stderr);
+ }
+} /* end of update_progress */
+
+/* Name: finish_progress()
+ *
+ * Description:
+ *
+ * This function clears the current progress line if needed.
+ *
+ * Algorithm:
+ *
+ * Check to see if prog_start is different than prog_time
+ * Clear the progress line
+ *
+ * Global Variables:
+ *
+ *
+ * Arguments:
+ *
+ * None
+ *
+ * Return Values:
+ *
+ * None
+ *
+ * Author: Keith W. Sheffield
+ * Date: 06/26/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+void finish_progress()
+{
+ if (prog_start != prog_time)
+ fputs(PROG_CLEAR, stderr);
+
+} /* end of finish_progress */
diff --git a/read.c b/read.c
new file mode 100644
index 0000000..e469ccb
--- /dev/null
+++ b/read.c
@@ -0,0 +1,368 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/read.c,v 0.2 2002/08/08 07:58:35 ksheff Exp $ */
+/*
+ * read.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ * Derived from dump.c Copyright (C) 1994 Theodore Ts'o <tytso@mit.edu>
+ *
+ */
+
+static char rcsid[] = "$Id: read.c,v 0.2 2002/08/08 07:58:35 ksheff Exp $";
+
+static char copyright[] = "Copyright 2002 Keith W Sheffield";
+
+#ifndef READ_C
+#define READ_C
+#endif
+
+/* Description */
+/*
+ *
+ *
+ */
+/*
+ * $Log: read.c,v $
+ * Revision 0.2 2002/08/08 07:58:35 ksheff
+ * Split the read loop from retrieve_data() out to its own function:
+ * read_to_eof() and made retrieve_data() able to seek to an offset before
+ * starting to read.
+ *
+ * Revision 0.1 2002/02/27 04:48:52 ksheff
+ * initial revision
+ *
+ */
+
+/* Feature Test Switches */
+/* Headers */
+#include "e2tools.h"
+
+/* Local Prototypes */
+
+long
+get_file(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ char *infile, char *outfile, int keep);
+
+long
+retrieve_data(ext2_filsys fs, ext2_ino_t src, int dest_fd,
+ char *dest_name, int keep, ext2_off_t offset,
+ ext2_off_t *ret_pos);
+
+long
+read_to_eof(ext2_file_t infile, int dest_fd, ext2_off_t offset,
+ ext2_off_t *ret_pos);
+
+
+static void
+fix_perms(const struct ext2_inode *inode, int fd, const char *name);
+
+/* Name: get_file()
+ *
+ * Description:
+ *
+ * This function copies a file from the current ext2fs directory to disk
+ * or stdout.
+ *
+ * Algorithm:
+ *
+ * Check input parameters
+ * If the output file is NULL
+ * Get the file descriptor for stdout
+ * Otherwise
+ * Open the output file
+ * Get the inode number for the input file
+ * Copy the contents to the output file
+ * Close output file
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current file system
+ * ext2_ino_t root; The root directory
+ * ext2_ino_t cwd; The current working directory
+ * char *infile; The name of the input file
+ * char *outfile; The name of the output file
+ * int keep; Flag indicating if the permissions should be kept
+ *
+ * Return Values:
+ *
+ * 0 - the file was copied successfully
+ * the error code of whatever went wrong.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/20/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+
+long
+get_file(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+ char *infile, char *outfile, int keep)
+{
+ int fd;
+ ext2_ino_t src;
+ int dest;
+ int retval;
+
+ if (fs == NULL || infile == NULL)
+ {
+ fputs("Invalid input parameter. Exiting get_file() with -1\n",
+ stderr);
+ return (-1);
+ }
+
+ /* open the output file if we need to */
+ if (outfile == NULL)
+ dest = fileno(stdout);
+ else if (-1 == (dest = open(outfile, O_CREAT | O_WRONLY | O_TRUNC, 0666)))
+ {
+ perror(outfile);
+ return(-1);
+ }
+
+ /* get the inode number associated with the input file */
+ if ((retval = ext2fs_namei(fs, root, cwd, infile, &src)))
+ {
+ if (retval == EXT2_ET_FILE_NOT_FOUND)
+ {
+ fprintf(stderr, "%s not found\n", infile);
+ if (outfile)
+ {
+ close(dest);
+#ifndef DEBUG
+ unlink(outfile);
+#endif
+ }
+ return(0);
+ }
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ /* get the data from the ext2fs */
+ if ((retval = retrieve_data(fs, src, dest, outfile, keep, 0, NULL)))
+ {
+ if (outfile)
+ {
+ close(dest);
+#ifndef DEBUG
+ unlink(outfile);
+#endif
+ }
+ return(retval);
+ }
+ if (outfile)
+ close(dest);
+ return(0);
+
+} /* end of get_file */
+
+
+/* Name: retrieve_data()
+ *
+ * Description:
+ *
+ * This function retrieves the data stored as a file in an ext2fs file
+ * system.
+ *
+ * Algorithm:
+ *
+ * Get the inode associated with the file name
+ * Open the file in the ext2fs file system
+ * Copy the contents of the ext2fs file to the output file descriptor
+ * Close the ext2fs file
+ * If the permissions are to be kept
+ * Call fix_perms
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The filesystem being read from
+ * ext2_ino_t src; The source inode number
+ * int dest_fd; The destination file descriptor
+ * char *dest_name; The name of the destination file
+ * int keep; Keep the permissions/ownership, etc. from ext2fs
+ *
+ * Return Values:
+ *
+ * 0 - file read successfully
+ * error code of what went wrong.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/20/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 08/07/02 K.Sheffield Moved the copy loop to read_to_eof()
+ *
+ */
+
+long
+retrieve_data(ext2_filsys fs, ext2_ino_t src, int dest_fd,
+ char *dest_name, int keep, ext2_off_t offset,
+ ext2_off_t *ret_pos)
+{
+ struct ext2_inode inode;
+ ext2_file_t infile;
+ int retval;
+
+ if (keep && (retval = ext2fs_read_inode(fs, src, &inode)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ if ((retval = ext2fs_file_open(fs, src, 0, &infile)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ if (read_to_eof(infile, dest_fd, offset, ret_pos))
+ {
+ if ((retval = ext2fs_file_close(infile)))
+ fputs(error_message(retval), stderr);
+ return(-1);
+ }
+
+ if ((retval = ext2fs_file_close(infile)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ if (keep)
+ fix_perms(&inode, dest_fd, dest_name);
+
+ return(0);
+
+} /* end of retrieve_data */
+
+/* Name: read_to_eof()
+ *
+ * Description:
+ *
+ * This function reads from an ext2_file_t file and outputs the contents
+ * to a standard file descriptor.
+ *
+ * Algorithm:
+ *
+ * Seek to the desired location
+ * While one is able to read data from the ext2fs file
+ * Write data to the output file descriptor.
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * ext2_file_t infile; Input file
+ * int dest_fd; The destination file descriptor
+ * ext2_off_t offset; The offset in the file to seek
+ * ext2_off_t *ret_pos; The returned file position
+ *
+ * Return Values:
+ *
+ *
+ * Author: Keith W. Sheffield
+ * Date: 08/07/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ *
+ */
+long
+read_to_eof(ext2_file_t infile, int dest_fd, ext2_off_t offset,
+ ext2_off_t *ret_pos)
+{
+ char buf[4096];
+ unsigned int bytes_read;
+ int bytes_written;
+ int retval;
+
+ if (offset != 0 &&
+ (retval = ext2fs_file_lseek(infile, offset, EXT2_SEEK_SET, NULL)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ /* read all that we can and dump it to the output file descriptor */
+ do
+ {
+ if ((retval = ext2fs_file_read(infile, buf, sizeof(buf), &bytes_read)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+ }
+ while (bytes_read > 0 &&
+ bytes_read == (bytes_written = write(dest_fd, buf, bytes_read)));
+
+ if (bytes_read)
+ {
+ perror("read_to_eof");
+ return(-1);
+ }
+
+ if (ret_pos != NULL &&
+ (retval = ext2fs_file_lseek(infile, 0, EXT2_SEEK_CUR, ret_pos)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ return(0);
+
+} /* end of read_to_eof */
+
+/* blatantly copied from code written by T Ts'o w/ minor changes */
+static void
+fix_perms(const struct ext2_inode *inode, int fd, const char *name)
+{
+ struct utimbuf ut;
+ int i;
+
+ if (fd != -1)
+ i = fchmod(fd, ext2_mode_xlate(inode->i_mode));
+ else
+ i = chmod(name, ext2_mode_xlate(inode->i_mode));
+ if (i == -1)
+ perror(name);
+
+#ifndef HAVE_FCHOWN
+ i = chown(name, inode->i_uid, inode->i_gid);
+#else
+ if (fd != -1)
+ i = fchown(fd, inode->i_uid, inode->i_gid);
+ else
+ i = chown(name, inode->i_uid, inode->i_gid);
+#endif
+ if (i == -1)
+ perror(name);
+
+ if (fd != -1)
+ close(fd);
+
+ ut.actime = inode->i_atime;
+ ut.modtime = inode->i_mtime;
+ if (utime(name, &ut) == -1)
+ perror(name);
+
+}
+
+
+
diff --git a/rm.c b/rm.c
new file mode 100644
index 0000000..d4b083e
--- /dev/null
+++ b/rm.c
@@ -0,0 +1,413 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/rm.c,v 0.3 2004/04/06 23:39:28 ksheff Exp $ */
+/*
+ * rm.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ * Derived from debugfs.c Copyright (C) 1993 Theodore Ts'o <tytso@mit.edu>
+ * and modified by Robert Sanders <gt8134b@prism.gatech.edu>
+ * as well as portions of the ext2fs library (C) 1993-1995 Theodore Ts'o
+ */
+
+#ifndef RM_C
+#define RM_C
+#endif
+
+/* Description */
+/*
+ * This file contains function used to remove files in an ext2fs filesystem.
+ *
+ */
+/*
+ * $Log: rm.c,v $
+ * Revision 0.3 2004/04/06 23:39:28 ksheff
+ * Corrected getopt and usage strings.
+ *
+ * Revision 0.2 2002/06/05 23:39:13 ksheff
+ * Added ability to delete files based on a regular expression and recursive
+ * deletion of directories.
+ *
+ * Revision 0.1 2002/04/10 10:42:40 ksheff
+ * initial revision
+ *
+ */
+
+
+/* Headers */
+#include "e2tools.h"
+#include <regex.h>
+
+static ext2_filsys gbl_fs = NULL;
+static char *gbl_filesys = NULL;
+static char *gbl_path_end = NULL;
+static char gbl_dir_name[8192];
+
+struct regexp_args
+{
+ int verbose;
+ int recursive;
+ regex_t *reg;
+};
+
+/* Local Prototypes */
+long
+e2rm(int argc, char *argv[]);
+static
+int rm_dir_proc(ext2_ino_t dir,int entry, struct ext2_dir_entry *dirent,
+ int offset, int blocksize, char *buf, void *verbose);
+static int
+recursive_rm(ext2_ino_t dir, char *name, struct ext2_dir_entry *dirent,
+ int verbose);
+static int
+rm_regex_proc(ext2_ino_t dir, int entry, struct ext2_dir_entry *dirent,
+ int offset, int blocksize, char *buf, void *private);
+
+/* Name: e2rm()
+ *
+ * Description:
+ *
+ * This function extracts the command line parameters and creates
+ * directories based on user input
+ *
+ * Algorithm:
+ *
+ * Extract any command line switches
+ * Sort the remaining arguments
+ * For each argument
+ * Open a new filesystem if needed
+ * Remove the file if it exists.
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * int argc; The number of arguments
+ * char *argv[]; the command line arguments
+ *
+ * Return Values:
+ *
+ * 0 - the filess were created successfully
+ * otherwise, an error code is returned
+ *
+ * Author: Keith W. Sheffield
+ * Date: 04/10/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 04/06/04 K.Sheffield Corrected getopt and usage strings.
+ */
+long
+e2rm(int argc, char *argv[])
+{
+ int verbose=0;
+ int errcnt=0;
+ int recursive=0;
+ char *last_filesys = NULL;
+ char *cur_filesys = NULL;
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ ext2_ino_t cwd;
+ char **cur_opt;
+ char *filespec;
+ long retval;
+ char *dir_name;
+ char *base_name;
+ ext2_ino_t curr_ino;
+ int c;
+ int num_files;
+ char *ptr;
+ struct regexp_args reg;
+
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt(argc, argv, "vr")) != EOF)
+ {
+ switch (c)
+ {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'r':
+ recursive = 1;
+ break;
+ default:
+ errcnt++;
+ break;
+ }
+ }
+
+ if (errcnt || argc == optind)
+ {
+ fputs("Usage: e2rm [-vr] filesystem:filepath...\n", stderr);
+ return(1);
+ }
+
+ num_files = argc - optind;
+
+ cur_opt = argv + optind;
+ if (num_files > 1 )
+ qsort(cur_opt, num_files, sizeof(char *), my_strcmp);
+
+ for(c=0;c<num_files;c++)
+ {
+ filespec = *cur_opt++;
+
+ /* dealing with a filesystem or a regular file */
+ if (NULL != (ptr = strchr(filespec, ':')))
+ {
+ /* separate the filesystem name from the file name */
+ *ptr++ = '\0';
+ cur_filesys = filespec;
+ filespec = ptr;
+
+ /* check to see if the filesystem has changed */
+ if (last_filesys == NULL ||
+ strcmp(last_filesys, cur_filesys) != 0)
+ {
+ if (last_filesys != NULL &&
+ (retval = ext2fs_close(fs)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 1)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ fprintf(stderr, "Error opening fileystem %s\n",
+ cur_filesys);
+ return retval;
+ }
+ cwd = root;
+ last_filesys = cur_filesys;
+ } /* end of filesystem change? */
+
+
+ if (get_file_parts(fs, root, filespec, &cwd, &dir_name, &base_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ if (is_file_regexp(base_name))
+ {
+ if (NULL == (reg.reg = (regex_t *) make_regexp(base_name)))
+ {
+ fprintf(stderr,
+ "Error creating regular expression for %s\n",
+ base_name);
+ continue;
+ }
+
+ gbl_fs = fs;
+ gbl_filesys = cur_filesys;
+
+ reg.verbose = verbose;
+ reg.recursive = recursive;
+
+ strcpy(gbl_dir_name, dir_name);
+ gbl_path_end = gbl_dir_name + strlen(gbl_dir_name);
+
+ retval = ext2fs_dir_iterate2(gbl_fs, cwd,
+ DIRENT_FLAG_INCLUDE_EMPTY, 0,
+ rm_regex_proc, (void *) &reg);
+ regfree(reg.reg);
+ continue;
+ }
+
+ /* check to see if the file name exists in the current directory */
+ else if ((retval = ext2fs_namei(fs, cwd, cwd, base_name, &curr_ino)))
+ {
+ if (retval != EXT2_ET_FILE_NOT_FOUND)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+ }
+ /* file name exists, let's see if is a directory */
+ else if ((retval = ext2fs_check_directory(fs, curr_ino)) == 0)
+ {
+ if (recursive)
+ {
+ gbl_fs = fs;
+ gbl_filesys = cur_filesys;
+
+ sprintf(gbl_dir_name, "%s/%s", (dir_name == NULL)?".":
+ dir_name, base_name);
+ gbl_path_end = gbl_dir_name + strlen(gbl_dir_name);
+
+ retval = ext2fs_dir_iterate2(gbl_fs, curr_ino,
+ DIRENT_FLAG_INCLUDE_EMPTY, 0,
+ rm_dir_proc,
+ (void *)
+ (verbose) ? &verbose : NULL);
+ }
+ else
+ {
+ printf("%s:%s/%s is a directory! Not removed\n", cur_filesys,
+ (dir_name == NULL)?".": dir_name, base_name);
+ continue;
+ }
+ }
+ if (retval != 0 && retval != EXT2_ET_NO_DIRECTORY)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+ /* delete the existing file if needed */
+ if ((retval = rm_file(fs, cwd, base_name, curr_ino)))
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+
+ if (verbose)
+ printf("Removed %s:%s/%s\n", cur_filesys,
+ (dir_name == NULL)?".":dir_name, base_name);
+ }
+
+ else if (verbose)
+ {
+ printf("%s is not a valid e2fs filesystem specification. skipping\n",
+ filespec);
+ }
+ }
+
+ if (fs != NULL &&
+ (retval = ext2fs_close(fs)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+ }
+ return(0);
+
+} /* end of e2rm */
+
+static int rm_dir_proc(ext2_ino_t dir, int entry,
+ struct ext2_dir_entry *dirent, int offset,
+ int blocksize, char *buf, void *verbose)
+{
+ char name[EXT2_NAME_LEN];
+ int thislen;
+
+ thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN) ?
+ (dirent->name_len & 0xFF) : EXT2_NAME_LEN;
+
+ if (dirent->name[0] == '.' &&
+ (thislen == 1 || (thislen == 2 && dirent->name[1] == '.')))
+ return 0;
+
+ strncpy(name, dirent->name, thislen);
+ name[thislen] = '\0';
+
+ if (entry == DIRENT_DELETED_FILE)
+ return 0;
+
+ return (recursive_rm(dir, name, dirent, (verbose) ? 1 : 0));
+}
+
+static int
+recursive_rm(ext2_ino_t dir, char *name, struct ext2_dir_entry *dirent,
+ int verbose)
+{
+ long retval;
+
+ /* file name exists, let's see if is a directory */
+ if ((retval = ext2fs_check_directory(gbl_fs, dirent->inode)) == 0)
+ {
+ *gbl_path_end++ = '/';
+ strncpy(gbl_path_end, dirent->name, dirent->name_len);
+ gbl_path_end += dirent->name_len;
+ *gbl_path_end = '\0';
+
+ retval = ext2fs_dir_iterate2(gbl_fs, dirent->inode,
+ DIRENT_FLAG_INCLUDE_EMPTY, 0,
+ rm_dir_proc, (verbose) ? &verbose : NULL);
+
+ while (gbl_path_end > gbl_dir_name && *gbl_path_end != '/')
+ gbl_path_end--;
+ *gbl_path_end = '\0';
+ }
+
+ if (retval !=0 && retval != EXT2_ET_NO_DIRECTORY)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+ /* delete the existing file if needed */
+ if ((retval = rm_file(gbl_fs, dir, name, dirent->inode)))
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+
+ if (verbose)
+ printf("Removed %s:%s/%s\n", gbl_filesys, gbl_dir_name, name);
+
+ return 0;
+}
+
+static int
+rm_regex_proc(ext2_ino_t dir, int entry, struct ext2_dir_entry *dirent,
+ int offset, int blocksize, char *buf, void *arg)
+{
+ long retval;
+ char name[EXT2_NAME_LEN];
+ int thislen;
+ struct regexp_args *reg = (struct regexp_args *) arg;
+
+ thislen = ((dirent->name_len & 0xFF) < EXT2_NAME_LEN) ?
+ (dirent->name_len & 0xFF) : EXT2_NAME_LEN;
+
+ if (dirent->name[0] == '.' &&
+ (thislen == 1 || (thislen == 2 && dirent->name[1] == '.')))
+ return 0;
+
+ strncpy(name, dirent->name, thislen);
+ name[thislen] = '\0';
+
+ if (entry == DIRENT_DELETED_FILE)
+ return 0;
+
+ if (0 == (retval = regexec(reg->reg, name, 0, NULL, 0)))
+ {
+ if (reg->recursive)
+ return (recursive_rm(dir, name, dirent, (reg->verbose) ? 1 : 0));
+ else
+ {
+ if ((retval = ext2fs_check_directory(gbl_fs, dirent->inode)))
+ {
+ if (retval != EXT2_ET_NO_DIRECTORY)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+ /* delete the existing file if needed */
+ if ((retval = rm_file(gbl_fs, dir, name, dirent->inode)))
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ return(retval);
+ }
+
+ if (reg->verbose)
+ printf("Removed %s:%s/%s\n", gbl_filesys, gbl_dir_name, name);
+ }
+ else
+ {
+ printf("%s:%s/%s is a directory! Not removed\n", gbl_filesys,
+ gbl_dir_name, name);
+ }
+ }
+ }
+ return (0);
+}
+
+
+
+
+
diff --git a/tail.c b/tail.c
new file mode 100644
index 0000000..3bbb621
--- /dev/null
+++ b/tail.c
@@ -0,0 +1,440 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/tail.c,v 0.2 2003/07/12 16:33:11 ksheff Exp $ */
+/*
+ * tail.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ */
+#ifndef TAIL_C
+#define TAIL_C
+#endif
+
+/* Description */
+/* This module implements a basic version of the tail command.
+ *
+ * The user can specify the number of lines to view from the bottom of the
+ * file. This is done by specifying -n #of_lines on the command line. The
+ * default is 5.
+ *
+ * The user can also run in 'follow' mode which prints new lines as they are
+ * appended to the end of the file. This can be specified by the -f option,
+ * which is dependent on the initial inode of the file being tailed or the -F
+ * option which will always use the inode associated with the file name. The
+ * latter can be useful for log files that get switched out.
+ *
+ * The -s #seconds option allows the user to specify the sleep interval while
+ * in follow mode. The default is 1.
+ *
+ */
+/*
+ * $Log: tail.c,v $
+ * Revision 0.2 2003/07/12 16:33:11 ksheff
+ * fixed a bug when no arguments are given.
+ *
+ * Revision 0.1 2002/08/08 08:01:51 ksheff
+ * Initial revision.
+ *
+ */
+
+/* Feature Test Switches */
+/* Headers */
+
+#include "e2tools.h"
+
+
+/* Macros */
+#define USAGE "Usage: e2tail [-n num_lines][-fF][-s sleep_interval] file\n"
+#define BLK_SIZE 4096
+
+#define FOLLOW_INODE 1
+#define FOLLOW_NAME 2
+
+/* Structures and Unions */
+
+/* External Variables */
+
+/* Global Variables */
+
+/* Local Variables */
+
+/* External Prototypes */
+
+/* Local Prototypes */
+long
+do_tail(int argc, char *argv[]);
+static long
+tail(ext2_filsys *fs, ext2_ino_t root, char *input, int num_lines,
+ int follow, int sleep_int, char *cur_filesys);
+
+
+/* Name: do_tail()
+ *
+ * Description:
+ *
+ * This function reads the command line arguments and displays the last lines
+ * at the end of a file in an ext2 file system.
+ *
+ * Algorithm:
+ *
+ * Read any command line switches
+ * Get the file specification for the file we are going to display.
+ * Open the file system read only
+ * Tail the file
+ * Close the file system
+ * return the status of the tail
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * int argc; The number of arguments
+ * char *argv[]; The command line arguments
+ *
+ * Return Values:
+ *
+ * 0 - the last number of lines was displayed correctly.
+ * an error occurred.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 08/07/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 07/12/03 K.Sheffield fixed a bug when no arguments are given.
+ */
+long
+do_tail(int argc, char *argv[])
+{
+ int verbose=0;
+ int follow=0;
+ int num_lines = 5;
+ int sleep_int = 1;
+ int errcnt=0;
+ char *cur_filesys = NULL;
+ ext2_filsys fs = NULL;
+ ext2_ino_t root;
+ long retval;
+ int curidx;
+ char *tail_dir;
+ int c;
+
+
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt(argc, argv, "vFfn:s:")) != EOF)
+ {
+ switch (c)
+ {
+ case 'v':
+ verbose = 1;
+ break;
+ case 'f':
+ follow = FOLLOW_INODE;
+ break;
+ case 'F':
+ follow = FOLLOW_NAME;
+ break;
+ case 'n':
+ num_lines = atoi(optarg);
+ break;
+ case 's':
+ sleep_int = atoi(optarg);
+ if (sleep_int < 1)
+ errcnt++;
+ break;
+ default:
+ errcnt++;
+ break;
+ }
+ }
+
+ curidx = optind;
+
+ if (errcnt || argc <= curidx)
+ {
+ fputs(USAGE, stderr);
+ return(1);
+ }
+
+ cur_filesys = argv[curidx++];
+ if (NULL == (tail_dir = strchr(cur_filesys, ':')))
+ {
+ fprintf(stderr, "Invalid file specification: %s\n", cur_filesys);
+ return(1);
+ }
+ *tail_dir++ = '\0';
+
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 0)))
+ {
+ fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys);
+ return retval;
+ }
+
+ retval = tail(&fs, root, tail_dir, num_lines, follow, sleep_int,
+ cur_filesys) ? -1 : 0;
+ ext2fs_close(fs);
+ return(retval);
+}
+
+/* Name: tail()
+ *
+ * Description:
+ *
+ * This function displays the last lines at the end of a file in an ext2
+ * file system.
+ *
+ * Algorithm:
+ *
+ * Get the directory and basename of the file
+ * Determine the inode number for the file
+ * Open the file for reading
+ * Skip to the last block in the file
+ * While we have not found the last num_lines of newline characters
+ * Skip backwards in the file one block and read it
+ * Display the contents of the block from that point on.
+ * Display the rest of the file if not contained in the block
+ * Save the current location of the file.
+ * If we are following the file as it grows
+ * While forever
+ * Sleep
+ * Re-read the inode for the file
+ * If the size has changed
+ * Display the file from the saved point on
+ * Save the current location of the file.
+ *
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * ext2_filsys *fs; Our filesystem
+ * ext2_ino_t root; The root directory inode number
+ * char *input; The name of the input file to tail
+ * int num_lines; The number of lines to display
+ * int follow; Flag indicating if the we should follow any
+ * new contents to the file.
+ * int sleep_int; The number of seconds to sleep between checking
+ * for new lines
+ * char *cur_filesys
+ *
+ * Return Values:
+ *
+ * 0 - the last number of lines was displayed correctly.
+ * an error occurred.
+ *
+ * Author: Keith W. Sheffield
+ * Date: 08/07/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ */
+static long
+tail(ext2_filsys *fs_ptr, ext2_ino_t root, char *input, int num_lines,
+ int follow, int sleep_int, char *cur_filesys)
+{
+ ext2_filsys fs = *fs_ptr;
+ ext2_ino_t cwd;
+ ext2_ino_t tail_ino;
+ ext2_ino_t t_tail_ino;
+ char *tail_dir;
+ char *tail_name;
+ long retval;
+ char buf[BLK_SIZE];
+ unsigned int bytes_to_read;
+ unsigned int bytes_read;
+ char *ptr;
+ off_t pos;
+ struct ext2_inode inode;
+ ext2_file_t tail_fd;
+ ext2_off_t offset;
+ ext2_off_t cur_pos;
+
+ if (get_file_parts(fs, root, input, &cwd, &tail_dir, &tail_name))
+ {
+ ext2fs_close(fs);
+ return(-1);
+ }
+
+ /* get the inode number for the source file */
+ if ((retval = ext2fs_namei(fs, cwd, cwd, tail_name, &tail_ino)))
+ {
+ fprintf(stderr, "%s: file %s\n",error_message(retval),
+ tail_name);
+ return(retval);
+ }
+
+ /* open the file */
+ if ((retval = ext2fs_file_open(fs, tail_ino, 0, &tail_fd)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ /* get the length of the file and determine where to start reading */
+ inode.i_size = offset = ext2fs_file_get_size(tail_fd);
+ bytes_to_read = offset % BLK_SIZE;
+ if (bytes_to_read == 0)
+ bytes_to_read = BLK_SIZE;
+
+ offset -= bytes_to_read;
+ if (offset < 0)
+ offset = 0;
+
+ do
+ {
+ /* seek to the start of the last block in the file */
+ if ((retval = ext2fs_file_lseek(tail_fd, offset, EXT2_SEEK_SET, NULL)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+ /* read the last block in the file */
+ if ((retval = ext2fs_file_read(tail_fd, buf, bytes_to_read,
+ &bytes_read)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+ if (bytes_to_read != bytes_read)
+ {
+ fputs("error reading file\n", stderr);
+ return(-1);
+ }
+
+ ptr = buf + bytes_read - 1;
+ while (bytes_to_read--)
+ {
+ if (*ptr == '\n' && num_lines-- == 0)
+ {
+ /* if the newline wasn't the last character in the buffer, then
+ * print what's remaining.
+ */
+ if (bytes_to_read != bytes_read - 1)
+ {
+ ptr++;
+ write(1, ptr, bytes_read - bytes_to_read - 1);
+ }
+ offset = 0; /* make sure we break out of the main loop */
+ break;
+ }
+ ptr--;
+ }
+
+ offset -= (offset < BLK_SIZE) ? offset : BLK_SIZE;
+ bytes_to_read = BLK_SIZE;
+ }
+ while (offset > 0);
+
+ /* if we are here and have any lines left, we hit the beginning, so
+ * dump the rest of what's in memory out.
+ */
+
+ if (num_lines > 0)
+ write(1, buf, bytes_read);
+
+ /* retreive the current position in the file */
+ if ((retval = ext2fs_file_lseek(tail_fd, 0, EXT2_SEEK_CUR, &cur_pos)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ /* ok, if we are before the end of the file, then dump the rest of it */
+ if (cur_pos < inode.i_size)
+ {
+ if ((retval = read_to_eof(tail_fd, 1, cur_pos, &cur_pos)))
+ {
+ return retval;
+ }
+ }
+
+ if ((retval = ext2fs_file_close(tail_fd)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+
+ if (follow)
+ {
+ while(1)
+ {
+ sleep(sleep_int);
+ /* I don't know how to force a re-read of the file system info yet,
+ * so, just close the file system and reopen it.
+ */
+ ext2fs_close(fs);
+ if ((retval = open_filesystem(cur_filesys, &fs, &root, 0)))
+ {
+ *fs_ptr = NULL;
+ fprintf(stderr, "%s: %s\n", error_message(retval), cur_filesys);
+ return retval;
+ }
+ *fs_ptr = fs;
+
+ /* if we are following the name, find the directory and file name
+ * again.
+ */
+ if (follow == FOLLOW_NAME)
+ {
+ cwd = root;
+
+ if (tail_dir != NULL && *tail_dir != '\0' &&
+ strcmp(tail_dir, ",") != 0 &&
+ (retval = change_cwd(fs, root, &cwd, tail_dir)))
+ {
+ fprintf(stderr, "Error changing to directory %s\n",
+ tail_dir);
+ return(retval);
+ }
+
+ /* get the inode number for the source file */
+ if ((retval = ext2fs_namei(fs, cwd, cwd, tail_name,
+ &t_tail_ino)))
+ {
+ fprintf(stderr, "%s: file %s\n",error_message(retval),
+ tail_name);
+ return(retval);
+ }
+
+ /* if we are dealing with a new file, then start from the
+ * beginning.
+ */
+
+ if (t_tail_ino != tail_ino)
+ {
+ tail_ino = t_tail_ino;
+ cur_pos = 0;
+ }
+ }
+
+ if ((retval = ext2fs_read_inode(fs, tail_ino, &inode)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+ if (inode.i_size > cur_pos)
+ {
+ if ((retval = retrieve_data(fs, tail_ino, 1, NULL, 0, cur_pos,
+ &cur_pos)))
+ {
+ fputs(error_message(retval), stderr);
+ return retval;
+ }
+ }
+ else if (inode.i_size < cur_pos)
+ {
+ /* the file was truncated, so bail */
+ return(0);
+ }
+ }
+ }
+ return(0);
+}
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..5c8e5ea
--- /dev/null
+++ b/util.c
@@ -0,0 +1,320 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/util.c,v 0.4 2002/06/05 20:38:16 ksheff Exp $ */
+/*
+ * util.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ * Derived from debugfs.c Copyright (C) 1993 Theodore Ts'o <tytso@mit.edu>
+ * and modified by Robert Sanders <gt8134b@prism.gatech.edu>
+ */
+
+#ifndef UTIL_C
+#define UTIL_C
+#endif
+
+/* Description */
+/*
+ * Misc. utility functions
+ *
+ */
+/*
+ * $Log: util.c,v $
+ * Revision 0.4 2002/06/05 20:38:16 ksheff
+ * Added regular expression routines.
+ *
+ * Revision 0.3 2002/04/10 09:31:21 ksheff
+ * Added function init_stat_buf().
+ *
+ * Revision 0.2 2002/03/07 07:27:45 ksheff
+ * checked for return of ext2fs_unlink in rm_file().
+ *
+ * Revision 0.1 2002/02/27 04:49:11 ksheff
+ * initial revision
+ *
+ */
+
+/* Headers */
+#include "e2tools.h"
+#include <regex.h>
+
+/* Macros */
+
+/* Structures and Unions */
+typedef struct
+{
+ __u16 lmask;
+ mode_t mask;
+} MODE_XLAT_T;
+
+static MODE_XLAT_T xlat_tbl[] =
+{
+ { LINUX_S_IFREG, S_IFREG },
+ { LINUX_S_IFDIR, S_IFDIR },
+ { LINUX_S_IFCHR, S_IFCHR },
+ { LINUX_S_IFIFO, S_IFIFO },
+ { LINUX_S_ISUID, S_ISUID },
+ { LINUX_S_ISGID, S_ISGID },
+ { LINUX_S_ISVTX, S_ISVTX },
+ { LINUX_S_IRUSR, S_IRUSR },
+ { LINUX_S_IWUSR, S_IWUSR },
+ { LINUX_S_IXUSR, S_IXUSR },
+ { LINUX_S_IRGRP, S_IRGRP },
+ { LINUX_S_IWGRP, S_IWGRP },
+ { LINUX_S_IXGRP, S_IXGRP },
+ { LINUX_S_IROTH, S_IROTH },
+ { LINUX_S_IWOTH, S_IWOTH },
+ { LINUX_S_IXOTH, S_IXOTH },
+ { 0, 0 }
+};
+
+/* External Variables */
+
+/* Global Variables */
+
+/* Local Variables */
+
+/* External Prototypes */
+
+/* Local Prototypes */
+
+mode_t
+ext2_mode_xlate(__u16 lmode);
+__u16
+host_mode_xlate(mode_t hmode);
+static int
+release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
+ int blockcnt, void *private);
+long
+delete_file(ext2_filsys fs, ext2_ino_t inode);
+
+/* translate a ext2 mode to the host OS representation */
+mode_t ext2_mode_xlate(__u16 lmode)
+{
+ mode_t mode = 0;
+ int i;
+
+ for (i=0; xlat_tbl[i].lmask; i++)
+ {
+ if (lmode & xlat_tbl[i].lmask)
+ mode |= xlat_tbl[i].mask;
+ }
+ return mode;
+}
+
+/* translate a host OS mode to the ext2 representation */
+__u16 host_mode_xlate(mode_t hmode)
+{
+ __u16 mode = 0;
+ int i;
+
+ for (i=0; xlat_tbl[i].lmask; i++)
+ {
+ if (hmode & xlat_tbl[i].mask)
+ mode |= xlat_tbl[i].lmask;
+ }
+ return mode;
+}
+
+long
+open_filesystem(char *name, ext2_filsys *fs, ext2_ino_t *root, int rw_mode)
+{
+ int retval;
+ int closeval;
+
+
+ if ((retval = ext2fs_open(name, (rw_mode) ? EXT2_FLAG_RW : 0, 0, 0,
+ unix_io_manager, fs)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ *fs = NULL;
+ return retval;
+ }
+
+ if ((retval = ext2fs_read_inode_bitmap(*fs)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ if ((closeval = ext2fs_close(*fs)))
+ fputs(error_message(closeval), stderr);
+ *fs = NULL;
+ return retval;
+ }
+
+ if ((retval = ext2fs_read_block_bitmap(*fs)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ if ((closeval = ext2fs_close(*fs)))
+ fputs(error_message(closeval), stderr);
+ *fs = NULL;
+ return retval;
+ }
+
+ *root = EXT2_ROOT_INO;
+ return(0);
+}
+
+long
+read_inode(ext2_filsys fs, ext2_ino_t file, struct ext2_inode *inode)
+{
+ long retval;
+
+ if ((retval = ext2fs_read_inode(fs, file, inode)))
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+}
+
+long
+write_inode(ext2_filsys fs, ext2_ino_t file, struct ext2_inode *inode)
+{
+ long retval;
+
+ if ((retval = ext2fs_write_inode(fs, file, inode)))
+ fprintf(stderr, "%s\n", error_message(retval));
+ return retval;
+
+}
+
+long
+rm_file(ext2_filsys fs, ext2_ino_t cwd, char *outfile, ext2_ino_t delfile)
+{
+ struct ext2_inode inode;
+ long retval;
+
+ if ((retval = read_inode(fs, delfile, &inode)))
+ return(retval);
+
+ --inode.i_links_count;
+ if ((retval = write_inode(fs, delfile, &inode)))
+ return(retval);
+
+ if ((retval = ext2fs_unlink(fs, cwd, outfile, 0, 0)))
+ return(retval);
+
+ if (inode.i_links_count == 0)
+ return(delete_file(fs, delfile));
+
+ return(0);
+}
+
+long
+delete_file(ext2_filsys fs, ext2_ino_t inode)
+{
+ struct ext2_inode inode_buf;
+ long retval;
+
+ if ((retval = read_inode(fs, inode, &inode_buf)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return(retval);
+ }
+
+ inode_buf.i_dtime = time(NULL);
+ if ((retval = write_inode(fs, inode, &inode_buf)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return(retval);
+ }
+
+ if ((retval = ext2fs_block_iterate(fs, inode, 0, NULL,
+ release_blocks_proc, NULL)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ return(retval);
+ }
+
+ ext2fs_inode_alloc_stats(fs, inode, -1);
+
+ return(0);
+}
+
+static int
+release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
+ int blockcnt, void *private)
+{
+ blk_t block;
+
+ block = *blocknr;
+ ext2fs_block_alloc_stats(fs, block, -1);
+ return 0;
+}
+
+void
+init_stat_buf(struct stat *buf)
+{
+ if (buf)
+ {
+ memset(buf, 0, sizeof(struct stat));
+ buf->st_atime = buf->st_ctime = buf->st_mtime = time(NULL);
+ buf->st_uid = getuid();
+ buf->st_gid = getgid();
+ }
+}
+
+int
+is_file_regexp(char *ptr)
+{
+ char c;
+
+ while ((c = *ptr++) != '\0')
+ {
+ switch(c)
+ {
+ case '*':
+ case '[':
+ case ']':
+ case '?':
+ return(1);
+ break;
+ }
+ }
+ return(0);
+}
+
+regex_t *
+make_regexp(char *shell)
+{
+ char *tmpstr;
+ char *ptr;
+ static regex_t reg;
+ int l;
+ char c;
+
+ if (NULL == (tmpstr = alloca((strlen(shell)) << 1 + 3)))
+ {
+ perror("make_regexp");
+ return(NULL);
+ }
+
+ ptr = tmpstr;
+ *ptr++ = '^';
+
+ while ((c = *shell++) != '\0')
+ {
+ switch(c)
+ {
+ case '*':
+ *ptr++ = '.';
+ *ptr++ = c;
+ break;
+ case '?':
+ *ptr++ = '.';
+ break;
+ case '.':
+ *ptr++ = '\\';
+ *ptr++ = '.';
+ break;
+ default:
+ *ptr++ = c;
+ }
+ }
+ *ptr++ = '$';
+ *ptr = '\0';
+
+ if (regcomp(&reg, tmpstr, REG_NOSUB))
+ {
+ perror("make_regexp");
+ return(NULL);
+ }
+
+ return(&reg);
+}
diff --git a/write.c b/write.c
new file mode 100644
index 0000000..5f74332
--- /dev/null
+++ b/write.c
@@ -0,0 +1,377 @@
+/* $Header: /home/ksheff/src/e2tools/RCS/write.c,v 0.5 2004/04/07 01:12:30 ksheff Exp $ */
+/*
+ * write.c
+ *
+ * Copyright (C) 2002 Keith W Sheffield. This file may be redistributed
+ * under the terms of the GNU Public License.
+ *
+ * Derived from debugfs.c Copyright (C) 1993 Theodore Ts'o <tytso@mit.edu>
+ * and modified by Robert Sanders <gt8134b@prism.gatech.edu>
+ */
+
+static char rcsid[] = "$Id: write.c,v 0.5 2004/04/07 01:12:30 ksheff Exp $";
+
+#ifndef WRITE_C
+#define WRITE_C
+#endif
+
+/* Description */
+/* This file contains the functions used to write a file to an ext2fs
+ * filesystem.
+ *
+ */
+/*
+ * $Log: write.c,v $
+ * Revision 0.5 2004/04/07 01:12:30 ksheff
+ * Modified to use a default file stat specified by the user.
+ *
+ * Revision 0.4 2002/07/08 11:16:11 ksheff
+ * Additional error messages after perror().
+ *
+ * Revision 0.3 2002/06/26 11:12:48 ksheff
+ * Modified to call update_progress() so that the user can know the state of
+ * the file copy operation. The put_file function also calls ext2fs_flush()
+ * before exiting now.
+ *
+ * Revision 0.2 2002/03/07 07:15:40 ksheff
+ * Added parameter to put_file so that the original file's owner, group,
+ * permission bits, access, modification, and creation times would be used.
+ *
+ * Revision 0.1 2002/02/27 04:49:32 ksheff
+ * initial revision
+ *
+ */
+
+/* Headers */
+
+#include "e2tools.h"
+
+/* External Prototypes */
+
+extern void init_progress(char *file, struct stat *sbuf);
+extern void update_progress(unsigned long num_bytes);
+extern void finish_progress();
+
+/* Local Prototypes */
+
+long
+put_file(ext2_filsys fs, ext2_ino_t cwd, char *infile, char *outfile,
+ ext2_ino_t *outfile_ino, int keep, struct stat *def_stat);
+
+static long
+store_data(ext2_filsys fs, int fd, ext2_ino_t newfile, off_t *file_size);
+
+/* Name: put_file()
+ *
+ * Description:
+ *
+ * This function copies a file from disk or stdin to the current directory
+ *
+ * Algorithm:
+ *
+ * Check input parameters
+ * If the input file is NULL
+ * Get the file descriptor for stdin
+ * Initialize a file stat structure
+ * Otherwise
+ * Open the input file
+ * Get the file stat structure for the file
+ * Get a new inode for the file
+ * Link the inode to the currect directory
+ * If this fails because there isn't enough room in the directory
+ * Expand the directory and try again
+ * Set the file statistics for the current inode
+ * If the file is a regular file
+ * Copy it to the current inode
+ * Close the input file
+ *
+ * Global Variables:
+ *
+ * None.
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current file system
+ * ext2_ino_t cwd; The current working directory
+ * char *infile; The name of the input file
+ * char *outfile; The name of the output file
+ * int keep; Flag indicating to use the input file's stat info
+ * struct stat *def_stat; The default file stat information
+ *
+ * Return Values:
+ *
+ * 0 - the file was copied successfully
+ * any other value indicates an error
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/17/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 02/27/02 K.Sheffield Added parameter to pass back to caller the
+ * inode number of the output file.
+ * 03/05/02 K.Sheffield Fixed a bug with reading from stdin
+ * 03/06/02 K.Sheffield Added time/owner/group keep flag
+ * 06/26/02 K.Sheffield Flush file system added at the end
+ * 07/08/02 K.Sheffield Additional error messages after perror()
+ * 04/06/04 K.Sheffield Added a default file stat parameter
+ */
+long
+put_file(ext2_filsys fs, ext2_ino_t cwd, char *infile, char *outfile,
+ ext2_ino_t *outfile_ino, int keep, struct stat *def_stat)
+{
+ int fd;
+ struct stat statbuf;
+ ext2_ino_t newfile;
+ long retval;
+ struct ext2_inode inode;
+ mode_t cur_umask;
+
+ if (fs == NULL || outfile == NULL)
+ {
+ fputs("Invalid input parameter. Exiting put_file() with -1\n",
+ stderr);
+ return (-1);
+ }
+
+ if (infile == NULL)
+ {
+ fd = fileno(stdin);
+ memset(&statbuf, 0, sizeof(statbuf));
+ }
+ else
+ {
+ if (0 > (fd = open(infile, O_RDONLY)))
+ {
+ perror(infile);
+ fprintf(stderr, "Error opening input file: %s\n", infile);
+ return(-1);
+ }
+ if (0 > fstat(fd, &statbuf))
+ {
+ perror(infile);
+ fprintf(stderr, "Error stat()'ing input file: %s\n", infile);
+ close(fd);
+ return(-1);
+ }
+ }
+
+ if (keep == 0 || infile == NULL)
+ {
+ statbuf.st_atime = statbuf.st_ctime = statbuf.st_mtime = time(NULL);
+ umask(cur_umask = umask(0)); /* get the current umask */
+ if (def_stat != NULL)
+ {
+ statbuf.st_mode = S_IFREG |
+ ((def_stat->st_mode == 0) ? (0666 & ~cur_umask):def_stat->st_mode);
+ statbuf.st_uid = def_stat->st_uid;
+ statbuf.st_gid = def_stat->st_gid;
+ }
+ else
+ {
+ statbuf.st_mode = S_IFREG | (0666 & ~cur_umask);
+ statbuf.st_uid = getuid();
+ statbuf.st_gid = getgid();
+ }
+ }
+
+ if ((retval = ext2fs_namei(fs, cwd, cwd, outfile, &newfile)))
+ {
+ if (retval != EXT2_ET_FILE_NOT_FOUND)
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ close(fd);
+ return(retval);
+ }
+
+ }
+ /* file name exists, let's see if is a directory */
+ else if ((retval = ext2fs_check_directory(fs, newfile)))
+ {
+ if (retval != EXT2_ET_NO_DIRECTORY ||
+ (retval = rm_file(fs, cwd, outfile, newfile)))
+ {
+ fprintf(stderr, "%s\n",error_message(retval));
+ close(fd);
+ return(retval);
+ }
+ }
+ else
+ {
+ /* if we get here, then it's an existing directory */
+ fprintf(stderr, "%s is a directory!\n", outfile);
+ return(1);
+ }
+
+ /* ok, create a new inode and directory entry */
+ if ((retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ close(fd);
+ return retval;
+ }
+
+ if ((retval = ext2fs_link(fs, cwd, outfile, newfile, EXT2_FT_REG_FILE)))
+ {
+ /* check to see if we ran out of space in the directory */
+ if (retval == EXT2_ET_DIR_NO_SPACE)
+ {
+ /* try resizing the directory and try again */
+ if (0 == (retval = ext2fs_expand_dir(fs, cwd)))
+ retval = ext2fs_link(fs, cwd, outfile, newfile,
+ EXT2_FT_REG_FILE);
+ }
+ if (retval)
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ close(fd);
+ return retval;
+ }
+ }
+ ext2fs_inode_alloc_stats(fs, newfile, +1);
+ memset(&inode, 0, sizeof(inode));
+ inode.i_mode = host_mode_xlate(statbuf.st_mode);
+ inode.i_atime = statbuf.st_atime;
+ inode.i_ctime = statbuf.st_ctime;
+ inode.i_mtime = statbuf.st_mtime;
+ inode.i_links_count = 1;
+ inode.i_size = statbuf.st_size;
+ inode.i_uid = statbuf.st_uid;
+ inode.i_gid = statbuf.st_gid;
+
+ if ((retval = write_inode(fs, newfile, &inode)))
+ {
+ close(fd);
+ return (retval);
+ }
+
+ if (LINUX_S_ISREG(inode.i_mode) &&
+ (retval = store_data(fs, fd, newfile, &statbuf.st_size)))
+ {
+ close(fd);
+#ifndef DEBUG
+ rm_file(fs, cwd, outfile, newfile);
+
+#endif
+ return(retval);
+ }
+
+ close(fd);
+
+ /* if we were reading from standard input, figure out the size of
+ * the file and save it.
+ */
+
+ if (infile == NULL)
+ {
+ if ((retval = read_inode(fs, newfile, &inode)))
+ return(retval);
+
+ inode.i_size = statbuf.st_size;
+
+ if ((retval = write_inode(fs, newfile, &inode)))
+ return(retval);
+ }
+
+ /* save the files inode number for later use */
+ if (outfile_ino != NULL)
+ *outfile_ino = newfile;
+
+ return(ext2fs_flush(fs));
+
+} /* end of put_file */
+
+/* Name: store_data()
+ *
+ * Description:
+ *
+ * This function stores the contents of a file descriptor into the current ext2
+ * file system
+ *
+ * Algorithm:
+ *
+ * Open a new file in the ext2 file system
+ * While data can be read from the input file descriptor
+ * Write the data to the file on the ext2 filesystem
+ * Close the file
+ *
+ * Global Variables:
+ *
+ * None
+ *
+ * Arguments:
+ *
+ * ext2_filsys fs; The current file system
+ * int fd; Input file descriptor
+ * ext2_ino_t newfile; Inode number of the new file
+ * off_t *file_size; The size of the file written
+ *
+ * Return Values:
+ *
+ * 0 - file copied successfully
+ * otherwise the error code of what went wrong
+ *
+ * Author: Keith W. Sheffield
+ * Date: 02/18/2002
+ *
+ * Modification History:
+ *
+ * MM/DD/YY Name Description
+ * 06/26/02 K.Sheffield Added a call to update_progress()
+ */
+static long
+store_data(ext2_filsys fs, int fd, ext2_ino_t newfile, off_t *file_size)
+{
+ ext2_file_t outfile;
+ long retval;
+ int bytes_read;
+ unsigned int bytes_written;
+ char buf[8192];
+ char *ptr;
+ off_t total = 0;
+
+ if ((retval = ext2fs_file_open(fs, newfile, EXT2_FILE_WRITE, &outfile)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ ext2fs_file_close(outfile);
+ *file_size = 0;
+ return retval;
+ }
+
+ while (0 < (bytes_read = read(fd, buf, sizeof(buf))))
+ {
+ ptr = buf;
+ while (bytes_read > 0)
+ {
+ if ((retval = ext2fs_file_write(outfile, ptr, bytes_read,
+ &bytes_written)))
+ {
+ fprintf(stderr, "%s\n", error_message(retval));
+ ext2fs_file_close(outfile);
+ *file_size = total;
+ return retval;
+ }
+ bytes_read -= bytes_written;
+ total += bytes_written;
+ ptr += bytes_written;
+ }
+ update_progress((unsigned long) total);
+ }
+
+ if (bytes_read < 0)
+ {
+ perror("store_data");
+ retval = errno;
+ }
+ else
+ retval = 0;
+
+ finish_progress();
+
+ ext2fs_file_close(outfile);
+ *file_size = total;
+ return retval;
+
+} /* end of store_data */
+