Improved docs, and created 0.3.8 branch
This commit is contained in:
parent
ddc4ccc691
commit
165f73dd30
4
libisofs/branches/ZeroTwoEight/AUTHORS
Normal file
4
libisofs/branches/ZeroTwoEight/AUTHORS
Normal file
@ -0,0 +1,4 @@
|
||||
Developers:
|
||||
|
||||
Mario Danic
|
||||
|
4
libisofs/branches/ZeroTwoEight/CONTRIBUTORS
Normal file
4
libisofs/branches/ZeroTwoEight/CONTRIBUTORS
Normal file
@ -0,0 +1,4 @@
|
||||
Joe Neeman
|
||||
Philippe Rouquier
|
||||
Suriyan Laohaprapanon
|
||||
Vreixo Formoso Lopes
|
280
libisofs/branches/ZeroTwoEight/COPYING
Normal file
280
libisofs/branches/ZeroTwoEight/COPYING
Normal file
@ -0,0 +1,280 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
19
libisofs/branches/ZeroTwoEight/COPYRIGHT
Normal file
19
libisofs/branches/ZeroTwoEight/COPYRIGHT
Normal file
@ -0,0 +1,19 @@
|
||||
Derek Foreman <derek@signalmarketing.com> and Ben Jansens <xor@orodu.net>
|
||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
||||
Mario Danic <mario.danic@gmail.com>, Thomas Schmitt <scdbackup@gmx.net>
|
||||
Copyright (C) 2006 Mario Danic, Thomas Schmitt
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
1
libisofs/branches/ZeroTwoEight/ChangeLog
Normal file
1
libisofs/branches/ZeroTwoEight/ChangeLog
Normal file
@ -0,0 +1 @@
|
||||
nothing here now
|
234
libisofs/branches/ZeroTwoEight/INSTALL
Normal file
234
libisofs/branches/ZeroTwoEight/INSTALL
Normal file
@ -0,0 +1,234 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||
2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is free documentation; the Free Software Foundation gives
|
||||
unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell commands `./configure; make; make install' should
|
||||
configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package.
|
||||
|
||||
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, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
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 you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' 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.
|
||||
|
||||
Running `configure' might take a while. 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. Run `./configure --help' for
|
||||
details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
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 can use 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 `..'.
|
||||
|
||||
With a non-GNU `make', it is safer 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' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' 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' cannot figure out automatically,
|
||||
but needs to determine by the type of machine the package will run on.
|
||||
Usually, assuming the package is built to be run on the _same_
|
||||
architectures, `configure' can figure that out, but if it prints a
|
||||
message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS KERNEL-OS
|
||||
|
||||
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 machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
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.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--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.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
134
libisofs/branches/ZeroTwoEight/Makefile.am
Normal file
134
libisofs/branches/ZeroTwoEight/Makefile.am
Normal file
@ -0,0 +1,134 @@
|
||||
pkgconfigdir=$(libdir)/pkgconfig
|
||||
libincludedir=$(includedir)/libisofs
|
||||
|
||||
lib_LTLIBRARIES = libisofs/libisofs.la
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
# Build libraries
|
||||
|
||||
libisofs_libisofs_la_LDFLAGS = \
|
||||
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||
libisofs_libisofs_la_SOURCES = \
|
||||
libisofs/tree.h \
|
||||
libisofs/tree.c \
|
||||
libisofs/volume.h \
|
||||
libisofs/volume.c \
|
||||
libisofs/util.h \
|
||||
libisofs/util.c \
|
||||
libisofs/ecma119.c \
|
||||
libisofs/ecma119.h \
|
||||
libisofs/ecma119_tree.c \
|
||||
libisofs/ecma119_tree.h \
|
||||
libisofs/susp.h \
|
||||
libisofs/susp.c \
|
||||
libisofs/rockridge.h \
|
||||
libisofs/rockridge.c \
|
||||
libisofs/joliet.c \
|
||||
libisofs/joliet.h \
|
||||
libisofs/exclude.c \
|
||||
libisofs/exclude.h \
|
||||
libisofs/hash.h \
|
||||
libisofs/hash.c \
|
||||
libisofs/file.h \
|
||||
libisofs/file.c \
|
||||
libisofs/eltorito.h \
|
||||
libisofs/eltorito.c
|
||||
|
||||
libinclude_HEADERS = \
|
||||
libisofs/libisofs.h
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
## Build test applications
|
||||
noinst_PROGRAMS = \
|
||||
test/iso
|
||||
|
||||
test_iso_CPPFLAGS = -Ilibisofs
|
||||
test_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_iso_SOURCES = test/iso.c
|
||||
|
||||
## Build unit test
|
||||
|
||||
check_PROGRAMS = \
|
||||
test/test
|
||||
|
||||
test_test_CPPFLAGS = -Ilibisofs
|
||||
test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lcunit
|
||||
test_test_LDFLAGS = -L.. -lm
|
||||
|
||||
test_test_SOURCES = \
|
||||
test/test_exclude.c \
|
||||
test/test_tree.c \
|
||||
test/test_ecma119_tree.c \
|
||||
test/test_file_hashtable.c \
|
||||
test/test_util.c \
|
||||
test/test_volume.c \
|
||||
test/test.c
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
## Build documentation (You need Doxygen for this to work)
|
||||
webhost = http://libburn-api.pykix.org
|
||||
webpath = /
|
||||
docdir = $(DESTDIR)$(prefix)/share/doc/$(PACKAGE)-$(VERSION)
|
||||
|
||||
doc: doc/html
|
||||
|
||||
doc/html: doc/doxygen.conf
|
||||
if [ -f ./doc/doc.lock ]; then \
|
||||
$(RM) -r doc/html; \
|
||||
doxygen doc/doxygen.conf; \
|
||||
fi
|
||||
|
||||
doc-upload: doc/html
|
||||
scp -r $</* $(webhost):$(webpath)
|
||||
|
||||
all: doc
|
||||
|
||||
install-data-local:
|
||||
if [ -f ./doc/doc.lock ]; then \
|
||||
$(mkinstalldirs) $(docdir)/html; \
|
||||
$(INSTALL_DATA) doc/html/* $(docdir)/html; \
|
||||
fi
|
||||
|
||||
uninstall-local:
|
||||
rm -rf $(docdir)
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
# Indent source files
|
||||
indent_files = \
|
||||
$(libisofs_libisofs_la_SOURCES) \
|
||||
$(test_iso_SOURCES)
|
||||
|
||||
|
||||
indent: $(indent_files)
|
||||
indent -bad -bap -nbbb -nbbo -nbc -bli0 -br -bls \
|
||||
-cdw -ce -cli0 -ncs -nbfda -i8 -l79 -lc79 \
|
||||
-lp -saf -sai -nprs -npsl -saw -sob -ss -ut \
|
||||
-sbi0 -nsc -ts8 -npcs -ncdb -fca \
|
||||
$^
|
||||
|
||||
.PHONY: indent
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
# Extra things
|
||||
nodist_pkgconfig_DATA = \
|
||||
libisofs-1.pc
|
||||
|
||||
EXTRA_DIST = \
|
||||
libisofs-1.pc.in \
|
||||
version.h.in \
|
||||
doc/comments \
|
||||
doc/doxygen.conf.in \
|
||||
README \
|
||||
AUTHORS \
|
||||
CONTRIBUTORS \
|
||||
COPYRIGHT \
|
||||
COPYING \
|
||||
NEWS \
|
||||
INSTALL \
|
||||
ChangeLog
|
||||
|
1
libisofs/branches/ZeroTwoEight/NEWS
Normal file
1
libisofs/branches/ZeroTwoEight/NEWS
Normal file
@ -0,0 +1 @@
|
||||
nothing here now
|
231
libisofs/branches/ZeroTwoEight/README
Normal file
231
libisofs/branches/ZeroTwoEight/README
Normal file
@ -0,0 +1,231 @@
|
||||
------------------------------------------------------------------------------
|
||||
libburnia.pykix.org
|
||||
------------------------------------------------------------------------------
|
||||
This all is under GPL.
|
||||
(See GPL reference, our clarification and commitment at the end of this text)
|
||||
------------------------------------------------------------------------------
|
||||
libburnia.pykix.org
|
||||
By Mario Danic <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
|
||||
Copyright (C) 2006 Mario Danic, Thomas Schmitt
|
||||
|
||||
Still containing parts of
|
||||
Libburn. By Derek Foreman <derek@signalmarketing.com> and
|
||||
Ben Jansens <xor@orodu.net>
|
||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
||||
These parts are to be replaced by own code of above libburnia.pykix.org
|
||||
copyright holders and then libburnia.pykix.org is to be their sole copyright.
|
||||
This is done to achieve the right to issue the clarification and the
|
||||
commitment as written at the end of this text.
|
||||
The rights and merits of the Libburn-copyright holders Derek Foreman and
|
||||
Ben Jansens will be duely respected.
|
||||
|
||||
This libburnia.pykix.org toplevel README (C) 2006 Thomas Schmitt
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Build and Installation
|
||||
|
||||
Our build system is based on autotools. For preparing the build of a SVN
|
||||
snapshot you will need autotools of at least version 1.7.
|
||||
Check out from SVN by
|
||||
svn co http://libburnia-svn.pykix.org/libburn/trunk libburn_pykix
|
||||
go into directory libburn_pykix and apply autotools by
|
||||
./bootstrap
|
||||
|
||||
Alternatively you may unpack a release tarball for which you do not need
|
||||
autotools installed.
|
||||
|
||||
To build a libburnia.pykix.org subproject it should be sufficient to go
|
||||
into its toplevel directory (here: "libburn_pykix") and execute
|
||||
./configure
|
||||
make
|
||||
|
||||
To make the libraries accessible for running resp. developing applications
|
||||
make install
|
||||
|
||||
|
||||
The other half of the project, libisofs, is hosted in the libburnia SVN, too:
|
||||
svn co http://libburnia-svn.pykix.org/libisofs/trunk libisofs_pykix
|
||||
See README file there.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Overview of libburnia.pykix.org
|
||||
|
||||
libburnia.pykix.org is an open-source software project for reading, mastering
|
||||
and writing optical discs. For now this means only CD-R and CD-RW.
|
||||
|
||||
The project comprises of several more or less interdependent parts which
|
||||
together strive to be a usable foundation for application development.
|
||||
These are libraries, language bindings, and middleware binaries which emulate
|
||||
classical (and valuable) Linux tools.
|
||||
|
||||
Our scope is currently Linux 2.4 and 2.6 only. For ports to other systems
|
||||
we would need : login on a development machine resp. a live OS on CD or DVD,
|
||||
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
|
||||
volunteers for testing of realistic use cases.
|
||||
|
||||
We do have a workable code base for burning data CDs, though. The burn API is
|
||||
quite comprehensively documented and can be used to build a presentable
|
||||
application.
|
||||
We do have a functional binary which emulates parts of cdrecord in order to
|
||||
prove that usability, and in order to allow you to explore libburnia's scope
|
||||
by help of existing cdrecord frontends.
|
||||
|
||||
The project components (list subject to growth, hopefully):
|
||||
|
||||
- libburn is the library by which preformatted data get onto optical media.
|
||||
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
|
||||
/dev/hdX (e.g. on kernel 2.6).
|
||||
libburn is the foundation of our cdrecord emulation.
|
||||
|
||||
- libisofs is the library to pack up hard disk files and directories into a
|
||||
ISO 9660 disk image. This may then be brought to CD via libburn.
|
||||
libisofs is to be the foundation of our upcoming mkisofs emulation.
|
||||
|
||||
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
|
||||
Cdrecord is a powerful GPL'ed burn program included in Joerg
|
||||
Schilling's cdrtools. cdrskin strives to be a second source for
|
||||
the services traditionally provided by cdrecord.
|
||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
||||
Many bytes have been copied from the message output of cdrecord
|
||||
runs, though.
|
||||
See cdrskin/README for more.
|
||||
|
||||
- test is a collection of application gestures and examples given by the
|
||||
authors of the library features. The main API example for libburn
|
||||
is test/libburner.c .
|
||||
Explore these examples if you look for inspiration.
|
||||
|
||||
We plan to be a responsive upstream. Bear with us. We are still practicing.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Project history as far as known to me:
|
||||
|
||||
- Founded in 2002 as it seems. See mailing list archives
|
||||
http://lists.freedesktop.org/archives/libburn/
|
||||
The site of this founder team is reachable and offers download of a
|
||||
(somewhat outdated) tarball and from CVS :
|
||||
http://icculus.org/burn/
|
||||
Copyright holders and most probably founders:
|
||||
Derek Foreman and Ben Jansens.
|
||||
|
||||
- I came to using libburn in 2005. Founded the cdrskin project and submitted
|
||||
necessary patches which were accepted or implemented better. Except one
|
||||
remaining patch which prevented cdrskin from using vanilla libburn from CVS.
|
||||
The cdrskin project site is reachable and offers download of the heavily
|
||||
patched (elsewise outdated) tarball under the name cdrskin-0.1.2 :
|
||||
http://scdbackup.sourceforge.net/cdrskin_eng.html
|
||||
It has meanwhile moved to use vanilla libburn.pykix.org , though.
|
||||
Version 0.1.4 constitutes the first release of this kind.
|
||||
|
||||
- In Juli 2006 our team mate Mario Danic announced a revival of libburn
|
||||
which by about nearly everybody else was perceived as unfriendly fork.
|
||||
Derek Foreman four days later posted a message which expressed his
|
||||
discontent.
|
||||
The situation first caused me to publically regret it and then - after i
|
||||
got the opportunity to move in with cdrskin - gave me true reason to
|
||||
personally apologize to Derek Foreman, Ben Jansens and the contibutors at
|
||||
icculus.org/burn. Posted to both projects:
|
||||
http://lists.freedesktop.org/archives/libburn/2006-August/000446.html
|
||||
http://mailman-mail1.webfaction.com/pipermail/libburn-hackers/2006-August/000024.html
|
||||
|
||||
- Mid August 2006 project cdrskin established a branch office in
|
||||
libburn.pykix.org so that all maintainers of our tools have one single place
|
||||
to get the current (at least slightely) usable coordinated versions of
|
||||
everything.
|
||||
Project cdrskin will live forth independendly for a while but it is committed
|
||||
to stay in sync with libburn.pykix.org (or some successor, if ever).
|
||||
cdrskin is also committed to support icculus.org/burn if the pending fork
|
||||
is made reality by content changes in that project. It will cease to maintain
|
||||
a patched version of icculus.org/burn though. Precondition for a new
|
||||
release of cdrskin on base of icculus.org/burn would be the pending
|
||||
"whitelist patch" therefore.
|
||||
I would rather prefer if both projects find consense and merge, or at least
|
||||
cooperate. I have not given up hope totally, yet.
|
||||
I, personally, will honor any approach.
|
||||
|
||||
- 2nd September 2006 the decision is made to strive for a consolidation of
|
||||
copyright and a commitment to GPL in a reasonable and open minded way.
|
||||
This is to avoid long term problems with code of unknown origin and
|
||||
with finding consense among the not so clearly defined group of copyright
|
||||
claimers and -holders.
|
||||
libisofs is already claimed sole copyright Mario Danic.
|
||||
cdrskin and libburner are already claimed sole copyright Thomas Schmitt.
|
||||
Rewrites of other components will follow and concluded by claiming full
|
||||
copyright within the group of libburn.pykix.org-copyright holders.
|
||||
|
||||
- 16th September 2006 feature freeze for release of libburn-0.2.2 .
|
||||
|
||||
- 20th September 2006 release of libburn-0.2.2 .
|
||||
|
||||
- 26th October 2006 feature freeze for cdrskin-0.2.4 based on libburn-0.2.3 .
|
||||
This version of cdrskin is much more cdrecord compatible in repect
|
||||
to drive addressing and audio features.
|
||||
|
||||
- 30th October 2006 release of cdrskin-0.2.4 .
|
||||
|
||||
- 13th November 2006 splitting releases of libburn+cdrskin from libisofs.
|
||||
|
||||
- 24th November 2006 release of libburn-0.2.6 and cdrskin-0.2.6 . cdrskin has
|
||||
become suitable for unaware frontends as long as they perform only the core
|
||||
of cdrecord use cases (including open-ended input streams, audio, and
|
||||
multi-session).
|
||||
|
||||
- 28th November 2006 the umbrella project which encloses both, libisofs and
|
||||
libburn, is now called libburnia. For the origin of this name, see
|
||||
http://en.wikipedia.org/wiki/Liburnians .
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Clarification in my name and in the name of Mario Danic, upcoming copyright
|
||||
holders on toplevel of libburnia. To be fully in effect after the remaining
|
||||
other copyrighted code has been replaced by ours and by copyright-free
|
||||
contributions of our friends:
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
We, the copyright holders, agree on the interpretation that
|
||||
dynamical linking of our libraries constitutes "use of" and
|
||||
not "derivation from" our work in the sense of GPL, provided
|
||||
those libraries are compiled from our unaltered code.
|
||||
|
||||
Thus you may link our libraries dynamically with applications
|
||||
which are not under GPL. You may distribute our libraries and
|
||||
application tools in binary form, if you fulfill the usual
|
||||
condition of GPL to offer a copy of the source code -altered
|
||||
or unaltered- under GPL.
|
||||
|
||||
We ask you politely to use our work in open source spirit
|
||||
and with the due reference to the entire open source community.
|
||||
|
||||
If there should really arise the case where above clarification
|
||||
does not suffice to fulfill a clear and neat request in open source
|
||||
spirit that would otherwise be declined for mere formal reasons,
|
||||
only in that case we will duely consider to issue a special license
|
||||
covering only that special case.
|
||||
It is the open source idea of responsible freedom which will be
|
||||
decisive and you will have to prove that you exhausted all own
|
||||
means to qualify for GPL.
|
||||
|
||||
For now we are firmly committed to maintain one single license: GPL.
|
||||
|
||||
signed: Mario Danic, Thomas Schmitt
|
||||
|
29
libisofs/branches/ZeroTwoEight/TODO
Normal file
29
libisofs/branches/ZeroTwoEight/TODO
Normal file
@ -0,0 +1,29 @@
|
||||
FEATURES
|
||||
========
|
||||
|
||||
El-Torito
|
||||
Support for multiple images
|
||||
HFS/HFS+
|
||||
CD reading
|
||||
Multisession
|
||||
UDF
|
||||
ISO relaxed contraints
|
||||
ISO 9660:1998
|
||||
|
||||
Support for special files (only dirs, reg. files and symlinks are supported).
|
||||
|
||||
TESTS
|
||||
=====
|
||||
|
||||
For all
|
||||
|
||||
IMPLEMENTATION
|
||||
==============
|
||||
|
||||
a way to return NULL sources meaning a failure!!
|
||||
Error message queue
|
||||
Public API for all things already implemented
|
||||
Better charset support
|
||||
default input charset to locale one, no always UTF-8
|
||||
|
||||
|
22
libisofs/branches/ZeroTwoEight/acinclude.m4
Normal file
22
libisofs/branches/ZeroTwoEight/acinclude.m4
Normal file
@ -0,0 +1,22 @@
|
||||
AC_DEFUN([TARGET_SHIZZLE],
|
||||
[
|
||||
ARCH=""
|
||||
|
||||
AC_MSG_CHECKING([target operating system])
|
||||
|
||||
case $target in
|
||||
*-*-linux*)
|
||||
ARCH=linux
|
||||
LIBBURN_ARCH_LIBS=
|
||||
;;
|
||||
*-*-freebsd*)
|
||||
ARCH=freebsd
|
||||
LIBBURN_ARCH_LIBS=-lcam
|
||||
;;
|
||||
*)
|
||||
AC_ERROR([You are attempting to compile for an unsupported platform])
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_MSG_RESULT([$ARCH])
|
||||
])
|
17
libisofs/branches/ZeroTwoEight/bindings/python/README
Normal file
17
libisofs/branches/ZeroTwoEight/bindings/python/README
Normal file
@ -0,0 +1,17 @@
|
||||
libisofs python bindings
|
||||
========================
|
||||
|
||||
The Python bindings are layered on two levels. The low-level 1:1 mapping of
|
||||
the C API is done through ctypes. The higher level bindings build a
|
||||
pythonic API on that mapping.
|
||||
|
||||
The low-level API is in isofs.core. That file is autogenerated using
|
||||
pyglet's ctypes code generator, which can be found at:
|
||||
|
||||
http://pyglet.googlecode.com/svn/trunk/tools/wraptypes/
|
||||
|
||||
Note that this is not a permanent solution. Right now the generated code
|
||||
is committed to the repository, to facilitate development. In the longer
|
||||
term, the wraptypes tool should be added to the libburnia repository and
|
||||
the core binding generated by the build system.
|
||||
|
@ -0,0 +1,2 @@
|
||||
from defines import *
|
||||
from isofs import IsoFS
|
185
libisofs/branches/ZeroTwoEight/bindings/python/isofs/core.py
Normal file
185
libisofs/branches/ZeroTwoEight/bindings/python/isofs/core.py
Normal file
@ -0,0 +1,185 @@
|
||||
'''Wrapper for isofs
|
||||
|
||||
Generated with:
|
||||
../wraptypes/wrap.py -ocore.py -lisofs ../../../libisofs/libisofs.h
|
||||
|
||||
Do not modify this file.
|
||||
'''
|
||||
|
||||
__docformat__ = 'restructuredtext'
|
||||
__version__ = '$Id: wrap.py 738 2007-03-12 04:53:42Z Alex.Holkner $'
|
||||
|
||||
import ctypes
|
||||
from ctypes import *
|
||||
from ctypes.util import find_library as _find_library
|
||||
|
||||
#_libpath = _find_library('isofs')
|
||||
#if not _libpath:
|
||||
# raise ImportError('Could not locate isofs library')
|
||||
|
||||
# If you are a developer, comment the above three lines and uncomment
|
||||
# the following line, to hardcode the library path.
|
||||
_libpath = 'libisofs.so'
|
||||
|
||||
_lib = cdll.LoadLibrary(_libpath)
|
||||
|
||||
_int_types = (c_int16, c_int32)
|
||||
if hasattr(ctypes, 'c_int64'):
|
||||
# Some builds of ctypes apparently do not have c_int64
|
||||
# defined; it's a pretty good bet that these builds do not
|
||||
# have 64-bit pointers.
|
||||
_int_types += (ctypes.c_int64,)
|
||||
for t in _int_types:
|
||||
if sizeof(t) == sizeof(c_size_t):
|
||||
c_ptrdiff_t = t
|
||||
|
||||
class c_void(Structure):
|
||||
# c_void_p is a buggy return type, converting to int, so
|
||||
# POINTER(None) == c_void_p is actually written as
|
||||
# POINTER(c_void), so it can be treated as a real pointer.
|
||||
_fields_ = [('dummy', c_int)]
|
||||
|
||||
|
||||
|
||||
class struct_iso_volume(Structure):
|
||||
__slots__ = [
|
||||
]
|
||||
struct_iso_volume._fields_ = [
|
||||
('_opaque_struct', c_int)
|
||||
]
|
||||
|
||||
class struct_iso_tree_node(Structure):
|
||||
__slots__ = [
|
||||
]
|
||||
struct_iso_tree_node._fields_ = [
|
||||
('_opaque_struct', c_int)
|
||||
]
|
||||
|
||||
class struct_iso_volset(Structure):
|
||||
__slots__ = [
|
||||
]
|
||||
struct_iso_volset._fields_ = [
|
||||
('_opaque_struct', c_int)
|
||||
]
|
||||
|
||||
class struct_burn_source(Structure):
|
||||
__slots__ = [
|
||||
]
|
||||
struct_burn_source._fields_ = [
|
||||
('_opaque_struct', c_int)
|
||||
]
|
||||
|
||||
# ../../../libisofs/libisofs.h:45
|
||||
iso_volume_new = _lib.iso_volume_new
|
||||
iso_volume_new.restype = POINTER(struct_iso_volume)
|
||||
iso_volume_new.argtypes = [c_char_p, c_char_p, c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:49
|
||||
iso_volume_new_with_root = _lib.iso_volume_new_with_root
|
||||
iso_volume_new_with_root.restype = POINTER(struct_iso_volume)
|
||||
iso_volume_new_with_root.argtypes = [c_char_p, c_char_p, c_char_p, POINTER(struct_iso_tree_node)]
|
||||
|
||||
# ../../../libisofs/libisofs.h:57
|
||||
iso_volume_free = _lib.iso_volume_free
|
||||
iso_volume_free.restype = None
|
||||
iso_volume_free.argtypes = [POINTER(struct_iso_volume)]
|
||||
|
||||
# ../../../libisofs/libisofs.h:62
|
||||
iso_volset_free = _lib.iso_volset_free
|
||||
iso_volset_free.restype = None
|
||||
iso_volset_free.argtypes = [POINTER(struct_iso_volset)]
|
||||
|
||||
# ../../../libisofs/libisofs.h:67
|
||||
iso_volume_get_root = _lib.iso_volume_get_root
|
||||
iso_volume_get_root.restype = POINTER(struct_iso_tree_node)
|
||||
iso_volume_get_root.argtypes = [POINTER(struct_iso_volume)]
|
||||
|
||||
# ../../../libisofs/libisofs.h:72
|
||||
iso_volume_set_volume_id = _lib.iso_volume_set_volume_id
|
||||
iso_volume_set_volume_id.restype = None
|
||||
iso_volume_set_volume_id.argtypes = [POINTER(struct_iso_volume), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:78
|
||||
iso_volume_set_publisher_id = _lib.iso_volume_set_publisher_id
|
||||
iso_volume_set_publisher_id.restype = None
|
||||
iso_volume_set_publisher_id.argtypes = [POINTER(struct_iso_volume), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:84
|
||||
iso_volume_set_data_preparer_id = _lib.iso_volume_set_data_preparer_id
|
||||
iso_volume_set_data_preparer_id.restype = None
|
||||
iso_volume_set_data_preparer_id.argtypes = [POINTER(struct_iso_volume), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:96
|
||||
iso_tree_volume_path_to_node = _lib.iso_tree_volume_path_to_node
|
||||
iso_tree_volume_path_to_node.restype = POINTER(struct_iso_tree_node)
|
||||
iso_tree_volume_path_to_node.argtypes = [POINTER(struct_iso_volume), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:107
|
||||
iso_tree_volume_add_path = _lib.iso_tree_volume_add_path
|
||||
iso_tree_volume_add_path.restype = POINTER(struct_iso_tree_node)
|
||||
iso_tree_volume_add_path.argtypes = [POINTER(struct_iso_volume), c_char_p, c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:119
|
||||
iso_tree_volume_add_new_dir = _lib.iso_tree_volume_add_new_dir
|
||||
iso_tree_volume_add_new_dir.restype = POINTER(struct_iso_tree_node)
|
||||
iso_tree_volume_add_new_dir.argtypes = [POINTER(struct_iso_volume), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:128
|
||||
iso_volset_new = _lib.iso_volset_new
|
||||
iso_volset_new.restype = POINTER(struct_iso_volset)
|
||||
iso_volset_new.argtypes = [POINTER(struct_iso_volume), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:141
|
||||
iso_tree_add_node = _lib.iso_tree_add_node
|
||||
iso_tree_add_node.restype = POINTER(struct_iso_tree_node)
|
||||
iso_tree_add_node.argtypes = [POINTER(struct_iso_tree_node), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:157
|
||||
iso_tree_radd_dir = _lib.iso_tree_radd_dir
|
||||
iso_tree_radd_dir.restype = POINTER(struct_iso_tree_node)
|
||||
iso_tree_radd_dir.argtypes = [POINTER(struct_iso_tree_node), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:166
|
||||
iso_exclude_add_path = _lib.iso_exclude_add_path
|
||||
iso_exclude_add_path.restype = None
|
||||
iso_exclude_add_path.argtypes = [c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:173
|
||||
iso_exclude_remove_path = _lib.iso_exclude_remove_path
|
||||
iso_exclude_remove_path.restype = None
|
||||
iso_exclude_remove_path.argtypes = [c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:178
|
||||
iso_exclude_empty = _lib.iso_exclude_empty
|
||||
iso_exclude_empty.restype = None
|
||||
iso_exclude_empty.argtypes = []
|
||||
|
||||
# ../../../libisofs/libisofs.h:191
|
||||
iso_tree_add_new_dir = _lib.iso_tree_add_new_dir
|
||||
iso_tree_add_new_dir.restype = POINTER(struct_iso_tree_node)
|
||||
iso_tree_add_new_dir.argtypes = [POINTER(struct_iso_tree_node), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:197
|
||||
iso_tree_node_set_name = _lib.iso_tree_node_set_name
|
||||
iso_tree_node_set_name.restype = None
|
||||
iso_tree_node_set_name.argtypes = [POINTER(struct_iso_tree_node), c_char_p]
|
||||
|
||||
# ../../../libisofs/libisofs.h:204
|
||||
iso_tree_print = _lib.iso_tree_print
|
||||
iso_tree_print.restype = None
|
||||
iso_tree_print.argtypes = [POINTER(struct_iso_tree_node), c_int]
|
||||
|
||||
# ../../../libisofs/libisofs.h:220
|
||||
iso_source_new_ecma119 = _lib.iso_source_new_ecma119
|
||||
iso_source_new_ecma119.restype = POINTER(struct_burn_source)
|
||||
iso_source_new_ecma119.argtypes = [POINTER(struct_iso_volset), c_int, c_int, c_int]
|
||||
|
||||
|
||||
__all__ = ['iso_volume_new', 'iso_volume_new_with_root', 'iso_volume_free',
|
||||
'iso_volset_free', 'iso_volume_get_root', 'iso_volume_set_volume_id',
|
||||
'iso_volume_set_publisher_id', 'iso_volume_set_data_preparer_id',
|
||||
'iso_tree_volume_path_to_node', 'iso_tree_volume_add_path',
|
||||
'iso_tree_volume_add_new_dir', 'iso_volset_new', 'iso_tree_add_node',
|
||||
'iso_tree_radd_dir', 'iso_exclude_add_path', 'iso_exclude_remove_path',
|
||||
'iso_exclude_empty', 'iso_tree_add_new_dir', 'iso_tree_node_set_name',
|
||||
'iso_tree_print', 'iso_source_new_ecma119']
|
@ -0,0 +1,9 @@
|
||||
# The automatic code generator does not wrap enums into python. As
|
||||
# isofs has only two enum values publicly defined, they are hardcoded
|
||||
# here.
|
||||
|
||||
# from enum ecma119_extension_flag
|
||||
ECMA119_ROCKRIDGE = 1
|
||||
ECMA119_JOLIET = 2
|
||||
|
||||
__all__ = ['ECMA119_ROCKRIDGE', 'ECMA119_JOLIET']
|
@ -0,0 +1,58 @@
|
||||
# High level interface to the isofs library.
|
||||
|
||||
import core
|
||||
import defines
|
||||
import os.path
|
||||
|
||||
def _wrap_volume_property(var_name, core_setter):
|
||||
def get(self):
|
||||
return getattr(self, var_name)
|
||||
def set(self, value):
|
||||
setattr(self, var_name, value)
|
||||
core_setter(self._volume, value)
|
||||
return property(get, set)
|
||||
|
||||
class IsoFS(object):
|
||||
def __init__(self, volume_id='', publisher_id='',
|
||||
data_preparer_id=''):
|
||||
self._volume_id = volume_id
|
||||
self._publisher_id = publisher_id
|
||||
self._data_preparer_id = data_preparer_id
|
||||
|
||||
self._volume = core.iso_volume_new(
|
||||
volume_id, publisher_id, data_preparer_id)
|
||||
self._volset = core.iso_volset_new(self._volume, volume_id)
|
||||
|
||||
def __del__(self):
|
||||
core.iso_volume_free(self._volume)
|
||||
core.iso_volset_free(self._volset)
|
||||
|
||||
volume_id = _wrap_volume_property(
|
||||
'_volume_id', core.iso_volume_set_volume_id)
|
||||
publisher_id = _wrap_volume_property(
|
||||
'_publisher_id', core.iso_volume_set_publisher_id)
|
||||
data_preparer_id = _wrap_volume_property(
|
||||
'_data_preparer_id', core.iso_volume_set_data_preparer_id)
|
||||
|
||||
def add(self, disc_path, path, exclude=None): #, make_parents=False):
|
||||
disc_path = os.path.normpath(disc_path)
|
||||
path = os.path.abspath(os.path.normpath(path))
|
||||
exclude = exclude or []
|
||||
|
||||
# Does the disc parent exist?
|
||||
disc_parent, _ = os.path.split(disc_path)
|
||||
if not core.iso_tree_volume_path_to_node(self._volume, disc_parent):
|
||||
print "No such parent"
|
||||
return # TODO: Raise exception and/or create all missing
|
||||
# parents.
|
||||
|
||||
# Flush all ignores that may have stayed over.
|
||||
core.iso_exclude_empty()
|
||||
for exclude_path in exclude:
|
||||
core.iso_exclude_add_path(exclude_path)
|
||||
|
||||
core.iso_tree_volume_add_path(self._volume, disc_path, path)
|
||||
|
||||
def display(self):
|
||||
root = core.iso_volume_get_root(self._volume)
|
||||
core.iso_tree_print(root, 0)
|
10
libisofs/branches/ZeroTwoEight/bootstrap
Executable file
10
libisofs/branches/ZeroTwoEight/bootstrap
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
aclocal
|
||||
libtoolize --copy --force
|
||||
autoconf
|
||||
|
||||
# ts A61101 : libburn is not prepared for config.h
|
||||
# autoheader
|
||||
|
||||
automake --foreign --add-missing --copy --include-deps
|
117
libisofs/branches/ZeroTwoEight/configure.ac
Normal file
117
libisofs/branches/ZeroTwoEight/configure.ac
Normal file
@ -0,0 +1,117 @@
|
||||
AC_INIT([libisofs], [0.2.4], [http://libburnia.pykix.org])
|
||||
AC_PREREQ([2.50])
|
||||
dnl AC_CONFIG_HEADER([config.h])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
AC_CANONICAL_TARGET
|
||||
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
|
||||
dnl A61101 This breaks Linux build (makes 32 bit off_t)
|
||||
dnl http://sourceware.org/autobook/autobook/autobook_96.html says
|
||||
dnl one must include some config.h and this was a pitfall.
|
||||
dnl So why dig the pit at all ?
|
||||
dnl AM_CONFIG_HEADER(config.h)
|
||||
|
||||
dnl Making releases:
|
||||
dnl BURN_MICRO_VERSION += 1;
|
||||
dnl BURN_INTERFACE_AGE += 1;
|
||||
dnl BURN_BINARY_AGE += 1;
|
||||
dnl if any functions have been added, set BURN_INTERFACE_AGE to 0.
|
||||
dnl if backwards compatibility has been broken,
|
||||
dnl set BURN_BINARY_AGE and BURN_INTERFACE_AGE to 0.
|
||||
dnl
|
||||
dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
|
||||
dnl
|
||||
BURN_MAJOR_VERSION=0
|
||||
BURN_MINOR_VERSION=2
|
||||
BURN_MICRO_VERSION=4
|
||||
BURN_INTERFACE_AGE=0
|
||||
BURN_BINARY_AGE=0
|
||||
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
|
||||
|
||||
AC_SUBST(BURN_MAJOR_VERSION)
|
||||
AC_SUBST(BURN_MINOR_VERSION)
|
||||
AC_SUBST(BURN_MICRO_VERSION)
|
||||
AC_SUBST(BURN_INTERFACE_AGE)
|
||||
AC_SUBST(BURN_BINARY_AGE)
|
||||
AC_SUBST(BURN_VERSION)
|
||||
|
||||
dnl Libtool versioning
|
||||
LT_RELEASE=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION
|
||||
LT_CURRENT=`expr $BURN_MICRO_VERSION - $BURN_INTERFACE_AGE`
|
||||
LT_REVISION=$BURN_INTERFACE_AGE
|
||||
LT_AGE=`expr $BURN_BINARY_AGE - $BURN_INTERFACE_AGE`
|
||||
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
|
||||
|
||||
AC_SUBST(LT_RELEASE)
|
||||
AC_SUBST(LT_CURRENT)
|
||||
AC_SUBST(LT_REVISION)
|
||||
AC_SUBST(LT_AGE)
|
||||
AC_SUBST(LT_CURRENT_MINUS_AGE)
|
||||
|
||||
AC_PREFIX_DEFAULT([/usr/local])
|
||||
test "$prefix" = "NONE" && prefix=$ac_default_prefix
|
||||
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AM_PROG_CC_C_O
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
dnl Large file support
|
||||
AC_SYS_LARGEFILE
|
||||
AC_FUNC_FSEEKO
|
||||
AC_CHECK_FUNC([fseeko])
|
||||
if test ! $ac_cv_func_fseeko; then
|
||||
AC_ERROR([Libisofs requires largefile support.])
|
||||
fi
|
||||
|
||||
AC_PROG_LIBTOOL
|
||||
AC_SUBST(LIBTOOL_DEPS)
|
||||
LIBTOOL="$LIBTOOL --silent"
|
||||
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_CHECK_HEADERS()
|
||||
|
||||
AC_CHECK_MEMBER([struct tm.tm_gmtoff],
|
||||
[AC_DEFINE(HAVE_TM_GMTOFF, 1,
|
||||
[Define this if tm structure includes a tm_gmtoff entry.])],
|
||||
,
|
||||
[#include <time.h>])
|
||||
|
||||
THREAD_LIBS=-lpthread
|
||||
AC_SUBST(THREAD_LIBS)
|
||||
|
||||
TARGET_SHIZZLE
|
||||
AC_SUBST(ARCH)
|
||||
AC_SUBST(LIBBURN_ARCH_LIBS)
|
||||
|
||||
dnl Add compiler-specific flags
|
||||
|
||||
dnl See if the user wants aggressive optimizations of the code
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --enable-debug Disable aggressive optimizations [default=yes]],
|
||||
, enable_debug=yes)
|
||||
if test x$enable_debug != xyes; then
|
||||
if test x$GCC = xyes; then
|
||||
CFLAGS="$CFLAGS -O3"
|
||||
CFLAGS="$CFLAGS -fexpensive-optimizations"
|
||||
fi
|
||||
CFLAGS="$CFLAGS -DNDEBUG"
|
||||
else
|
||||
if test x$GCC = xyes; then
|
||||
CFLAGS="$CFLAGS -g -pedantic -Wall"
|
||||
fi
|
||||
CFLAGS="$CFLAGS -DDEBUG"
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
doc/doxygen.conf
|
||||
version.h
|
||||
libisofs-1.pc
|
||||
])
|
||||
AC_OUTPUT
|
4
libisofs/branches/ZeroTwoEight/doc/Makefile
Normal file
4
libisofs/branches/ZeroTwoEight/doc/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
all clean:
|
||||
$(MAKE) -C .. -$(MAKEFLAGS) $@
|
||||
|
||||
.PHONY: all clean
|
123
libisofs/branches/ZeroTwoEight/doc/comments
Normal file
123
libisofs/branches/ZeroTwoEight/doc/comments
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
@author Mario Danic, Thomas Schmitt
|
||||
|
||||
@mainpage Libburn Documentation Index
|
||||
|
||||
@section intro Introduction
|
||||
|
||||
Libburn is an open-source library for reading, mastering and writing
|
||||
optical discs. For now this means only CD-R and CD-RW.
|
||||
|
||||
The project comprises of several more or less interdependent parts which
|
||||
together strive to be a usable foundation for application development.
|
||||
These are libraries, language bindings, and middleware binaries which emulate
|
||||
classical (and valuable) Linux tools.
|
||||
|
||||
Our scope is currently Linux 2.4 and 2.6 only. For ports to other systems
|
||||
we would need : login on a development machine resp. a live OS on CD or DVD,
|
||||
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
|
||||
volunteers for testing of realistic use cases.
|
||||
|
||||
We do have a workable code base for burning data CDs, though. The burn API is
|
||||
quite comprehensively documented and can be used to build a presentable
|
||||
application.
|
||||
We do have a functional binary which emulates parts of cdrecord in order to
|
||||
prove that usability, and in order to allow you to explore libburn's scope
|
||||
by help of existing cdrecord frontends.
|
||||
|
||||
@subsection components The project components (list subject to growth, hopefully):
|
||||
|
||||
- libburn is the library by which preformatted data get onto optical media.
|
||||
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
|
||||
/dev/hdX (e.g. on kernel 2.6).
|
||||
libburn is the foundation of our cdrecord emulation.
|
||||
|
||||
- libisofs is the library to pack up hard disk files and directories into a
|
||||
ISO 9660 disk image. This may then be brought to CD via libburn.
|
||||
libisofs is to be the foundation of our upcoming mkisofs emulation.
|
||||
|
||||
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
|
||||
cdrecord is a powerful GPL'ed burn program included in Joerg
|
||||
Schilling's cdrtools. cdrskin strives to be a second source for
|
||||
the services traditionally provided by cdrecord.
|
||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
||||
Many bytes have been copied from the message output of cdrecord
|
||||
runs, though.
|
||||
See cdrskin/README for more.
|
||||
|
||||
- "test" is a collection of application gestures and examples given by the
|
||||
authors of the library features. The main API example of libburn
|
||||
is named test/libburner.c .
|
||||
Explore these examples if you look for inspiration.
|
||||
|
||||
We plan to be a responsive upstream. Bear with us.
|
||||
|
||||
|
||||
@section using Using the libraries
|
||||
|
||||
Our build system is based on autotools.
|
||||
User experience tells us that you will need at least autotools version 1.7.
|
||||
|
||||
To build libburn and its subprojects it should be sufficient to go into
|
||||
its toplevel directory and execute
|
||||
|
||||
- ./bootstrap (needed if you downloaded from SVN)
|
||||
|
||||
- ./configure
|
||||
|
||||
- make
|
||||
|
||||
To make the libraries accessible for running resp. developing applications
|
||||
|
||||
- make install
|
||||
|
||||
Both libraries are written in C language and get built by autotools.
|
||||
Thus we expect them to be useable by a wide range of Linux-implemented
|
||||
languages and development tools.
|
||||
|
||||
|
||||
@section libburner Libburner
|
||||
|
||||
libburner is a minimal demo application for the library libburn
|
||||
(see: libburn/libburn.h) as provided on http://libburn.pykix.org .
|
||||
It can list the available devices, can blank a CD-RW and
|
||||
can burn to CD-R or CD-RW.
|
||||
|
||||
It's main purpose, nevertheless, is to show you how to use libburn and also
|
||||
to serve the libburn team as reference application. libburner does indeed
|
||||
define the standard way how above three gestures can be implemented and
|
||||
stay upward compatible for a good while.
|
||||
|
||||
@subsection libburner-help Libburner --help
|
||||
<pre>
|
||||
Usage: test/libburner
|
||||
[--drive <address>|<driveno>|"-"]
|
||||
[--blank_fast|--blank_full] [--audio]
|
||||
[--try_to_simulate] [--stdin_size <bytes>]
|
||||
[<one or more imagefiles>|"-"]
|
||||
Examples
|
||||
A bus scan (needs rw-permissions to see a drive):
|
||||
test/libburner --drive -
|
||||
Burn a file to drive chosen by number:
|
||||
test/libburner --drive 0 my_image_file
|
||||
Burn a file to drive chosen by persistent address:
|
||||
test/libburner --drive /dev/hdc my_image_file
|
||||
Blank a used CD-RW (is combinable with burning in one run):
|
||||
test/libburner --drive /dev/hdc --blank_fast
|
||||
Burn two audio tracks
|
||||
lame --decode -t /path/to/track1.mp3 track1.cd
|
||||
test/dewav /path/to/track2.wav -o track2.cd
|
||||
test/libburner --drive /dev/hdc --audio track1.cd track2.cd
|
||||
Burn a compressed afio archive on-the-fly, pad up to 700 MB:
|
||||
( cd my_directory ; find . -print | afio -oZ - ) | \
|
||||
test/libburner --drive /dev/hdc --stdin_size 734003200 -
|
||||
To be read from *not mounted* CD via: afio -tvZ /dev/hdc
|
||||
Program tar would need a clean EOF which our padded CD cannot deliver.
|
||||
</pre>
|
||||
|
||||
@subsection libburner-source Sourceode of libburner
|
||||
|
||||
Click on blue names of functions, structures, variables, etc in oder to
|
||||
get to the according specs of libburn API or libburner sourcecode.
|
||||
|
||||
*/
|
121
libisofs/branches/ZeroTwoEight/doc/comments_test_ts
Normal file
121
libisofs/branches/ZeroTwoEight/doc/comments_test_ts
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
@author Mario Danic, Thomas Schmitt
|
||||
|
||||
@mainpage Libburn Documentation Index
|
||||
|
||||
@section intro Introduction
|
||||
|
||||
Libburn is an open-source library for reading, mastering and writing
|
||||
optical discs. For now this means only CD-R and CD-RW.
|
||||
|
||||
The project comprises of several more or less interdependent parts which
|
||||
together strive to be a usable foundation for application development.
|
||||
These are libraries, language bindings, and middleware binaries which emulate
|
||||
classical (and valuable) Linux tools.
|
||||
|
||||
Our scope is currently Linux 2.4 and 2.6 and we will have a hard time to widen
|
||||
this for now, because of our history. The project could need advise from or
|
||||
membership of skilled kernel people and people who know how to talk CD/DVD
|
||||
drives into doing things.
|
||||
|
||||
We do have a workable code base for burning data CDs, though. The burn API is
|
||||
quite comprehensively documented and can be used to build a presentable
|
||||
application.
|
||||
We do have a functional binary which emulates parts of cdrecord in order to
|
||||
prove that usability, and in order to allow you to explore libburn's scope
|
||||
by help of existing cdrecord frontends.
|
||||
|
||||
@subsection components The project components (list subject to growth, hopefully):
|
||||
|
||||
- libburn is the library by which preformatted data get onto optical media.
|
||||
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
|
||||
/dev/hdX (e.g. on kernel 2.6).
|
||||
libburn is the foundation of our cdrecord emulation.
|
||||
|
||||
- libisofs is the library to pack up hard disk files and directories into a
|
||||
ISO 9660 disk image. This may then be brought to CD via libburn.
|
||||
libisofs is to be the foundation of our upcoming mkisofs emulation.
|
||||
|
||||
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
|
||||
cdrecord is a powerful GPL'ed burn program included in Joerg
|
||||
Schilling's cdrtools. cdrskin strives to be a second source for
|
||||
the services traditionally provided by cdrecord.
|
||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
||||
Many bytes have been copied from the message output of cdrecord
|
||||
runs, though.
|
||||
See cdrskin/README for more.
|
||||
|
||||
- "test" is a collection of application gestures and examples given by the
|
||||
authors of the library features. The main API example of libburn
|
||||
is named test/libburner.c .
|
||||
Explore these examples if you look for inspiration.
|
||||
|
||||
We plan to be a responsive upstream. Bear with us.
|
||||
|
||||
|
||||
@section using Using the libraries
|
||||
|
||||
Our build system is based on autotools.
|
||||
User experience tells us that you will need at least autotools version 1.7.
|
||||
|
||||
To build libburn and its subprojects it should be sufficient to go into
|
||||
its toplevel directory and execute
|
||||
|
||||
- ./bootstrap (needed if you downloaded from SVN)
|
||||
|
||||
- ./configure
|
||||
|
||||
- make
|
||||
|
||||
To make the libraries accessible for running resp. developing applications
|
||||
|
||||
- make install
|
||||
|
||||
Both libraries are written in C language and get built by autotools.
|
||||
Thus we expect them to be useable by a wide range of Linux-implemented
|
||||
languages and development tools.
|
||||
|
||||
|
||||
@section libburner Libburner
|
||||
|
||||
libburner is a minimal demo application for the library libburn
|
||||
(see: libburn/libburn.h) as provided on http://libburn.pykix.org .
|
||||
It can list the available devices, can blank a CD-RW and
|
||||
can burn to CD-R or CD-RW.
|
||||
|
||||
It's main purpose, nevertheless, is to show you how to use libburn and also
|
||||
to serve the libburn team as reference application. libburner does indeed
|
||||
define the standard way how above three gestures can be implemented and
|
||||
stay upward compatible for a good while.
|
||||
|
||||
@subsection libburner-help Libburner --help
|
||||
<pre>
|
||||
Usage: test/libburner
|
||||
[--drive <address>|<driveno>|"-"]
|
||||
[--verbose <level>] [--blank_fast|--blank_full]
|
||||
[--burn_for_real|--try_to_simulate] [--stdin_size <bytes>]
|
||||
[<imagefile>|"-"]
|
||||
Examples
|
||||
A bus scan (needs rw-permissions to see a drive):
|
||||
test/libburner --drive -
|
||||
Burn a file to drive chosen by number:
|
||||
test/libburner --drive 0 --burn_for_real my_image_file
|
||||
Burn a file to drive chosen by persistent address:
|
||||
test/libburner --drive /dev/hdc --burn_for_real my_image_file
|
||||
Blank a used CD-RW (is combinable with burning in one run):
|
||||
test/libburner --drive 0 --blank_fast
|
||||
Burn a compressed afio archive on-the-fly, pad up to 700 MB:
|
||||
( cd my_directory ; find . -print | afio -oZ - ) | \
|
||||
test/libburner --drive /dev/hdc --burn_for_real --stdin_size 734003200 -
|
||||
To be read from *not mounted* CD via:
|
||||
afio -tvZ /dev/hdc
|
||||
Program tar would need a clean EOF which our padded CD cannot deliver.
|
||||
</pre>
|
||||
|
||||
@subsection libburner-source Sourceode of libburner
|
||||
|
||||
Click on blue names of functions, structures, variables, etc in oder to
|
||||
get to the according specs of libburn API or libburner sourcecode.
|
||||
|
||||
@include libburner.c
|
||||
*/
|
186
libisofs/branches/ZeroTwoEight/doc/doxygen.conf.in
Normal file
186
libisofs/branches/ZeroTwoEight/doc/doxygen.conf.in
Normal file
@ -0,0 +1,186 @@
|
||||
# Doxyfile 1.2.18
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# General configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = @PACKAGE_NAME@
|
||||
PROJECT_NUMBER = @PACKAGE_VERSION@
|
||||
OUTPUT_DIRECTORY =
|
||||
OUTPUT_LANGUAGE = English
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = @top_srcdir@
|
||||
INTERNAL_DOCS = NO
|
||||
STRIP_CODE_COMMENTS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
SHORT_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
MULTILINE_CPP_IS_BRIEF = YES
|
||||
DETAILS_AT_TOP = YES
|
||||
INHERIT_DOCS = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 4
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ALIASES =
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SHOW_USED_FILES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = YES
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = libisofs doc
|
||||
FILE_PATTERNS = libisofs.h comments
|
||||
RECURSIVE = NO
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH = test
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX = OB OTK _
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = doc/html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 200
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = letter
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = DOXYGEN
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
TEMPLATE_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
GRAPHICAL_HIERARCHY = NO
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
11
libisofs/branches/ZeroTwoEight/libisofs-1.pc.in
Normal file
11
libisofs/branches/ZeroTwoEight/libisofs-1.pc.in
Normal file
@ -0,0 +1,11 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libisofs
|
||||
Description: ISO9660 filesystem creation library
|
||||
Version: @VERSION@
|
||||
Requires:
|
||||
Libs: -L${libdir} -lisofs
|
||||
Cflags: -I${includedir}/libisofs
|
4
libisofs/branches/ZeroTwoEight/libisofs/Makefile
Executable file
4
libisofs/branches/ZeroTwoEight/libisofs/Makefile
Executable file
@ -0,0 +1,4 @@
|
||||
all clean:
|
||||
$(MAKE) -C .. -$(MAKEFLAGS) $@
|
||||
|
||||
.PHONY: all clean
|
840
libisofs/branches/ZeroTwoEight/libisofs/ecma119.c
Executable file
840
libisofs/branches/ZeroTwoEight/libisofs/ecma119.c
Executable file
@ -0,0 +1,840 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "ecma119.h"
|
||||
#include "ecma119_tree.h"
|
||||
#include "susp.h"
|
||||
#include "rockridge.h"
|
||||
#include "joliet.h"
|
||||
#include "volume.h"
|
||||
#include "tree.h"
|
||||
#include "util.h"
|
||||
#include "file.h"
|
||||
#include "libisofs.h"
|
||||
#include "libburn/libburn.h"
|
||||
#include "eltorito.h"
|
||||
|
||||
/* burn-source compatible stuff */
|
||||
static int
|
||||
bs_read(struct burn_source *bs, unsigned char *buf, int size);
|
||||
static off_t
|
||||
bs_get_size(struct burn_source *bs);
|
||||
static void
|
||||
bs_free_data(struct burn_source *bs);
|
||||
|
||||
typedef void (*write_fn)(struct ecma119_write_target*, uint8_t*);
|
||||
|
||||
/* return true if the given state is only required for Joliet volumes */
|
||||
static int
|
||||
is_joliet_state(enum ecma119_write_state);
|
||||
|
||||
static void
|
||||
next_state(struct ecma119_write_target *t);
|
||||
|
||||
/* write t->state_data to the buf, one block at a time */
|
||||
static void
|
||||
write_data_chunk(struct ecma119_write_target *t, uint8_t *buf);
|
||||
|
||||
/* writing functions. All these functions assume the buf is large enough */
|
||||
static void
|
||||
write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
|
||||
static void
|
||||
write_vol_desc_terminator(struct ecma119_write_target *t, uint8_t *buf);
|
||||
static void
|
||||
write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf);
|
||||
static void
|
||||
write_l_path_table(struct ecma119_write_target *t, uint8_t *buf);
|
||||
static void
|
||||
write_m_path_table(struct ecma119_write_target *t, uint8_t *buf);
|
||||
static void
|
||||
write_one_dir_record(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *dir,
|
||||
int file_id,
|
||||
uint8_t *buf);
|
||||
static void
|
||||
write_one_dir(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *dir,
|
||||
uint8_t *buf);
|
||||
static void
|
||||
write_dirs(struct ecma119_write_target *t, uint8_t *buf);
|
||||
|
||||
/* wrapper functions for writing */
|
||||
static void wr_system_area(struct ecma119_write_target*, uint8_t*);
|
||||
static void wr_pri_vol_desc(struct ecma119_write_target*, uint8_t*);
|
||||
static void wr_vol_desc_term(struct ecma119_write_target*, uint8_t*);
|
||||
static void wr_l_path_table(struct ecma119_write_target*, uint8_t*);
|
||||
static void wr_m_path_table(struct ecma119_write_target*, uint8_t*);
|
||||
static void wr_dir_records(struct ecma119_write_target*, uint8_t*);
|
||||
static void wr_files(struct ecma119_write_target*, uint8_t*);
|
||||
|
||||
static const write_fn writers[] =
|
||||
{
|
||||
NULL,
|
||||
wr_system_area,
|
||||
wr_pri_vol_desc,
|
||||
el_torito_wr_boot_vol_desc,
|
||||
joliet_wr_sup_vol_desc,
|
||||
wr_vol_desc_term,
|
||||
wr_l_path_table,
|
||||
wr_m_path_table,
|
||||
joliet_wr_l_path_table,
|
||||
joliet_wr_m_path_table,
|
||||
wr_dir_records,
|
||||
joliet_wr_dir_records,
|
||||
el_torito_wr_catalog,
|
||||
wr_files
|
||||
};
|
||||
|
||||
/* When a writer is created, we
|
||||
* 1) create an ecma119 tree
|
||||
* 2) add SUSP fields (if necessary)
|
||||
* 3) calculate the size and position of all nodes in the tree
|
||||
* 4) finalize SUSP fields (if necessary)
|
||||
*/
|
||||
|
||||
static void
|
||||
add_susp_fields_rec(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *node)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
rrip_add_PX(t, node);
|
||||
rrip_add_NM(t, node);
|
||||
rrip_add_TF(t, node);
|
||||
|
||||
switch (node->type) {
|
||||
case ECMA119_FILE:
|
||||
break;
|
||||
case ECMA119_SYMLINK:
|
||||
rrip_add_SL(t, node);
|
||||
break;
|
||||
case ECMA119_DIR:
|
||||
if (node->info.dir.real_parent != node->parent) {
|
||||
rrip_add_RE(t, node);
|
||||
rrip_add_PL(t, node);
|
||||
}
|
||||
for (i = 0; i < node->info.dir.nchildren; i++) {
|
||||
add_susp_fields_rec(t, node->info.dir.children[i]);
|
||||
}
|
||||
break;
|
||||
case ECMA119_PLACEHOLDER:
|
||||
rrip_add_CL(t, node);
|
||||
break;
|
||||
default:
|
||||
// FIXME support for device blocks by uncommenting this
|
||||
//if (node->iso_self->attrib.st_rdev)
|
||||
// rrip_add_PN(t, node);
|
||||
break;
|
||||
}
|
||||
susp_add_CE(t, node);
|
||||
}
|
||||
|
||||
static void
|
||||
add_susp_fields(struct ecma119_write_target *t)
|
||||
{
|
||||
susp_add_SP(t, t->root);
|
||||
rrip_add_ER(t, t->root);
|
||||
add_susp_fields_rec(t, t->root);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill out the dir.len and dir.CE_len fields for each
|
||||
* ecma119_tree_node that is a directory. Also calculate the total number of
|
||||
* directories and the number of files for which we need to write out data.
|
||||
* (dirlist_len and filelist_len)
|
||||
*/
|
||||
static void
|
||||
calc_dir_size(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *dir)
|
||||
{
|
||||
size_t i;
|
||||
size_t newlen;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
t->dirlist_len++;
|
||||
dir->info.dir.len = 34 + dir->info.dir.self_susp.non_CE_len
|
||||
+ 34 + dir->info.dir.parent_susp.non_CE_len;
|
||||
dir->info.dir.CE_len = dir->info.dir.self_susp.CE_len
|
||||
+ dir->info.dir.parent_susp.CE_len;
|
||||
for (i = 0; i < dir->info.dir.nchildren; ++i) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
|
||||
newlen = dir->info.dir.len + ch->dirent_len + ch->susp.non_CE_len;
|
||||
if ((newlen % 2048) < (dir->info.dir.len % 2048)) {
|
||||
dir->info.dir.len = newlen + (2048 - (dir->info.dir.len % 2048));
|
||||
} else {
|
||||
dir->info.dir.len += ch->dirent_len + ch->susp.non_CE_len;
|
||||
}
|
||||
dir->info.dir.CE_len += ch->susp.CE_len;
|
||||
}
|
||||
t->total_dir_size += round_up(dir->info.dir.len + dir->info.dir.CE_len,
|
||||
t->block_size);
|
||||
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
//struct iso_tree_node *iso = ch->iso_self;
|
||||
if (ch->type == ECMA119_DIR) {
|
||||
calc_dir_size(t, ch);
|
||||
}
|
||||
// else if (iso && iso->attrib.st_size
|
||||
// && iso->loc.type == LIBISO_FILESYS
|
||||
// && iso->loc.path) {
|
||||
// t->filelist_len++;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill out the block field in each ecma119_tree_node that is a directory and
|
||||
* fill out t->dirlist.
|
||||
*/
|
||||
static void
|
||||
calc_dir_pos(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *dir)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
dir->info.dir.block = t->curblock;
|
||||
t->curblock += div_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size);
|
||||
t->dirlist[t->curfile++] = dir;
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
if (ch->type == ECMA119_DIR)
|
||||
calc_dir_pos(t, ch);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_file(const void *f1, const void *f2)
|
||||
{
|
||||
struct iso_file *f = *((struct iso_file**)f1);
|
||||
struct iso_file *g = *((struct iso_file**)f2);
|
||||
/* higher weighted first */
|
||||
return g->sort_weight - f->sort_weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill out the block field for each file and fill out t->filelist.
|
||||
*/
|
||||
static void
|
||||
calc_file_pos(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *dir)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
t->filelist = calloc(1, sizeof(struct iso_file *) * t->file_table->count);
|
||||
|
||||
for (i = 0; i < FILE_HASH_NODES; ++i) {
|
||||
|
||||
struct iso_file_hash_node *node;
|
||||
|
||||
node = t->file_table->table[i];
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
do {
|
||||
struct iso_file *file = node->file;
|
||||
if (file->size)
|
||||
t->filelist[t->curfile++] = file;
|
||||
node = node->next;
|
||||
} while (node);
|
||||
}
|
||||
|
||||
t->filelist_len = t->curfile;
|
||||
|
||||
/* sort */
|
||||
if ( t->sort_files )
|
||||
qsort(t->filelist, t->filelist_len, sizeof(void*), cmp_file);
|
||||
|
||||
/* fill block value */
|
||||
for ( i = 0; i < t->filelist_len; ++i) {
|
||||
struct iso_file *file = t->filelist[i];
|
||||
file->block = t->curblock;
|
||||
t->curblock += div_up(file->size, t->block_size);
|
||||
}
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
t->curfile = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new ecma119_write_target from the given volume number of the
|
||||
* given volume set.
|
||||
*
|
||||
* \pre \p volnum is less than \p volset-\>volset_size.
|
||||
* \post For each node in the tree, writer_data has been allocated.
|
||||
* \post The directory heirarchy has been reorganised to be ecma119-compatible.
|
||||
*/
|
||||
static struct ecma119_write_target*
|
||||
ecma119_target_new(struct iso_volset *volset,
|
||||
const struct ecma119_source_opts *opts)
|
||||
{
|
||||
struct ecma119_write_target *t =
|
||||
calloc(1, sizeof(struct ecma119_write_target));
|
||||
size_t i, j, cur;
|
||||
struct iso_tree_node *iso_root =
|
||||
(struct iso_tree_node*) volset->volume[opts->volnum]->root;
|
||||
|
||||
t->cache_inodes = opts->no_cache_inodes ? 0 : 1;
|
||||
t->replace_mode = opts->default_mode ? 0 : 1;
|
||||
if ( opts->replace_dir_mode )
|
||||
t->replace_mode |= 0x02;
|
||||
if ( opts->replace_file_mode )
|
||||
t->replace_mode |= 0x04;
|
||||
if ( opts->replace_gid )
|
||||
t->replace_mode |= 0x08;
|
||||
if ( opts->replace_uid )
|
||||
t->replace_mode |= 0x10;
|
||||
t->dir_mode = opts->dir_mode;
|
||||
t->file_mode = opts->file_mode;
|
||||
t->gid = opts->gid;
|
||||
t->uid = opts->uid;
|
||||
|
||||
//TODO get defailt values for current locale, no UTF-8
|
||||
t->input_charset = opts->input_charset ? opts->input_charset : "UTF-8";
|
||||
t->ouput_charset = opts->ouput_charset ? opts->ouput_charset : "UTF-8";
|
||||
t->sort_files = opts->sort_files;
|
||||
|
||||
t->file_table = iso_file_table_new(t->cache_inodes);
|
||||
volset->refcount++;
|
||||
t->iso_level = opts->level;
|
||||
t->block_size = 2048;
|
||||
t->relaxed_constraints = opts->relaxed_constraints;
|
||||
|
||||
t->rockridge = (opts->flags & ECMA119_ROCKRIDGE) ? 1 : 0;
|
||||
t->joliet = (opts->flags & ECMA119_JOLIET) ? 1 : 0;
|
||||
|
||||
t->catalog = volset->volume[opts->volnum]->bootcat;
|
||||
t->eltorito = t->catalog ? 1 : 0;
|
||||
|
||||
t->root = ecma119_tree_create(t, iso_root);
|
||||
if (t->joliet)
|
||||
t->joliet_root = joliet_tree_create(t, iso_root);
|
||||
t->volset = volset;
|
||||
t->volnum = opts->volnum;
|
||||
t->now = time(NULL);
|
||||
|
||||
if (t->rockridge)
|
||||
add_susp_fields(t);
|
||||
|
||||
calc_dir_size(t, t->root);
|
||||
if (t->joliet) {
|
||||
joliet_calc_dir_size(t, t->joliet_root);
|
||||
t->pathlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len_joliet);
|
||||
t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len_joliet);
|
||||
}
|
||||
|
||||
t->dirlist = calloc(1, sizeof(void*) * t->dirlist_len);
|
||||
t->pathlist = calloc(1, sizeof(void*) * t->dirlist_len);
|
||||
|
||||
/* fill out the pathlist */
|
||||
t->pathlist[0] = t->root;
|
||||
t->path_table_size = 10; /* root directory record */
|
||||
cur = 1;
|
||||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
struct ecma119_tree_node *dir = t->pathlist[i];
|
||||
for (j = 0; j < dir->info.dir.nchildren; j++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[j];
|
||||
if (ch->type == ECMA119_DIR) {
|
||||
size_t len = 8 + strlen(ch->iso_name);
|
||||
t->pathlist[cur++] = ch;
|
||||
t->path_table_size += len + len % 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t->curblock = 16 /* system area */
|
||||
+ 1 /* volume desc */
|
||||
+ 1; /* volume desc terminator */
|
||||
|
||||
if (t->eltorito)
|
||||
t->curblock += 1; /* boot record volume descriptor */
|
||||
if (t->joliet) /* supplementary vol desc */
|
||||
t->curblock += div_up (2048, t->block_size);
|
||||
|
||||
t->l_path_table_pos = t->curblock;
|
||||
t->curblock += div_up(t->path_table_size, t->block_size);
|
||||
t->m_path_table_pos = t->curblock;
|
||||
t->curblock += div_up(t->path_table_size, t->block_size);
|
||||
if (t->joliet) {
|
||||
joliet_prepare_path_tables(t);
|
||||
t->l_path_table_pos_joliet = t->curblock;
|
||||
t->curblock += div_up(t->path_table_size_joliet, t->block_size);
|
||||
t->m_path_table_pos_joliet = t->curblock;
|
||||
t->curblock += div_up(t->path_table_size_joliet, t->block_size);
|
||||
}
|
||||
|
||||
calc_dir_pos(t, t->root);
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
t->curfile = 0;
|
||||
if (t->joliet) {
|
||||
|
||||
joliet_calc_dir_pos(t, t->joliet_root);
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
t->curfile = 0;
|
||||
}
|
||||
|
||||
/* el-torito? */
|
||||
if (t->eltorito) {
|
||||
|
||||
/* add catalog block */
|
||||
t->catalog->file->block = t->curblock;
|
||||
t->curblock += div_up(2048, t->block_size);
|
||||
el_torito_get_image_files(t);
|
||||
}
|
||||
|
||||
calc_file_pos(t, t->root);
|
||||
|
||||
if (t->eltorito)
|
||||
el_torito_patch_image_files(t);
|
||||
|
||||
if (t->rockridge) {
|
||||
susp_finalize(t, t->root);
|
||||
rrip_finalize(t, t->root);
|
||||
}
|
||||
|
||||
t->total_size = t->curblock * t->block_size;
|
||||
t->vol_space_size = t->curblock;
|
||||
|
||||
/* prepare for writing */
|
||||
t->curblock = 0;
|
||||
t->state = ECMA119_WRITE_SYSTEM_AREA;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static int
|
||||
is_joliet_state(enum ecma119_write_state state)
|
||||
{
|
||||
return state == ECMA119_WRITE_SUP_VOL_DESC_JOLIET
|
||||
|| state == ECMA119_WRITE_L_PATH_TABLE_JOLIET
|
||||
|| state == ECMA119_WRITE_M_PATH_TABLE_JOLIET
|
||||
|| state == ECMA119_WRITE_DIR_RECORDS_JOLIET;
|
||||
}
|
||||
|
||||
static int
|
||||
is_eltorito_state(enum ecma119_write_state state)
|
||||
{
|
||||
return state == ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC
|
||||
|| state == ECMA119_WRITE_ELTORITO_CATALOG;
|
||||
}
|
||||
|
||||
static void
|
||||
next_state(struct ecma119_write_target *t)
|
||||
{
|
||||
t->state++;
|
||||
while ( (!t->joliet && is_joliet_state(t->state))
|
||||
||(!t->eltorito && is_eltorito_state(t->state)) )
|
||||
t->state++;
|
||||
|
||||
printf ("now in state %d, curblock=%d\n", (int)t->state, (int)t->curblock);
|
||||
}
|
||||
|
||||
static void
|
||||
wr_system_area(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
memset(buf, 0, t->block_size);
|
||||
if (t->curblock == 15) {
|
||||
next_state(t);
|
||||
}
|
||||
}
|
||||
static void
|
||||
wr_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t, write_pri_vol_desc, 2048, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
wr_vol_desc_term(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t, write_vol_desc_terminator, 2048, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
wr_l_path_table(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t, write_l_path_table, t->path_table_size, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
wr_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t, write_m_path_table, t->path_table_size, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
wr_dir_records(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t, write_dirs, t->total_dir_size, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
wr_files(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
struct state_files *f_st = &t->state_files;
|
||||
size_t nread;
|
||||
struct iso_file *f = t->filelist[f_st->file];
|
||||
const char *path = f->path;
|
||||
|
||||
|
||||
if (!f_st->fd) {
|
||||
printf("Writing file %s\n", path);
|
||||
f_st->data_len = f->size;
|
||||
f_st->fd = fopen(path, "r");
|
||||
if (!f_st->fd)
|
||||
err(1, "couldn't open %s for reading", path);
|
||||
assert(t->curblock == f->block);
|
||||
}
|
||||
|
||||
nread = fread(buf, 1, t->block_size, f_st->fd);
|
||||
f_st->pos += t->block_size;
|
||||
if (nread < 0)
|
||||
warn("problem reading from %s", path);
|
||||
else if (nread != t->block_size && f_st->pos < f_st->data_len)
|
||||
warnx("incomplete read from %s", path);
|
||||
if (f_st->pos >= f_st->data_len) {
|
||||
fclose(f_st->fd);
|
||||
f_st->fd = 0;
|
||||
f_st->pos = 0;
|
||||
f_st->file++;
|
||||
if (f_st->file >= t->filelist_len)
|
||||
next_state(t);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
struct ecma119_pri_vol_desc *vol = (struct ecma119_pri_vol_desc*)buf;
|
||||
struct iso_volume *volume = t->volset->volume[t->volnum];
|
||||
char *vol_id = str2d_char(volume->volume_id, t->input_charset);
|
||||
char *pub_id = str2a_char(volume->publisher_id, t->input_charset);
|
||||
char *data_id = str2a_char(volume->data_preparer_id, t->input_charset);
|
||||
char *volset_id = str2d_char(t->volset->volset_id, t->input_charset);
|
||||
|
||||
char *system_id = str2a_char(volume->system_id, t->input_charset);
|
||||
char *application_id = str2a_char(volume->application_id, t->input_charset);
|
||||
char *copyright_file_id = str2d_char(volume->copyright_file_id, t->input_charset);
|
||||
char *abstract_file_id = str2d_char(volume->abstract_file_id, t->input_charset);
|
||||
char *biblio_file_id = str2d_char(volume->biblio_file_id, t->input_charset);
|
||||
|
||||
vol->vol_desc_type[0] = 1;
|
||||
memcpy(vol->std_identifier, "CD001", 5);
|
||||
vol->vol_desc_version[0] = 1;
|
||||
if (system_id)
|
||||
strncpy((char*)vol->system_id, system_id, 32);
|
||||
else
|
||||
/* put linux by default? */
|
||||
memcpy(vol->system_id, "LINUX", 5);
|
||||
if (vol_id)
|
||||
strncpy((char*)vol->volume_id, vol_id, 32);
|
||||
iso_bb(vol->vol_space_size, t->vol_space_size, 4);
|
||||
iso_bb(vol->vol_set_size, t->volset->volset_size, 2);
|
||||
iso_bb(vol->vol_seq_number, t->volnum + 1, 2);
|
||||
iso_bb(vol->block_size, t->block_size, 2);
|
||||
iso_bb(vol->path_table_size, t->path_table_size, 4);
|
||||
iso_lsb(vol->l_path_table_pos, t->l_path_table_pos, 4);
|
||||
iso_msb(vol->m_path_table_pos, t->m_path_table_pos, 4);
|
||||
|
||||
write_one_dir_record(t, t->root, 3, vol->root_dir_record);
|
||||
|
||||
/* mmm, why not check for null? */
|
||||
strncpy((char*)vol->vol_set_id, volset_id, 128);
|
||||
strncpy((char*)vol->publisher_id, pub_id, 128);
|
||||
strncpy((char*)vol->data_prep_id, data_id, 128);
|
||||
|
||||
if (application_id)
|
||||
strncpy((char*)vol->application_id, application_id, 128);
|
||||
if (copyright_file_id)
|
||||
strncpy((char*)vol->copyright_file_id, copyright_file_id, 37);
|
||||
if (abstract_file_id)
|
||||
strncpy((char*)vol->abstract_file_id, abstract_file_id, 37);
|
||||
if (biblio_file_id)
|
||||
strncpy((char*)vol->bibliographic_file_id, biblio_file_id, 37);
|
||||
|
||||
iso_datetime_17(vol->vol_creation_time, t->now);
|
||||
iso_datetime_17(vol->vol_modification_time, t->now);
|
||||
iso_datetime_17(vol->vol_effective_time, t->now);
|
||||
vol->file_structure_version[0] = 1;
|
||||
|
||||
free(vol_id);
|
||||
free(volset_id);
|
||||
free(pub_id);
|
||||
free(data_id);
|
||||
free(system_id);
|
||||
free(application_id);
|
||||
free(copyright_file_id);
|
||||
free(abstract_file_id);
|
||||
free(biblio_file_id);
|
||||
}
|
||||
|
||||
static void
|
||||
write_vol_desc_terminator(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
struct ecma119_vol_desc_terminator *vol =
|
||||
(struct ecma119_vol_desc_terminator*) buf;
|
||||
|
||||
vol->vol_desc_type[0] = 255;
|
||||
memcpy(vol->std_identifier, "CD001", 5);
|
||||
vol->vol_desc_version[0] = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf)
|
||||
{
|
||||
void (*write_int)(uint8_t*, uint32_t, int) = l_type ? iso_lsb
|
||||
: iso_msb;
|
||||
size_t i;
|
||||
struct ecma119_path_table_record *rec;
|
||||
struct ecma119_tree_node *dir;
|
||||
int parent = 0;
|
||||
|
||||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
dir = t->pathlist[i];
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
while ((i) && t->pathlist[parent] != dir->parent)
|
||||
parent++;
|
||||
assert(parent < i || i == 0);
|
||||
|
||||
rec = (struct ecma119_path_table_record*) buf;
|
||||
rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->iso_name) : 1;
|
||||
rec->len_xa[0] = 0;
|
||||
write_int(rec->block, dir->info.dir.block, 4);
|
||||
write_int(rec->parent, parent + 1, 2);
|
||||
if (dir->parent)
|
||||
memcpy(rec->dir_id, dir->iso_name, rec->len_di[0]);
|
||||
buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_l_path_table(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
write_path_table(t, 1, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
write_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
write_path_table(t, 0, buf);
|
||||
}
|
||||
|
||||
/* if file_id is >= 0, we use it instead of the filename. As a magic number,
|
||||
* file_id == 3 means that we are writing the root directory record (in order
|
||||
* to distinguish it from the "." entry in the root directory) */
|
||||
static void
|
||||
write_one_dir_record(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *node,
|
||||
int file_id,
|
||||
uint8_t *buf)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t block;
|
||||
uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len;
|
||||
uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->iso_name);
|
||||
uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id);
|
||||
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->iso_name;
|
||||
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
|
||||
|
||||
if (node->type == ECMA119_DIR) {
|
||||
len = node->info.dir.len;
|
||||
block = node->info.dir.block;
|
||||
} else if (node->type == ECMA119_FILE) {
|
||||
len = node->info.file->size;
|
||||
block = node->info.file->block;
|
||||
} else {
|
||||
/* for nodes other than files and dirs, we set both len and block to 0 */
|
||||
len = 0;
|
||||
block = 0;
|
||||
}
|
||||
|
||||
/* we don't write out susp fields for the root node */
|
||||
if (t->rockridge) {
|
||||
if (file_id == 0) {
|
||||
assert(node->type == ECMA119_DIR);
|
||||
susp_write(t, &node->info.dir.self_susp, &buf[len_dr]);
|
||||
len_dr += node->info.dir.self_susp.non_CE_len;
|
||||
} else if (file_id == 1) {
|
||||
assert(node->type == ECMA119_DIR);
|
||||
susp_write(t, &node->info.dir.parent_susp, &buf[len_dr]);
|
||||
len_dr += node->info.dir.parent_susp.non_CE_len;
|
||||
} else if (file_id < 0) {
|
||||
susp_write(t, &node->susp, &buf[len_dr]);
|
||||
len_dr += node->susp.non_CE_len;
|
||||
}
|
||||
}
|
||||
if (file_id == 1 && node->parent)
|
||||
node = node->parent;
|
||||
|
||||
rec->len_dr[0] = len_dr;
|
||||
iso_bb(rec->block, block, 4);
|
||||
iso_bb(rec->length, len, 4);
|
||||
iso_datetime_7(rec->recording_time, t->now);
|
||||
rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0;
|
||||
iso_bb(rec->vol_seq_number, t->volnum + 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
memcpy(rec->file_id, name, len_fi);
|
||||
}
|
||||
|
||||
static void
|
||||
write_one_dir(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *dir,
|
||||
uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
int j;
|
||||
size_t len;
|
||||
uint8_t *orig_buf = buf;
|
||||
uint8_t *prior_buf = buf;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
/* write the "." and ".." entries first */
|
||||
write_one_dir_record(t, dir, 0, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
|
||||
write_one_dir_record(t, dir, 1, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
write_one_dir_record(t, dir->info.dir.children[i], -1, buf);
|
||||
len = ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
if ((buf + len - prior_buf) >= 2048) {
|
||||
for (j = len - 1; j >= 0; j--) {
|
||||
prior_buf[2048 + j] = buf[j];
|
||||
buf[j] = 0;
|
||||
}
|
||||
prior_buf += 2048;
|
||||
buf = prior_buf + len;
|
||||
}
|
||||
else {
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* write the susp continuation areas */
|
||||
if (t->rockridge) {
|
||||
susp_write_CE(t, &dir->info.dir.self_susp, buf);
|
||||
buf += dir->info.dir.self_susp.CE_len;
|
||||
susp_write_CE(t, &dir->info.dir.parent_susp, buf);
|
||||
buf += dir->info.dir.parent_susp.CE_len;
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
susp_write_CE(t, &dir->info.dir.children[i]->susp, buf);
|
||||
buf += dir->info.dir.children[i]->susp.CE_len;
|
||||
}
|
||||
}
|
||||
assert (buf - orig_buf == dir->info.dir.len + dir->info.dir.CE_len);
|
||||
}
|
||||
|
||||
static void
|
||||
write_dirs(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
struct ecma119_tree_node *dir;
|
||||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
dir = t->dirlist[i];
|
||||
write_one_dir(t, dir, buf);
|
||||
buf += round_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ecma119_start_chunking(struct ecma119_write_target *t,
|
||||
write_fn writer,
|
||||
off_t data_size,
|
||||
uint8_t *buf)
|
||||
{
|
||||
if (data_size != t->state_data_size) {
|
||||
data_size = round_up(data_size, t->block_size);
|
||||
t->state_data = realloc(t->state_data, data_size);
|
||||
t->state_data_size = data_size;
|
||||
}
|
||||
memset(t->state_data, 0, t->state_data_size);
|
||||
t->state_data_off = 0;
|
||||
t->state_data_valid = 1;
|
||||
writer(t, t->state_data);
|
||||
write_data_chunk(t, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
write_data_chunk(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
memcpy(buf, t->state_data + t->state_data_off, t->block_size);
|
||||
t->state_data_off += t->block_size;
|
||||
if (t->state_data_off >= t->state_data_size) {
|
||||
assert (t->state_data_off <= t->state_data_size);
|
||||
t->state_data_valid = 0;
|
||||
next_state(t);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bs_read(struct burn_source *bs, unsigned char *buf, int size)
|
||||
{
|
||||
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
|
||||
if (size != t->block_size) {
|
||||
warnx("you must read data in block-sized chunks (%d bytes)",
|
||||
(int)t->block_size);
|
||||
return 0;
|
||||
} else if (t->curblock >= t->vol_space_size) {
|
||||
return 0;
|
||||
}
|
||||
if (t->state_data_valid)
|
||||
write_data_chunk(t, buf);
|
||||
else
|
||||
writers[t->state](t, buf);
|
||||
t->curblock++;
|
||||
return size;
|
||||
}
|
||||
|
||||
static off_t
|
||||
bs_get_size(struct burn_source *bs)
|
||||
{
|
||||
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
|
||||
return t->total_size;
|
||||
}
|
||||
|
||||
static void
|
||||
bs_free_data(struct burn_source *bs)
|
||||
{
|
||||
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
|
||||
ecma119_tree_free(t->root);
|
||||
iso_file_table_clear(t->file_table);
|
||||
|
||||
free(t->dirlist);
|
||||
free(t->pathlist);
|
||||
free(t->dirlist_joliet);
|
||||
free(t->pathlist_joliet);
|
||||
free(t->filelist);
|
||||
free(t->state_data);
|
||||
if (t->joliet)
|
||||
joliet_tree_free(t->joliet_root);
|
||||
if (t->state_files.fd)
|
||||
fclose(t->state_files.fd);
|
||||
}
|
||||
|
||||
struct burn_source *iso_source_new_ecma119(struct iso_volset *volset,
|
||||
struct ecma119_source_opts *opts)
|
||||
{
|
||||
struct burn_source *ret = calloc(1, sizeof(struct burn_source));
|
||||
ret->refcount = 1;
|
||||
ret->read = bs_read;
|
||||
ret->get_size = bs_get_size;
|
||||
ret->free_data = bs_free_data;
|
||||
ret->data = ecma119_target_new(volset, opts);
|
||||
return ret;
|
||||
}
|
306
libisofs/branches/ZeroTwoEight/libisofs/ecma119.h
Executable file
306
libisofs/branches/ZeroTwoEight/libisofs/ecma119.h
Executable file
@ -0,0 +1,306 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* \file ecma119.h
|
||||
*
|
||||
* Structures and definitions used for writing an emca119 (ISO9660) compatible
|
||||
* volume.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_ECMA119_H
|
||||
#define LIBISO_ECMA119_H
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h> /* for FILE */
|
||||
#include <sys/types.h>
|
||||
#include "susp.h"
|
||||
|
||||
struct ecma119_tree_node;
|
||||
struct joliet_tree_node;
|
||||
|
||||
/**
|
||||
* The possible states that the ecma119 writer can be in.
|
||||
*/
|
||||
enum ecma119_write_state
|
||||
{
|
||||
ECMA119_WRITE_BEFORE,
|
||||
|
||||
ECMA119_WRITE_SYSTEM_AREA,
|
||||
ECMA119_WRITE_PRI_VOL_DESC,
|
||||
ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC,
|
||||
ECMA119_WRITE_SUP_VOL_DESC_JOLIET,
|
||||
ECMA119_WRITE_VOL_DESC_TERMINATOR,
|
||||
ECMA119_WRITE_L_PATH_TABLE,
|
||||
ECMA119_WRITE_M_PATH_TABLE,
|
||||
ECMA119_WRITE_L_PATH_TABLE_JOLIET,
|
||||
ECMA119_WRITE_M_PATH_TABLE_JOLIET,
|
||||
ECMA119_WRITE_DIR_RECORDS,
|
||||
ECMA119_WRITE_DIR_RECORDS_JOLIET,
|
||||
ECMA119_WRITE_ELTORITO_CATALOG,
|
||||
ECMA119_WRITE_FILES,
|
||||
|
||||
ECMA119_WRITE_DONE
|
||||
};
|
||||
|
||||
/**
|
||||
* Data describing the state of the ecma119 writer. Everything here should be
|
||||
* considered private!
|
||||
*/
|
||||
struct ecma119_write_target
|
||||
{
|
||||
struct ecma119_tree_node *root;
|
||||
struct joliet_tree_node *joliet_root;
|
||||
struct iso_volset *volset;
|
||||
int volnum;
|
||||
|
||||
time_t now; /**< Time at which writing began. */
|
||||
off_t total_size; /**< Total size of the output. This only
|
||||
* includes the current volume. */
|
||||
uint32_t vol_space_size;
|
||||
|
||||
unsigned int rockridge:1;
|
||||
unsigned int joliet:1;
|
||||
unsigned int iso_level:2;
|
||||
unsigned int eltorito:1;
|
||||
|
||||
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
|
||||
|
||||
struct el_torito_boot_catalog *catalog;
|
||||
|
||||
int replace_mode; /**< Replace ownership and modes of files
|
||||
*
|
||||
* 0. filesystem values
|
||||
* 1. useful values
|
||||
* bits 1-4 bitmask:
|
||||
* 2 - replace dir
|
||||
* 3 - replace file
|
||||
* 4 - replace gid
|
||||
* 5 - replace uid
|
||||
*/
|
||||
mode_t dir_mode;
|
||||
mode_t file_mode;
|
||||
gid_t gid;
|
||||
uid_t uid;
|
||||
|
||||
char *input_charset;
|
||||
char *ouput_charset;
|
||||
|
||||
int cache_inodes;
|
||||
|
||||
int sort_files; /**< if sort files or not. Sorting is based of
|
||||
* the weight of each file */
|
||||
|
||||
/**
|
||||
* In the CD, each file must have an unique inode number. So each
|
||||
* time we add a new file, this is incremented.
|
||||
*/
|
||||
ino_t ino;
|
||||
|
||||
int curblock;
|
||||
uint16_t block_size;
|
||||
uint32_t path_table_size;
|
||||
uint32_t path_table_size_joliet;
|
||||
uint32_t l_path_table_pos;
|
||||
uint32_t m_path_table_pos;
|
||||
uint32_t l_path_table_pos_joliet;
|
||||
uint32_t m_path_table_pos_joliet;
|
||||
uint32_t total_dir_size;
|
||||
uint32_t total_dir_size_joliet;
|
||||
|
||||
struct ecma119_tree_node **dirlist;
|
||||
/**< A pre-order list of directories
|
||||
* (this is the order in which we write
|
||||
* out directory records).
|
||||
*/
|
||||
struct ecma119_tree_node **pathlist;
|
||||
/**< A breadth-first list of
|
||||
* directories. This is used for
|
||||
* writing out the path tables.
|
||||
*/
|
||||
size_t dirlist_len; /**< The length of the previous 2 lists.
|
||||
*/
|
||||
|
||||
|
||||
struct iso_file_table *file_table;
|
||||
/**<
|
||||
* A hash table with info about all files
|
||||
*/
|
||||
|
||||
struct iso_file **filelist; /**< A pre-order list of files.*/
|
||||
size_t filelist_len; /* Length of the previous list. */
|
||||
|
||||
int curfile; /**< Used as a helper field for writing
|
||||
out filelist and dirlist */
|
||||
|
||||
/* Joliet versions of the above lists. Since Joliet doesn't require
|
||||
* directory relocation, the order of these lists might be different
|
||||
* from the lists above (but they will be the same length).
|
||||
*/
|
||||
struct joliet_tree_node **dirlist_joliet;
|
||||
struct joliet_tree_node **pathlist_joliet;
|
||||
|
||||
size_t dirlist_len_joliet;
|
||||
|
||||
enum ecma119_write_state state; /* The current state of the writer. */
|
||||
|
||||
/* Most writers work by
|
||||
* 1) making sure state_data is big enough for their data
|
||||
* 2) writing _all_ their data into state_data
|
||||
* 3) relying on write_data_chunk to write the data block
|
||||
* by block.
|
||||
*/
|
||||
uint8_t *state_data;
|
||||
off_t state_data_size;
|
||||
off_t state_data_off;
|
||||
int state_data_valid;
|
||||
|
||||
/* for writing out files */
|
||||
struct state_files {
|
||||
off_t pos; /* The number of bytes we have written
|
||||
* so far in the current file.
|
||||
*/
|
||||
off_t data_len;/* The number of bytes in the currently
|
||||
* open file.
|
||||
*/
|
||||
FILE *fd; /* The currently open file. */
|
||||
int file; /* The index in filelist that we are
|
||||
* currently writing (or about to write). */
|
||||
} state_files;
|
||||
};
|
||||
|
||||
#define BP(a,b) [(b) - (a) + 1]
|
||||
|
||||
struct ecma119_pri_vol_desc
|
||||
{
|
||||
uint8_t vol_desc_type BP(1, 1);
|
||||
uint8_t std_identifier BP(2, 6);
|
||||
uint8_t vol_desc_version BP(7, 7);
|
||||
uint8_t unused1 BP(8, 8);
|
||||
uint8_t system_id BP(9, 40);
|
||||
uint8_t volume_id BP(41, 72);
|
||||
uint8_t unused2 BP(73, 80);
|
||||
uint8_t vol_space_size BP(81, 88);
|
||||
uint8_t unused3 BP(89, 120);
|
||||
uint8_t vol_set_size BP(121, 124);
|
||||
uint8_t vol_seq_number BP(125, 128);
|
||||
uint8_t block_size BP(129, 132);
|
||||
uint8_t path_table_size BP(133, 140);
|
||||
uint8_t l_path_table_pos BP(141, 144);
|
||||
uint8_t opt_l_path_table_pos BP(145, 148);
|
||||
uint8_t m_path_table_pos BP(149, 152);
|
||||
uint8_t opt_m_path_table_pos BP(153, 156);
|
||||
uint8_t root_dir_record BP(157, 190);
|
||||
uint8_t vol_set_id BP(191, 318);
|
||||
uint8_t publisher_id BP(319, 446);
|
||||
uint8_t data_prep_id BP(447, 574);
|
||||
uint8_t application_id BP(575, 702);
|
||||
uint8_t copyright_file_id BP(703, 739);
|
||||
uint8_t abstract_file_id BP(740, 776);
|
||||
uint8_t bibliographic_file_id BP(777, 813);
|
||||
uint8_t vol_creation_time BP(814, 830);
|
||||
uint8_t vol_modification_time BP(831, 847);
|
||||
uint8_t vol_expiration_time BP(848, 864);
|
||||
uint8_t vol_effective_time BP(865, 881);
|
||||
uint8_t file_structure_version BP(882, 882);
|
||||
uint8_t reserved1 BP(883, 883);
|
||||
uint8_t app_use BP(884, 1395);
|
||||
uint8_t reserved2 BP(1396, 2048);
|
||||
};
|
||||
|
||||
struct ecma119_sup_vol_desc
|
||||
{
|
||||
uint8_t vol_desc_type BP(1, 1);
|
||||
uint8_t std_identifier BP(2, 6);
|
||||
uint8_t vol_desc_version BP(7, 7);
|
||||
uint8_t vol_flags BP(8, 8);
|
||||
uint8_t system_id BP(9, 40);
|
||||
uint8_t volume_id BP(41, 72);
|
||||
uint8_t unused2 BP(73, 80);
|
||||
uint8_t vol_space_size BP(81, 88);
|
||||
uint8_t esc_sequences BP(89, 120);
|
||||
uint8_t vol_set_size BP(121, 124);
|
||||
uint8_t vol_seq_number BP(125, 128);
|
||||
uint8_t block_size BP(129, 132);
|
||||
uint8_t path_table_size BP(133, 140);
|
||||
uint8_t l_path_table_pos BP(141, 144);
|
||||
uint8_t opt_l_path_table_pos BP(145, 148);
|
||||
uint8_t m_path_table_pos BP(149, 152);
|
||||
uint8_t opt_m_path_table_pos BP(153, 156);
|
||||
uint8_t root_dir_record BP(157, 190);
|
||||
uint8_t vol_set_id BP(191, 318);
|
||||
uint8_t publisher_id BP(319, 446);
|
||||
uint8_t data_prep_id BP(447, 574);
|
||||
uint8_t application_id BP(575, 702);
|
||||
uint8_t copyright_file_id BP(703, 739);
|
||||
uint8_t abstract_file_id BP(740, 776);
|
||||
uint8_t bibliographic_file_id BP(777, 813);
|
||||
uint8_t vol_creation_time BP(814, 830);
|
||||
uint8_t vol_modification_time BP(831, 847);
|
||||
uint8_t vol_expiration_time BP(848, 864);
|
||||
uint8_t vol_effective_time BP(865, 881);
|
||||
uint8_t file_structure_version BP(882, 882);
|
||||
uint8_t reserved1 BP(883, 883);
|
||||
uint8_t app_use BP(884, 1395);
|
||||
uint8_t reserved2 BP(1396, 2048);
|
||||
};
|
||||
|
||||
struct ecma119_boot_rec_vol_desc
|
||||
{
|
||||
uint8_t vol_desc_type BP(1, 1);
|
||||
uint8_t std_identifier BP(2, 6);
|
||||
uint8_t vol_desc_version BP(7, 7);
|
||||
uint8_t boot_sys_id BP(8, 39);
|
||||
uint8_t boot_id BP(40, 71);
|
||||
uint8_t boot_catalog BP(72, 75);
|
||||
uint8_t unused BP(76, 2048);
|
||||
};
|
||||
|
||||
struct ecma119_vol_desc_terminator
|
||||
{
|
||||
uint8_t vol_desc_type BP(1, 1);
|
||||
uint8_t std_identifier BP(2, 6);
|
||||
uint8_t vol_desc_version BP(7, 7);
|
||||
uint8_t reserved BP(8, 2048);
|
||||
};
|
||||
|
||||
struct ecma119_dir_record
|
||||
{
|
||||
uint8_t len_dr BP(1, 1);
|
||||
uint8_t len_xa BP(2, 2);
|
||||
uint8_t block BP(3, 10);
|
||||
uint8_t length BP(11, 18);
|
||||
uint8_t recording_time BP(19, 25);
|
||||
uint8_t flags BP(26, 26);
|
||||
uint8_t file_unit_size BP(27, 27);
|
||||
uint8_t interleave_gap_size BP(28, 28);
|
||||
uint8_t vol_seq_number BP(29, 32);
|
||||
uint8_t len_fi BP(33, 33);
|
||||
uint8_t file_id BP(34, 34); /* 34 to 33+len_fi */
|
||||
/* padding field (if len_fi is even) */
|
||||
/* system use (len_dr - len_su + 1 to len_dr) */
|
||||
};
|
||||
|
||||
struct ecma119_path_table_record
|
||||
{
|
||||
uint8_t len_di BP(1, 1);
|
||||
uint8_t len_xa BP(2, 2);
|
||||
uint8_t block BP(3, 6);
|
||||
uint8_t parent BP(7, 8);
|
||||
uint8_t dir_id BP(9, 9); /* 9 to 8+len_di */
|
||||
/* padding field (if len_di is odd) */
|
||||
};
|
||||
|
||||
/**
|
||||
* A utility function for writers that want to write their data all at once
|
||||
* rather than block-by-block. This creates a buffer of size \p size, passes
|
||||
* it to the given writer, then hands out block-sized chunks.
|
||||
*/
|
||||
void
|
||||
ecma119_start_chunking(struct ecma119_write_target *t,
|
||||
void (*)(struct ecma119_write_target*, uint8_t*),
|
||||
off_t size,
|
||||
uint8_t *buf);
|
||||
|
||||
#endif /* LIBISO_ECMA119_H */
|
623
libisofs/branches/ZeroTwoEight/libisofs/ecma119_tree.c
Normal file
623
libisofs/branches/ZeroTwoEight/libisofs/ecma119_tree.c
Normal file
@ -0,0 +1,623 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ecma119.h"
|
||||
#include "ecma119_tree.h"
|
||||
#include "tree.h"
|
||||
#include "util.h"
|
||||
#include "eltorito.h"
|
||||
|
||||
static size_t calc_dirent_len(struct ecma119_tree_node *n)
|
||||
{
|
||||
int ret = n->iso_name ? strlen(n->iso_name) + 33 : 34;
|
||||
if (ret % 2) ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the file permissions and user/group id of an ECMA-119 node.
|
||||
* This is used when a replace mode is selected, i.e., when we want to
|
||||
* create a disc where the mode of each file or directory will be
|
||||
* different than the mode in the original source.
|
||||
*/
|
||||
static void
|
||||
replace_node_mode(struct ecma119_write_target *t, struct stat *st)
|
||||
{
|
||||
if ( S_ISDIR(st->st_mode) ) {
|
||||
if ( t->replace_mode & 0x02 ) {
|
||||
/* replace dir mode with specific */
|
||||
st->st_mode &= S_IFMT;
|
||||
st->st_mode |= t->dir_mode;
|
||||
} else if (t->replace_mode & 0x01) {
|
||||
/* replace dir mode with default */
|
||||
/* read perm */
|
||||
mode_t new_mode = (st->st_mode & S_IFMT) | 0444;
|
||||
/* search bit if any */
|
||||
if ( st->st_mode & 0111)
|
||||
new_mode |= 0111;
|
||||
st->st_mode = new_mode;
|
||||
}
|
||||
} else {
|
||||
if ( t->replace_mode & 0x04 ) {
|
||||
/* replace file mode with specific */
|
||||
st->st_mode &= S_IFMT;
|
||||
st->st_mode |= t->file_mode;
|
||||
} else if (t->replace_mode & 0x01) {
|
||||
/* replace file mode with default */
|
||||
/* read perm */
|
||||
mode_t new_mode = (st->st_mode & S_IFMT) | 0444;
|
||||
/* execute bit if any */
|
||||
if ( st->st_mode & 0111)
|
||||
new_mode |= 0111;
|
||||
st->st_mode = new_mode;
|
||||
}
|
||||
|
||||
}
|
||||
if ( t->replace_mode & 0x08 ) {
|
||||
/* replace gid mode with specific */
|
||||
st->st_gid = t->gid;
|
||||
} else if (t->replace_mode & 0x01) {
|
||||
st->st_gid = 0;
|
||||
}
|
||||
if ( t->replace_mode & 0x10 ) {
|
||||
/* replace gid mode with specific */
|
||||
st->st_uid = t->uid;
|
||||
} else if (t->replace_mode & 0x01) {
|
||||
st->st_uid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ECMA-119 node from the given iso tree node, and initializes
|
||||
* the fields that are common to all kind of nodes (dir, reg file, symlink...).
|
||||
*
|
||||
* @param t
|
||||
* The options for the ECMA-119 tree that is being created
|
||||
* @param parent
|
||||
* The parent of the node, or NULL if it's the root.
|
||||
* @param iso
|
||||
* The node from which this function creates a ECMA-119 node
|
||||
* @return
|
||||
* The created node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_ecma119_node(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
char *(*iso_name)(const char *, const char *) = ISO_ISDIR(iso) ?
|
||||
((t->iso_level == 1) ? iso_1_dirid : iso_2_dirid)
|
||||
: ((t->iso_level == 1) ? iso_1_fileid : iso_2_fileid);
|
||||
char *(*iso_r_name)(const char *, const char *, int) =
|
||||
ISO_ISDIR(iso) ? iso_r_dirid : iso_r_fileid;
|
||||
|
||||
assert(t && (!parent || parent->type == ECMA119_DIR) && iso );
|
||||
|
||||
ret = calloc(1, sizeof(struct ecma119_tree_node));
|
||||
|
||||
/*
|
||||
* If selected one ISO relaxed constraints other than NO_DIR_REALOCATION,
|
||||
* we use the function that computes the relaxed name, otherwise normal
|
||||
* function for specified level is used.
|
||||
*/
|
||||
ret->iso_name = iso->name ?
|
||||
( t->relaxed_constraints & ~ECMA119_NO_DIR_REALOCATION ?
|
||||
iso_r_name(iso->name, t->input_charset, t->relaxed_constraints) :
|
||||
iso_name(iso->name, t->input_charset)
|
||||
) : NULL;
|
||||
ret->dirent_len = calc_dirent_len(ret);
|
||||
|
||||
/* iso node keeps the same file attribs as the original file. */
|
||||
ret->attrib = iso->attrib;
|
||||
|
||||
/*
|
||||
* When using RR extension and replace mode, we will replace the
|
||||
* permissions and uid/gid of each file with those previously selected
|
||||
* by the user.
|
||||
*/
|
||||
if ( t->rockridge && t->replace_mode )
|
||||
replace_node_mode(t, &ret->attrib);
|
||||
|
||||
if (!iso->name)
|
||||
ret->full_name = NULL;
|
||||
else if ( strcmp(t->input_charset,t->ouput_charset) )
|
||||
/* convert the file name charset */
|
||||
ret->full_name = convert_str(iso->name, t->input_charset,
|
||||
t->ouput_charset);
|
||||
else
|
||||
ret->full_name = strdup(iso->name);
|
||||
ret->target = t;
|
||||
ret->parent = parent;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a directory from a iso directory
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_dir(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node_dir *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
|
||||
assert(t && (!parent || parent->type == ECMA119_DIR)
|
||||
&& iso && S_ISDIR(iso->node.attrib.st_mode));
|
||||
|
||||
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
|
||||
ret->type = ECMA119_DIR;
|
||||
ret->info.dir.real_parent = parent;
|
||||
ret->info.dir.depth = parent ? parent->info.dir.depth + 1 : 1;
|
||||
ret->info.dir.nchildren = 0;
|
||||
ret->info.dir.children = calloc(1, sizeof(void*) * iso->nchildren);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a regular file from a iso file
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_file(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node_file *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
struct iso_file *file;
|
||||
|
||||
assert(t && iso && parent && parent->type == ECMA119_DIR);
|
||||
|
||||
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
|
||||
ret->type = ECMA119_FILE;
|
||||
|
||||
/* get iso_file struct */
|
||||
file = iso_file_table_lookup(t->file_table, iso);
|
||||
if ( file == NULL ) {
|
||||
/*
|
||||
* If the file is not already added to the disc, we add it now
|
||||
* to the file table, and get a new inode number for it.
|
||||
*/
|
||||
file = iso_file_new(iso);
|
||||
iso_file_table_add_file(t->file_table, file);
|
||||
file->ino = ++t->ino;
|
||||
} else {
|
||||
/* increment number of hard-links */
|
||||
file->nlink++;
|
||||
}
|
||||
|
||||
ret->attrib.st_nlink = file->nlink;
|
||||
ret->attrib.st_ino = file->ino;
|
||||
ret->info.file = file;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a placeholder for a relocated
|
||||
* dir.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5 for details
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_placeholder(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct ecma119_tree_node *real)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
|
||||
assert(t && real && real->type == ECMA119_DIR
|
||||
&& parent && parent->type == ECMA119_DIR);
|
||||
|
||||
ret = calloc(1, sizeof(struct ecma119_tree_node));
|
||||
ret->iso_name = real->iso_name; /* TODO strdup? */
|
||||
/* FIXME
|
||||
* if we strdup above, if name changes in mangle_all,
|
||||
* this probably keeps as original.
|
||||
* if not, both change, but we need to update dirent_len.
|
||||
* I think that attributes of a placeholder must be taken from
|
||||
* real_me, not keept here.
|
||||
* FIXME
|
||||
* Another question is that real is a dir, while placeholder is
|
||||
* a file, and ISO name restricctions are different, what to do?
|
||||
*/
|
||||
ret->dirent_len = real->dirent_len;
|
||||
ret->attrib = real->attrib;
|
||||
ret->full_name = strdup(real->full_name);
|
||||
ret->target = t;
|
||||
ret->parent = parent;
|
||||
ret->type = ECMA119_PLACEHOLDER;
|
||||
ret->info.real_me = real;
|
||||
ret->attrib.st_nlink = 1;
|
||||
ret->attrib.st_ino = ++t->ino;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a symbolic link from a iso symlink
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_symlink(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node_symlink *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
|
||||
assert(t && iso && parent && parent->type == ECMA119_DIR);
|
||||
|
||||
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
|
||||
ret->iso_name = iso->node.name ? ((t->iso_level == 1) ?
|
||||
iso_1_fileid(iso->node.name, t->input_charset)
|
||||
: iso_2_fileid(iso->node.name, t->input_charset))
|
||||
: NULL;
|
||||
ret->type = ECMA119_SYMLINK;
|
||||
ret->info.dest = iso->dest; /* TODO strdup? */
|
||||
ret->attrib.st_nlink = 1;
|
||||
ret->attrib.st_ino = ++t->ino;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a boot catalog. This is like a
|
||||
* regular file, but its contents are taken from a El-Torito boot catalog,
|
||||
* and not from a file in the local filesystem.
|
||||
*
|
||||
* See "El Torito" Bootable CD-ROM Format Specification Version 1.0 for
|
||||
* more details.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_boot_catalog(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node_boot_catalog *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
struct iso_file *file;
|
||||
|
||||
assert(t && iso && parent && parent->type == ECMA119_DIR);
|
||||
|
||||
/*
|
||||
* This will simply create a ECMA119 file, with the only difference
|
||||
* that the iso_file is not taken from table, but from boot catalog
|
||||
*/
|
||||
|
||||
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
|
||||
ret->type = ECMA119_FILE;
|
||||
|
||||
file = iso->catalog->file;
|
||||
file->ino = ++t->ino;
|
||||
|
||||
ret->attrib.st_nlink = file->nlink;
|
||||
ret->attrib.st_ino = file->ino;
|
||||
ret->info.file = file;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node that corresponds to the given iso tree node.
|
||||
* If that node is a dir, this function recurses over all their children,
|
||||
* thus creating a ECMA-119 tree whose root is the given iso dir.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_tree(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret = NULL;
|
||||
|
||||
assert(t && iso);
|
||||
|
||||
if ( iso->hide_flags & LIBISO_HIDE_ON_RR )
|
||||
return NULL;
|
||||
|
||||
switch ( iso->type ) {
|
||||
case LIBISO_NODE_FILE:
|
||||
ret = create_file(t, parent, (struct iso_tree_node_file*)iso);
|
||||
break;
|
||||
case LIBISO_NODE_SYMLINK:
|
||||
if ( !t->rockridge )
|
||||
printf("Can't add symlinks to a non ISO tree. Skipping %s \n",
|
||||
iso->name);
|
||||
else
|
||||
ret = create_symlink(t, parent, (struct iso_tree_node_symlink*)iso);
|
||||
break;
|
||||
case LIBISO_NODE_DIR:
|
||||
{
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir = (struct iso_tree_node_dir*)iso;
|
||||
ret = create_dir(t, parent, dir);
|
||||
for (i = 0; i < dir->nchildren; i++) {
|
||||
struct ecma119_tree_node *child;
|
||||
child = create_tree(t, ret, dir->children[i]);
|
||||
if (child)
|
||||
ret->info.dir.children[ret->info.dir.nchildren++] = child;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LIBISO_NODE_BOOTCATALOG:
|
||||
ret = create_boot_catalog(t, parent,
|
||||
(struct iso_tree_node_boot_catalog*)iso);
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
assert( 0 );
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
ecma119_tree_free(struct ecma119_tree_node *root)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (root->type == ECMA119_DIR) {
|
||||
for (i=0; i < root->info.dir.nchildren; i++) {
|
||||
ecma119_tree_free(root->info.dir.children[i]);
|
||||
}
|
||||
free(root->info.dir.children);
|
||||
}
|
||||
free(root->iso_name);
|
||||
free(root->full_name);
|
||||
free(root);
|
||||
}
|
||||
|
||||
static size_t
|
||||
max_child_name_len(struct ecma119_tree_node *root)
|
||||
{
|
||||
size_t ret = 0, i;
|
||||
|
||||
assert(root->type == ECMA119_DIR);
|
||||
for (i=0; i < root->info.dir.nchildren; i++) {
|
||||
size_t len = strlen(root->info.dir.children[i]->iso_name);
|
||||
ret = MAX(ret, len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Relocates a directory, as specified in Rock Ridge Specification
|
||||
* (see IEEE P1282, section 4.1.5). This is needed when the number of levels
|
||||
* on a directory hierarchy exceeds 8, or the length of a path is higher
|
||||
* than 255 characters, as specified in ECMA-119, section 6.8.2.1
|
||||
*/
|
||||
static void
|
||||
reparent(struct ecma119_tree_node *child,
|
||||
struct ecma119_tree_node *parent)
|
||||
{
|
||||
int found = 0;
|
||||
size_t i;
|
||||
struct ecma119_tree_node *placeholder;
|
||||
|
||||
assert(child && parent && parent->type == ECMA119_DIR && child->parent);
|
||||
|
||||
/* replace the child in the original parent with a placeholder */
|
||||
for (i=0; i < child->parent->info.dir.nchildren; i++) {
|
||||
if (child->parent->info.dir.children[i] == child) {
|
||||
placeholder = create_placeholder(child->target,
|
||||
child->parent, child);
|
||||
child->parent->info.dir.children[i] = placeholder;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(found);
|
||||
|
||||
/* add the child to its new parent */
|
||||
child->parent = parent;
|
||||
parent->info.dir.nchildren++;
|
||||
parent->info.dir.children = realloc( parent->info.dir.children,
|
||||
sizeof(void*) * parent->info.dir.nchildren );
|
||||
parent->info.dir.children[parent->info.dir.nchildren-1] = child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the tree, if necessary, to ensure that
|
||||
* - the depth is at most 8
|
||||
* - each path length is at most 255 characters
|
||||
* This restriction is imposed by ECMA-119 specification (see ECMA-119,
|
||||
* 6.8.2.1).
|
||||
*/
|
||||
static void
|
||||
reorder_tree(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *root,
|
||||
struct ecma119_tree_node *cur)
|
||||
{
|
||||
size_t max_path;
|
||||
|
||||
assert(root && cur && cur->type == ECMA119_DIR);
|
||||
|
||||
cur->info.dir.depth = cur->parent ? cur->parent->info.dir.depth + 1 : 1;
|
||||
cur->info.dir.path_len = cur->parent ? cur->parent->info.dir.path_len
|
||||
+ strlen(cur->iso_name) : 0;
|
||||
max_path = cur->info.dir.path_len + cur->info.dir.depth
|
||||
+ max_child_name_len(cur);
|
||||
|
||||
if (cur->info.dir.depth > 8 || max_path > 255) {
|
||||
|
||||
if (t->rockridge) {
|
||||
reparent(cur, root);
|
||||
/* we are appended to the root's children now, so there is no
|
||||
* need to recurse (the root will hit us again) */
|
||||
} else {
|
||||
/* we need to delete cur */
|
||||
size_t i,j;
|
||||
struct ecma119_tree_node *parent = cur->parent;
|
||||
|
||||
printf("Can't dirs deeper than 8 without RR. Skipping %s\n",
|
||||
cur->full_name);
|
||||
for (i=0; i < parent->info.dir.nchildren; ++i) {
|
||||
if (parent->info.dir.children[i] == cur) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert ( i < parent->info.dir.nchildren);
|
||||
for ( j = i; j < parent->info.dir.nchildren - 1; ++j)
|
||||
parent->info.dir.children[j] = parent->info.dir.children[j+1];
|
||||
parent->info.dir.nchildren--;
|
||||
ecma119_tree_free(cur);
|
||||
}
|
||||
} else {
|
||||
size_t i;
|
||||
|
||||
for (i=0; i < cur->info.dir.nchildren; i++) {
|
||||
if (cur->info.dir.children[i]->type == ECMA119_DIR)
|
||||
reorder_tree(t, root, cur->info.dir.children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the iso name of two ECMA-119 nodes
|
||||
*/
|
||||
static int
|
||||
cmp_node(const void *f1, const void *f2)
|
||||
{
|
||||
struct ecma119_tree_node *f = *((struct ecma119_tree_node**)f1);
|
||||
struct ecma119_tree_node *g = *((struct ecma119_tree_node**)f2);
|
||||
return strcmp(f->iso_name, g->iso_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts a the children of each directory in the ECMA-119 tree represented
|
||||
* by \p root, acording to the order specified in ECMA-119, section 9.3.
|
||||
*/
|
||||
static void
|
||||
sort_tree(struct ecma119_tree_node *root)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(root && root->type == ECMA119_DIR);
|
||||
|
||||
qsort(root->info.dir.children, root->info.dir.nchildren,
|
||||
sizeof(void*), cmp_node);
|
||||
for (i=0; i < root->info.dir.nchildren; i++) {
|
||||
if (root->info.dir.children[i]->type == ECMA119_DIR)
|
||||
sort_tree(root->info.dir.children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change num_change characters of the given filename in order to ensure the
|
||||
* name is unique. If the name is short enough (depending on the ISO level),
|
||||
* we can append the characters instead of changing them.
|
||||
*
|
||||
* \p seq_num is the index of this file in the sequence of identical filenames.
|
||||
*
|
||||
* For example, seq_num=3, num_change=2, name="HELLOTHERE.TXT" changes name to
|
||||
* "HELLOTHE03.TXT"
|
||||
*/
|
||||
static void
|
||||
mangle_name(char **name, int num_change, int level, int seq_num)
|
||||
{
|
||||
char *dot = strrchr(*name, '.');
|
||||
char *semi = strrchr(*name, ';');
|
||||
size_t len = strlen(*name);
|
||||
char base[len+1], ext[len+1];
|
||||
char fmt[12];
|
||||
size_t baselen, extlen;
|
||||
|
||||
if (num_change >= len) {
|
||||
return;
|
||||
}
|
||||
strncpy(base, *name, len+1);
|
||||
if (dot) {
|
||||
base[dot - *name] = '\0';
|
||||
strncpy(ext, dot+1, len+1);
|
||||
if (semi) {
|
||||
ext[semi - dot - 1] = '\0';
|
||||
}
|
||||
} else {
|
||||
base[len-2] = '\0';
|
||||
ext[0] = '\0';
|
||||
}
|
||||
baselen = strlen(base);
|
||||
extlen = strlen(ext);
|
||||
if (level == 1 && baselen + num_change > 8) {
|
||||
base[8 - num_change] = '\0';
|
||||
} else if (level != 1 && baselen + extlen + num_change > 30) {
|
||||
base[30 - extlen - num_change] = '\0';
|
||||
}
|
||||
|
||||
sprintf(fmt, "%%s%%0%1dd.%%s;1", num_change);
|
||||
*name = realloc(*name, baselen + extlen + num_change + 4);
|
||||
sprintf(*name, fmt, base, seq_num, ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the ISO name of each children of the given dir is unique,
|
||||
* changing some of them if needed.
|
||||
*/
|
||||
static void
|
||||
mangle_all(struct ecma119_tree_node *dir)
|
||||
{
|
||||
size_t i, j, k;
|
||||
struct ecma119_dir_info d = dir->info.dir;
|
||||
size_t n_change;
|
||||
int changed;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
do {
|
||||
changed = 0;
|
||||
for (i=0; i < d.nchildren; i++) {
|
||||
/* find the number of consecutive equal names */
|
||||
j = 1;
|
||||
while ( i+j < d.nchildren &&
|
||||
!strcmp(d.children[i]->iso_name,
|
||||
d.children[i+j]->iso_name) )
|
||||
j++;
|
||||
if (j == 1) continue;
|
||||
|
||||
/* mangle the names */
|
||||
changed = 1;
|
||||
n_change = j / 10 + 1;
|
||||
for (k=0; k < j; k++) {
|
||||
mangle_name(&(d.children[i+k]->iso_name),
|
||||
n_change,
|
||||
dir->target->iso_level,
|
||||
k);
|
||||
d.children[i+k]->dirent_len =
|
||||
calc_dirent_len(d.children[i+k]);
|
||||
}
|
||||
|
||||
/* skip ahead by the number of mangled names */
|
||||
i += j - 1;
|
||||
}
|
||||
} while (changed);
|
||||
|
||||
for (i=0; i < d.nchildren; i++) {
|
||||
if (d.children[i]->type == ECMA119_DIR)
|
||||
mangle_all(d.children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
struct ecma119_tree_node*
|
||||
ecma119_tree_create(struct ecma119_write_target *t,
|
||||
struct iso_tree_node *iso_root)
|
||||
{
|
||||
t->root = create_tree(t, NULL, iso_root);
|
||||
if ( !(t->relaxed_constraints & ECMA119_NO_DIR_REALOCATION) )
|
||||
reorder_tree(t, t->root, t->root);
|
||||
sort_tree(t->root);
|
||||
mangle_all(t->root);
|
||||
return t->root;
|
||||
}
|
||||
|
||||
void
|
||||
ecma119_tree_print(struct ecma119_tree_node *root, int spaces)
|
||||
{
|
||||
size_t i;
|
||||
char sp[spaces+1];
|
||||
|
||||
memset(sp, ' ', spaces);
|
||||
sp[spaces] = '\0';
|
||||
|
||||
printf("%s%s\n", sp, root->iso_name);
|
||||
if (root->type == ECMA119_DIR)
|
||||
for (i=0; i < root->info.dir.nchildren; i++)
|
||||
ecma119_tree_print(root->info.dir.children[i], spaces+2);
|
||||
}
|
98
libisofs/branches/ZeroTwoEight/libisofs/ecma119_tree.h
Normal file
98
libisofs/branches/ZeroTwoEight/libisofs/ecma119_tree.h
Normal file
@ -0,0 +1,98 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* \file ecma119_tree.h
|
||||
*
|
||||
* Declarations for creating, modifying and printing filesystem trees that
|
||||
* are compatible with ecma119.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_ECMA119_TREE_H
|
||||
#define LIBISO_ECMA119_TREE_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "file.h"
|
||||
|
||||
struct ecma119_write_target;
|
||||
struct iso_tree_node;
|
||||
|
||||
enum ecma119_node_type {
|
||||
ECMA119_FILE,
|
||||
ECMA119_SYMLINK,
|
||||
ECMA119_DIR,
|
||||
ECMA119_PLACEHOLDER /**< placeholder for a relocated dir. */
|
||||
};
|
||||
|
||||
struct ecma119_dir_info {
|
||||
struct susp_info self_susp; /**< susp entries for "." */
|
||||
struct susp_info parent_susp; /**< susp entries for ".." */
|
||||
|
||||
size_t len; /**< sum of the lengths of children's
|
||||
* Directory Records (including SU) */
|
||||
size_t CE_len; /**< sum of the lengths of children's
|
||||
* SUSP CE areas */
|
||||
size_t block;
|
||||
|
||||
int depth;
|
||||
size_t path_len; /**< The length of a path up to, and
|
||||
* including, this directory. This
|
||||
* cannot exceed 255. */
|
||||
size_t nchildren;
|
||||
struct ecma119_tree_node **children;
|
||||
|
||||
struct ecma119_tree_node *real_parent;
|
||||
/**< The parent before relocation */
|
||||
};
|
||||
|
||||
/**
|
||||
* A node for a tree containing all the information necessary for writing
|
||||
* an ISO9660 volume.
|
||||
*/
|
||||
struct ecma119_tree_node
|
||||
{
|
||||
char *iso_name; /**< in ASCII, conforming to the
|
||||
* current ISO level. */
|
||||
char *full_name; /**< full name, in current locale (TODO put this in UTF-8?) */
|
||||
size_t dirent_len; /**< Length of the directory record,
|
||||
* not including SU. */
|
||||
|
||||
struct ecma119_tree_node *parent;
|
||||
struct ecma119_write_target *target;
|
||||
|
||||
struct stat attrib;
|
||||
|
||||
struct susp_info susp;
|
||||
|
||||
enum ecma119_node_type type; /**< file, symlink, directory or placeholder */
|
||||
union {
|
||||
struct iso_file *file;
|
||||
char *dest;
|
||||
struct ecma119_dir_info dir;
|
||||
struct ecma119_tree_node *real_me; /**< this field points to
|
||||
* the relocated directory.
|
||||
*/
|
||||
} info;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ecma119_tree that corresponds to the tree represented by
|
||||
* \p iso_root.
|
||||
*/
|
||||
struct ecma119_tree_node*
|
||||
ecma119_tree_create(struct ecma119_write_target *target,
|
||||
struct iso_tree_node *iso_root);
|
||||
|
||||
/**
|
||||
* Free an ecma119 tree.
|
||||
*/
|
||||
void
|
||||
ecma119_tree_free(struct ecma119_tree_node *root);
|
||||
|
||||
/**
|
||||
* Print an ecma119 tree.
|
||||
*/
|
||||
void
|
||||
ecma119_tree_print(struct ecma119_tree_node *root, int spaces);
|
||||
|
||||
#endif /* LIBISO_ECMA119_TREE_H */
|
454
libisofs/branches/ZeroTwoEight/libisofs/eltorito.c
Normal file
454
libisofs/branches/ZeroTwoEight/libisofs/eltorito.c
Normal file
@ -0,0 +1,454 @@
|
||||
#include "libisofs.h"
|
||||
|
||||
#include "eltorito.h"
|
||||
#include "volume.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
struct el_torito_validation_entry {
|
||||
uint8_t header_id BP(1, 1);
|
||||
uint8_t platform_id BP(2, 2);
|
||||
uint8_t reserved BP(3, 4);
|
||||
uint8_t id_string BP(5, 28);
|
||||
uint8_t checksum BP(29, 30);
|
||||
uint8_t key_byte1 BP(31, 31);
|
||||
uint8_t key_byte2 BP(32, 32);
|
||||
};
|
||||
|
||||
struct el_torito_default_entry {
|
||||
uint8_t boot_indicator BP(1, 1);
|
||||
uint8_t boot_media_type BP(2, 2);
|
||||
uint8_t load_seg BP(3, 4);
|
||||
uint8_t system_type BP(5, 5);
|
||||
uint8_t unused1 BP(6, 6);
|
||||
uint8_t sec_count BP(7, 8);
|
||||
uint8_t block BP(9, 12);
|
||||
uint8_t unused2 BP(13, 32);
|
||||
};
|
||||
|
||||
struct el_torito_section_header_entry {
|
||||
uint8_t header_indicator BP(1, 1);
|
||||
uint8_t platform_id BP(2, 2);
|
||||
uint8_t number BP(3, 4);
|
||||
uint8_t character BP(5, 32);
|
||||
};
|
||||
|
||||
struct el_torito_section_entry {
|
||||
uint8_t boot_indicator BP(1, 1);
|
||||
uint8_t boot_media_type BP(2, 2);
|
||||
uint8_t load_seg BP(3, 4);
|
||||
uint8_t system_type BP(5, 5);
|
||||
uint8_t unused1 BP(6, 6);
|
||||
uint8_t sec_count BP(7, 8);
|
||||
uint8_t block BP(9, 12);
|
||||
uint8_t selec_criteria BP(13, 13);
|
||||
uint8_t vendor_sc BP(14, 32);
|
||||
};
|
||||
|
||||
/**
|
||||
* This table should be written with accuracy values at offset
|
||||
* 8 of boot image, when used ISOLINUX boot loader
|
||||
*/
|
||||
struct boot_info_table {
|
||||
uint8_t bi_pvd BP(1, 4); /* LBA of primary volume descriptor */
|
||||
uint8_t bi_file BP(5, 8); /* LBA of boot file */
|
||||
uint8_t bi_length BP(9, 12); /* Length of boot file */
|
||||
uint8_t bi_csum BP(13, 16); /* Checksum of boot file */
|
||||
uint8_t bi_reserved BP(17, 56); /* Reserved */
|
||||
};
|
||||
|
||||
struct partition_desc {
|
||||
uint8_t boot_ind;
|
||||
uint8_t begin_chs[3];
|
||||
uint8_t type;
|
||||
uint8_t end_chs[3];
|
||||
uint8_t start[4];
|
||||
uint8_t size[4];
|
||||
};
|
||||
|
||||
struct hard_disc_mbr {
|
||||
uint8_t code_area[440];
|
||||
uint8_t opt_disk_sg[4];
|
||||
uint8_t pad[2];
|
||||
struct partition_desc partition[4];
|
||||
uint8_t sign1;
|
||||
uint8_t sign2;
|
||||
};
|
||||
|
||||
static struct el_torito_boot_image *
|
||||
create_image(struct iso_tree_node *image,
|
||||
enum eltorito_boot_media_type type)
|
||||
{
|
||||
struct el_torito_boot_image *boot;
|
||||
int boot_media_type = 0;
|
||||
int load_sectors = 0; /* number of sector to load */
|
||||
unsigned char partition_type = 0;
|
||||
|
||||
switch (type) {
|
||||
case ELTORITO_FLOPPY_EMUL:
|
||||
switch (image->attrib.st_size) {
|
||||
case 1200 * 1024:
|
||||
boot_media_type = 1; /* 1.2 meg diskette */
|
||||
break;
|
||||
case 1440 * 1024:
|
||||
boot_media_type = 2; /* 1.44 meg diskette */
|
||||
break;
|
||||
case 2880 * 1024:
|
||||
boot_media_type = 3; /* 2.88 meg diskette */
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid image size %d Kb. Must be one of 1.2, 1.44"
|
||||
"or 2.88 Mb", (int) image->attrib.st_size / 1024);
|
||||
libisofs_errno = ELTORITO_WRONG_IMAGE_SIZE;
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
/* it seems that for floppy emulation we need to load
|
||||
* a single sector (512b) */
|
||||
load_sectors = 1;
|
||||
break;
|
||||
case ELTORITO_HARD_DISC_EMUL:
|
||||
{
|
||||
size_t i;
|
||||
int fd;
|
||||
struct hard_disc_mbr mbr;
|
||||
int used_partition;
|
||||
|
||||
/* read the MBR on disc and get the type of the partition */
|
||||
fd = open(((struct iso_tree_node_file*)image)->path, O_RDONLY);
|
||||
if ( fd == -1 ) {
|
||||
fprintf(stderr, "Can't open image file\n");
|
||||
return NULL;
|
||||
}
|
||||
if ( read(fd, &mbr, sizeof(mbr)) ) {
|
||||
fprintf(stderr, "Can't read MBR from image file\n");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* check valid MBR signature */
|
||||
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
|
||||
fprintf(stderr, "Invalid MBR. Wrong signature.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ensure single partition */
|
||||
used_partition = -1;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (mbr.partition[i].type != 0) {
|
||||
/* it's an used partition */
|
||||
if (used_partition != -1) {
|
||||
fprintf(stderr, "Invalid MBR. At least 2 paritions: %d and "
|
||||
"%d, are being used\n", used_partition, i);
|
||||
return NULL;
|
||||
} else
|
||||
used_partition = i;
|
||||
}
|
||||
}
|
||||
partition_type = mbr.partition[used_partition].type;
|
||||
}
|
||||
boot_media_type = 4;
|
||||
|
||||
/* only load the MBR */
|
||||
load_sectors = 1;
|
||||
break;
|
||||
case ELTORITO_NO_EMUL:
|
||||
boot_media_type = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
boot = calloc(1, sizeof(struct el_torito_boot_image));
|
||||
boot->bootable = 1;
|
||||
boot->image = (struct iso_tree_node_file *) image;
|
||||
boot->type = boot_media_type;
|
||||
boot->load_size = load_sectors;
|
||||
boot->partition_type = partition_type;
|
||||
return boot;
|
||||
}
|
||||
|
||||
static struct iso_tree_node_boot_catalog*
|
||||
create_boot_catalog_node(struct iso_tree_node_dir *parent,
|
||||
const char *name)
|
||||
{
|
||||
struct iso_tree_node_boot_catalog *boot;
|
||||
|
||||
assert( parent && name );
|
||||
|
||||
boot = calloc(1, sizeof(struct iso_tree_node_boot_catalog));
|
||||
boot->node.attrib.st_mode = S_IFREG | 0444;
|
||||
boot->node.attrib.st_atime =
|
||||
boot->node.attrib.st_mtime =
|
||||
boot->node.attrib.st_ctime = time(NULL);
|
||||
boot->node.type = LIBISO_NODE_BOOTCATALOG;
|
||||
boot->node.name = strdup(name);
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
|
||||
return boot;
|
||||
}
|
||||
|
||||
struct el_torito_boot_image *
|
||||
iso_volume_create_boot_catalog(struct iso_volume *volume,
|
||||
struct iso_tree_node *image,
|
||||
enum eltorito_boot_media_type type,
|
||||
struct iso_tree_node_dir *dir,
|
||||
char *name)
|
||||
{
|
||||
struct el_torito_boot_image *boot_image;
|
||||
struct iso_tree_node_boot_catalog *boot_node;
|
||||
struct el_torito_boot_catalog *catalog;
|
||||
|
||||
assert( volume && !volume->bootcat);
|
||||
assert( image && ISO_ISREG(image) && dir && name);
|
||||
|
||||
boot_image = create_image(image, type);
|
||||
if ( !boot_image )
|
||||
return NULL;
|
||||
|
||||
/* creates the catalog with the given default image */
|
||||
catalog = malloc(sizeof(struct el_torito_boot_catalog));
|
||||
catalog->nentries = 1;
|
||||
catalog->entries = malloc(sizeof(struct el_torito_boot_image *));
|
||||
catalog->entries[0] = boot_image;
|
||||
catalog->file = malloc(sizeof(struct iso_file));
|
||||
catalog->file->size = 2048;
|
||||
|
||||
/* add catalog file */
|
||||
boot_node = create_boot_catalog_node(dir, name);
|
||||
boot_node->catalog = catalog;
|
||||
|
||||
volume->bootcat = catalog;
|
||||
|
||||
return boot_image;
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment)
|
||||
{
|
||||
if (bootimg->type != ELTORITO_NO_EMUL)
|
||||
return;
|
||||
bootimg->load_seg = segment;
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_set_load_size(struct el_torito_boot_image *bootimg, int sectors)
|
||||
{
|
||||
if (bootimg->type != ELTORITO_NO_EMUL)
|
||||
return;
|
||||
bootimg->load_size = sectors;
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_set_no_bootable(struct el_torito_boot_image *bootimg)
|
||||
{
|
||||
bootimg->bootable = 0;
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg)
|
||||
{
|
||||
bootimg->patch_isolinux = 1;
|
||||
}
|
||||
|
||||
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(cat);
|
||||
|
||||
for(i = 0; i < cat->nentries; ++i) {
|
||||
free(cat->entries[i]);
|
||||
}
|
||||
free(cat->entries);
|
||||
free(cat->file);
|
||||
free(cat);
|
||||
}
|
||||
|
||||
void el_torito_get_image_files(struct ecma119_write_target *t)
|
||||
{
|
||||
size_t i;
|
||||
struct el_torito_boot_catalog *cat = t->catalog;
|
||||
assert(cat);
|
||||
|
||||
for(i = 0; i < cat->nentries; ++i) {
|
||||
|
||||
struct iso_tree_node_file *image = cat->entries[i]->image;
|
||||
struct iso_file *file = iso_file_table_lookup(t->file_table, image);
|
||||
if ( file == NULL ) {
|
||||
file = iso_file_new(image);
|
||||
iso_file_table_add_file(t->file_table, file);
|
||||
}
|
||||
cat->entries[i]->file = file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the Boot Record Volume Descriptor
|
||||
*/
|
||||
static void
|
||||
write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
struct el_torito_boot_catalog *cat = t->catalog;
|
||||
struct ecma119_boot_rec_vol_desc *vol =
|
||||
(struct ecma119_boot_rec_vol_desc*)buf;
|
||||
|
||||
assert(cat);
|
||||
|
||||
vol->vol_desc_type[0] = 0;
|
||||
memcpy(vol->std_identifier, "CD001", 5);
|
||||
vol->vol_desc_version[0] = 1;
|
||||
memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23);
|
||||
iso_lsb(vol->boot_catalog, cat->file->block, 4);
|
||||
}
|
||||
|
||||
static void
|
||||
write_validation_entry(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
int checksum;
|
||||
|
||||
struct el_torito_validation_entry *ve =
|
||||
(struct el_torito_validation_entry*)buf;
|
||||
ve->header_id[0] = 1;
|
||||
ve->platform_id[0] = 0; /* 0: 80x86, 1: PowerPC, 2: Mac */
|
||||
ve->key_byte1[0] = 0x55;
|
||||
ve->key_byte2[0] = 0xAA;
|
||||
|
||||
/* calculate the checksum, to ensure sum of all words is 0 */
|
||||
checksum = 0;
|
||||
for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
|
||||
checksum -= buf[i];
|
||||
checksum -= (buf[i] << 8);
|
||||
}
|
||||
iso_lsb(ve->checksum, checksum, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
patch_boot_file(struct el_torito_boot_image *img)
|
||||
{
|
||||
struct boot_info_table info;
|
||||
int fd;
|
||||
uint32_t checksum;
|
||||
ssize_t len;
|
||||
uint8_t buf[4];
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
/* open image */
|
||||
fd = open(img->image->path, O_RDWR);
|
||||
if ( fd == -1 ) {
|
||||
//TODO what do do? exit or just continue?
|
||||
fprintf(stderr, "Can't patch boot image %s\n", img->image->path);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* compute checksum, as the the sum of all 32 bit words in boot image
|
||||
* from offset 64 */
|
||||
checksum = 0;
|
||||
lseek(fd, (off_t) 64, SEEK_SET);
|
||||
|
||||
//TODO this can (must) be optimizied by reading to a longer buffer
|
||||
while ( (len = read(fd, buf, 4) ) == 4 ) {
|
||||
checksum += iso_read_lsb(buf, 4);
|
||||
}
|
||||
if ( len != 0 ) {
|
||||
/* error reading file, or file length not multiple of 4 */
|
||||
//TODO what do do? exit or just continue?
|
||||
fprintf(stderr, "Can't patch boot image %s\n", img->image->path);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* fill boot info table */
|
||||
iso_lsb(info.bi_pvd, 16, 4); //FIXME this should be changed when we implement ms
|
||||
iso_lsb(info.bi_file, img->file->block, 4);
|
||||
iso_lsb(info.bi_length, img->image->node.attrib.st_size, 4);
|
||||
iso_lsb(info.bi_csum, checksum, 4);
|
||||
|
||||
/* patch file */
|
||||
lseek(fd, (off_t) 8, SEEK_SET);
|
||||
write(fd, &info, sizeof(info));
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_patch_image_files(struct ecma119_write_target *t)
|
||||
{
|
||||
size_t i;
|
||||
struct el_torito_boot_catalog *cat = t->catalog;
|
||||
assert(cat);
|
||||
|
||||
for (i = 0; i < cat->nentries; ++i) {
|
||||
struct el_torito_boot_image *img = cat->entries[i];
|
||||
if ( img->patch_isolinux )
|
||||
patch_boot_file(img);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write one section entry.
|
||||
* Currently this is used for both default and other entries since we
|
||||
* put selection criteria no 0 (no sel. criteria)
|
||||
*/
|
||||
static void
|
||||
write_section_entry(uint8_t *buf, struct el_torito_boot_image *img)
|
||||
{
|
||||
struct el_torito_section_entry *se =
|
||||
(struct el_torito_section_entry*)buf;
|
||||
|
||||
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
|
||||
se->boot_media_type[0] = img->type;
|
||||
iso_lsb(se->load_seg, img->load_seg, 2);
|
||||
se->system_type[0] = 0; //TODO need to get the partition type
|
||||
iso_lsb(se->sec_count, img->load_size, 2);
|
||||
iso_lsb(se->block, img->file->block, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write El-Torito Boot Catalog
|
||||
*/
|
||||
static void
|
||||
write_catalog(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
struct el_torito_boot_catalog *cat = t->catalog;
|
||||
assert(cat);
|
||||
assert(cat->nentries >= 1 && cat->nentries < 63);
|
||||
|
||||
write_validation_entry(t, buf);
|
||||
|
||||
/* write default entry */
|
||||
write_section_entry(buf + 32, cat->entries[0]);
|
||||
|
||||
//TODO write all images
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
assert(t->catalog);
|
||||
ecma119_start_chunking(t,
|
||||
write_boot_vol_desc,
|
||||
2048,
|
||||
buf);
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
assert(t->catalog);
|
||||
ecma119_start_chunking(t,
|
||||
write_catalog,
|
||||
2048,
|
||||
buf);
|
||||
}
|
60
libisofs/branches/ZeroTwoEight/libisofs/eltorito.h
Normal file
60
libisofs/branches/ZeroTwoEight/libisofs/eltorito.h
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef ELTORITO_H_
|
||||
#define ELTORITO_H_
|
||||
|
||||
#include "tree.h"
|
||||
#include "file.h"
|
||||
#include "ecma119.h"
|
||||
|
||||
/**
|
||||
* Location of the boot catalog
|
||||
*/
|
||||
struct iso_tree_node_boot_catalog
|
||||
{
|
||||
struct iso_tree_node node;
|
||||
struct el_torito_boot_catalog *catalog;
|
||||
};
|
||||
|
||||
struct el_torito_boot_catalog {
|
||||
int nentries;
|
||||
struct el_torito_boot_image **entries;
|
||||
struct iso_file *file; /**< The catalog file */
|
||||
};
|
||||
|
||||
struct el_torito_boot_image {
|
||||
unsigned char bootable; /**< If the entry is bootable. */
|
||||
unsigned char patch_isolinux; /**< If the image will be patched */
|
||||
unsigned char type; /**< The type of image */
|
||||
unsigned char partition_type; /**< type of partition for HD-emul images */
|
||||
short load_seg; /**< Load segment for the initial boot image. */
|
||||
short load_size; /**< Number of sector to load. */
|
||||
struct iso_tree_node_file *image;
|
||||
struct iso_file *file;
|
||||
};
|
||||
|
||||
/*struct el_torito_boot_entry *
|
||||
el_torito_add_boot_entry(struct el_torito_boot_catalog *cat,
|
||||
struct iso_tree_node_file *image);
|
||||
*/
|
||||
|
||||
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat);
|
||||
|
||||
/**
|
||||
* For each boot image file, this gets the related iso_file object.
|
||||
* In most cases, the file is already in the hash table. However, if the
|
||||
* boot record is hidden in both ISO/RR and joliet trees, this ensures
|
||||
* that boot images will be written to image.
|
||||
*/
|
||||
void el_torito_get_image_files(struct ecma119_write_target *t);
|
||||
|
||||
/**
|
||||
* Patch image files if selected. This is needed for isolinux boot images
|
||||
*/
|
||||
void el_torito_patch_image_files(struct ecma119_write_target *t);
|
||||
|
||||
void
|
||||
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
|
||||
|
||||
void
|
||||
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf);
|
||||
|
||||
#endif /*ELTORITO_H_*/
|
38
libisofs/branches/ZeroTwoEight/libisofs/exclude.c
Normal file
38
libisofs/branches/ZeroTwoEight/libisofs/exclude.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include "exclude.h"
|
||||
|
||||
void
|
||||
iso_exclude_add_path(struct iso_hash_table *table, const char *path)
|
||||
{
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
table->num += iso_hash_insert(table->table, path);
|
||||
}
|
||||
|
||||
/*void
|
||||
iso_exclude_remove_path(struct iso_hash_table *table, const char *path)
|
||||
{
|
||||
if (!table->num || !path)
|
||||
return;
|
||||
|
||||
table->num -= iso_hash_remove(table->table, path);
|
||||
}*/
|
||||
|
||||
void
|
||||
iso_exclude_empty(struct iso_hash_table *table)
|
||||
{
|
||||
if (!table->num)
|
||||
return;
|
||||
|
||||
iso_hash_empty(table->table);
|
||||
table->num=0;
|
||||
}
|
||||
|
||||
int
|
||||
iso_exclude_lookup(struct iso_hash_table *table, const char *path)
|
||||
{
|
||||
if (!table->num || !path)
|
||||
return 0;
|
||||
|
||||
return iso_hash_lookup(table->table, path);
|
||||
}
|
37
libisofs/branches/ZeroTwoEight/libisofs/exclude.h
Normal file
37
libisofs/branches/ZeroTwoEight/libisofs/exclude.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef ISO_EXCLUDE_H
|
||||
#define ISO_EXCLUDE_H
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
struct iso_hash_table {
|
||||
struct iso_hash_node *table[HASH_NODES];
|
||||
int num;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a path to ignore when adding a directory recursively.
|
||||
*
|
||||
* \param path The path, on the local filesystem, of the file.
|
||||
*/
|
||||
int iso_exclude_lookup(struct iso_hash_table *table, const char *path);
|
||||
|
||||
/**
|
||||
* Add the path of a file or directory to ignore when adding a directory recursively.
|
||||
*
|
||||
* \param path The path, on the local filesystem, of the file.
|
||||
*/
|
||||
void iso_exclude_add_path(struct iso_hash_table *table, const char *path);
|
||||
|
||||
/**
|
||||
* Remove a path that was set to be ignored when adding a directory recusively.
|
||||
*
|
||||
* \param path The path, on the local filesystem, of the file.
|
||||
*/
|
||||
//void iso_exclude_remove_path(struct iso_hash_table *table, const char *path);
|
||||
|
||||
/**
|
||||
* Remove all paths that were set to be ignored when adding a directory recusively.
|
||||
*/
|
||||
void iso_exclude_empty(struct iso_hash_table *table);
|
||||
|
||||
#endif /* ISO_EXCLUDE */
|
188
libisofs/branches/ZeroTwoEight/libisofs/file.c
Normal file
188
libisofs/branches/ZeroTwoEight/libisofs/file.c
Normal file
@ -0,0 +1,188 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "file.h"
|
||||
#include "tree.h"
|
||||
|
||||
//TODO: refactor both hash and this hash table into a single one!!
|
||||
|
||||
struct iso_file *
|
||||
iso_file_new(struct iso_tree_node_file *f)
|
||||
{
|
||||
struct iso_file *file = calloc(1, sizeof(struct iso_file));
|
||||
file->path = f->path; /*TODO strdup? it needs to be free on clear then */
|
||||
file->size = f->node.attrib.st_size;
|
||||
file->nlink = 1;
|
||||
file->real_dev = f->node.attrib.st_dev;
|
||||
file->real_ino = f->node.attrib.st_ino;
|
||||
file->sort_weight = f->sort_weight;
|
||||
return file;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
iso_file_table_hash(const char *path)
|
||||
{
|
||||
unsigned int hash_num=0;
|
||||
const char *c;
|
||||
|
||||
c=path;
|
||||
while(*c)
|
||||
hash_num = (hash_num << 15) + (hash_num << 3) + (hash_num >> 3) + *c++;
|
||||
|
||||
return hash_num % FILE_HASH_NODES;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
iso_file_table_hash_inode(dev_t dev, ino_t ino)
|
||||
{
|
||||
return (dev ^ ino) % FILE_HASH_NODES;
|
||||
}
|
||||
|
||||
struct iso_file_table*
|
||||
iso_file_table_new(int cache_inodes)
|
||||
{
|
||||
struct iso_file_table *table = calloc(1, sizeof(struct iso_file_table));
|
||||
table->cache_inodes = cache_inodes;
|
||||
return table;
|
||||
}
|
||||
|
||||
static struct iso_file_hash_node *
|
||||
iso_file_table_node_new(struct iso_file *file)
|
||||
{
|
||||
struct iso_file_hash_node *node;
|
||||
node = calloc(1, sizeof(struct iso_file_hash_node) );
|
||||
node->file = file;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
iso_file_table_node_free(struct iso_file_hash_node *node)
|
||||
{
|
||||
free(node->file);
|
||||
free(node);
|
||||
}
|
||||
|
||||
void
|
||||
iso_file_table_clear(struct iso_file_table *ft)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < FILE_HASH_NODES; i++) {
|
||||
struct iso_file_hash_node *node;
|
||||
|
||||
node=ft->table[i];
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
ft->table[i] = NULL;
|
||||
|
||||
do {
|
||||
struct iso_file_hash_node *next;
|
||||
|
||||
next = node->next;
|
||||
iso_file_table_node_free(node);
|
||||
node = next;
|
||||
} while (node);
|
||||
}
|
||||
ft->count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* return 0 if equal, != 0 if not
|
||||
*/
|
||||
static int
|
||||
iso_table_compare_files(struct iso_file_table *ft,
|
||||
struct iso_file *f1, struct iso_file *f2)
|
||||
{
|
||||
if (ft->cache_inodes) {
|
||||
return (f1->real_dev != f2->real_dev) || (f1->real_ino != f2->real_ino);
|
||||
} else {
|
||||
return strcmp(f1->path, f2->path);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f)
|
||||
{
|
||||
struct iso_file_hash_node *node;
|
||||
unsigned int hash_num;
|
||||
|
||||
/* find the hash number */
|
||||
if (ft->cache_inodes)
|
||||
hash_num = iso_file_table_hash_inode(f->real_dev, f->real_ino);
|
||||
else
|
||||
hash_num = iso_file_table_hash(f->path);
|
||||
|
||||
/* insert it */
|
||||
node = ft->table[hash_num];
|
||||
|
||||
/* unfortunately, we can't safely consider that a file
|
||||
* won't be twice in the hash table so make sure it
|
||||
* doesn't already exists */
|
||||
if (!node) {
|
||||
ft->table[hash_num]=iso_file_table_node_new(f);
|
||||
ft->count++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* if it's already in, we don't do anything */
|
||||
if (!iso_table_compare_files(ft, f, node->file))
|
||||
return 0;
|
||||
|
||||
while (node->next) {
|
||||
node = node->next;
|
||||
|
||||
/* if it's already in, we don't do anything */
|
||||
if (!iso_table_compare_files(ft, f, node->file))
|
||||
return 0;
|
||||
}
|
||||
|
||||
node->next = iso_file_table_node_new(f);
|
||||
ft->count++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct iso_file *
|
||||
iso_file_table_lookup(struct iso_file_table *ft, struct iso_tree_node_file *f)
|
||||
{
|
||||
struct iso_file_hash_node *node;
|
||||
unsigned int hash_num;
|
||||
int equal;
|
||||
|
||||
/* find the hash number */
|
||||
if ( ft->cache_inodes )
|
||||
hash_num = iso_file_table_hash_inode(f->node.attrib.st_dev,
|
||||
f->node.attrib.st_ino);
|
||||
else
|
||||
hash_num = iso_file_table_hash(f->path);
|
||||
|
||||
node = ft->table[hash_num];
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
equal = ft->cache_inodes ?
|
||||
((f->node.attrib.st_dev == node->file->real_dev)
|
||||
&& (f->node.attrib.st_ino == node->file->real_ino))
|
||||
: !strcmp(f->path, node->file->path);
|
||||
if (equal)
|
||||
return node->file;
|
||||
|
||||
while (node->next) {
|
||||
node = node->next;
|
||||
|
||||
equal = ft->cache_inodes ?
|
||||
((f->node.attrib.st_dev == node->file->real_dev)
|
||||
&& (f->node.attrib.st_ino == node->file->real_ino))
|
||||
: !strcmp(f->path, node->file->path);
|
||||
if (equal)
|
||||
return node->file;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
69
libisofs/branches/ZeroTwoEight/libisofs/file.h
Normal file
69
libisofs/branches/ZeroTwoEight/libisofs/file.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* \file file.h
|
||||
*
|
||||
* Declare the structs to keep track of the files to be written into image.
|
||||
* These files are stored in a hash table. Two modes of operation are supported:
|
||||
* when cache inodes is enabled, the files are indexed into the table by the
|
||||
* device and inode id in the local filesystem. This way, two different files
|
||||
* with same inode and device id are treated as if they were a single file.
|
||||
* This is usually the correct behavior, as a different file with same inode
|
||||
* and device used to be a hard link.
|
||||
* When cache inode is disabled, indexing is done by path on local filesystem.
|
||||
*/
|
||||
|
||||
#ifndef FILE_H_
|
||||
#define FILE_H_
|
||||
|
||||
#define FILE_HASH_NODES 2048
|
||||
|
||||
struct iso_file {
|
||||
char *path; /**< Path of the file on local filesystem */
|
||||
off_t size; /**< size of this file */
|
||||
ino_t ino; /**< This will be the inode number on CD of the file (RR) */
|
||||
nlink_t nlink; /**< Number of hard links of the file on CD (RR) */
|
||||
size_t block; /**< Block where this file is to be written on image */
|
||||
dev_t real_dev;
|
||||
ino_t real_ino; /**< for lookup by inode caching */
|
||||
int sort_weight;
|
||||
};
|
||||
|
||||
struct iso_file_hash_node {
|
||||
struct iso_file_hash_node *next;
|
||||
struct iso_file *file;
|
||||
};
|
||||
|
||||
struct iso_file_table {
|
||||
struct iso_file_hash_node *table[FILE_HASH_NODES];
|
||||
size_t count;
|
||||
int cache_inodes; /**< 1 to index by inode number */
|
||||
};
|
||||
|
||||
struct iso_tree_node_file;
|
||||
|
||||
/**
|
||||
* Create a struct that represents the specified iso_tree_node_file,
|
||||
* suitable to be stored into the table,
|
||||
*/
|
||||
struct iso_file *iso_file_new(struct iso_tree_node_file*);
|
||||
|
||||
struct iso_file_table *iso_file_table_new(int cache_inodes);
|
||||
|
||||
/**
|
||||
* Clear a hash table. All iso_file structs stored will also be freed,
|
||||
* but not the path of each iso_file
|
||||
*/
|
||||
void iso_file_table_clear(struct iso_file_table *ft);
|
||||
|
||||
/**
|
||||
* Add a new file to the table.
|
||||
* \return 1 if the file is added, 0 if the file already exist on table
|
||||
*/
|
||||
int iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f);
|
||||
|
||||
struct iso_file *iso_file_table_lookup(struct iso_file_table *ft,
|
||||
struct iso_tree_node_file *f);
|
||||
|
||||
#endif /*FILE_H_*/
|
158
libisofs/branches/ZeroTwoEight/libisofs/hash.c
Normal file
158
libisofs/branches/ZeroTwoEight/libisofs/hash.c
Normal file
@ -0,0 +1,158 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
static unsigned int
|
||||
iso_hash_path(const char *path)
|
||||
{
|
||||
unsigned int hash_num=0;
|
||||
const char *c;
|
||||
|
||||
c=path;
|
||||
while(*c)
|
||||
hash_num = (hash_num << 15) + (hash_num << 3) + (hash_num >> 3) + *c++;
|
||||
|
||||
return hash_num % HASH_NODES;
|
||||
}
|
||||
|
||||
int
|
||||
iso_hash_lookup(struct iso_hash_node **table, const char *path)
|
||||
{
|
||||
struct iso_hash_node *node;
|
||||
unsigned int hash_num;
|
||||
|
||||
hash_num = iso_hash_path(path);
|
||||
|
||||
node=table[hash_num];
|
||||
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(path, node->path))
|
||||
return 1;
|
||||
|
||||
while (node->next) {
|
||||
node=node->next;
|
||||
|
||||
if (!strcmp(path, node->path))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct iso_hash_node*
|
||||
iso_hash_node_new (const char *path)
|
||||
{
|
||||
struct iso_hash_node *node;
|
||||
|
||||
/*create an element to be inserted in the hash table */
|
||||
node=malloc(sizeof(struct iso_hash_node));
|
||||
node->path=strdup(path);
|
||||
node->next=NULL;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
int
|
||||
iso_hash_insert(struct iso_hash_node **table, const char *path)
|
||||
{
|
||||
struct iso_hash_node *node;
|
||||
unsigned int hash_num;
|
||||
|
||||
/* find the hash number */
|
||||
hash_num = iso_hash_path(path);
|
||||
|
||||
/* insert it */
|
||||
node = table[hash_num];
|
||||
|
||||
/* unfortunately, we can't safely consider that a path
|
||||
* won't be twice in the hash table so make sure it
|
||||
* doesn't already exists */
|
||||
if (!node) {
|
||||
table[hash_num]=iso_hash_node_new(path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* if it's already in, we don't do anything */
|
||||
if (!strcmp(path, node->path))
|
||||
return 0;
|
||||
|
||||
while (node->next) {
|
||||
node = node->next;
|
||||
|
||||
/* if it's already in, we don't do anything */
|
||||
if (!strcmp (path, node->path))
|
||||
return 0;
|
||||
}
|
||||
|
||||
node->next = iso_hash_node_new(path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
iso_hash_node_free(struct iso_hash_node *node)
|
||||
{
|
||||
free(node->path);
|
||||
free(node);
|
||||
}
|
||||
|
||||
int
|
||||
iso_hash_remove(struct iso_hash_node **table, const char *path)
|
||||
{
|
||||
unsigned int hash_num;
|
||||
struct iso_hash_node *node;
|
||||
|
||||
hash_num = iso_hash_path(path);
|
||||
|
||||
node=table[hash_num];
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(path, node->path)) {
|
||||
table[hash_num]=node->next;
|
||||
iso_hash_node_free(node);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (node->next) {
|
||||
struct iso_hash_node *prev;
|
||||
|
||||
prev = node;
|
||||
node = node->next;
|
||||
|
||||
if (!strcmp (path, node->path)) {
|
||||
prev->next=node->next;
|
||||
iso_hash_node_free(node);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
iso_hash_empty(struct iso_hash_node **table)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < HASH_NODES; i++) {
|
||||
struct iso_hash_node *node;
|
||||
|
||||
node=table[i];
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
table[i]=NULL;
|
||||
|
||||
do {
|
||||
struct iso_hash_node *next;
|
||||
|
||||
next=node->next;
|
||||
iso_hash_node_free(node);
|
||||
node=next;
|
||||
} while (node);
|
||||
}
|
||||
}
|
||||
|
46
libisofs/branches/ZeroTwoEight/libisofs/hash.h
Normal file
46
libisofs/branches/ZeroTwoEight/libisofs/hash.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef ISO_HASH_H
|
||||
#define ISO_HASH_H
|
||||
|
||||
struct iso_hash_node {
|
||||
struct iso_hash_node *next;
|
||||
char *path;
|
||||
};
|
||||
|
||||
#define HASH_NODES 128
|
||||
|
||||
/**
|
||||
* Searches in the hash table if the path exists.
|
||||
*
|
||||
* \param table The hash table.
|
||||
* \param path The path of the file to look for.
|
||||
*
|
||||
* \return 1 if the path exists in the hash table, 0 otherwise.
|
||||
*/
|
||||
int iso_hash_lookup(struct iso_hash_node **table, const char *path);
|
||||
|
||||
/**
|
||||
* Insert a new path in the hash table.
|
||||
*
|
||||
* \param table The hash table.
|
||||
* \param path The path of a file to add to the hash table.
|
||||
*
|
||||
* \return 1 if the file wasn't already in the hash table, 0 otherwise.
|
||||
*/
|
||||
int iso_hash_insert(struct iso_hash_node **table, const char *path);
|
||||
|
||||
/**
|
||||
* Remove a path from the hash table.
|
||||
*
|
||||
* \param table The hash table.
|
||||
* \param path The path of a file to remove from the hash table.
|
||||
*
|
||||
* \return 1 if the file was found and removed, 0 otherwise.
|
||||
*/
|
||||
int iso_hash_remove(struct iso_hash_node **table, const char *path);
|
||||
|
||||
/**
|
||||
* Empty the hash table.
|
||||
*/
|
||||
void iso_hash_empty(struct iso_hash_node **table);
|
||||
|
||||
#endif /* ISO_HASH_H */
|
464
libisofs/branches/ZeroTwoEight/libisofs/joliet.c
Normal file
464
libisofs/branches/ZeroTwoEight/libisofs/joliet.c
Normal file
@ -0,0 +1,464 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
#include "joliet.h"
|
||||
#include "ecma119.h"
|
||||
#include "ecma119_tree.h"
|
||||
#include "tree.h"
|
||||
#include "util.h"
|
||||
#include "volume.h"
|
||||
#include "eltorito.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct joliet_tree_node*
|
||||
create_node(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *parent,
|
||||
struct iso_tree_node *iso)
|
||||
{
|
||||
struct joliet_tree_node *ret =
|
||||
calloc(1, sizeof(struct joliet_tree_node));
|
||||
|
||||
ret->name = iso_j_id(iso->name, t->input_charset);
|
||||
ret->dirent_len = 34 + (ret->name ? ucslen(ret->name) * 2 : 0);
|
||||
ret->parent = parent;
|
||||
ret->target = t;
|
||||
|
||||
if ( ISO_ISDIR(iso) ) {
|
||||
struct iso_tree_node_dir *dir = (struct iso_tree_node_dir *) iso;
|
||||
ret->info.dir.children = calloc(sizeof(void*), dir->nchildren);
|
||||
ret->type = JOLIET_DIR;
|
||||
} else if (ISO_ISREG(iso)) {
|
||||
/* it's a file */
|
||||
struct iso_tree_node_file *iso_f = (struct iso_tree_node_file *) iso;
|
||||
struct iso_file *file;
|
||||
file = iso_file_table_lookup(t->file_table, iso_f);
|
||||
if ( file == NULL ) {
|
||||
file = iso_file_new(iso_f);
|
||||
iso_file_table_add_file(t->file_table, file);
|
||||
}
|
||||
ret->info.file = file;
|
||||
ret->type = JOLIET_FILE;
|
||||
} else {
|
||||
/* it's boot catalog info */
|
||||
struct iso_tree_node_boot_catalog *iso_b =
|
||||
(struct iso_tree_node_boot_catalog *) iso;
|
||||
struct iso_file *file;
|
||||
file = iso_b->catalog->file;
|
||||
ret->info.file = file;
|
||||
ret->type = JOLIET_FILE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct joliet_tree_node*
|
||||
create_tree(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *parent,
|
||||
struct iso_tree_node *iso)
|
||||
{
|
||||
struct joliet_tree_node *root;
|
||||
assert(t && iso);
|
||||
|
||||
if ( iso->hide_flags & LIBISO_HIDE_ON_JOLIET )
|
||||
return NULL;
|
||||
|
||||
switch (iso->type) {
|
||||
case LIBISO_NODE_FILE:
|
||||
case LIBISO_NODE_BOOTCATALOG:
|
||||
root = create_node(t, parent, iso);
|
||||
break;
|
||||
case LIBISO_NODE_DIR:
|
||||
{
|
||||
size_t i;
|
||||
struct joliet_tree_node *node;
|
||||
struct iso_tree_node_dir *dir;
|
||||
root = create_node(t, parent, iso);
|
||||
dir = (struct iso_tree_node_dir*)iso;
|
||||
for (i = 0; i < dir->nchildren; ++i) {
|
||||
node = create_tree(t, root, dir->children[i]);
|
||||
if ( node != NULL ) {
|
||||
root->info.dir.children[root->info.dir.nchildren++] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//TODO replace this printf
|
||||
printf("Can't add this kind of node to a Joliet tree");
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_node(const void *f1, const void *f2)
|
||||
{
|
||||
struct joliet_tree_node *f = *((struct joliet_tree_node**)f1);
|
||||
struct joliet_tree_node *g = *((struct joliet_tree_node**)f2);
|
||||
return ucscmp(f->name, g->name);
|
||||
}
|
||||
|
||||
static void
|
||||
sort_tree(struct joliet_tree_node *root)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(root && (root->type == JOLIET_DIR));
|
||||
|
||||
qsort(root->info.dir.children, root->info.dir.nchildren,
|
||||
sizeof(void*), cmp_node);
|
||||
for (i = 0; i < root->info.dir.nchildren; i++) {
|
||||
struct joliet_tree_node *child = root->info.dir.children[i];
|
||||
if ( child->type == JOLIET_DIR )
|
||||
sort_tree(child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
joliet_prepare_path_tables(struct ecma119_write_target *t)
|
||||
{
|
||||
size_t cur, i, j;
|
||||
|
||||
t->pathlist_joliet[0] = t->joliet_root;
|
||||
t->path_table_size_joliet = 10; /* root directory record */
|
||||
cur = 1;
|
||||
|
||||
for (i = 0; i < t->dirlist_len_joliet; i++) {
|
||||
struct joliet_tree_node *dir = t->pathlist_joliet[i];
|
||||
for (j = 0; j < dir->info.dir.nchildren; j++) {
|
||||
struct joliet_tree_node *ch = dir->info.dir.children[j];
|
||||
if (ch->type == JOLIET_DIR) {
|
||||
size_t len = 8 + ucslen(ch->name)*2;
|
||||
t->pathlist_joliet[cur++] = ch;
|
||||
t->path_table_size_joliet += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the size of each directory.
|
||||
*/
|
||||
void
|
||||
joliet_calc_dir_size(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *root)
|
||||
{
|
||||
size_t i;
|
||||
size_t newlen;
|
||||
struct joliet_tree_node *ch;
|
||||
|
||||
assert(root && (root->type == JOLIET_DIR) );
|
||||
|
||||
t->dirlist_len_joliet++;
|
||||
root->info.dir.len = 68; /* for "." and ".." entries */
|
||||
for (i = 0; i < root->info.dir.nchildren; ++i) {
|
||||
ch = root->info.dir.children[i];
|
||||
newlen = root->info.dir.len + ch->dirent_len;
|
||||
if ((newlen % 2048) < (root->info.dir.len % 2048)) {
|
||||
root->info.dir.len = newlen + (2048 - (root->info.dir.len % 2048));
|
||||
} else {
|
||||
root->info.dir.len += ch->dirent_len;
|
||||
}
|
||||
if (ch->type == JOLIET_DIR)
|
||||
joliet_calc_dir_size(t, ch);
|
||||
}
|
||||
t->total_dir_size_joliet += round_up (root->info.dir.len, t->block_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the position of each directory. Also fill out t->dirlist_joliet.
|
||||
*/
|
||||
void
|
||||
joliet_calc_dir_pos(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *root)
|
||||
{
|
||||
size_t i;
|
||||
struct joliet_tree_node *ch;
|
||||
|
||||
assert(root && (root->type == JOLIET_DIR));
|
||||
|
||||
root->info.dir.block = t->curblock;
|
||||
t->curblock += div_up(root->info.dir.len, t->block_size);
|
||||
|
||||
t->dirlist_joliet[t->curfile++] = root;
|
||||
for (i = 0; i < root->info.dir.nchildren; i++) {
|
||||
ch = root->info.dir.children[i];
|
||||
if (ch->type == JOLIET_DIR)
|
||||
joliet_calc_dir_pos(t, ch);
|
||||
}
|
||||
}
|
||||
|
||||
struct joliet_tree_node*
|
||||
joliet_tree_create(struct ecma119_write_target *t,
|
||||
struct iso_tree_node *iso_root)
|
||||
{
|
||||
struct joliet_tree_node *root = create_tree(t, NULL, iso_root);
|
||||
|
||||
sort_tree(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
void
|
||||
joliet_tree_free(struct joliet_tree_node *root)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (root->type == JOLIET_DIR) {
|
||||
for (i=0; i < root->info.dir.nchildren; i++) {
|
||||
joliet_tree_free(root->info.dir.children[i]);
|
||||
}
|
||||
free(root->info.dir.children);
|
||||
}
|
||||
free(root->name);
|
||||
free(root);
|
||||
}
|
||||
|
||||
/* ugh. this is mostly C&P */
|
||||
static void
|
||||
write_path_table(struct ecma119_write_target *t,
|
||||
int l_type,
|
||||
uint8_t *buf)
|
||||
{
|
||||
void (*write_int)(uint8_t*, uint32_t, int) = l_type ?
|
||||
iso_lsb : iso_msb;
|
||||
|
||||
size_t i;
|
||||
struct ecma119_path_table_record *rec;
|
||||
struct joliet_tree_node *dir;
|
||||
int parent = 0;
|
||||
|
||||
assert (t->joliet);
|
||||
|
||||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
dir = t->pathlist_joliet[i];
|
||||
while ((i) && t->pathlist_joliet[parent] != dir->parent)
|
||||
parent++;
|
||||
assert(parent < i || i == 0);
|
||||
|
||||
rec = (struct ecma119_path_table_record*) buf;
|
||||
rec->len_di[0] = dir->parent ?
|
||||
(uint8_t) ucslen(dir->name) * 2 : 1;
|
||||
rec->len_xa[0] = 0;
|
||||
write_int(rec->block, dir->info.dir.block, 4);
|
||||
write_int(rec->parent, parent + 1, 2);
|
||||
if (dir->parent)
|
||||
memcpy(rec->dir_id, dir->name, rec->len_di[0]);
|
||||
buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* if file_id is >= 0, we use it instead of the filename. As a magic number,
|
||||
* file_id == 3 means that we are writing the root directory record (in order
|
||||
* to distinguish it from the "." entry in the root directory) */
|
||||
static void
|
||||
write_one_dir_record(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *node,
|
||||
int file_id,
|
||||
uint8_t *buf)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t block;
|
||||
uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len;
|
||||
uint8_t len_fi = (file_id >= 0) ? 1 : ucslen(node->name) * 2;
|
||||
uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id);
|
||||
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name;
|
||||
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
|
||||
|
||||
if (node->type == JOLIET_DIR) {
|
||||
len = node->info.dir.len;
|
||||
block = node->info.dir.block;
|
||||
} else {
|
||||
/* file */
|
||||
len = node->info.file->size;
|
||||
block = node->info.file->block;
|
||||
}
|
||||
|
||||
if (file_id == 1 && node->parent)
|
||||
node = node->parent;
|
||||
|
||||
rec->len_dr[0] = len_dr;
|
||||
iso_bb(rec->block, block, 4);
|
||||
iso_bb(rec->length, len, 4);
|
||||
iso_datetime_7(rec->recording_time, t->now);
|
||||
rec->flags[0] = (node->type == JOLIET_DIR) ? 2 : 0;
|
||||
iso_bb(rec->vol_seq_number, t->volnum + 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
memcpy(rec->file_id, name, len_fi);
|
||||
}
|
||||
|
||||
static void
|
||||
write_l_path_table(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
write_path_table (t, 1, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
write_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
write_path_table (t, 0, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
struct ecma119_sup_vol_desc *vol = (struct ecma119_sup_vol_desc*)buf;
|
||||
struct iso_volume *volume = t->volset->volume[t->volnum];
|
||||
uint16_t *vol_id = str2ucs(volume->volume_id, t->input_charset);
|
||||
uint16_t *pub_id = str2ucs(volume->publisher_id, t->input_charset);
|
||||
uint16_t *data_id = str2ucs(volume->data_preparer_id, t->input_charset);
|
||||
uint16_t *volset_id = str2ucs(t->volset->volset_id, t->input_charset);
|
||||
int vol_id_len = MIN(32, ucslen(vol_id) * 2);
|
||||
int pub_id_len = MIN(128, ucslen(pub_id) * 2);
|
||||
int data_id_len = MIN(128, ucslen(data_id) * 2);
|
||||
int volset_id_len = MIN(128, ucslen(volset_id) * 2);
|
||||
|
||||
uint16_t *system_id = str2ucs(volume->system_id, t->input_charset);
|
||||
uint16_t *application_id = str2ucs(volume->application_id, t->input_charset);
|
||||
uint16_t *copyright_file_id = str2ucs(volume->copyright_file_id, t->input_charset);
|
||||
uint16_t *abstract_file_id = str2ucs(volume->abstract_file_id, t->input_charset);
|
||||
uint16_t *biblio_file_id = str2ucs(volume->biblio_file_id, t->input_charset);
|
||||
int system_id_len = MIN(32, ucslen(system_id) * 2);
|
||||
int application_id_len = MIN(128, ucslen(application_id) * 2);
|
||||
int copyright_file_id_len = MIN(37, ucslen(copyright_file_id) * 2);
|
||||
int abstract_file_id_len = MIN(37, ucslen(abstract_file_id) * 2);
|
||||
int biblio_file_id_len = MIN(37, ucslen(biblio_file_id) * 2);
|
||||
|
||||
vol->vol_desc_type[0] = 2;
|
||||
memcpy(vol->std_identifier, "CD001", 5);
|
||||
vol->vol_desc_version[0] = 1;
|
||||
if (vol_id)
|
||||
memcpy(vol->volume_id, vol_id, vol_id_len);
|
||||
memcpy(vol->esc_sequences, "%/E", 3);
|
||||
iso_bb(vol->vol_space_size, t->vol_space_size, 4);
|
||||
iso_bb(vol->vol_set_size, t->volset->volset_size, 2);
|
||||
iso_bb(vol->vol_seq_number, t->volnum + 1, 2);
|
||||
iso_bb(vol->block_size, t->block_size, 2);
|
||||
iso_bb(vol->path_table_size, t->path_table_size_joliet, 4);
|
||||
iso_lsb(vol->l_path_table_pos, t->l_path_table_pos_joliet, 4);
|
||||
iso_msb(vol->m_path_table_pos, t->m_path_table_pos_joliet, 4);
|
||||
|
||||
write_one_dir_record(t, t->joliet_root, 3, vol->root_dir_record);
|
||||
|
||||
memcpy(vol->vol_set_id, volset_id, volset_id_len);
|
||||
memcpy(vol->publisher_id, pub_id, pub_id_len);
|
||||
memcpy(vol->data_prep_id, data_id, data_id_len);
|
||||
|
||||
memcpy(vol->system_id, system_id, system_id_len);
|
||||
memcpy(vol->application_id, "APPID", application_id_len);
|
||||
memcpy(vol->copyright_file_id, copyright_file_id, copyright_file_id_len);
|
||||
memcpy(vol->abstract_file_id, abstract_file_id, abstract_file_id_len);
|
||||
memcpy(vol->bibliographic_file_id, biblio_file_id, biblio_file_id_len);
|
||||
|
||||
iso_datetime_17(vol->vol_creation_time, t->now);
|
||||
iso_datetime_17(vol->vol_modification_time, t->now);
|
||||
iso_datetime_17(vol->vol_effective_time, t->now);
|
||||
vol->file_structure_version[0] = 1;
|
||||
|
||||
free(vol_id);
|
||||
free(volset_id);
|
||||
free(pub_id);
|
||||
free(data_id);
|
||||
free(system_id);
|
||||
free(application_id);
|
||||
free(copyright_file_id);
|
||||
free(abstract_file_id);
|
||||
free(biblio_file_id);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
write_one_dir(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *dir,
|
||||
uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
int j;
|
||||
size_t len;
|
||||
uint8_t *orig_buf = buf;
|
||||
uint8_t *prior_buf = buf;
|
||||
|
||||
assert(dir->type == JOLIET_DIR);
|
||||
/* write the "." and ".." entries first */
|
||||
write_one_dir_record(t, dir, 0, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
|
||||
write_one_dir_record(t, dir, 1, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
write_one_dir_record(t, dir->info.dir.children[i], -1, buf);
|
||||
len = ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
if ((buf + len - prior_buf) >= 2048) {
|
||||
for (j = len - 1; j >= 0; j--) {
|
||||
prior_buf[2048 + j] = buf[j];
|
||||
buf[j] = 0;
|
||||
}
|
||||
prior_buf += 2048;
|
||||
buf = prior_buf + len;
|
||||
}
|
||||
else {
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
}
|
||||
}
|
||||
|
||||
assert (buf - orig_buf == dir->info.dir.len);
|
||||
}
|
||||
|
||||
static void
|
||||
write_dirs(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
struct joliet_tree_node *dir;
|
||||
|
||||
assert (t->curblock == t->dirlist_joliet[0]->info.dir.block);
|
||||
for (i = 0; i < t->dirlist_len_joliet; i++) {
|
||||
dir = t->dirlist_joliet[i];
|
||||
write_one_dir(t, dir, buf);
|
||||
buf += round_up(dir->info.dir.len, t->block_size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
joliet_wr_sup_vol_desc(struct ecma119_write_target *t,
|
||||
uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t,
|
||||
write_sup_vol_desc,
|
||||
2048,
|
||||
buf);
|
||||
}
|
||||
|
||||
void
|
||||
joliet_wr_l_path_table(struct ecma119_write_target *t,
|
||||
uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t,
|
||||
write_l_path_table,
|
||||
t->path_table_size_joliet,
|
||||
buf);
|
||||
}
|
||||
|
||||
void
|
||||
joliet_wr_m_path_table(struct ecma119_write_target *t,
|
||||
uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t,
|
||||
write_m_path_table,
|
||||
t->path_table_size_joliet,
|
||||
buf);
|
||||
}
|
||||
|
||||
void
|
||||
joliet_wr_dir_records(struct ecma119_write_target *t,
|
||||
uint8_t *buf)
|
||||
{
|
||||
ecma119_start_chunking(t,
|
||||
write_dirs,
|
||||
t->total_dir_size_joliet,
|
||||
buf);
|
||||
}
|
||||
|
89
libisofs/branches/ZeroTwoEight/libisofs/joliet.h
Normal file
89
libisofs/branches/ZeroTwoEight/libisofs/joliet.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* \file joliet.h
|
||||
*
|
||||
* Declare the filesystems trees that are Joliet-compatible and the public
|
||||
* functions for tying them into an ecma119 volume.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_JOLIET_H
|
||||
#define LIBISO_JOLIET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct ecma119_write_target;
|
||||
struct iso_tree_node;
|
||||
|
||||
enum joliet_node_type {
|
||||
JOLIET_FILE,
|
||||
JOLIET_DIR
|
||||
};
|
||||
|
||||
struct joliet_dir_info {
|
||||
struct joliet_tree_node **children;
|
||||
size_t nchildren;
|
||||
size_t len;
|
||||
size_t block;
|
||||
};
|
||||
|
||||
struct joliet_tree_node
|
||||
{
|
||||
uint16_t *name; /**< In UCS-2BE. */
|
||||
size_t dirent_len;
|
||||
|
||||
struct joliet_tree_node *parent;
|
||||
struct ecma119_write_target *target;
|
||||
|
||||
enum joliet_node_type type;
|
||||
union {
|
||||
struct iso_file *file;
|
||||
struct joliet_dir_info dir;
|
||||
} info;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new joliet_tree that corresponds to the tree represented by
|
||||
* \p iso_root.
|
||||
*/
|
||||
struct joliet_tree_node*
|
||||
joliet_tree_create(struct ecma119_write_target *target,
|
||||
struct iso_tree_node *iso_root);
|
||||
|
||||
/**
|
||||
* Calculate the size of each directory in the joliet heirarchy.
|
||||
*/
|
||||
void
|
||||
joliet_calc_dir_size(struct ecma119_write_target *t, struct joliet_tree_node*);
|
||||
|
||||
/**
|
||||
* Calculate the position of each directory in the joliet heirarchy.
|
||||
*/
|
||||
void
|
||||
joliet_calc_dir_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
|
||||
|
||||
/**
|
||||
* Calculate the size of the joliet path table and fill in the list of
|
||||
* directories.
|
||||
*/
|
||||
void
|
||||
joliet_prepare_path_tables(struct ecma119_write_target *t);
|
||||
|
||||
void
|
||||
joliet_tree_free(struct joliet_tree_node *root);
|
||||
|
||||
void
|
||||
joliet_wr_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
|
||||
|
||||
void
|
||||
joliet_wr_l_path_table(struct ecma119_write_target *t, uint8_t *buf);
|
||||
|
||||
void
|
||||
joliet_wr_m_path_table(struct ecma119_write_target *t, uint8_t *buf);
|
||||
|
||||
void
|
||||
joliet_wr_dir_records(struct ecma119_write_target *t, uint8_t *buf);
|
||||
|
||||
#endif /* LIBISO_JOLIET_H */
|
544
libisofs/branches/ZeroTwoEight/libisofs/libisofs.h
Executable file
544
libisofs/branches/ZeroTwoEight/libisofs/libisofs.h
Executable file
@ -0,0 +1,544 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* Create an ISO-9660 data volume with Rock Ridge and Joliet extensions.
|
||||
* Usage is easy:
|
||||
* - Create a new volume.
|
||||
* - Add files and directories.
|
||||
* - Write the volume to a file or create a burn source for use with Libburn.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_LIBISOFS_H
|
||||
#define LIBISO_LIBISOFS_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/* #include <libburn.h> */
|
||||
struct burn_source;
|
||||
|
||||
/**
|
||||
* Data volume.
|
||||
* @see volume.h for details.
|
||||
*/
|
||||
struct iso_volume;
|
||||
|
||||
/**
|
||||
* A set of data volumes.
|
||||
* @see volume.h for details.
|
||||
*/
|
||||
struct iso_volset;
|
||||
|
||||
/**
|
||||
* A node in the filesystem tree.
|
||||
* \see tree.h
|
||||
*/
|
||||
struct iso_tree_node;
|
||||
|
||||
/**
|
||||
* El-Torito boot image
|
||||
* \see eltorito.h
|
||||
*/
|
||||
struct el_torito_boot_image;
|
||||
|
||||
/**
|
||||
* A directory in the filesystem tree.
|
||||
* The first member of this is an iso_tree_node.
|
||||
* \see tree.h
|
||||
*/
|
||||
struct iso_tree_node_dir;
|
||||
|
||||
/**
|
||||
* Extensions addition to ECMA-119 (ISO-9660) image. Usage of at least
|
||||
* one of these flags is highly recommended if the disc will be used on a
|
||||
* modern OS.
|
||||
*/
|
||||
enum ecma119_extension_flag {
|
||||
/**
|
||||
* Add the standard Rock Ridge extensions. This adds POSIX filesystem
|
||||
* features to the ECMA-119 image. Thus, usage of this flag is highly
|
||||
* recommended for images used on GNU/Linux systems. With the usage
|
||||
* of RR extension, the resulting image will have long filenames (up to
|
||||
* 255 characters), deeper directory structure, POSIX permissions and
|
||||
* owner info on files and directories, support for symbolic links or
|
||||
* special files... All that attributes can be modified/setted with the
|
||||
* appropiate function.
|
||||
*/
|
||||
ECMA119_ROCKRIDGE = (1<<0),
|
||||
/**
|
||||
* Add the non-standard Joliet extension to the image. This extension is
|
||||
* heavily used in Microsoft Windows systems, so if you plan to use your
|
||||
* disc on such a system you should add this extension. Usage of Joliet
|
||||
* supplies longer filesystem length (up to 64 unicode characters), and
|
||||
* deeper directory structure.
|
||||
*/
|
||||
ECMA119_JOLIET = (1<<1)
|
||||
};
|
||||
|
||||
/**
|
||||
* Flag used to hide a file in the RR/ISO or Joliet tree.
|
||||
*
|
||||
* \see iso_tree_node_set_hidden
|
||||
*/
|
||||
enum hide_node_flag {
|
||||
LIBISO_HIDE_ON_RR = 1 << 0,
|
||||
LIBISO_HIDE_ON_JOLIET = 1 << 1
|
||||
};
|
||||
|
||||
/**
|
||||
* El-Torito bootable image type.
|
||||
*/
|
||||
enum eltorito_boot_media_type {
|
||||
ELTORITO_FLOPPY_EMUL,
|
||||
ELTORITO_HARD_DISC_EMUL,
|
||||
ELTORITO_NO_EMUL
|
||||
};
|
||||
|
||||
enum ecma119_relaxed_constraints_flag {
|
||||
ECMA119_OMIT_VERSION_NUMBERS = (1<<0),
|
||||
/* 37 char filenames involves no version number */
|
||||
ECMA119_37_CHAR_FILENAMES = (1<<1) | (1<<0),
|
||||
ECMA119_NO_DIR_REALOCATION = (1<<2),
|
||||
ECMA119_RELAXED_FILENAMES = (1<<3)
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds the options for the image generation.
|
||||
*/
|
||||
struct ecma119_source_opts {
|
||||
int volnum; /**< The volume in the set which you want to write (usually 0) */
|
||||
int level; /**< ISO level to write at. */
|
||||
int flags; /**< Which extensions to support. */
|
||||
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
|
||||
unsigned int no_cache_inodes:1;
|
||||
/**< If use inode caching or not. Set it to 1 to prevent
|
||||
* inode caching.
|
||||
* Usage of inode caching allows detection of hard-links,
|
||||
* which contents are only written once to disc this way.
|
||||
* Don't use inode caching in systems with non unique inodes
|
||||
* per device.
|
||||
*/
|
||||
unsigned int sort_files:1;
|
||||
/**< If files should be sorted based on their weight. */
|
||||
unsigned int default_mode:1;
|
||||
/**<
|
||||
* The default values for files and directory permissions,
|
||||
* gid and uid. This option can be overwritten when set
|
||||
* one of the following.
|
||||
* 0 to use useful values, 1 to use node modes (this are
|
||||
* the same as filesystem ones if not changed after added
|
||||
* to tree).
|
||||
*/
|
||||
unsigned int replace_dir_mode:1;
|
||||
/**<
|
||||
* When 1, permissions for all dirs will be replaced by the
|
||||
* specified in dir_mode field.
|
||||
*/
|
||||
unsigned int replace_file_mode:1;
|
||||
/**<
|
||||
* When 1, permissions for all files will be replaced by the
|
||||
* specified in file_mode field.
|
||||
*/
|
||||
unsigned int replace_uid:1;
|
||||
/**<
|
||||
* When 1, uid of all nodes (both files and dirs) will be
|
||||
* replaced by the specified in uid field.
|
||||
*/
|
||||
unsigned int replace_gid:1;
|
||||
/**<
|
||||
* When 1, gid of all nodes (both files and dirs) will be
|
||||
* replaced by the specified in gid field.
|
||||
*/
|
||||
mode_t dir_mode; /**< Mode to use on dirs when replace_dir_mode is set. */
|
||||
mode_t file_mode; /**< Mode to use on files when replace_file_mode is set. */
|
||||
gid_t gid; /**< gid to use when replace_gid is set. */
|
||||
uid_t uid; /**< uid to use when replace_uid is set. */
|
||||
char *input_charset; /**< NULL to use default charset */
|
||||
char *ouput_charset; /**< NULL to use default charset */
|
||||
};
|
||||
|
||||
/**
|
||||
* This will hold the error code for some functions, if them fail.
|
||||
*/
|
||||
int libisofs_errno;
|
||||
|
||||
/* an unexpected internal error */
|
||||
#define INTERNAL_ERROR -1
|
||||
/* file don't exists, or can't be stat'ed */
|
||||
#define NO_FILE 1
|
||||
/* user haven't read access to file */
|
||||
#define NO_READ_ACCESS 2
|
||||
/* unexpected file type, eg., passing a dir instead of a regular file */
|
||||
#define UNEXPECTED_FILE_TYPE 3
|
||||
/* invalid boot image size */
|
||||
#define ELTORITO_WRONG_IMAGE_SIZE 4
|
||||
|
||||
/**
|
||||
* Controls the bahavior of iso_tree_radd_dir function
|
||||
*/
|
||||
struct iso_tree_radd_dir_behavior {
|
||||
char** excludes; /**< List of paths (file or directory) to be ignored. */
|
||||
//int follow_sym_link;
|
||||
int stop_on_error; /**< Stop when an error was found?. */
|
||||
int error; /**< set to 1 on error */
|
||||
//int notify_errors;
|
||||
//char** errors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new volume.
|
||||
* The parameters can be set to NULL if you wish to set them later.
|
||||
*/
|
||||
struct iso_volume *iso_volume_new(const char *volume_id,
|
||||
const char *publisher_id,
|
||||
const char *data_preparer_id);
|
||||
|
||||
struct iso_volume *iso_volume_new_with_root(const char *volume_id,
|
||||
const char *publisher_id,
|
||||
const char *data_preparer_id,
|
||||
struct iso_tree_node_dir *root);
|
||||
|
||||
/**
|
||||
* Free a volume.
|
||||
*/
|
||||
void iso_volume_free(struct iso_volume *volume);
|
||||
|
||||
/**
|
||||
* Free a set of data volumes.
|
||||
*/
|
||||
void iso_volset_free(struct iso_volset *volume);
|
||||
|
||||
/**
|
||||
* Get the root directory for a volume.
|
||||
*/
|
||||
struct iso_tree_node_dir *iso_volume_get_root(const struct iso_volume *volume);
|
||||
|
||||
/**
|
||||
* Fill in the volume identifier for a volume.
|
||||
*/
|
||||
void iso_volume_set_volume_id(struct iso_volume *volume,
|
||||
const char *volume_id);
|
||||
|
||||
/**
|
||||
* Fill in the publisher for a volume.
|
||||
*/
|
||||
void iso_volume_set_publisher_id(struct iso_volume *volume,
|
||||
const char *publisher_id);
|
||||
|
||||
/**
|
||||
* Fill in the data preparer for a volume.
|
||||
*/
|
||||
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
|
||||
const char *data_preparer_id);
|
||||
|
||||
/**
|
||||
* Fill in the system id for a volume. Up to 32 characters.
|
||||
*/
|
||||
void iso_volume_set_system_id(struct iso_volume *volume,
|
||||
const char *system_id);
|
||||
|
||||
/**
|
||||
* Fill in the application id for a volume. Up to 128 chars.
|
||||
*/
|
||||
void iso_volume_set_application_id(struct iso_volume *volume,
|
||||
const char *application_id);
|
||||
|
||||
/**
|
||||
* Fill copyright information for the volume. Usually this refers
|
||||
* to a file on disc. Up to 37 characters.
|
||||
*/
|
||||
void iso_volume_set_copyright_file_id(struct iso_volume *volume,
|
||||
const char *copyright_file_id);
|
||||
|
||||
/**
|
||||
* Fill abstract information for the volume. Usually this refers
|
||||
* to a file on disc. Up to 37 characters.
|
||||
*/
|
||||
void iso_volume_set_abstract_file_id(struct iso_volume *volume,
|
||||
const char *abstract_file_id);
|
||||
|
||||
/**
|
||||
* Fill biblio information for the volume. Usually this refers
|
||||
* to a file on disc. Up to 37 characters.
|
||||
*/
|
||||
void iso_volume_set_biblio_file_id(struct iso_volume *volume,
|
||||
const char *biblio_file_id);
|
||||
|
||||
/**
|
||||
* Create a bootable volume by adding a El-Torito boot image.
|
||||
*
|
||||
* \param volume The volume to make bootable.
|
||||
* \param image The tree node with the file to use as default boot image.
|
||||
* \param type The boot media type. This can be one of 3 types:
|
||||
* - Floppy emulation: Boot image files must be exactly
|
||||
* 1200 kB, 1440 kB or 2880 kB.
|
||||
* - Hard disc emulation: The image must begin with a master
|
||||
* boot record with a single image.
|
||||
* - No emulation. You should specify load segment and load size
|
||||
* of image.
|
||||
* \param dir The directory node where the boot catalog will be located
|
||||
* in image. Usually both boot catalog and boot image will be
|
||||
* located in the same dir, maybe /boot.
|
||||
* \param name The name of the boot catalog.
|
||||
*
|
||||
* \return The default El-Torito bootable image. If specified image file
|
||||
* seems to be not correct, this returns NULL and libisofs_errno
|
||||
* is set propertly.
|
||||
*
|
||||
* \pre \p volume is a volume without any boot catalog yet
|
||||
* \pre \p image is a file tree node already inserted in the volume tree.
|
||||
* \pre \p dir is a directory node already inserted in the volume tree.
|
||||
* \pre \p name There isn't any dir child with the same name.
|
||||
*
|
||||
*/
|
||||
struct el_torito_boot_image *
|
||||
iso_volume_create_boot_catalog(struct iso_volume *volume,
|
||||
struct iso_tree_node *image,
|
||||
enum eltorito_boot_media_type type,
|
||||
struct iso_tree_node_dir *dir,
|
||||
char *name);
|
||||
|
||||
/**
|
||||
* Sets the load segment for the initial boot image. This is only for
|
||||
* no emulation boot images, and is a NOP for other image types.
|
||||
*/
|
||||
void
|
||||
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment);
|
||||
|
||||
/**
|
||||
* Sets the number of sectors (512b) to be load at load segment during
|
||||
* the initial boot procedure. This is only for
|
||||
* no emulation boot images, and is a NOP for other image types.
|
||||
*/
|
||||
void
|
||||
el_torito_set_load_size(struct el_torito_boot_image *bootimg, int sectors);
|
||||
|
||||
/**
|
||||
* Marks the specified boot image as not bootable
|
||||
*/
|
||||
void
|
||||
el_torito_set_no_bootable(struct el_torito_boot_image *bootimg);
|
||||
|
||||
/**
|
||||
* Specifies that this image needs to be patched. This involves the writting
|
||||
* of a 56 bytes boot information table at offset 8 of the boot image file.
|
||||
* Be aware that libisofs will modify original boot image file, so do a backup
|
||||
* if needed.
|
||||
* This is needed for isolinux boot images.
|
||||
*/
|
||||
void
|
||||
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg);
|
||||
|
||||
/**
|
||||
* Locate a node by its path on disc.
|
||||
*
|
||||
* \param volume The volume to search in.
|
||||
* \param path The path, in the image, of the file.
|
||||
*
|
||||
* \return The node found or NULL.
|
||||
*
|
||||
* TODO we need a way to allow developers know which kind of node is.
|
||||
* Think about this when designing the read api
|
||||
*/
|
||||
struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path);
|
||||
|
||||
/**
|
||||
* Add a file or a directory (recursively) to a volume by specifying its path on the volume.
|
||||
*
|
||||
* \param volume The volume to add the file to.
|
||||
* \param disc_path The path on the disc at which to add the disc.
|
||||
* \param path The path, on the local filesystem, of the file.
|
||||
*
|
||||
* \return The node for the file or NULL if the parent doesn't exists on the disc.
|
||||
*/
|
||||
//struct iso_tree_node *iso_tree_volume_add_path(struct iso_volume *volume,
|
||||
// const char *disc_path,
|
||||
// const char *path);
|
||||
|
||||
/**
|
||||
* Creates a new, empty directory on the volume.
|
||||
*
|
||||
* \param volume The volume to add the directory to.
|
||||
* \param disc_path The path on the volume at which to add the directory.
|
||||
*
|
||||
* \return A pointer to the newly created directory.
|
||||
*/
|
||||
//struct iso_tree_node *iso_tree_volume_add_new_dir(struct iso_volume *volume,
|
||||
// const char *disc_path);
|
||||
|
||||
/**
|
||||
* Create a new Volume Set consisting of only one volume.
|
||||
* @param volume The first and only volume for the volset to contain.
|
||||
* @param volset_id The Volume Set ID.
|
||||
* @return A new iso_volset.
|
||||
*/
|
||||
struct iso_volset *iso_volset_new(struct iso_volume *volume,
|
||||
const char *volset_id);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new root dir for a filesystem tree
|
||||
*/
|
||||
struct iso_tree_node_dir *iso_tree_new_root();
|
||||
|
||||
/**
|
||||
* Add a file to a directory.
|
||||
*
|
||||
* \param path The path, on the local filesystem, of the file.
|
||||
*
|
||||
* \pre \p parent is non-NULL.
|
||||
* \pre \p path is non-NULL.
|
||||
* \return An iso_tree_node_file whose path is \p path and whose parent is
|
||||
* \p parent.
|
||||
* On error, returns NULL and libisofs_errno is set appropriately:
|
||||
* NO_FILE if path doesn't point to a valid file.
|
||||
* NO_READ_ACCESS if user haven't read access on file
|
||||
* UNEXPECTED_FILE_TYPE if path doesn't point to a regular file
|
||||
*/
|
||||
struct iso_tree_node *iso_tree_add_file(struct iso_tree_node_dir *parent,
|
||||
const char *path);
|
||||
|
||||
/**
|
||||
* Add a symbolic link to a directory.
|
||||
*
|
||||
* \param name The name of the symbolic link
|
||||
* \param dest The distination of the link, i.e., the file this link points
|
||||
* to
|
||||
*
|
||||
* \pre \p parent, name and dest are non-NULL.
|
||||
*
|
||||
* \return An iso_tree_node_symlink
|
||||
*/
|
||||
struct iso_tree_node *iso_tree_add_symlink(struct iso_tree_node_dir *parent,
|
||||
const char *name, const char *dest);
|
||||
|
||||
/**
|
||||
* Add a new, empty directory to the tree.
|
||||
*
|
||||
* \pre \p parent is non-NULL.
|
||||
* \pre \p name is unique among the children and files belonging to \p parent.
|
||||
* Also, it doesn't contain '/' characters.
|
||||
*
|
||||
* \post \p parent contains a child directory whose name is \p name and whose
|
||||
* POSIX attributes are the same as \p parent's.
|
||||
* \return a pointer to the newly created directory.
|
||||
*/
|
||||
struct iso_tree_node_dir *iso_tree_add_dir(struct iso_tree_node_dir *parent,
|
||||
const char *name);
|
||||
|
||||
/* TODO iso_tree_new_special */
|
||||
|
||||
/**
|
||||
* Add a file to a directory.
|
||||
*
|
||||
* \param path The path, on the local filesystem, of the file.
|
||||
*
|
||||
* \pre \p parent is non-NULL.
|
||||
* \pre \p path is non-NULL and is a valid path to a file or directory on the local
|
||||
* filesystem.
|
||||
* \return An iso_tree_node whose path is \p path and whose parent is \p parent.
|
||||
* On error, returns NULL and libisofs_errno is set appropriately:
|
||||
* NO_FILE if path doesn't point to a valid file.
|
||||
* NO_READ_ACCESS if user haven't read access on file
|
||||
* UNEXPECTED_FILE_TYPE if path refers to non supported file type
|
||||
* (at the momment, only dirs, symlinks and regular
|
||||
* files are supported).
|
||||
*/
|
||||
struct iso_tree_node *iso_tree_add_node(struct iso_tree_node_dir *parent,
|
||||
const char *path);
|
||||
|
||||
/**
|
||||
* Recursively add an existing directory to the tree.
|
||||
* Warning: when using this, you'll lose pointers to files or subdirectories.
|
||||
* If you want to have pointers to all files and directories,
|
||||
* use iso_tree_add_file, iso_tree_add_node and iso_tree_add_dir.
|
||||
*
|
||||
* \param path The path, on the local filesystem, of the directory to add.
|
||||
*
|
||||
* \pre \p parent is non-NULL.
|
||||
* \pre \p path is non-NULL and is a valid path to a directory on the local
|
||||
* filesystem.
|
||||
*/
|
||||
void iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
|
||||
struct iso_tree_radd_dir_behavior *behavior);
|
||||
|
||||
/**
|
||||
* Set the name of a tree node (using the current locale).
|
||||
*/
|
||||
void iso_tree_node_set_name(struct iso_tree_node *node, const char *name);
|
||||
|
||||
/**
|
||||
* Set if the node will be hidden in RR/ISO tree, Joliet tree or both.
|
||||
*
|
||||
* If the file is setted as hidden in one tree, it won't be included there, so
|
||||
* it won't be visible in a OS accessing CD using that tree. For example,
|
||||
* GNU/Linux systems access to Rock Ridge / ISO9960 tree in order to see
|
||||
* what is recorded on CD, while MS Windows make use of the Joliet tree. If a
|
||||
* file is hidden only in Joliet, it won't be visible in Windows systems,
|
||||
* while still visible in Linux.
|
||||
*
|
||||
* If a file is hidden in both trees, it won't be written to image.
|
||||
*
|
||||
* \param node The node that is to be hidden.
|
||||
* \param hide_attrs hide_node_flag's to set the trees in which file
|
||||
* will be hidden.
|
||||
*/
|
||||
void iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs);
|
||||
|
||||
/**
|
||||
* Set the group id for the node. This attribute is only useful when
|
||||
* Rock Ridge extensions are enabled.
|
||||
*/
|
||||
void iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid);
|
||||
|
||||
/**
|
||||
* Set the user id for the node. This attribute is only useful when
|
||||
* Rock Ridge extensions are enabled.
|
||||
*/
|
||||
void iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid);
|
||||
|
||||
/**
|
||||
* Set the permissions for the node. This attribute is only useful when
|
||||
* Rock Ridge extensions are enabled.
|
||||
*
|
||||
* \param mode bitmask with the permissions of the node, as specified
|
||||
* in 'man 2 stat'. The file type bitfields will be ignored,
|
||||
* only file permissions will be modified.
|
||||
*/
|
||||
void iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode);
|
||||
|
||||
/**
|
||||
* Sets the order in which a node will be written on image. High weihted files
|
||||
* will be written first, so in a disc them will be written near the center.
|
||||
*
|
||||
* \param node The node which weight will be changed. If it's a dir, this
|
||||
* function will change the weight of all its children. For nodes
|
||||
* other that dirs or regular files, this function has no effect.
|
||||
* \param w The weight as a integer number, the greater this value is, the
|
||||
* closer from the begining of image the file will be written.
|
||||
*/
|
||||
void iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w);
|
||||
|
||||
/**
|
||||
* Recursively print a directory to stdout.
|
||||
* \param spaces The initial number of spaces on the left. Set to 0 if you
|
||||
* supply a root directory.
|
||||
*/
|
||||
void iso_tree_print(const struct iso_tree_node *root, int spaces);
|
||||
|
||||
/** Create a burn_source which can be used as a data source for a track
|
||||
*
|
||||
* The volume set used to create the libburn_source can _not_ be modified
|
||||
* until the libburn_source is freed.
|
||||
*
|
||||
* \param volumeset The volume set from which you want to write
|
||||
* \param opts The options for image generation
|
||||
*
|
||||
* \pre \p volumeset is non-NULL
|
||||
* \pre \p volnum is less than \p volset->volset_size.
|
||||
* \return A burn_source to be used for the data source for a track
|
||||
*/
|
||||
struct burn_source* iso_source_new_ecma119(struct iso_volset *volumeset,
|
||||
struct ecma119_source_opts *opts);
|
||||
|
||||
#endif /* LIBISO_LIBISOFS_H */
|
313
libisofs/branches/ZeroTwoEight/libisofs/rockridge.c
Executable file
313
libisofs/branches/ZeroTwoEight/libisofs/rockridge.c
Executable file
@ -0,0 +1,313 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
#include "rockridge.h"
|
||||
#include "util.h"
|
||||
#include "ecma119.h"
|
||||
#include "ecma119_tree.h"
|
||||
#include "tree.h"
|
||||
#include "susp.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
|
||||
void
|
||||
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||
{
|
||||
unsigned char *ER = malloc(182);
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
ER[0] = 'E';
|
||||
ER[1] = 'R';
|
||||
ER[2] = 182;
|
||||
ER[3] = 1;
|
||||
ER[4] = 9;
|
||||
ER[5] = 72;
|
||||
ER[6] = 93;
|
||||
ER[7] = 1;
|
||||
memcpy(&ER[8], "IEEE_1282", 9);
|
||||
memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
|
||||
"FILE SYSTEM SEMANTICS.", 72);
|
||||
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
|
||||
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
|
||||
susp_append(t, &dir->info.dir.self_susp, ER);
|
||||
}
|
||||
|
||||
/* create a PX field from the permissions on the current node. */
|
||||
uint8_t *rrip_make_PX(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *node)
|
||||
{
|
||||
uint8_t *PX = malloc(44);
|
||||
|
||||
PX[0] = 'P';
|
||||
PX[1] = 'X';
|
||||
PX[2] = 44;
|
||||
PX[3] = 1;
|
||||
iso_bb(&PX[4], node->attrib.st_mode, 4);
|
||||
iso_bb(&PX[12], node->attrib.st_nlink, 4);
|
||||
iso_bb(&PX[20], node->attrib.st_uid, 4);
|
||||
iso_bb(&PX[28], node->attrib.st_gid, 4);
|
||||
iso_bb(&PX[36], node->attrib.st_ino, 4);
|
||||
return PX;
|
||||
}
|
||||
|
||||
/** See IEEE 1282 4.1.1 */
|
||||
void rrip_add_PX(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
susp_append(t, &node->susp, rrip_make_PX(t, node));
|
||||
if (node->type == ECMA119_DIR) {
|
||||
susp_append(t, &node->info.dir.self_susp, rrip_make_PX(t, node));
|
||||
susp_append(t, &node->info.dir.parent_susp, rrip_make_PX(t, node));
|
||||
}
|
||||
}
|
||||
|
||||
void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
uint8_t *PN = malloc(20);
|
||||
|
||||
PN[0] = 'P';
|
||||
PN[1] = 'N';
|
||||
PN[2] = 20;
|
||||
PN[3] = 1;
|
||||
iso_bb(&PN[4], node->attrib.st_dev >> 32, 4);
|
||||
iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4);
|
||||
susp_append(t, &node->susp, PN);
|
||||
}
|
||||
|
||||
static void rrip_SL_append_comp(int *n, uint8_t ***comps,
|
||||
char *s, int size, char fl)
|
||||
{
|
||||
uint8_t *comp = malloc(size + 2);
|
||||
|
||||
(*n)++;
|
||||
comp[0] = fl;
|
||||
comp[1] = size;
|
||||
*comps = realloc(*comps, (*n) * sizeof(void*));
|
||||
(*comps)[(*n) - 1] = comp;
|
||||
|
||||
if (size) {
|
||||
memcpy(&comp[2], s, size);
|
||||
}
|
||||
}
|
||||
|
||||
static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
|
||||
uint8_t ***comps)
|
||||
{
|
||||
int size = cur - prev;
|
||||
|
||||
if (size == 0) {
|
||||
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 3);
|
||||
return;
|
||||
}
|
||||
|
||||
if (size == 1 && prev[0] == '.') {
|
||||
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 1);
|
||||
return;
|
||||
}
|
||||
if (size == 2 && !strncmp(prev, "..", 2)) {
|
||||
rrip_SL_append_comp(n_comp, comps, prev, 0, 1 << 2);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we can't make a component any bigger than 250 (is this really a
|
||||
problem)? because then it won't fit inside the SL field */
|
||||
while (size > 248) {
|
||||
size -= 248;
|
||||
rrip_SL_append_comp(n_comp, comps, prev, 248, 1 << 0);
|
||||
}
|
||||
|
||||
rrip_SL_append_comp(n_comp, comps, prev, size, 0);
|
||||
}
|
||||
|
||||
void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
int path_size;
|
||||
char *path = NULL, *cur, *prev;
|
||||
int i, j;
|
||||
|
||||
uint8_t **comp = NULL;
|
||||
int n_comp = 0;
|
||||
int total_comp_len = 0;
|
||||
int written = 0, pos;
|
||||
|
||||
uint8_t *SL;
|
||||
|
||||
path = node->info.dest;
|
||||
path_size = strlen(path);
|
||||
|
||||
prev = path;
|
||||
for (cur = strchr(path, '/'); cur && *cur; cur = strchr(cur, '/')) {
|
||||
rrip_SL_add_component(prev, cur, &n_comp, &comp);
|
||||
cur++;
|
||||
prev = cur;
|
||||
}
|
||||
|
||||
/* if there was no trailing '/', we need to add the last component. */
|
||||
if (prev == path || prev != &path[path_size - 1]) {
|
||||
rrip_SL_add_component(prev, &path[path_size], &n_comp, &comp);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_comp; i++) {
|
||||
total_comp_len += comp[i][1] + 2;
|
||||
if (total_comp_len > 250) {
|
||||
total_comp_len -= comp[i][1] + 2;
|
||||
SL = malloc(total_comp_len + 5);
|
||||
SL[0] = 'S';
|
||||
SL[1] = 'L';
|
||||
SL[2] = total_comp_len + 5;
|
||||
SL[3] = 1;
|
||||
SL[4] = 1; /* CONTINUE */
|
||||
pos = 5;
|
||||
for (j = written; j < i; j++) {
|
||||
memcpy(&SL[pos], comp[j], comp[j][2]);
|
||||
pos += comp[j][2];
|
||||
}
|
||||
susp_append(t, &node->susp, SL);
|
||||
written = i - 1;
|
||||
total_comp_len = comp[i][1];
|
||||
}
|
||||
}
|
||||
SL = malloc(total_comp_len + 5);
|
||||
SL[0] = 'S';
|
||||
SL[1] = 'L';
|
||||
SL[2] = total_comp_len + 5;
|
||||
SL[3] = 1;
|
||||
SL[4] = 0;
|
||||
pos = 5;
|
||||
|
||||
for (j = written; j < n_comp; j++) {
|
||||
memcpy(&SL[pos], comp[j], comp[j][1] + 2);
|
||||
pos += comp[j][1] + 2;
|
||||
}
|
||||
susp_append(t, &node->susp, SL);
|
||||
|
||||
/* free the components */
|
||||
for (i = 0; i < n_comp; i++) {
|
||||
free(comp[i]);
|
||||
}
|
||||
free(comp);
|
||||
}
|
||||
|
||||
static void rrip_add_NM_single(struct ecma119_write_target *t,
|
||||
struct susp_info *susp,
|
||||
char *name, int size, int flags)
|
||||
{
|
||||
uint8_t *NM = malloc(size + 5);
|
||||
|
||||
NM[0] = 'N';
|
||||
NM[1] = 'M';
|
||||
NM[2] = size + 5;
|
||||
NM[3] = 1;
|
||||
NM[4] = flags;
|
||||
if (size) {
|
||||
memcpy(&NM[5], name, size);
|
||||
}
|
||||
susp_append(t, susp, NM);
|
||||
}
|
||||
|
||||
void
|
||||
rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
char *name = node->full_name;
|
||||
int len = name ? strlen(name) : 0;
|
||||
char *pos = name;
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
if (node->type == ECMA119_DIR) {
|
||||
rrip_add_NM_single(t, &node->info.dir.self_susp, pos, 0, 1 << 1);
|
||||
rrip_add_NM_single(t, &node->info.dir.parent_susp, pos, 0, 1 << 2);
|
||||
}
|
||||
|
||||
while (len > 250) {
|
||||
rrip_add_NM_single(t, &node->susp, pos, 250, 1);
|
||||
len -= 250;
|
||||
pos += 250;
|
||||
}
|
||||
rrip_add_NM_single(t, &node->susp, pos, len, 0);
|
||||
}
|
||||
|
||||
void rrip_add_CL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
uint8_t *CL = calloc(1, 12);
|
||||
|
||||
CL[0] = 'C';
|
||||
CL[1] = 'L';
|
||||
CL[2] = 12;
|
||||
CL[3] = 1;
|
||||
susp_append(t, &node->susp, CL);
|
||||
}
|
||||
|
||||
void
|
||||
rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
uint8_t *PL = calloc(1, 12);
|
||||
|
||||
PL[0] = 'P';
|
||||
PL[1] = 'L';
|
||||
PL[2] = 12;
|
||||
PL[3] = 1;
|
||||
susp_append(t, &node->info.dir.parent_susp, PL);
|
||||
}
|
||||
|
||||
void
|
||||
rrip_add_RE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
uint8_t *RE = malloc(4);
|
||||
|
||||
RE[0] = 'R';
|
||||
RE[1] = 'E';
|
||||
RE[2] = 4;
|
||||
RE[3] = 1;
|
||||
susp_append(t, &node->susp, RE);
|
||||
}
|
||||
|
||||
void
|
||||
rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
uint8_t *TF = malloc(5 + 3 * 7);
|
||||
|
||||
TF[0] = 'T';
|
||||
TF[1] = 'F';
|
||||
TF[2] = 5 + 3 * 7;
|
||||
TF[3] = 1;
|
||||
TF[4] = (1 << 1) | (1 << 2) | (1 << 3);
|
||||
iso_datetime_7(&TF[5], node->attrib.st_mtime);
|
||||
iso_datetime_7(&TF[12], node->attrib.st_atime);
|
||||
iso_datetime_7(&TF[19], node->attrib.st_ctime);
|
||||
susp_append(t, &node->susp, TF);
|
||||
}
|
||||
|
||||
void
|
||||
rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
if (dir->parent != dir->info.dir.real_parent) {
|
||||
uint8_t *PL = susp_find(&dir->info.dir.parent_susp, "PL");
|
||||
|
||||
assert(PL);
|
||||
iso_bb(&PL[4], dir->info.dir.real_parent->info.dir.block, 4);
|
||||
}
|
||||
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
|
||||
if (ch->type == ECMA119_PLACEHOLDER) {
|
||||
uint8_t *CL = susp_find(&ch->susp, "CL");
|
||||
|
||||
assert(CL);
|
||||
iso_bb(&CL[4], ch->info.real_me->info.dir.block, 4);
|
||||
} else if (ch->type == ECMA119_DIR) {
|
||||
rrip_finalize(t, ch);
|
||||
}
|
||||
}
|
||||
}
|
112
libisofs/branches/ZeroTwoEight/libisofs/rockridge.h
Executable file
112
libisofs/branches/ZeroTwoEight/libisofs/rockridge.h
Executable file
@ -0,0 +1,112 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* Functions and structures used for Rock Ridge support.
|
||||
*
|
||||
* See IEEE P1282, Rock Ridge Interchange Protocol, Draft Standard version
|
||||
* 1.12 for further details.
|
||||
*/
|
||||
|
||||
#ifndef ISO_ROCKRIDGE_H
|
||||
#define ISO_ROCKRIDGE_H
|
||||
|
||||
struct ecma119_write_target;
|
||||
struct ecma119_tree_node;
|
||||
|
||||
/**
|
||||
* Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification.
|
||||
*
|
||||
* The "ER" System Use Entry is used to uniquely identify a specification
|
||||
* compliant with SUSP. This method adds to the given tree node "." entry
|
||||
* the "ER" corresponding to the RR protocol.
|
||||
*
|
||||
* See IEEE P1281, section 5.5 and IEEE P1282, section 4.3 for more details.
|
||||
*/
|
||||
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PX System Use Entry to the given tree node and, if that node is
|
||||
* a directory, to its "." and ".." entries. The PX System Use Entry is
|
||||
* used to add POSIX file attributes, such as access permissions or user and
|
||||
* group id, to a ECMA 119 directory record.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.1 for more details.
|
||||
*/
|
||||
void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PN System Use Entry to the given tree node.
|
||||
* The PN System Use Entry is used to store the device number, and it's
|
||||
* mandatory if the tree node corresponds to a character or block device.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.2 for more details.
|
||||
*/
|
||||
void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a SL System Use Entry to the given tree node. This is used to store
|
||||
* the content of a symbolic link, and is mandatory if the tree node
|
||||
* indicates a symbolic link.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.3 for more details.
|
||||
*/
|
||||
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a NM System Use Entry to the given tree node. The purpose of this
|
||||
* System Use Entry is to store the content of an Alternate Name to support
|
||||
* POSIX-style or other names.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.4 for more details.
|
||||
*/
|
||||
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/*
|
||||
* The next 3 System Use Entries are used to handle Deep Directory
|
||||
* Hierarchies, i.e., hierarchies where the number of directory levels
|
||||
* exceed the eight limit of ECMA-119.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add to the given tree node a CL System Use Entry, that is used to record
|
||||
* the new location of a directory which has been relocated.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.1 for more details.
|
||||
*/
|
||||
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PL System Use Entry, used to record the location of the original
|
||||
* parent directory of a directory which has been relocated.
|
||||
*
|
||||
* This is special because it doesn't modify the susp fields of the directory
|
||||
* that gets passed to it; it modifies the susp fields of the ".." entry in
|
||||
* that directory.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.2 for more details.
|
||||
*/
|
||||
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a RE System Use Entry to the given tree node. The purpose of the
|
||||
* this System Use Entry is to indicate to an RRIP-compliant receiving
|
||||
* system that the Directory Record in which an "RE" System Use Entry is
|
||||
* recorded has been relocated from another position in the original
|
||||
* Directory Hierarchy.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.3 for more details.
|
||||
*/
|
||||
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add to the given tree node a TF System Use Entry, used to record some
|
||||
* time stamps related to the file.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.6 for more details.
|
||||
*/
|
||||
void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
|
||||
void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
#endif /* ISO_ROCKRIDGE_H */
|
256
libisofs/branches/ZeroTwoEight/libisofs/susp.c
Executable file
256
libisofs/branches/ZeroTwoEight/libisofs/susp.c
Executable file
@ -0,0 +1,256 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
#include "susp.h"
|
||||
#include "util.h"
|
||||
#include "ecma119.h"
|
||||
#include "ecma119_tree.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
void susp_insert(struct ecma119_write_target *t,
|
||||
struct susp_info *susp,
|
||||
uint8_t *data,
|
||||
int pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (pos < 0) {
|
||||
pos = susp->n_susp_fields;
|
||||
}
|
||||
|
||||
assert(pos <= susp->n_susp_fields);
|
||||
susp->n_susp_fields++;
|
||||
susp->susp_fields = realloc(susp->susp_fields,
|
||||
sizeof(void*) * susp->n_susp_fields);
|
||||
|
||||
for (i = susp->n_susp_fields-1; i > pos; i--) {
|
||||
susp->susp_fields[i] = susp->susp_fields[i - 1];
|
||||
}
|
||||
susp->susp_fields[pos] = data;
|
||||
}
|
||||
|
||||
void susp_append(struct ecma119_write_target *t,
|
||||
struct susp_info *susp,
|
||||
uint8_t *data)
|
||||
{
|
||||
susp_insert(t, susp, data, susp->n_susp_fields);
|
||||
}
|
||||
|
||||
uint8_t *susp_find(struct susp_info *susp, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < susp->n_susp_fields; i++) {
|
||||
if (!strncmp((char *)susp->susp_fields[i], name, 2)) {
|
||||
return susp->susp_fields[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Utility function for susp_add_CE because susp_add_CE needs to act 3 times
|
||||
* on directories (for the "." and ".." entries.
|
||||
*
|
||||
* \param len The amount of space available for the System Use area.
|
||||
*/
|
||||
#define CE_LEN 28
|
||||
static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
|
||||
struct susp_info *susp,
|
||||
int len)
|
||||
{
|
||||
int susp_length = 0, tmp_len;
|
||||
int i;
|
||||
unsigned char *CE;
|
||||
|
||||
for (i = 0; i < susp->n_susp_fields; i++) {
|
||||
susp_length += susp->susp_fields[i][2];
|
||||
}
|
||||
if (susp_length <= len) {
|
||||
/* no need for a CE field */
|
||||
susp->non_CE_len = susp_length;
|
||||
susp->n_fields_fit = susp->n_susp_fields;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmp_len = susp_length;
|
||||
for (i = susp->n_susp_fields - 1; i >= 0; i--) {
|
||||
tmp_len -= susp->susp_fields[i][2];
|
||||
if (tmp_len + CE_LEN <= len) {
|
||||
susp->non_CE_len = tmp_len + CE_LEN;
|
||||
susp->CE_len = susp_length - tmp_len;
|
||||
|
||||
/* i+1 because we have to count the CE field */
|
||||
susp->n_fields_fit = i + 1;
|
||||
|
||||
CE = calloc(1, CE_LEN);
|
||||
/* we don't fill in the BLOCK LOCATION or OFFSET
|
||||
fields yet. */
|
||||
CE[0] = 'C';
|
||||
CE[1] = 'E';
|
||||
CE[2] = (char)CE_LEN;
|
||||
CE[3] = (char)1;
|
||||
iso_bb(&CE[20], susp_length - tmp_len, 4);
|
||||
|
||||
return CE;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
try_add_CE(struct ecma119_write_target *t,
|
||||
struct susp_info *susp,
|
||||
size_t dirent_len)
|
||||
{
|
||||
uint8_t *CE = susp_add_single_CE(t, susp, 255 - dirent_len);
|
||||
if (CE)
|
||||
susp_insert(t, susp, CE, susp->n_fields_fit - 1);
|
||||
}
|
||||
|
||||
/** See IEEE P1281 Draft Version 1.12/5.2. Because this function depends on the
|
||||
* length of the other SUSP fields, it should always be calculated last. */
|
||||
void
|
||||
susp_add_CE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
try_add_CE(t, &node->susp, node->dirent_len);
|
||||
if (node->type == ECMA119_DIR) {
|
||||
try_add_CE(t, &node->info.dir.self_susp, 34);
|
||||
try_add_CE(t, &node->info.dir.parent_susp, 34);
|
||||
}
|
||||
}
|
||||
|
||||
/** See IEEE P1281 Draft Version 1.12/5.3 */
|
||||
void
|
||||
susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||
{
|
||||
unsigned char *SP = malloc(7);
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
SP[0] = 'S';
|
||||
SP[1] = 'P';
|
||||
SP[2] = (char)7;
|
||||
SP[3] = (char)1;
|
||||
SP[4] = 0xbe;
|
||||
SP[5] = 0xef;
|
||||
SP[6] = 0;
|
||||
susp_append(t, &dir->info.dir.self_susp, SP);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** See IEEE P1281 Draft Version 1.12/5.4 */
|
||||
static void susp_add_ST(struct ecma119_write_target *t,
|
||||
struct iso_tree_node *node)
|
||||
{
|
||||
unsigned char *ST = malloc(4);
|
||||
|
||||
ST[0] = 'S';
|
||||
ST[1] = 'T';
|
||||
ST[2] = (char)4;
|
||||
ST[3] = (char)1;
|
||||
susp_append(t, node, ST);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* calculate the location of the CE areas. Since CE areas don't need to be
|
||||
* aligned to a block boundary, we contatenate all CE areas from a single
|
||||
* directory and dump them immediately after all the directory records.
|
||||
*
|
||||
* Requires that the following be known:
|
||||
* - position of the current directory (dir->info.dir.block)
|
||||
* - length of the current directory (dir->info.dir.len)
|
||||
* - sum of the children's CE lengths (dir->info.dir.CE_len)
|
||||
*/
|
||||
static void
|
||||
susp_fin_1_CE(struct ecma119_write_target *t,
|
||||
struct susp_info *susp,
|
||||
size_t block,
|
||||
size_t *offset)
|
||||
{
|
||||
uint8_t *CE = susp->susp_fields[susp->n_fields_fit - 1];
|
||||
|
||||
if (!susp->CE_len) {
|
||||
return;
|
||||
}
|
||||
iso_bb(&CE[4], block + (*offset) / t->block_size, 4);
|
||||
iso_bb(&CE[12], (*offset) % t->block_size, 4);
|
||||
*offset += susp->CE_len;
|
||||
}
|
||||
|
||||
static void susp_fin_CE(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *dir)
|
||||
{
|
||||
int i;
|
||||
size_t CE_offset = dir->info.dir.len;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
susp_fin_1_CE(t, &dir->info.dir.self_susp, dir->info.dir.block, &CE_offset);
|
||||
susp_fin_1_CE(t, &dir->info.dir.parent_susp, dir->info.dir.block, &CE_offset);
|
||||
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
susp_fin_1_CE(t, &ch->susp, dir->info.dir.block, &CE_offset);
|
||||
}
|
||||
assert(CE_offset == dir->info.dir.len + dir->info.dir.CE_len);
|
||||
}
|
||||
|
||||
void
|
||||
susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(dir->type = ECMA119_DIR);
|
||||
|
||||
if (dir->info.dir.depth != 1) {
|
||||
susp_fin_CE(t, dir);
|
||||
}
|
||||
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
if (dir->info.dir.children[i]->type == ECMA119_DIR)
|
||||
susp_finalize(t, dir->info.dir.children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void susp_write(struct ecma119_write_target *t,
|
||||
struct susp_info *susp,
|
||||
unsigned char *buf)
|
||||
{
|
||||
int i;
|
||||
int pos = 0;
|
||||
|
||||
for (i = 0; i < susp->n_fields_fit; i++) {
|
||||
memcpy(&buf[pos], susp->susp_fields[i],
|
||||
susp->susp_fields[i][2]);
|
||||
pos += susp->susp_fields[i][2];
|
||||
}
|
||||
}
|
||||
|
||||
void susp_write_CE(struct ecma119_write_target *t, struct susp_info *susp,
|
||||
unsigned char *buf)
|
||||
{
|
||||
int i;
|
||||
int pos = 0;
|
||||
|
||||
for (i = susp->n_fields_fit; i < susp->n_susp_fields; i++) {
|
||||
memcpy(&buf[pos], susp->susp_fields[i],
|
||||
susp->susp_fields[i][2]);
|
||||
pos += susp->susp_fields[i][2];
|
||||
}
|
||||
}
|
||||
|
||||
void susp_free_fields(struct susp_info *susp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<susp->n_susp_fields; i++) {
|
||||
free(susp->susp_fields[i]);
|
||||
}
|
||||
if (susp->susp_fields) {
|
||||
free(susp->susp_fields);
|
||||
}
|
||||
memset(susp, 0, sizeof(struct susp_info));
|
||||
}
|
76
libisofs/branches/ZeroTwoEight/libisofs/susp.h
Executable file
76
libisofs/branches/ZeroTwoEight/libisofs/susp.h
Executable file
@ -0,0 +1,76 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* Functions and structures used for SUSP (IEEE 1281).
|
||||
*
|
||||
* Please refer to IEEE P1281 System Use Sharing Protocol, draft standard
|
||||
* version 1.12 for more details.
|
||||
*/
|
||||
|
||||
#ifndef __ISO_SUSP
|
||||
#define __ISO_SUSP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* SUSP is only present in standard ecma119 */
|
||||
struct ecma119_write_target;
|
||||
struct ecma119_tree_node;
|
||||
|
||||
/** This contains the information that needs to go in the SUSP area of a file.
|
||||
*/
|
||||
struct susp_info
|
||||
{
|
||||
int n_susp_fields; /**< Number of SUSP fields */
|
||||
uint8_t **susp_fields; /**< Data for each SUSP field */
|
||||
|
||||
/* the next 3 relate to CE and are filled out by susp_add_CE. */
|
||||
int n_fields_fit; /**< How many of the above SUSP fields fit
|
||||
* within this node's dirent. */
|
||||
int non_CE_len; /**< Length of the part of the SUSP area that
|
||||
* fits in the dirent. */
|
||||
int CE_len; /**< Length of the part of the SUSP area that
|
||||
* will go in a CE area. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a CE System Use Entry to the given tree node. A "CE" is used to add
|
||||
* a continuation area, where additional System Use Entry can be written.
|
||||
* See IEEE P1281, section 5.1.
|
||||
*/
|
||||
void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a SP System Use Entry to the "." entry of the directory. The SP provide
|
||||
* an identifier that the SUSP is used within the volume. The SP shall be
|
||||
* recorded in the "." entry of the root directory.
|
||||
* See IEEE P1281, section 5.3 for more details.
|
||||
*
|
||||
* this is special because it doesn't modify the susp fields of the
|
||||
* directory; it modifies the susp fields of the "." entry in the directory.
|
||||
*/
|
||||
void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/** Once all the directories and files are laid out, recurse through the tree
|
||||
* and finalize all SUSP CE entries. */
|
||||
void susp_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
void susp_append(struct ecma119_write_target *,
|
||||
struct susp_info *,
|
||||
uint8_t *);
|
||||
void susp_insert(struct ecma119_write_target *,
|
||||
struct susp_info *,
|
||||
uint8_t *,
|
||||
int pos);
|
||||
uint8_t *susp_find(struct susp_info *,
|
||||
const char *);
|
||||
|
||||
void susp_write(struct ecma119_write_target *,
|
||||
struct susp_info *,
|
||||
uint8_t *);
|
||||
void susp_write_CE(struct ecma119_write_target *,
|
||||
struct susp_info *,
|
||||
uint8_t *);
|
||||
|
||||
void susp_free_fields(struct susp_info *);
|
||||
|
||||
#endif /* __ISO_SUSP */
|
401
libisofs/branches/ZeroTwoEight/libisofs/tree.c
Executable file
401
libisofs/branches/ZeroTwoEight/libisofs/tree.c
Executable file
@ -0,0 +1,401 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* \file tree.c
|
||||
*
|
||||
* Implement filesystem trees.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tree.h"
|
||||
#include "exclude.h"
|
||||
|
||||
static void
|
||||
set_default_stat(struct stat *s)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
|
||||
memset(s, 0, sizeof(struct stat));
|
||||
s->st_mode = 0555;
|
||||
s->st_atime = s->st_mtime = s->st_ctime = now;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_add_child(struct iso_tree_node_dir *parent,
|
||||
struct iso_tree_node *child)
|
||||
{
|
||||
assert( parent && child);
|
||||
|
||||
parent->nchildren++;
|
||||
parent->children =
|
||||
realloc(parent->children, parent->nchildren * sizeof(void*));
|
||||
parent->children[parent->nchildren-1] = child;
|
||||
child->parent = parent;
|
||||
}
|
||||
|
||||
struct iso_tree_node_dir*
|
||||
iso_tree_new_root()
|
||||
{
|
||||
struct iso_tree_node_dir *root;
|
||||
|
||||
root = calloc(1, sizeof(struct iso_tree_node_dir));
|
||||
|
||||
set_default_stat(&root->node.attrib);
|
||||
root->node.attrib.st_mode = S_IFDIR | 0777;
|
||||
root->node.type = LIBISO_NODE_DIR;
|
||||
return root;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_file(struct iso_tree_node_dir *parent, const char *path)
|
||||
{
|
||||
struct iso_tree_node_file *f;
|
||||
char *p;
|
||||
struct stat st;
|
||||
|
||||
assert( parent && path);
|
||||
|
||||
if (lstat(path, &st) == -1) {
|
||||
libisofs_errno = NO_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !S_ISREG(st.st_mode) ) {
|
||||
libisofs_errno = UNEXPECTED_FILE_TYPE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( access(path, R_OK) ) {
|
||||
libisofs_errno = NO_READ_ACCESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f = calloc(1, sizeof(struct iso_tree_node_file));
|
||||
|
||||
/* fill fields */
|
||||
f->node.attrib = st;
|
||||
f->path = strdup(path);
|
||||
f->node.type = LIBISO_NODE_FILE;
|
||||
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
f->node.name = strdup( basename(p) );
|
||||
free(p);
|
||||
|
||||
/* add to parent (this also sets f->node->parent) */
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) f);
|
||||
|
||||
return (struct iso_tree_node*) f;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_symlink(struct iso_tree_node_dir *parent,
|
||||
const char *name, const char *dest)
|
||||
{
|
||||
struct iso_tree_node_symlink *link;
|
||||
|
||||
assert( parent && name && dest);
|
||||
|
||||
link = calloc(1, sizeof(struct iso_tree_node_symlink));
|
||||
|
||||
/* fill fields */
|
||||
set_default_stat(&link->node.attrib);
|
||||
link->node.attrib.st_mode |= S_IFLNK;//TODO Not needed
|
||||
link->node.name = strdup(name);
|
||||
link->node.type = LIBISO_NODE_SYMLINK;
|
||||
link->dest = strdup(dest);
|
||||
|
||||
/* add to parent (this also sets link->node->parent) */
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) link);
|
||||
|
||||
return (struct iso_tree_node*) link;
|
||||
}
|
||||
|
||||
struct iso_tree_node_dir*
|
||||
iso_tree_add_dir(struct iso_tree_node_dir *parent,
|
||||
const char *name)
|
||||
{
|
||||
struct iso_tree_node_dir *dir;
|
||||
|
||||
assert( parent && name );
|
||||
|
||||
dir = calloc(1, sizeof(struct iso_tree_node_dir));
|
||||
|
||||
dir->node.attrib = parent->node.attrib;
|
||||
dir->node.type = LIBISO_NODE_DIR;
|
||||
dir->node.name = strdup(name);
|
||||
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_name(struct iso_tree_node *node, const char *name)
|
||||
{
|
||||
free(node->name);
|
||||
node->name = strdup(name);
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs)
|
||||
{
|
||||
assert(node);
|
||||
node->hide_flags = hide_attrs;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid)
|
||||
{
|
||||
assert(node);
|
||||
node->attrib.st_gid = gid;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid)
|
||||
{
|
||||
assert(node);
|
||||
node->attrib.st_uid = uid;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode)
|
||||
{
|
||||
assert(node);
|
||||
node->attrib.st_mode = (node->attrib.st_mode & S_IFMT) |
|
||||
(mode & ~S_IFMT);
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w)
|
||||
{
|
||||
assert(node);
|
||||
if ( ISO_ISDIR(node) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir;
|
||||
dir = (struct iso_tree_node_dir *) node;
|
||||
for (i=0; i < dir->nchildren; i++) {
|
||||
iso_tree_node_set_sort_weight(dir->children[i], w);
|
||||
}
|
||||
} else if ( ISO_ISREG(node) ) {
|
||||
struct iso_tree_node_file *file;
|
||||
file = (struct iso_tree_node_file *) node;
|
||||
file->sort_weight = w;
|
||||
}
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_node(struct iso_tree_node_dir *parent,
|
||||
const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
assert( parent && path);
|
||||
|
||||
if (lstat(path, &st) == -1) {
|
||||
libisofs_errno = NO_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( access(path, R_OK) ) {
|
||||
libisofs_errno = NO_READ_ACCESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (st.st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
/* regular file */
|
||||
node = iso_tree_add_file(parent, path);
|
||||
break;
|
||||
case S_IFLNK:
|
||||
/* symlink */
|
||||
{
|
||||
char dest[PATH_MAX];
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
n = readlink(path, dest, PATH_MAX);
|
||||
if ( n == -1 ) {
|
||||
libisofs_errno = INTERNAL_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
dest[n] = '\0';
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
node = iso_tree_add_symlink(parent, basename(p), dest);
|
||||
free(p);
|
||||
node->attrib = st;
|
||||
}
|
||||
break;
|
||||
case S_IFDIR:
|
||||
/* directory */
|
||||
{
|
||||
char *p;
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
node = (struct iso_tree_node*) iso_tree_add_dir(parent, basename(p));
|
||||
free(p);
|
||||
node->attrib = st;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
libisofs_errno = UNEXPECTED_FILE_TYPE;
|
||||
node = NULL;
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_free(struct iso_tree_node *root)
|
||||
{
|
||||
if ( ISO_ISDIR(root) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir;
|
||||
dir = (struct iso_tree_node_dir *) root;
|
||||
for (i=0; i < dir->nchildren; i++) {
|
||||
iso_tree_free(dir->children[i]);
|
||||
}
|
||||
free(dir->children);
|
||||
} else if ( ISO_ISLNK(root) ) {
|
||||
struct iso_tree_node_symlink *link;
|
||||
link = (struct iso_tree_node_symlink *) root;
|
||||
free(link->dest);
|
||||
} else if ( ISO_ISREG(root) ) {
|
||||
struct iso_tree_node_file *file;
|
||||
file = (struct iso_tree_node_file *) root;
|
||||
free(file->path);
|
||||
}
|
||||
free(root->name);
|
||||
free(root);
|
||||
}
|
||||
|
||||
static void
|
||||
iso_tree_radd_dir_aux(struct iso_tree_node_dir *parent, const char *path,
|
||||
struct iso_tree_radd_dir_behavior *behavior,
|
||||
struct iso_hash_table *excludes)
|
||||
{
|
||||
struct iso_tree_node *new;
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
warn("couldn't open directory %s: %s\n", path, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
char child[strlen(ent->d_name) + strlen(path) + 2];
|
||||
|
||||
if (behavior->stop_on_error & behavior->error)
|
||||
break;
|
||||
|
||||
if (strcmp(ent->d_name, ".") == 0 ||
|
||||
strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
//TODO check if path already finished in '/'
|
||||
sprintf(child, "%s/%s", path, ent->d_name);
|
||||
|
||||
/* see if this child is excluded. */
|
||||
if (iso_exclude_lookup(excludes, child))
|
||||
continue;
|
||||
|
||||
new = iso_tree_add_node(parent, child);
|
||||
if (!new || !ISO_ISDIR(new)) {
|
||||
if (!new)
|
||||
behavior->error = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
iso_tree_radd_dir_aux( (struct iso_tree_node_dir *) new, child,
|
||||
behavior, excludes);
|
||||
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
|
||||
struct iso_tree_radd_dir_behavior *behavior)
|
||||
{
|
||||
struct iso_tree_node_dir *dir;
|
||||
struct iso_hash_table table = { {0,}, 0};
|
||||
|
||||
assert ( parent && path );
|
||||
|
||||
behavior->error = 0;
|
||||
|
||||
/* initialize exclude hash_table */
|
||||
if ( behavior->excludes ) {
|
||||
char *exclude;
|
||||
int i = 0;
|
||||
while ( (exclude = behavior->excludes[i++]) ) {
|
||||
iso_exclude_add_path(&table, exclude);
|
||||
}
|
||||
}
|
||||
|
||||
/* recurse into dir */
|
||||
iso_tree_radd_dir_aux(parent, path, behavior, &table);
|
||||
|
||||
/* clear hashtable */
|
||||
iso_exclude_empty(&table);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_print(const struct iso_tree_node *root, int spaces)
|
||||
{
|
||||
char sp[spaces+1];
|
||||
|
||||
memset(sp, ' ', spaces);
|
||||
sp[spaces] = '\0';
|
||||
|
||||
printf("%s%s\n", sp, root->name);
|
||||
|
||||
if ( ISO_ISDIR(root) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir;
|
||||
|
||||
dir = (struct iso_tree_node_dir *) root;
|
||||
for (i=0; i < dir->nchildren; i++) {
|
||||
iso_tree_print(dir->children[i], spaces+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_print_verbose(const struct iso_tree_node *root,
|
||||
print_dir_callback dir,
|
||||
print_file_callback file,
|
||||
void *callback_data,
|
||||
int spaces)
|
||||
{
|
||||
|
||||
(ISO_ISDIR(root) ? dir : file)
|
||||
(root, callback_data, spaces);
|
||||
|
||||
if ( ISO_ISDIR(root) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir_node;
|
||||
|
||||
dir_node = (struct iso_tree_node_dir *) root;
|
||||
for (i=0; i < dir_node->nchildren; i++) {
|
||||
iso_tree_print_verbose(dir_node->children[i], dir,
|
||||
file, callback_data, spaces+2);
|
||||
}
|
||||
}
|
||||
}
|
177
libisofs/branches/ZeroTwoEight/libisofs/tree.h
Executable file
177
libisofs/branches/ZeroTwoEight/libisofs/tree.h
Executable file
@ -0,0 +1,177 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* \file tree.h
|
||||
*
|
||||
* Declare the structure of a libisofs filesystem tree. The files in this
|
||||
* tree can come from either the local filesystem or from another .iso image
|
||||
* (for multisession).
|
||||
*
|
||||
* This tree preserves as much information as it can about the files; names
|
||||
* are stored in wchar_t and we preserve POSIX attributes. This tree does
|
||||
* *not* include information that is necessary for writing out, for example,
|
||||
* an ISO level 1 tree. That information will go in a different tree because
|
||||
* the structure is sufficiently different.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_TREE_H
|
||||
#define LIBISO_TREE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdint.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "libisofs.h"
|
||||
|
||||
//enum file_location {
|
||||
// LIBISO_FILESYS,
|
||||
// LIBISO_PREVSESSION,
|
||||
// LIBISO_NONE /**< for files/dirs that were added with
|
||||
// * iso_tree_add_new_XXX. */
|
||||
//};
|
||||
|
||||
/**
|
||||
* This tells us where to read the data from a file. Either we read from the
|
||||
* local filesystem or we just point to the block on a previous session.
|
||||
*/
|
||||
//struct iso_file_location
|
||||
//{
|
||||
// enum file_location type;
|
||||
// /* union {*/
|
||||
// char *path; /* in the current locale */
|
||||
// uint32_t block;
|
||||
// /* };*/
|
||||
//};
|
||||
|
||||
enum iso_tree_node_type {
|
||||
LIBISO_NODE_DIR,
|
||||
LIBISO_NODE_FILE,
|
||||
LIBISO_NODE_SYMLINK,
|
||||
LIBISO_NODE_BOOTCATALOG
|
||||
};
|
||||
|
||||
/**
|
||||
* A node in the filesystem tree.
|
||||
*/
|
||||
struct iso_tree_node
|
||||
{
|
||||
struct iso_tree_node_dir *parent;
|
||||
char *name;
|
||||
struct stat attrib; /**< The POSIX attributes of this node as
|
||||
* documented in "man 2 stat". */
|
||||
|
||||
int hide_flags; /**< If the node is to be hidden in RR/ISO or
|
||||
* Joilet tree */
|
||||
enum iso_tree_node_type type;
|
||||
};
|
||||
|
||||
/**
|
||||
* A node in the filesystem tree that represents a regular file
|
||||
*/
|
||||
struct iso_tree_node_file
|
||||
{
|
||||
struct iso_tree_node node;
|
||||
|
||||
char *path; /**< the path of the file on local filesystem */
|
||||
int sort_weight; /**< It sorts the order in which the file data is
|
||||
* written to the CD image. Higher weighting files
|
||||
* are written at the beginning of image */
|
||||
|
||||
/* when read from an existing ISO image, we need to store the
|
||||
* block where file contents are written, and not the path.
|
||||
* Maybe instead of a char *path we will need to go back to
|
||||
* struct iso_file_location loc;
|
||||
*/
|
||||
/* struct iso_file_location loc; */
|
||||
/**< Only used for regular files and symbolic
|
||||
* links (ie. files for which we might have to
|
||||
* copy data). */
|
||||
};
|
||||
|
||||
/**
|
||||
* A node in the filesystem tree that represents a symbolic link
|
||||
*/
|
||||
struct iso_tree_node_symlink
|
||||
{
|
||||
struct iso_tree_node node;
|
||||
|
||||
char *dest; /**< Destination of the link */
|
||||
};
|
||||
|
||||
/**
|
||||
* A directory on the filesystem tree
|
||||
*/
|
||||
struct iso_tree_node_dir
|
||||
{
|
||||
struct iso_tree_node node;
|
||||
|
||||
size_t nchildren; /**< The number of children of this
|
||||
* directory (if this is a directory). */
|
||||
struct iso_tree_node **children;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively free a directory.
|
||||
*
|
||||
* \param root The root of the directory heirarchy to free.
|
||||
*
|
||||
* \pre \p root is non-NULL.
|
||||
*/
|
||||
void iso_tree_free(struct iso_tree_node *root);
|
||||
|
||||
/**
|
||||
* Adds a child to a directory
|
||||
*/
|
||||
void iso_tree_add_child(struct iso_tree_node_dir *parent,
|
||||
struct iso_tree_node *child);
|
||||
|
||||
/**
|
||||
* A function that prints verbose information about a directory.
|
||||
*
|
||||
* \param dir The directory about which to print information.
|
||||
* \param data Unspecified function-dependent data.
|
||||
* \param spaces The number of spaces to prepend to the output.
|
||||
*
|
||||
* \see iso_tree_print_verbose
|
||||
*/
|
||||
typedef void (*print_dir_callback) (const struct iso_tree_node *dir,
|
||||
void *data,
|
||||
int spaces);
|
||||
/**
|
||||
* A function that prints verbose information about a file.
|
||||
*
|
||||
* \param dir The file about which to print information.
|
||||
* \param data Unspecified function-dependent data.
|
||||
* \param spaces The number of spaces to prepend to the output.
|
||||
*
|
||||
* \see iso_tree_print_verbose
|
||||
*/
|
||||
typedef void (*print_file_callback) (const struct iso_tree_node *file,
|
||||
void *data,
|
||||
int spaces);
|
||||
|
||||
/**
|
||||
* Recursively print a directory heirarchy. For each node in the directory
|
||||
* heirarchy, call a callback function to print information more verbosely.
|
||||
*
|
||||
* \param root The root of the directory heirarchy to print.
|
||||
* \param dir The callback function to call for each directory in the tree.
|
||||
* \param file The callback function to call for each file in the tree.
|
||||
* \param callback_data The data to pass to the callback functions.
|
||||
* \param spaces The number of spaces to prepend to the output.
|
||||
*
|
||||
* \pre \p root is not NULL.
|
||||
* \pre Neither of the callback functions modifies the directory heirarchy.
|
||||
*/
|
||||
void iso_tree_print_verbose(const struct iso_tree_node *root,
|
||||
print_dir_callback dir,
|
||||
print_file_callback file,
|
||||
void *callback_data,
|
||||
int spaces);
|
||||
|
||||
#define ISO_ISDIR(n) (n->type == LIBISO_NODE_DIR)
|
||||
#define ISO_ISREG(n) (n->type == LIBISO_NODE_FILE)
|
||||
#define ISO_ISLNK(n) (n->type == LIBISO_NODE_SYMLINK)
|
||||
|
||||
#endif /* LIBISO_TREE_H */
|
842
libisofs/branches/ZeroTwoEight/libisofs/util.c
Executable file
842
libisofs/branches/ZeroTwoEight/libisofs/util.c
Executable file
@ -0,0 +1,842 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* Utility functions for the Libisofs library.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <wchar.h>
|
||||
#include <iconv.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "libisofs.h"
|
||||
|
||||
/* avoids warning and names in iso, joliet and rockridge can't be > 255 bytes
|
||||
* anyway. There are at most 31 characters in iso level 1, 255 for rockridge,
|
||||
* 64 characters (* 2 since UCS) for joliet. */
|
||||
#define NAME_BUFFER_SIZE 255
|
||||
|
||||
int div_up(int n, int div)
|
||||
{
|
||||
return (n + div - 1) / div;
|
||||
}
|
||||
|
||||
int round_up(int n, int mul)
|
||||
{
|
||||
return div_up(n, mul) * mul;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a string between charsets.
|
||||
* This assumes '\0' means end-of-string, what is not necessarily true,
|
||||
* but given there are lots of strdup around there, it will fail in other
|
||||
* places anyway...
|
||||
*/
|
||||
char *
|
||||
convert_str(const char *str, const char *icharset, const char *ocharset)
|
||||
{
|
||||
char *ret;
|
||||
size_t inbytes;
|
||||
size_t outbytes;
|
||||
|
||||
inbytes = strlen(str);
|
||||
outbytes = (inbytes+1) * MB_LEN_MAX;
|
||||
{
|
||||
/* ensure enought space */
|
||||
char out[outbytes];
|
||||
char *src;
|
||||
size_t n;
|
||||
|
||||
iconv_t conv = iconv_open(ocharset, icharset);
|
||||
if (conv == (iconv_t)(-1)) {
|
||||
printf("Can't convert from %s to %s\n", icharset, ocharset);
|
||||
return NULL;
|
||||
}
|
||||
src = (char *)str;
|
||||
ret = (char *)out;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
if (n == -1) {
|
||||
/* error just return input stream */
|
||||
perror("Convert error.");
|
||||
printf("Maybe string %s is not encoded in %s\n", str, icharset);
|
||||
|
||||
iconv_close(conv);
|
||||
return strdup(str);
|
||||
}
|
||||
iconv_close(conv);
|
||||
*ret = '\0';
|
||||
|
||||
ret = strdup(out);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a str in a specified codeset to WCHAR_T.
|
||||
* The result must be free() when no more needed
|
||||
*/
|
||||
static wchar_t *str2wchar(const char *str, const char *codeset)
|
||||
{
|
||||
iconv_t conv;
|
||||
size_t inbytes;
|
||||
size_t outbytes;
|
||||
char *ret;
|
||||
char *src;
|
||||
wchar_t *wstr;
|
||||
size_t n;
|
||||
|
||||
conv = iconv_open("WCHAR_T", codeset);
|
||||
if (conv == (iconv_t)-1) {
|
||||
perror("Invalid encodings\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inbytes = strlen(str);
|
||||
outbytes = (inbytes + 1) * sizeof(wchar_t);
|
||||
|
||||
/* we are sure that numchars <= inbytes */
|
||||
wstr = malloc(outbytes);
|
||||
ret = (char *)wstr;
|
||||
src = (char *)str;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
while (n == -1) {
|
||||
|
||||
if( errno != EINVAL ) {
|
||||
/* error, should never occur */
|
||||
iconv_close(conv);
|
||||
perror("Convert error\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* invalid input string charset, just log and ignore */
|
||||
printf("String %s is not encoded in %s\n", str, codeset);
|
||||
inbytes--;
|
||||
|
||||
if(!inbytes)
|
||||
break;
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
}
|
||||
iconv_close(conv);
|
||||
|
||||
*( (wchar_t *)ret )='\0';
|
||||
return wstr;
|
||||
}
|
||||
|
||||
/* this function must always return a name
|
||||
* since the caller never checks if a NULL
|
||||
* is returned. It also avoids some warnings. */
|
||||
char *str2ascii(const char *src_arg, const char *icharset)
|
||||
{
|
||||
wchar_t *wsrc_;
|
||||
char *ret;
|
||||
char *ret_;
|
||||
char *src;
|
||||
iconv_t conv;
|
||||
size_t numchars;
|
||||
size_t outbytes;
|
||||
size_t inbytes;
|
||||
size_t n;
|
||||
|
||||
assert(icharset);
|
||||
|
||||
if (!src_arg)
|
||||
return NULL;
|
||||
|
||||
/* convert the string to a wide character string. Note: outbytes
|
||||
* is in fact the number of characters in the string and doesn't
|
||||
* include the last NULL character.
|
||||
*
|
||||
* For now, just assume input to be in UTF-8, we can change
|
||||
* this later.
|
||||
*/
|
||||
|
||||
wsrc_ = str2wchar(src_arg, icharset);
|
||||
|
||||
if (!wsrc_)
|
||||
return NULL;
|
||||
|
||||
src = (char *)wsrc_;
|
||||
numchars = wcslen(wsrc_);
|
||||
|
||||
|
||||
inbytes = numchars * sizeof(wchar_t);
|
||||
|
||||
ret_ = malloc(numchars+1);
|
||||
outbytes = numchars;
|
||||
ret = ret_;
|
||||
|
||||
/* initialize iconv */
|
||||
conv = iconv_open("ASCII", "WCHAR_T");
|
||||
if (conv == (iconv_t)-1) {
|
||||
free(wsrc_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
while(n == -1) {
|
||||
/* The destination buffer is too small. Stops here. */
|
||||
if(errno == E2BIG)
|
||||
break;
|
||||
|
||||
/* An incomplete multi bytes sequence was found. We
|
||||
* can't do anything here. That's quite unlikely. */
|
||||
if(errno == EINVAL)
|
||||
break;
|
||||
|
||||
/* The last possible error is an invalid multi bytes
|
||||
* sequence. Just replace the character with a "_".
|
||||
* Probably the character doesn't exist in ascii like
|
||||
* "é, è, à, ç, ..." in French. */
|
||||
*ret++ = '_';
|
||||
outbytes--;
|
||||
|
||||
if(!outbytes)
|
||||
break;
|
||||
|
||||
/* There was an error with one character but some other remain
|
||||
* to be converted. That's probably a multibyte character.
|
||||
* See above comment. */
|
||||
src += sizeof(wchar_t);
|
||||
inbytes -= sizeof(wchar_t);
|
||||
|
||||
if(!inbytes)
|
||||
break;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
}
|
||||
|
||||
iconv_close(conv);
|
||||
|
||||
*ret='\0';
|
||||
free(wsrc_);
|
||||
|
||||
return ret_;
|
||||
}
|
||||
|
||||
/* FIXME: C&P */
|
||||
uint16_t *str2ucs(const char *src_arg, const char *icharset)
|
||||
{
|
||||
wchar_t *wsrc_;
|
||||
char *src;
|
||||
char *ret_;
|
||||
char *ret;
|
||||
iconv_t conv;
|
||||
size_t outbytes;
|
||||
size_t numchars;
|
||||
size_t inbytes;
|
||||
size_t n;
|
||||
|
||||
if (!src_arg)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
|
||||
|
||||
/* convert the string to a wide character string. Note: outbytes
|
||||
* is in fact the number of characters in the string and doesn't
|
||||
* include the last NULL character.
|
||||
*/
|
||||
|
||||
wsrc_ = str2wchar(src_arg, icharset);
|
||||
if (!wsrc_)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
src = (char*)wsrc_;
|
||||
numchars = wcslen(wsrc_);
|
||||
|
||||
inbytes = numchars * sizeof(wchar_t);
|
||||
|
||||
outbytes = numchars * sizeof(uint16_t);
|
||||
ret_ = malloc ((numchars+1) * sizeof(uint16_t));
|
||||
ret = ret_;
|
||||
|
||||
/* initialize iconv */
|
||||
conv = iconv_open("UCS-2BE", "WCHAR_T");
|
||||
if (conv == (iconv_t)-1)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
while(n == -1) {
|
||||
/* The destination buffer is too small. Stops here. */
|
||||
if(errno == E2BIG)
|
||||
break;
|
||||
|
||||
/* An incomplete multi bytes sequence was found. We
|
||||
* can't do anything here. That's quite unlikely. */
|
||||
if(errno == EINVAL)
|
||||
break;
|
||||
|
||||
/* The last possible error is an invalid multi bytes
|
||||
* sequence. Just replace the character with a "_".
|
||||
* Probably the character doesn't exist in ascii like
|
||||
* "é, è, à, ç, ..." in French. */
|
||||
*((uint16_t*) ret) = '_';
|
||||
ret += sizeof(uint16_t);
|
||||
outbytes -= sizeof(uint16_t);
|
||||
|
||||
if(!outbytes)
|
||||
break;
|
||||
|
||||
/* There was an error with one character but some other remain
|
||||
* to be converted. That's probably a multibyte character.
|
||||
* See above comment. */
|
||||
src += sizeof(wchar_t);
|
||||
inbytes -= sizeof(wchar_t);
|
||||
|
||||
if(!inbytes)
|
||||
break;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
}
|
||||
|
||||
iconv_close(conv);
|
||||
|
||||
/* close the ucs string */
|
||||
*((uint16_t*) ret) = 0;
|
||||
|
||||
return (uint16_t*)ret_;
|
||||
}
|
||||
|
||||
static int valid_d_char(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
|
||||
}
|
||||
|
||||
static int valid_a_char(char c)
|
||||
{
|
||||
return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c == '_');
|
||||
}
|
||||
|
||||
static int valid_j_char(uint16_t c)
|
||||
{
|
||||
return !(c < (uint16_t)' ' || c == (uint16_t)'*' || c == (uint16_t)'/'
|
||||
|| c == (uint16_t)':' || c == (uint16_t)';'
|
||||
|| c == (uint16_t)'?' || c == (uint16_t)'\\');
|
||||
}
|
||||
|
||||
/* FIXME: where are these documented? */
|
||||
static int valid_p_char(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
|
||||
|| (c >= 'a' && c <= 'z')
|
||||
|| (c == '.') || (c == '_') || (c == '-');
|
||||
}
|
||||
|
||||
char *str2d_char(const char *str, const char *icharset) {
|
||||
char *ret;
|
||||
size_t len, i;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
ret = str2ascii(str, icharset);
|
||||
len = strlen(ret);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
char c = toupper(ret[i]);
|
||||
ret[i] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *str2a_char(const char *str, const char *icharset) {
|
||||
char *ret;
|
||||
size_t len, i;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
ret = str2ascii(str, icharset);
|
||||
len = strlen(ret);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
char c = toupper(ret[i]);
|
||||
ret[i] = valid_a_char(c) ? c : '_';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *iso_dirid(const char *src, int size, const char *icharset)
|
||||
{
|
||||
char *ret = str2ascii(src, icharset);
|
||||
size_t len, i;
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
len = strlen(ret);
|
||||
if (len > size) {
|
||||
ret[size] = '\0';
|
||||
len = size;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
char c = toupper(ret[i]);
|
||||
ret[i] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *iso_1_dirid(const char *src, const char *icharset)
|
||||
{
|
||||
return iso_dirid(src, 8, icharset);
|
||||
}
|
||||
|
||||
char *iso_2_dirid(const char *src, const char *icharset)
|
||||
{
|
||||
return iso_dirid(src, 31, icharset);
|
||||
}
|
||||
|
||||
char *iso_r_dirid(const char *src, const char *icharset, int flags)
|
||||
{
|
||||
char *ret = str2ascii(src, icharset);
|
||||
size_t size, len, i;
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
size = flags & ECMA119_37_CHAR_FILENAMES ? 37 : 31;
|
||||
|
||||
len = strlen(ret);
|
||||
if (len > size) {
|
||||
ret[size] = '\0';
|
||||
len = size;
|
||||
}
|
||||
|
||||
if (flags & ECMA119_RELAXED_FILENAMES)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
char c = toupper(ret[i]);
|
||||
ret[i] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *iso_1_fileid(const char *src_arg, const char *icharset)
|
||||
{
|
||||
char *src = str2ascii(src_arg, icharset);
|
||||
char *dest;
|
||||
char *dot; /* Position of the last dot in the
|
||||
filename, will be used to calculate
|
||||
lname and lext. */
|
||||
int lname, lext, pos, i;
|
||||
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2
|
||||
(;1) + 1 (\0) */
|
||||
dot = strrchr(src, '.');
|
||||
|
||||
lext = dot ? strlen(dot + 1) : 0;
|
||||
lname = strlen(src) - lext - (dot ? 1 : 0);
|
||||
|
||||
/* If we can't build a filename, return NULL. */
|
||||
if (lname == 0 && lext == 0) {
|
||||
free(src);
|
||||
free(dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
/* Convert up to 8 characters of the filename. */
|
||||
for (i = 0; i < lname && i < 8; i++) {
|
||||
char c = toupper(src[i]);
|
||||
|
||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
/* This dot is mandatory, even if there is no extension. */
|
||||
dest[pos++] = '.';
|
||||
/* Convert up to 3 characters of the extension, if any. */
|
||||
for (i = 0; i < lext && i < 3; i++) {
|
||||
char c = toupper(src[lname + 1 + i]);
|
||||
|
||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
/* File versions are mandatory, even if they aren't used. */
|
||||
dest[pos++] = ';';
|
||||
dest[pos++] = '1';
|
||||
dest[pos] = '\0';
|
||||
dest = (char *)realloc(dest, pos + 1);
|
||||
|
||||
free(src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *iso_2_fileid(const char *src_arg, const char *icharset)
|
||||
{
|
||||
char *src = str2ascii(src_arg, icharset);
|
||||
char *dest;
|
||||
char *dot;
|
||||
int lname, lext, lnname, lnext, pos, i;
|
||||
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2
|
||||
(;1) + 1 (\0) */
|
||||
dot = strrchr(src, '.');
|
||||
|
||||
/* Since the maximum length can be divided freely over the name and
|
||||
extension, we need to calculate their new lengths (lnname and
|
||||
lnext). If the original filename is too long, we start by trimming
|
||||
the extension, but keep a minimum extension length of 3. */
|
||||
if (dot == NULL || *(dot + 1) == '\0') {
|
||||
lname = strlen(src);
|
||||
lnname = (lname > 30) ? 30 : lname;
|
||||
lext = lnext = 0;
|
||||
} else {
|
||||
lext = strlen(dot + 1);
|
||||
lname = strlen(src) - lext - 1;
|
||||
lnext = (strlen(src) > 31 && lext > 3)
|
||||
? (lname < 27 ? 30 - lname : 3) : lext;
|
||||
lnname = (strlen(src) > 31) ? 30 - lnext : lname;
|
||||
}
|
||||
|
||||
if (lnname == 0 && lnext == 0) {
|
||||
free(src);
|
||||
free(dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
/* Convert up to lnname characters of the filename. */
|
||||
for (i = 0; i < lnname; i++) {
|
||||
char c = toupper(src[i]);
|
||||
|
||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
dest[pos++] = '.';
|
||||
/* Convert up to lnext characters of the extension, if any. */
|
||||
for (i = 0; i < lnext; i++) {
|
||||
char c = toupper(src[lname + 1 + i]);
|
||||
|
||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
dest[pos++] = ';';
|
||||
dest[pos++] = '1';
|
||||
dest[pos] = '\0';
|
||||
dest = (char *)realloc(dest, pos + 1);
|
||||
|
||||
free(src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *
|
||||
iso_r_fileid(const char *src_arg, const char *icharset, int flag)
|
||||
{
|
||||
char *src = str2ascii(src_arg, icharset);
|
||||
char *dest;
|
||||
char *dot;
|
||||
int lname, lext, lnname, lnext, pos, i;
|
||||
|
||||
size_t size = flag & (1<<1) ? 37 : 33;
|
||||
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
dest = malloc(size+1);
|
||||
|
||||
if (flag & ECMA119_RELAXED_FILENAMES) {
|
||||
strncpy(dest, src, size);
|
||||
dest[size] = '\0'; /* ensure 37 / 33 max length */
|
||||
pos = strlen(dest);
|
||||
pos = pos < (size == 37 ? 37 : 31) ? pos : (size == 37 ? 37 : 31);
|
||||
if ( !(flag & ECMA119_OMIT_VERSION_NUMBERS) ) {
|
||||
dest[pos++] = ';';
|
||||
dest[pos++] = '1';
|
||||
}
|
||||
dest[pos] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* no relaxed filenames */
|
||||
dot = strrchr(src, '.');
|
||||
|
||||
size_t max = size == 37 ? 36 : 30;
|
||||
/* Since the maximum length can be divided freely over the name and
|
||||
extension, we need to calculate their new lengths (lnname and
|
||||
lnext). If the original filename is too long, we start by trimming
|
||||
the extension, but keep a minimum extension length of 3. */
|
||||
if (dot == NULL || *(dot + 1) == '\0') {
|
||||
lname = strlen(src);
|
||||
lnname = (lname > max) ? max : lname;
|
||||
lext = lnext = 0;
|
||||
} else {
|
||||
lext = strlen(dot + 1);
|
||||
lname = strlen(src) - lext - 1;
|
||||
lnext = (strlen(src) > max + 1 && lext > 3)
|
||||
? (lname < max - 3 ? max - lname : 3) : lext;
|
||||
lnname = (strlen(src) > max +1) ? max - lnext : lname;
|
||||
}
|
||||
|
||||
if (lnname == 0 && lnext == 0) {
|
||||
free(src);
|
||||
free(dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
/* Convert up to lnname characters of the filename. */
|
||||
for (i = 0; i < lnname; i++) {
|
||||
char c = toupper(src[i]);
|
||||
|
||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
dest[pos++] = '.';
|
||||
/* Convert up to lnext characters of the extension, if any. */
|
||||
for (i = 0; i < lnext; i++) {
|
||||
char c = toupper(src[lname + 1 + i]);
|
||||
|
||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
if ( !(flag & ECMA119_OMIT_VERSION_NUMBERS) ) {
|
||||
dest[pos++] = ';';
|
||||
dest[pos++] = '1';
|
||||
}
|
||||
dest[pos] = '\0';
|
||||
dest = (char *)realloc(dest, pos + 1);
|
||||
|
||||
free(src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *
|
||||
iso_p_fileid(const char *src, const char *icharset)
|
||||
{
|
||||
char *ret = str2ascii(src, icharset);
|
||||
size_t i, len;
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
len = strlen(ret);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!valid_p_char(ret[i])) {
|
||||
ret[i] = (uint16_t)'_';
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t *
|
||||
iso_j_id(const char *src_arg, const char *icharset)
|
||||
{
|
||||
uint16_t *j_str = str2ucs(src_arg, icharset);
|
||||
size_t len = ucslen(j_str);
|
||||
size_t n;
|
||||
|
||||
if (len > 128) {
|
||||
j_str[128] = '\0';
|
||||
len = 128;
|
||||
}
|
||||
|
||||
for (n = 0; n < len; n++)
|
||||
if (!valid_j_char(j_str[n]))
|
||||
j_str[n] = '_';
|
||||
return j_str;
|
||||
}
|
||||
|
||||
void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(bytes <= 4);
|
||||
|
||||
for (i = 0; i < bytes; ++i)
|
||||
buf[i] = (num >> (8 * i)) & 0xff;
|
||||
}
|
||||
|
||||
void iso_msb(uint8_t *buf, uint32_t num, int bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(bytes <= 4);
|
||||
|
||||
for (i = 0; i < bytes; ++i)
|
||||
buf[bytes - 1 - i] = (num >> (8 * i)) & 0xff;
|
||||
}
|
||||
|
||||
void iso_bb(uint8_t *buf, uint32_t num, int bytes)
|
||||
{
|
||||
iso_lsb(buf, num, bytes);
|
||||
iso_msb(buf+bytes, num, bytes);
|
||||
}
|
||||
|
||||
void iso_datetime_7(unsigned char *buf, time_t t)
|
||||
{
|
||||
static int tzsetup = 0;
|
||||
int tzoffset;
|
||||
struct tm tm;
|
||||
|
||||
if (!tzsetup) {
|
||||
tzset();
|
||||
tzsetup = 1;
|
||||
}
|
||||
|
||||
localtime_r(&t, &tm);
|
||||
|
||||
buf[0] = tm.tm_year;
|
||||
buf[1] = tm.tm_mon + 1;
|
||||
buf[2] = tm.tm_mday;
|
||||
buf[3] = tm.tm_hour;
|
||||
buf[4] = tm.tm_min;
|
||||
buf[5] = tm.tm_sec;
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
tzoffset = tm.tm_gmtoff / 60 / 15;
|
||||
#else
|
||||
tzoffset = timezone / 60 / 15;
|
||||
#endif
|
||||
if (tzoffset > 52)
|
||||
tzoffset -= 101;
|
||||
buf[6] = tzoffset;
|
||||
}
|
||||
|
||||
time_t iso_datetime_read_7(const uint8_t *buf)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
tm.tm_year = buf[0];
|
||||
tm.tm_mon = buf[1] + 1;
|
||||
tm.tm_mday = buf[2];
|
||||
tm.tm_hour = buf[3];
|
||||
tm.tm_min = buf[4];
|
||||
tm.tm_sec = buf[5];
|
||||
|
||||
return mktime(&tm) - buf[6] * 60 * 60;
|
||||
}
|
||||
|
||||
void iso_datetime_17(unsigned char *buf, time_t t)
|
||||
{
|
||||
static int tzsetup = 0;
|
||||
static int tzoffset;
|
||||
struct tm tm;
|
||||
|
||||
if (t == (time_t) - 1) {
|
||||
/* unspecified time */
|
||||
memset(buf, '0', 16);
|
||||
buf[16] = 0;
|
||||
} else {
|
||||
if (!tzsetup) {
|
||||
tzset();
|
||||
tzsetup = 1;
|
||||
}
|
||||
|
||||
localtime_r(&t, &tm);
|
||||
|
||||
sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
|
||||
sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
|
||||
sprintf((char*)&buf[6], "%02d", tm.tm_mday);
|
||||
sprintf((char*)&buf[8], "%02d", tm.tm_hour);
|
||||
sprintf((char*)&buf[10], "%02d", tm.tm_min);
|
||||
sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
|
||||
memcpy(&buf[14], "00", 2);
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
tzoffset = tm.tm_gmtoff / 60 / 15;
|
||||
#else
|
||||
tzoffset = timezone / 60 / 15;
|
||||
#endif
|
||||
if (tzoffset > 52)
|
||||
tzoffset -= 101;
|
||||
buf[16] = tzoffset;
|
||||
}
|
||||
}
|
||||
|
||||
time_t iso_datetime_read_17(const uint8_t *buf)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
sscanf((char*)&buf[0], "%4d", &tm.tm_year);
|
||||
sscanf((char*)&buf[4], "%2d", &tm.tm_mon);
|
||||
sscanf((char*)&buf[6], "%2d", &tm.tm_mday);
|
||||
sscanf((char*)&buf[8], "%2d", &tm.tm_hour);
|
||||
sscanf((char*)&buf[10], "%2d", &tm.tm_min);
|
||||
sscanf((char*)&buf[12], "%2d", &tm.tm_sec);
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon -= 1;
|
||||
|
||||
return mktime(&tm) - buf[16] * 60 * 60;
|
||||
}
|
||||
|
||||
size_t ucslen(const uint16_t *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; str[i]; i++)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Although each character is 2 bytes, we actually compare byte-by-byte
|
||||
* (thats what the spec says).
|
||||
*/
|
||||
int ucscmp(const uint16_t *s1, const uint16_t *s2)
|
||||
{
|
||||
const char *s = (const char*)s1;
|
||||
const char *t = (const char*)s2;
|
||||
size_t len1 = ucslen(s1);
|
||||
size_t len2 = ucslen(s2);
|
||||
size_t i, len = MIN(len1, len2) * 2;
|
||||
|
||||
for (i=0; i < len; i++) {
|
||||
if (s[i] < t[i]) {
|
||||
return -1;
|
||||
} else if (s[i] > t[i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len1 < len2)
|
||||
return -1;
|
||||
else if (len1 > len2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t iso_read_lsb(const uint8_t *buf, int bytes)
|
||||
{
|
||||
int i;
|
||||
uint32_t ret = 0;
|
||||
|
||||
for (i=0; i<bytes; i++) {
|
||||
ret += ((uint32_t) buf[i]) << (i*8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t iso_read_msb(const uint8_t *buf, int bytes)
|
||||
{
|
||||
int i;
|
||||
uint32_t ret = 0;
|
||||
|
||||
for (i=0; i<bytes; i++) {
|
||||
ret += ((uint32_t) buf[bytes-i-1]) << (i*8);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t iso_read_bb(const uint8_t *buf, int bytes)
|
||||
{
|
||||
uint32_t v1 = iso_read_lsb(buf, bytes);
|
||||
uint32_t v2 = iso_read_msb(buf+bytes, bytes);
|
||||
|
||||
assert(v1 == v2);
|
||||
return v1;
|
||||
}
|
136
libisofs/branches/ZeroTwoEight/libisofs/util.h
Executable file
136
libisofs/branches/ZeroTwoEight/libisofs/util.h
Executable file
@ -0,0 +1,136 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* Utility functions for the Libisofs library.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_UTIL_H
|
||||
#define LIBISO_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
extern inline int div_up(int n, int div)
|
||||
{
|
||||
return (n + div - 1) / div;
|
||||
}
|
||||
|
||||
extern inline int round_up(int n, int mul)
|
||||
{
|
||||
return div_up(n, mul) * mul;
|
||||
}
|
||||
|
||||
char *convert_str(const char *str, const char *icharset, const char *ocharset);
|
||||
|
||||
wchar_t *towcs(const char *);
|
||||
char *str2ascii(const char*, const char *);
|
||||
uint16_t *str2ucs(const char *, const char *);
|
||||
|
||||
char *str2d_char(const char*, const char *);
|
||||
char *str2a_char(const char*, const char *);
|
||||
|
||||
/**
|
||||
* Create a level 1 directory identifier.
|
||||
*/
|
||||
char *iso_1_dirid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a level 2 directory identifier.
|
||||
*/
|
||||
char *iso_2_dirid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a directory identifier with relaxed constraints
|
||||
*/
|
||||
char *iso_r_dirid(const char *src, const char *icharset, int flags);
|
||||
|
||||
/**
|
||||
* Create a level 1 file identifier that consists of a name, extension and
|
||||
* version number. The resulting string will have a file name of maximum
|
||||
* length 8, followed by a separator (.), an optional extension of maximum
|
||||
* length 3, followed by a separator (;) and a version number (digit 1).
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_1_fileid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a level 2 file identifier that consists of a name, extension and
|
||||
* version number. The combined file name and extension length will not exceed
|
||||
* 30, the name and extension will be separated (.), and the extension will be
|
||||
* followed by a separator (;) and a version number (digit 1).
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_2_fileid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a file identifier with relaxed constraints.
|
||||
*/
|
||||
char *iso_r_fileid(const char *src, const char *icharset, int flags);
|
||||
|
||||
/**
|
||||
* Create a Joliet file or directory identifier that consists of a name,
|
||||
* extension and version number. The combined name and extension length will
|
||||
* not exceed 128 bytes, the name and extension will be separated (.),
|
||||
* and the extension will be followed by a separator (;) and a version number
|
||||
* (digit 1). All characters consist of 2 bytes and the resulting string is
|
||||
* NULL-terminated by a 2-byte NULL. Requires the locale to be set correctly.
|
||||
*
|
||||
* @param size will be set to the size (in bytes) of the identifier.
|
||||
* @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available.
|
||||
*/
|
||||
uint16_t *iso_j_id(const char *src, const char *icharset);
|
||||
|
||||
/**
|
||||
* FIXME: what are the requirements for these next two? Is this for RR?
|
||||
*
|
||||
* Create a POSIX portable file name that consists of a name and extension.
|
||||
* The resulting file name will not exceed 250 characters.
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_p_fileid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a POSIX portable directory name.
|
||||
* The resulting directory name will not exceed 250 characters.
|
||||
* @return NULL if the original name is of length 0.
|
||||
*/
|
||||
char *iso_p_dirid(const char *src);
|
||||
|
||||
void iso_lsb(uint8_t *buf, uint32_t num, int bytes);
|
||||
void iso_msb(uint8_t *buf, uint32_t num, int bytes);
|
||||
void iso_bb(uint8_t *buf, uint32_t num, int bytes);
|
||||
|
||||
uint32_t iso_read_lsb(const uint8_t *buf, int bytes);
|
||||
uint32_t iso_read_msb(const uint8_t *buf, int bytes);
|
||||
uint32_t iso_read_bb(const uint8_t *buf, int bytes);
|
||||
|
||||
/** Records the date/time into a 7 byte buffer (9.1.5) */
|
||||
void iso_datetime_7(uint8_t *buf, time_t t);
|
||||
|
||||
/** Records the date/time into a 17 byte buffer (8.4.26.1) */
|
||||
void iso_datetime_17(uint8_t *buf, time_t t);
|
||||
|
||||
time_t iso_datetime_read_7(const uint8_t *buf);
|
||||
time_t iso_datetime_read_17(const uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Like strlen, but for Joliet strings.
|
||||
*/
|
||||
size_t ucslen(const uint16_t *str);
|
||||
|
||||
/**
|
||||
* Like strcmp, but for Joliet strings.
|
||||
*/
|
||||
int ucscmp(const uint16_t *s1, const uint16_t *s2);
|
||||
|
||||
#endif /* LIBISO_UTIL_H */
|
258
libisofs/branches/ZeroTwoEight/libisofs/volume.c
Executable file
258
libisofs/branches/ZeroTwoEight/libisofs/volume.c
Executable file
@ -0,0 +1,258 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set ts=8 sts=8 sw=8 noet : */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "tree.h"
|
||||
#include "util.h"
|
||||
#include "volume.h"
|
||||
#include "eltorito.h"
|
||||
|
||||
struct iso_volset*
|
||||
iso_volset_new(struct iso_volume *vol, const char *id)
|
||||
{
|
||||
struct iso_volset *volset = calloc(1, sizeof(struct iso_volset));
|
||||
|
||||
volset->volset_size = 1;
|
||||
volset->refcount = 1;
|
||||
volset->volume = malloc(sizeof(void *));
|
||||
volset->volume[0] = vol;
|
||||
volset->volset_id = strdup(id);
|
||||
return volset;
|
||||
}
|
||||
|
||||
void
|
||||
iso_volset_free(struct iso_volset *volset)
|
||||
{
|
||||
if (--volset->refcount < 1) {
|
||||
int i;
|
||||
for (i = 0; i < volset->volset_size; i++) {
|
||||
iso_volume_free(volset->volume[i]);
|
||||
}
|
||||
free(volset->volume);
|
||||
free(volset->volset_id);
|
||||
free(volset);
|
||||
}
|
||||
}
|
||||
|
||||
struct iso_volume*
|
||||
iso_volume_new(const char *volume_id,
|
||||
const char *publisher_id,
|
||||
const char *data_preparer_id)
|
||||
{
|
||||
return iso_volume_new_with_root(volume_id,
|
||||
publisher_id,
|
||||
data_preparer_id,
|
||||
NULL);
|
||||
}
|
||||
|
||||
struct iso_volume*
|
||||
iso_volume_new_with_root(const char *volume_id,
|
||||
const char *publisher_id,
|
||||
const char *data_preparer_id,
|
||||
struct iso_tree_node_dir *root)
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = calloc(1, sizeof(struct iso_volume));
|
||||
volume->refcount = 1;
|
||||
|
||||
volume->root = root ? root : iso_tree_new_root();
|
||||
|
||||
if (volume_id != NULL)
|
||||
volume->volume_id = strdup(volume_id);
|
||||
if (publisher_id != NULL)
|
||||
volume->publisher_id = strdup(publisher_id);
|
||||
if (data_preparer_id != NULL)
|
||||
volume->data_preparer_id = strdup(data_preparer_id);
|
||||
return volume;
|
||||
}
|
||||
|
||||
void
|
||||
iso_volume_free(struct iso_volume *volume)
|
||||
{
|
||||
/* Only free if no references are in use. */
|
||||
if (--volume->refcount < 1) {
|
||||
iso_tree_free( (struct iso_tree_node*) volume->root);
|
||||
|
||||
free(volume->volume_id);
|
||||
free(volume->publisher_id);
|
||||
free(volume->data_preparer_id);
|
||||
free(volume->system_id);
|
||||
free(volume->application_id);
|
||||
free(volume->copyright_file_id);
|
||||
free(volume->abstract_file_id);
|
||||
free(volume->biblio_file_id);
|
||||
if (volume->bootcat)
|
||||
el_torito_boot_catalog_free(volume->bootcat);
|
||||
free(volume);
|
||||
}
|
||||
}
|
||||
|
||||
struct iso_tree_node_dir *
|
||||
iso_volume_get_root(const struct iso_volume *volume)
|
||||
{
|
||||
return volume->root;
|
||||
}
|
||||
|
||||
void iso_volume_set_volume_id(struct iso_volume *volume,
|
||||
const char *volume_id)
|
||||
{
|
||||
free(volume->volume_id);
|
||||
volume->volume_id = strdup(volume_id);
|
||||
}
|
||||
|
||||
void iso_volume_set_publisher_id(struct iso_volume *volume,
|
||||
const char *publisher_id)
|
||||
{
|
||||
free(volume->publisher_id);
|
||||
volume->publisher_id = strdup(publisher_id);
|
||||
}
|
||||
|
||||
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
|
||||
const char *data_preparer_id)
|
||||
{
|
||||
free(volume->data_preparer_id);
|
||||
volume->data_preparer_id = strdup(data_preparer_id);
|
||||
}
|
||||
|
||||
void iso_volume_set_system_id(struct iso_volume *volume,
|
||||
const char *system_id)
|
||||
{
|
||||
free(volume->system_id);
|
||||
volume->system_id = strdup(system_id);
|
||||
}
|
||||
|
||||
void iso_volume_set_application_id(struct iso_volume *volume,
|
||||
const char *application_id)
|
||||
{
|
||||
free(volume->application_id);
|
||||
volume->application_id = strdup(application_id);
|
||||
}
|
||||
|
||||
void iso_volume_set_copyright_file_id(struct iso_volume *volume,
|
||||
const char *copyright_file_id)
|
||||
{
|
||||
free(volume->copyright_file_id);
|
||||
volume->copyright_file_id = strdup(copyright_file_id);
|
||||
}
|
||||
|
||||
void iso_volume_set_abstract_file_id(struct iso_volume *volume,
|
||||
const char *abstract_file_id)
|
||||
{
|
||||
free(volume->abstract_file_id);
|
||||
volume->abstract_file_id = strdup(abstract_file_id);
|
||||
}
|
||||
|
||||
void iso_volume_set_biblio_file_id(struct iso_volume *volume,
|
||||
const char *biblio_file_id)
|
||||
{
|
||||
free(volume->biblio_file_id);
|
||||
volume->biblio_file_id = strdup(biblio_file_id);
|
||||
}
|
||||
|
||||
struct iso_tree_node *
|
||||
iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
|
||||
{
|
||||
struct iso_tree_node *node;
|
||||
struct iso_tree_node_dir *dir;
|
||||
char *ptr, *brk_info, *component;
|
||||
|
||||
/* get the first child at the root of the volume
|
||||
* that is "/" */
|
||||
dir = iso_volume_get_root(volume);
|
||||
node = (struct iso_tree_node *)dir;
|
||||
if (!strcmp(path, "/"))
|
||||
return node;
|
||||
|
||||
if (!dir->nchildren)
|
||||
return NULL;
|
||||
|
||||
ptr = strdup(path);
|
||||
|
||||
/* get the first component of the path */
|
||||
component=strtok_r(ptr, "/", &brk_info);
|
||||
while (component) {
|
||||
size_t max;
|
||||
size_t i;
|
||||
|
||||
if ( !ISO_ISDIR(node) ) {
|
||||
node=NULL;
|
||||
break;
|
||||
}
|
||||
dir = (struct iso_tree_node_dir *)node;
|
||||
|
||||
/* search among all the children of this directory if this path component exists */
|
||||
max=dir->nchildren;
|
||||
for (i=0; i < max; i++) {
|
||||
if (!strcmp(component, dir->children[i]->name)) {
|
||||
node=dir->children[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if a node could be found */
|
||||
if (i==max) {
|
||||
node=NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
component=strtok_r(NULL, "/", &brk_info);
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
return node;
|
||||
}
|
||||
|
||||
//
|
||||
//struct iso_tree_node *
|
||||
//iso_tree_volume_add_path(struct iso_volume *volume,
|
||||
// const char *disc_path,
|
||||
// const char *path)
|
||||
//{
|
||||
// char *tmp;
|
||||
// struct iso_tree_node *node;
|
||||
// struct iso_tree_node *parent_node;
|
||||
//
|
||||
// tmp=strdup(disc_path);
|
||||
// parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
|
||||
// free(tmp);
|
||||
//
|
||||
// if (!parent_node)
|
||||
// return NULL;
|
||||
//
|
||||
// node = iso_tree_radd_dir(parent_node, path);
|
||||
// if (!node)
|
||||
// return NULL;
|
||||
//
|
||||
// tmp=strdup(disc_path);
|
||||
// iso_tree_node_set_name(node, basename(tmp));
|
||||
// free(tmp);
|
||||
//
|
||||
// return node;
|
||||
//}
|
||||
//
|
||||
//struct iso_tree_node *
|
||||
//iso_tree_volume_add_new_dir(struct iso_volume *volume,
|
||||
// const char *disc_path)
|
||||
//{
|
||||
// char *tmp;
|
||||
// struct iso_tree_node *node;
|
||||
// struct iso_tree_node *parent_node;
|
||||
//
|
||||
// tmp=strdup(disc_path);
|
||||
// parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
|
||||
// free(tmp);
|
||||
//
|
||||
// if (!parent_node)
|
||||
// return NULL;
|
||||
//
|
||||
// tmp=strdup(disc_path);
|
||||
// node = iso_tree_add_new_dir(parent_node, basename(tmp));
|
||||
// free(tmp);
|
||||
//
|
||||
// return node;
|
||||
//}
|
53
libisofs/branches/ZeroTwoEight/libisofs/volume.h
Executable file
53
libisofs/branches/ZeroTwoEight/libisofs/volume.h
Executable file
@ -0,0 +1,53 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet sts=8 ts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* Extra declarations for use with the iso_volume structure.
|
||||
*/
|
||||
|
||||
#ifndef LIBISO_VOLUME_H
|
||||
#define LIBISO_VOLUME_H
|
||||
|
||||
#include "libisofs.h"
|
||||
|
||||
/**
|
||||
* Data volume.
|
||||
*/
|
||||
struct iso_volume
|
||||
{
|
||||
int refcount; /**< Number of used references to this
|
||||
volume. */
|
||||
|
||||
struct iso_tree_node_dir *root; /**< Root of the directory tree for the
|
||||
volume. */
|
||||
|
||||
char *volume_id; /**< Volume identifier. */
|
||||
char *publisher_id; /**< Volume publisher. */
|
||||
char *data_preparer_id; /**< Volume data preparer. */
|
||||
|
||||
char *system_id; /**< Volume system identifier. */
|
||||
char *application_id; /**< Volume application id */
|
||||
char *copyright_file_id;
|
||||
char *abstract_file_id;
|
||||
char *biblio_file_id;
|
||||
|
||||
struct el_torito_boot_catalog *bootcat; /**< El-Torito boot catalog */
|
||||
};
|
||||
|
||||
/**
|
||||
* A set of data volumes.
|
||||
*/
|
||||
struct iso_volset
|
||||
{
|
||||
int refcount;
|
||||
|
||||
struct iso_volume **volume; /**< The volumes belonging to this
|
||||
volume set. */
|
||||
int volset_size; /**< The number of volumes in this
|
||||
volume set. */
|
||||
|
||||
char *volset_id; /**< The id of this volume set, encoded
|
||||
in the current locale. */
|
||||
};
|
||||
|
||||
#endif /* __ISO_VOLUME */
|
33
libisofs/branches/ZeroTwoEight/test.sh
Normal file
33
libisofs/branches/ZeroTwoEight/test.sh
Normal file
@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
TEST_ROOT=/tmp/libisofs_test
|
||||
|
||||
rm -rf $TEST_ROOT
|
||||
|
||||
#create test folders
|
||||
mkdir -p $TEST_ROOT
|
||||
mkdir -p $TEST_ROOT/dir1/dir11
|
||||
chmod 755 $TEST_ROOT/dir1
|
||||
chmod 755 $TEST_ROOT/dir1/dir11
|
||||
|
||||
touch $TEST_ROOT/dir1/dir11/a
|
||||
echo "This file is to check correct file permissions. set them to 754" > $TEST_ROOT/dir1/permtest
|
||||
chmod 754 $TEST_ROOT/dir1/permtest
|
||||
|
||||
mkdir -p $TEST_ROOT/dir2
|
||||
ln -s $TEST_ROOT/dir1 "$TEST_ROOT/link to dir1"
|
||||
|
||||
echo "README file" > $TEST_ROOT/README
|
||||
chmod 555 $TEST_ROOT/README
|
||||
ln -s $TEST_ROOT/README "$TEST_ROOT/link to readme"
|
||||
|
||||
echo "No read file" > $TEST_ROOT/no_read
|
||||
chmod 000 $TEST_ROOT/no_read
|
||||
|
||||
if ! make check
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test/test
|
||||
|
4
libisofs/branches/ZeroTwoEight/test/Makefile
Normal file
4
libisofs/branches/ZeroTwoEight/test/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
all clean:
|
||||
$(MAKE) -C .. -$(MAKEFLAGS) $@
|
||||
|
||||
.PHONY: all clean
|
141
libisofs/branches/ZeroTwoEight/test/iso.c
Normal file
141
libisofs/branches/ZeroTwoEight/test/iso.c
Normal file
@ -0,0 +1,141 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set ts=8 sts=8 sw=8 noet : */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "libburn/libburn.h"
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
|
||||
#define SECSIZE 2048
|
||||
|
||||
const char * const optstring = "JRL:b:h";
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("test [OPTIONS] DIRECTORY OUTPUT\n");
|
||||
}
|
||||
|
||||
void help()
|
||||
{
|
||||
printf(
|
||||
"Options:\n"
|
||||
" -J Add Joliet support\n"
|
||||
" -R Add Rock Ridge support\n"
|
||||
" -L <num> Set the ISO level (1 or 2)\n"
|
||||
" -b file Specifies a boot image to add to image\n"
|
||||
" -h Print this message\n"
|
||||
);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct iso_volset *volset;
|
||||
struct iso_volume *volume;
|
||||
struct iso_tree_node_dir *root;
|
||||
struct burn_source *src;
|
||||
unsigned char buf[2048];
|
||||
FILE *fd;
|
||||
int c;
|
||||
struct iso_tree_radd_dir_behavior behav = {0,0,0};
|
||||
int level=1, flags=0;
|
||||
char *boot_img = NULL;
|
||||
|
||||
while ((c = getopt(argc, argv, optstring)) != -1) {
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage();
|
||||
help();
|
||||
exit(0);
|
||||
break;
|
||||
case 'J':
|
||||
flags |= ECMA119_JOLIET;
|
||||
break;
|
||||
case 'R':
|
||||
flags |= ECMA119_ROCKRIDGE;
|
||||
break;
|
||||
case 'L':
|
||||
level = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
boot_img = optarg;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
printf ("Please pass directory from which to build ISO\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if (argc < 3) {
|
||||
printf ("Please supply output file\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
fd = fopen(argv[optind+1], "w");
|
||||
if (!fd) {
|
||||
err(1, "error opening output file");
|
||||
}
|
||||
|
||||
root = iso_tree_new_root();
|
||||
iso_tree_radd_dir(root, argv[optind], &behav);
|
||||
if (!root) {
|
||||
err(1, "error opening input directory");
|
||||
}
|
||||
volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root );
|
||||
|
||||
if ( boot_img ) {
|
||||
/* adds El-Torito boot info. Tunned for isolinux */
|
||||
struct iso_tree_node_dir *boot = (struct iso_tree_node_dir *)
|
||||
iso_tree_volume_path_to_node(volume, "isolinux");
|
||||
struct iso_tree_node *img = iso_tree_volume_path_to_node(volume, boot_img);
|
||||
if (!img) {
|
||||
err(1, "boot image patch is not valid");
|
||||
}
|
||||
struct el_torito_boot_image *bootimg =
|
||||
iso_volume_create_boot_catalog(volume, img, ELTORITO_NO_EMUL,
|
||||
boot, "boot.cat");
|
||||
el_torito_set_load_size(bootimg, 4);
|
||||
el_torito_set_write_boot_info(bootimg);
|
||||
}
|
||||
|
||||
volset = iso_volset_new( volume, "VOLSETID" );
|
||||
|
||||
/* some tests */
|
||||
iso_volume_set_application_id(volume, "Libburnia");
|
||||
iso_volume_set_copyright_file_id(volume, "LICENSE");
|
||||
|
||||
int constraints = ECMA119_OMIT_VERSION_NUMBERS |
|
||||
ECMA119_37_CHAR_FILENAMES | ECMA119_NO_DIR_REALOCATION |
|
||||
ECMA119_RELAXED_FILENAMES;
|
||||
|
||||
struct ecma119_source_opts opts = {0, level, flags, constraints, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, "UTF-8", "UTF-8"};
|
||||
|
||||
src = iso_source_new_ecma119(volset, &opts);
|
||||
|
||||
while (src->read(src, buf, 2048) == 2048) {
|
||||
fwrite(buf, 1, 2048, fd);
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
return 0;
|
||||
}
|
297
libisofs/branches/ZeroTwoEight/test/iso.py
Normal file
297
libisofs/branches/ZeroTwoEight/test/iso.py
Normal file
@ -0,0 +1,297 @@
|
||||
|
||||
import struct
|
||||
import tree
|
||||
import sys
|
||||
|
||||
voldesc_fmt = "B" "5s" "B" "2041x"
|
||||
|
||||
# all these fields are common between the pri and sec voldescs
|
||||
privoldesc_fmt = "B" "5s" "B" "x" "32s" "32s" "8x" "8s" "32x" "4s" "4s" "4s" "8s" "4s4s" "4s4s" "34s" "128s" \
|
||||
"128s" "128s" "128s" "37s" "37s" "37s" "17s" "17s" "17s" "17s" "B" "x" "512s" "653x"
|
||||
|
||||
# the fields unique to the sec_vol_desc
|
||||
secvoldesc_fmt = "x" "5x" "x" "B" "32x" "32x" "8x" "8x" "32s" "4x" "4x" "4x" "8x" "4x4x" "4x4x" "34x" "128x" \
|
||||
"128x" "128x" "128x" "37x" "37x" "37x" "17x" "17x" "17x" "17x" "x" "x" "512x" "653x"
|
||||
|
||||
dirrecord_fmt = "B" "B" "8s" "8s" "7s" "B" "B" "B" "4s" "B" # + file identifier, padding field and SU area
|
||||
|
||||
pathrecord_fmt = "B" "B" "4s" "2s" # + directory identifier and padding field
|
||||
|
||||
def read_bb(str, le, be):
|
||||
val1, = struct.unpack(le, str)
|
||||
val2, = struct.unpack(be, str)
|
||||
if val1 != val2:
|
||||
print "val1=%d, val2=%d" % (val1, val2)
|
||||
raise AssertionError, "values are not equal in dual byte-order field"
|
||||
return val1
|
||||
|
||||
def read_bb4(str):
|
||||
return read_bb(str, "<I4x", ">4xI")
|
||||
|
||||
def read_bb2(str):
|
||||
return read_bb(str, "<H2x", ">2xH")
|
||||
|
||||
def read_lsb4(str):
|
||||
return struct.unpack("<I", str)[0]
|
||||
|
||||
def read_lsb2(str):
|
||||
return struct.unpack("<H", str)[0]
|
||||
|
||||
def read_msb4(str):
|
||||
return struct.unpack(">I", str)[0]
|
||||
|
||||
def read_msb2(str):
|
||||
return struct.unpack(">H", str)[0]
|
||||
|
||||
class VolDesc(object):
|
||||
def __init__(self, data):
|
||||
print "fmt len=%d, data len=%d" % ( struct.calcsize(voldesc_fmt), len(data) )
|
||||
self.vol_desc_type, self.standard_id, self.vol_desc_version = struct.unpack(voldesc_fmt, data)
|
||||
|
||||
class PriVolDesc(VolDesc):
|
||||
def __init__(self, data):
|
||||
self.vol_desc_type, \
|
||||
self.standard_id, \
|
||||
self.vol_desc_version, \
|
||||
self.system_id, \
|
||||
self.volume_id, \
|
||||
self.vol_space_size, \
|
||||
self.vol_set_size, \
|
||||
self.vol_seq_num, \
|
||||
self.block_size, \
|
||||
self.path_table_size, \
|
||||
self.l_table_pos, \
|
||||
self.l_table2_pos, \
|
||||
self.m_table_pos, \
|
||||
self.m_table2_pos, \
|
||||
self.root_record, \
|
||||
self.volset_id, \
|
||||
self.publisher_id, \
|
||||
self.preparer_id, \
|
||||
self.application_id, \
|
||||
self.copyright_file, \
|
||||
self.abstract_file, \
|
||||
self.bibliographic_file, \
|
||||
self.creation_timestamp, \
|
||||
self.modification_timestamp, \
|
||||
self.expiration_timestamp, \
|
||||
self.effective_timestamp, \
|
||||
self.file_struct_version, \
|
||||
self.application_use = struct.unpack(privoldesc_fmt, data)
|
||||
|
||||
# take care of reading the integer types
|
||||
self.vol_space_size = read_bb4(self.vol_space_size)
|
||||
self.vol_set_size = read_bb2(self.vol_set_size)
|
||||
self.vol_seq_num = read_bb2(self.vol_seq_num)
|
||||
self.block_size = read_bb2(self.block_size)
|
||||
self.path_table_size = read_bb4(self.path_table_size)
|
||||
self.l_table_pos = read_lsb4(self.l_table_pos)
|
||||
self.l_table2_pos = read_lsb4(self.l_table2_pos)
|
||||
self.m_table_pos = read_msb4(self.m_table_pos)
|
||||
self.m_table2_pos = read_msb4(self.m_table2_pos)
|
||||
|
||||
# parse the root directory record
|
||||
self.root_record = DirRecord(self.root_record)
|
||||
|
||||
def readPathTables(self, file):
|
||||
file.seek( self.block_size * self.l_table_pos )
|
||||
self.l_table = PathTable( file.read(self.path_table_size), 0 )
|
||||
file.seek( self.block_size * self.m_table_pos )
|
||||
self.m_table = PathTable( file.read(self.path_table_size), 1 )
|
||||
|
||||
if self.l_table2_pos:
|
||||
file.seek( self.block_size * self.l_table2_pos )
|
||||
self.l_table2 = PathTable( file.read(self.path_table_size), 0 )
|
||||
else:
|
||||
self.l_table2 = None
|
||||
|
||||
if self.m_table2_pos:
|
||||
file.seek( self.block_size * self.m_table2_pos )
|
||||
self.m_table2 = PathTable( file.read(self.path_table_size), 1 )
|
||||
else:
|
||||
self.m_table2 = None
|
||||
|
||||
def toTree(self, isofile):
|
||||
ret = tree.Tree(isofile=isofile.name)
|
||||
ret.root = self.root_record.toTreeNode(parent=None, isofile=isofile)
|
||||
return ret
|
||||
|
||||
class SecVolDesc(PriVolDesc):
|
||||
def __init__(self, data):
|
||||
super(SecVolDesc,self).__init__(data)
|
||||
self.flags, self.escape_sequences = struct.unpack(secvoldesc_fmt, data)
|
||||
|
||||
# return a single volume descriptor of the appropriate type
|
||||
def readVolDesc(data):
|
||||
desc = VolDesc(data)
|
||||
if desc.standard_id != "CD001":
|
||||
print "Unexpected standard_id " +desc.standard_id
|
||||
return None
|
||||
if desc.vol_desc_type == 1:
|
||||
return PriVolDesc(data)
|
||||
elif desc.vol_desc_type == 2:
|
||||
return SecVolDesc(data)
|
||||
elif desc.vol_desc_type == 3:
|
||||
print "I don't know about partitions yet!"
|
||||
return None
|
||||
elif desc.vol_desc_type == 255:
|
||||
return desc
|
||||
else:
|
||||
print "Unknown volume descriptor type %d" % (desc.vol_desc_type,)
|
||||
return None
|
||||
|
||||
def readVolDescSet(file):
|
||||
ret = [ readVolDesc(file.read(2048)) ]
|
||||
while ret[-1].vol_desc_type != 255:
|
||||
ret.append( readVolDesc(file.read(2048)) )
|
||||
|
||||
for vol in ret:
|
||||
if vol.vol_desc_type == 1 or vol.vol_desc_type == 2:
|
||||
vol.readPathTables(file)
|
||||
|
||||
return ret
|
||||
|
||||
class DirRecord:
|
||||
def __init__(self, data):
|
||||
self.len_dr, \
|
||||
self.len_xa, \
|
||||
self.block, \
|
||||
self.len_data, \
|
||||
self.timestamp, \
|
||||
self.flags, \
|
||||
self.unit_size, \
|
||||
self.gap_size, \
|
||||
self.vol_seq_number, \
|
||||
self.len_fi = struct.unpack(dirrecord_fmt, data[:33])
|
||||
self.children = []
|
||||
|
||||
if self.len_dr > len(data):
|
||||
raise AssertionError, "Error: not enough data to read in DirRecord()"
|
||||
elif self.len_dr < 34:
|
||||
raise AssertionError, "Error: directory record too short"
|
||||
|
||||
fmt = str(self.len_fi) + "s"
|
||||
if self.len_fi % 2 == 0:
|
||||
fmt += "1x"
|
||||
len_su = self.len_dr - (33 + self.len_fi + 1 - (self.len_fi % 2))
|
||||
fmt += str(len_su) + "s"
|
||||
|
||||
if len(data) >= self.len_dr:
|
||||
self.file_id, self.su = struct.unpack(fmt, data[33 : self.len_dr])
|
||||
else:
|
||||
print "Error: couldn't read file_id: not enough data"
|
||||
self.file_id = "BLANK"
|
||||
self.su = ""
|
||||
|
||||
# convert to integers
|
||||
self.block = read_bb4(self.block)
|
||||
self.len_data = read_bb4(self.len_data)
|
||||
self.vol_seq_number = read_bb2(self.vol_seq_number)
|
||||
|
||||
def toTreeNode(self, parent, isofile, path=""):
|
||||
ret = tree.TreeNode(parent=parent, isofile=isofile.name)
|
||||
if len(path) > 0:
|
||||
path += "/"
|
||||
path += self.file_id
|
||||
ret.path = path
|
||||
|
||||
if self.flags & 2: # we are a directory, recurse
|
||||
isofile.seek( 2048 * self.block )
|
||||
data = isofile.read( self.len_data )
|
||||
pos = 0
|
||||
while pos < self.len_data:
|
||||
try:
|
||||
child = DirRecord( data[pos:] )
|
||||
pos += child.len_dr
|
||||
if child.len_fi == 1 and (child.file_id == "\x00" or child.file_id == "\x01"):
|
||||
continue
|
||||
print "read child named " +child.file_id
|
||||
self.children.append( child )
|
||||
ret.children.append( child.toTreeNode(ret, isofile, path) )
|
||||
except AssertionError:
|
||||
print "Couldn't read child of directory %s, position is %d, len is %d" % \
|
||||
(path, pos, self.len_data)
|
||||
raise
|
||||
|
||||
return ret
|
||||
|
||||
class PathTableRecord:
|
||||
def __init__(self, data, readint2, readint4):
|
||||
self.len_di, self.len_xa, self.block, self.parent_number = struct.unpack(pathrecord_fmt, data[:8])
|
||||
|
||||
if len(data) < self.len_di + 8:
|
||||
raise AssertionError, "Error: not enough data to read path table record"
|
||||
|
||||
fmt = str(self.len_di) + "s"
|
||||
self.dir_id, = struct.unpack(fmt, data[8:8+self.len_di])
|
||||
|
||||
self.block = readint4(self.block)
|
||||
self.parent_number = readint2(self.parent_number)
|
||||
|
||||
class PathTable:
|
||||
def __init__(self, data, m_type):
|
||||
if m_type:
|
||||
readint2 = read_msb2
|
||||
readint4 = read_msb4
|
||||
else:
|
||||
readint2 = read_lsb2
|
||||
readint4 = read_lsb4
|
||||
pos = 0
|
||||
self.records = []
|
||||
while pos < len(data):
|
||||
try:
|
||||
self.records.append( PathTableRecord(data[pos:], readint2, readint4) )
|
||||
print "Read path record %d: dir_id %s, block %d, parent_number %d" %\
|
||||
(len(self.records), self.records[-1].dir_id, self.records[-1].block, self.records[-1].parent_number)
|
||||
pos += self.records[-1].len_di + 8
|
||||
pos += pos % 2
|
||||
except AssertionError:
|
||||
print "Last successfully read path table record had dir_id %s, block %d, parent_number %d" % \
|
||||
(self.records[-1].dir_id, self.records[-1].block, self.records[-1].parent_number)
|
||||
print "Error was near offset %x" % (pos,)
|
||||
raise
|
||||
|
||||
def findRecord(self, dir_id, block, parent_number):
|
||||
number=1
|
||||
for record in self.records:
|
||||
if record.dir_id == dir_id and record.block == block and record.parent_number == parent_number:
|
||||
return number, record
|
||||
number += 1
|
||||
|
||||
return None, None
|
||||
|
||||
# check this path table for consistency against the actual directory heirarchy
|
||||
def crossCheckDirRecords(self, root, parent_number=1):
|
||||
number, rec = self.findRecord(root.file_id, root.block, parent_number)
|
||||
|
||||
if not rec:
|
||||
print "Error: directory record parent_number %d, dir_id %s, block %d doesn't match a path table record" % \
|
||||
(parent_number, root.file_id, root.block)
|
||||
parent = self.records[parent_number]
|
||||
print "Parent has parent_number %d, dir_id %s, block %d" % (parent.parent_number, parent.dir_id, parent.block)
|
||||
return 0
|
||||
|
||||
for child in root.children:
|
||||
if child.flags & 2:
|
||||
self.crossCheckDirRecords(child, number)
|
||||
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print "Please enter the name of the .iso file to open"
|
||||
sys.exit(1)
|
||||
|
||||
f = file(sys.argv[1])
|
||||
f.seek(2048 * 16) # system area
|
||||
volumes = readVolDescSet(f)
|
||||
vol = volumes[0]
|
||||
t = vol.toTree(f)
|
||||
vol.l_table.crossCheckDirRecords(vol.root_record)
|
||||
vol.m_table.crossCheckDirRecords(vol.root_record)
|
||||
|
||||
vol = volumes[1]
|
||||
try:
|
||||
t = vol.toTree(f)
|
||||
vol.l_table.crossCheckDirRecords(vol.root_record)
|
||||
vol.m_table.crossCheckDirRecords(vol.root_record)
|
||||
except AttributeError:
|
||||
pass
|
28
libisofs/branches/ZeroTwoEight/test/test.c
Normal file
28
libisofs/branches/ZeroTwoEight/test/test.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include "test.h"
|
||||
|
||||
static void create_test_suite()
|
||||
{
|
||||
add_util_suite();
|
||||
add_tree_suite();
|
||||
add_exclude_suite();
|
||||
add_file_hashtable_suite();
|
||||
add_ecma119_tree_suite();
|
||||
add_volume_suite();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CU_pSuite pSuite = NULL;
|
||||
|
||||
/* initialize the CUnit test registry */
|
||||
if (CUE_SUCCESS != CU_initialize_registry())
|
||||
return CU_get_error();
|
||||
|
||||
create_test_suite();
|
||||
|
||||
/* Run all tests using the console interface */
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
24
libisofs/branches/ZeroTwoEight/test/test.h
Normal file
24
libisofs/branches/ZeroTwoEight/test/test.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef TEST_H_
|
||||
#define TEST_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <CUnit/Basic.h>
|
||||
|
||||
#include "libisofs.h"
|
||||
|
||||
void add_tree_suite();
|
||||
|
||||
void add_exclude_suite();
|
||||
|
||||
void add_file_hashtable_suite();
|
||||
|
||||
void add_util_suite();
|
||||
|
||||
void add_ecma119_tree_suite();
|
||||
|
||||
void add_volume_suite();
|
||||
|
||||
#endif /*TEST_H_*/
|
34
libisofs/branches/ZeroTwoEight/test/test_ecma119_tree.c
Normal file
34
libisofs/branches/ZeroTwoEight/test/test_ecma119_tree.c
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Unit test for ecma119_tree.h
|
||||
*/
|
||||
//FIXME not implemented yet!!
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "tree.h"
|
||||
#include "test.h"
|
||||
//#include "ecma119_tree.h"
|
||||
|
||||
/*
|
||||
* Also including C file, testing internal functions
|
||||
*/
|
||||
//#include "ecma119_tree.c"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static void test_calc_dirent_len()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void add_ecma119_tree_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("Ecma119TreeSuite", NULL, NULL);
|
||||
|
||||
//CU_add_test(pSuite, "test of calc_dirent_len()", test_calc_dirent_len);
|
||||
}
|
33
libisofs/branches/ZeroTwoEight/test/test_exclude.c
Normal file
33
libisofs/branches/ZeroTwoEight/test/test_exclude.c
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Unit test for exclude.h
|
||||
*/
|
||||
|
||||
|
||||
#include "exclude.h"
|
||||
#include "test.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void test_exclude()
|
||||
{
|
||||
struct iso_hash_table table = { {0,}, 0};
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/otherdir") );
|
||||
iso_exclude_add_path(&table, "/otherdir");
|
||||
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/otherdir") );
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
|
||||
iso_exclude_add_path(&table, "/dir");
|
||||
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/otherdir") );
|
||||
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/dir") );
|
||||
iso_exclude_empty(&table);
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/otherdir") );
|
||||
}
|
||||
|
||||
void add_exclude_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("ExcludeSuite", NULL, NULL);
|
||||
|
||||
CU_add_test(pSuite, "test of exclude", test_exclude);
|
||||
}
|
248
libisofs/branches/ZeroTwoEight/test/test_file_hashtable.c
Normal file
248
libisofs/branches/ZeroTwoEight/test/test_file_hashtable.c
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Unit test for file.h
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "file.h"
|
||||
#include "tree.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void test_iso_file_new()
|
||||
{
|
||||
struct iso_tree_node_file *file;
|
||||
struct iso_file *iso;
|
||||
|
||||
file = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file->node.name = "fileName";
|
||||
file->node.attrib.st_size = 12;
|
||||
file->node.attrib.st_dev = 15;
|
||||
file->node.attrib.st_ino = 204;
|
||||
file->path = "/tmp/filename";
|
||||
file->sort_weight = 1;
|
||||
|
||||
iso = iso_file_new(file);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(iso);
|
||||
CU_ASSERT_STRING_EQUAL(iso->path, "/tmp/filename");
|
||||
CU_ASSERT_EQUAL(iso->size, 12);
|
||||
CU_ASSERT_EQUAL(iso->ino, 0);
|
||||
CU_ASSERT_EQUAL(iso->nlink, 1);
|
||||
CU_ASSERT_EQUAL(iso->sort_weight, 1);
|
||||
CU_ASSERT_EQUAL(iso->real_dev, 15);
|
||||
CU_ASSERT_EQUAL(iso->real_ino, 204);
|
||||
}
|
||||
|
||||
static void test_add_lookup()
|
||||
{
|
||||
struct iso_file_table *table;
|
||||
struct iso_tree_node_file *file1;
|
||||
struct iso_tree_node_file *file2;
|
||||
struct iso_file *iso1;
|
||||
struct iso_file *iso2;
|
||||
struct iso_file *iso3;
|
||||
int r;
|
||||
|
||||
table = iso_file_table_new(1);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL( table );
|
||||
CU_ASSERT_TRUE( table->cache_inodes );
|
||||
CU_ASSERT_EQUAL(table->count, 0);
|
||||
|
||||
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file1->node.name = "fileName";
|
||||
file1->node.attrib.st_dev = 15;
|
||||
file1->node.attrib.st_ino = 204;
|
||||
file1->path = "/tmp/filename";
|
||||
|
||||
iso1 = iso_file_new(file1);
|
||||
|
||||
r = iso_file_table_add_file(table, iso1);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
CU_ASSERT_EQUAL(table->count, 1);
|
||||
|
||||
iso2 = iso_file_table_lookup(table, file1);
|
||||
CU_ASSERT_PTR_NOT_NULL(iso2);
|
||||
CU_ASSERT_PTR_EQUAL(iso2, iso1);
|
||||
|
||||
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file2->node.name = "fileName2";
|
||||
file2->node.attrib.st_dev = 152;
|
||||
file2->node.attrib.st_ino = 2042;
|
||||
file2->path = "/tmp/filename2";
|
||||
|
||||
iso3 = iso_file_new(file2);
|
||||
r = iso_file_table_add_file(table, iso3);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
CU_ASSERT_EQUAL(table->count, 2);
|
||||
|
||||
/* treat to add the same file again */
|
||||
r = iso_file_table_add_file(table, iso3);
|
||||
CU_ASSERT_EQUAL(r, 0);
|
||||
CU_ASSERT_EQUAL(table->count, 2);
|
||||
|
||||
iso2 = iso_file_table_lookup(table, file1);
|
||||
CU_ASSERT_PTR_NOT_NULL(iso2);
|
||||
CU_ASSERT_PTR_EQUAL(iso2, iso1);
|
||||
|
||||
iso2 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_NOT_NULL(iso2);
|
||||
CU_ASSERT_PTR_EQUAL(iso2, iso3);
|
||||
|
||||
iso3 = iso_file_new(file2);
|
||||
r = iso_file_table_add_file(table, iso3);
|
||||
CU_ASSERT_EQUAL(r, 0);
|
||||
CU_ASSERT_EQUAL(table->count, 2);
|
||||
|
||||
iso_file_table_clear(table);
|
||||
CU_ASSERT_EQUAL(table->count, 0);
|
||||
|
||||
iso2 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_NULL(iso2);
|
||||
|
||||
free( file1 );
|
||||
free( file2 );
|
||||
free( table );
|
||||
}
|
||||
|
||||
static void test_cache_inodes()
|
||||
{
|
||||
struct iso_file_table *table;
|
||||
struct iso_tree_node_file *file1;
|
||||
struct iso_tree_node_file *file2;
|
||||
struct iso_file *iso1;
|
||||
struct iso_file *iso2;
|
||||
struct iso_file *iso3;
|
||||
int r;
|
||||
|
||||
table = iso_file_table_new(1);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL( table );
|
||||
CU_ASSERT_TRUE( table->cache_inodes );
|
||||
CU_ASSERT_EQUAL(table->count, 0);
|
||||
|
||||
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file1->node.name = "fileName";
|
||||
file1->node.attrib.st_dev = 15;
|
||||
file1->node.attrib.st_ino = 204;
|
||||
file1->path = "/tmp/filename";
|
||||
|
||||
iso1 = iso_file_new(file1);
|
||||
|
||||
r = iso_file_table_add_file(table, iso1);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
|
||||
/* another file, different but with the same inode id */
|
||||
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file2->node.name = "another file";
|
||||
file2->node.attrib.st_dev = 15;
|
||||
file2->node.attrib.st_ino = 204;
|
||||
file2->path = "/tmp/another";
|
||||
iso2 = iso_file_new(file2);
|
||||
|
||||
/* ensure it's not added again... */
|
||||
r = iso_file_table_add_file(table, iso2);
|
||||
CU_ASSERT_EQUAL(r, 0);
|
||||
|
||||
/* ...and the lookup returns the first */
|
||||
iso3 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_EQUAL(iso1, iso3);
|
||||
|
||||
free(iso2);
|
||||
free(file2);
|
||||
|
||||
/* and now a file with same inode but different device */
|
||||
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file2->node.name = "different file";
|
||||
file2->node.attrib.st_dev = 16; /* different dev id */
|
||||
file2->node.attrib.st_ino = 204;
|
||||
file2->path = "/tmp/different";
|
||||
iso2 = iso_file_new(file2);
|
||||
|
||||
r = iso_file_table_add_file(table, iso2);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
iso3 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_NOT_EQUAL(iso3, iso1);
|
||||
CU_ASSERT_PTR_EQUAL(iso3, iso2);
|
||||
|
||||
iso_file_table_clear(table);
|
||||
free( file1 );
|
||||
free( file2 );
|
||||
free( table );
|
||||
}
|
||||
|
||||
static void test_no_cache_inodes()
|
||||
{
|
||||
struct iso_file_table *table;
|
||||
struct iso_tree_node_file *file1;
|
||||
struct iso_tree_node_file *file2;
|
||||
struct iso_tree_node_file *file3;
|
||||
struct iso_file *iso1;
|
||||
struct iso_file *iso2;
|
||||
struct iso_file *iso3;
|
||||
int r;
|
||||
|
||||
table = iso_file_table_new(0);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL( table );
|
||||
CU_ASSERT_FALSE( table->cache_inodes );
|
||||
CU_ASSERT_EQUAL(table->count, 0);
|
||||
|
||||
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file1->node.name = "fileName";
|
||||
file1->node.attrib.st_dev = 15;
|
||||
file1->node.attrib.st_ino = 204;
|
||||
file1->path = "/tmp/filename";
|
||||
|
||||
iso1 = iso_file_new(file1);
|
||||
|
||||
r = iso_file_table_add_file(table, iso1);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
|
||||
/* another file, different but with the same inode id */
|
||||
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file2->node.name = "another file";
|
||||
file2->node.attrib.st_dev = 15;
|
||||
file2->node.attrib.st_ino = 204;
|
||||
file2->path = "/tmp/another";
|
||||
iso2 = iso_file_new(file2);
|
||||
|
||||
/* ensure is added */
|
||||
r = iso_file_table_add_file(table, iso2);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
|
||||
iso3 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_EQUAL(iso3, iso2);
|
||||
|
||||
/* and now a file with same inode and path */
|
||||
file3 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file3->node.name = "different file";
|
||||
file3->node.attrib.st_dev = 15;
|
||||
file3->node.attrib.st_ino = 204;
|
||||
file3->path = "/tmp/filename";
|
||||
iso3 = iso_file_new(file3);
|
||||
|
||||
r = iso_file_table_add_file(table, iso3);
|
||||
CU_ASSERT_EQUAL(r, 0);
|
||||
iso3 = iso_file_table_lookup(table, file3);
|
||||
CU_ASSERT_PTR_EQUAL(iso3, iso1);
|
||||
|
||||
iso_file_table_clear(table);
|
||||
free(file1);
|
||||
free(file2);
|
||||
free(file3);
|
||||
free(table);
|
||||
}
|
||||
|
||||
|
||||
void add_file_hashtable_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("FileHashtableSuite", NULL, NULL);
|
||||
CU_add_test(pSuite, "test of iso_file_new()", test_iso_file_new);
|
||||
CU_add_test(pSuite, "test of add and lookup", test_add_lookup);
|
||||
CU_add_test(pSuite, "test with cache_inodes", test_cache_inodes);
|
||||
CU_add_test(pSuite, "test without cache_inodes", test_no_cache_inodes);
|
||||
}
|
395
libisofs/branches/ZeroTwoEight/test/test_tree.c
Normal file
395
libisofs/branches/ZeroTwoEight/test/test_tree.c
Normal file
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Unit test for tree.h
|
||||
*/
|
||||
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "tree.h"
|
||||
#include "test.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static void test_new_root() {
|
||||
struct iso_tree_node_dir *root;
|
||||
root = iso_tree_new_root();
|
||||
CU_ASSERT_PTR_NOT_NULL(root);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 0);
|
||||
CU_ASSERT_PTR_NULL(root->children);
|
||||
CU_ASSERT_PTR_NULL(root->node.parent);
|
||||
CU_ASSERT_PTR_NULL(root->node.name);
|
||||
CU_ASSERT(S_ISDIR(root->node.attrib.st_mode) );
|
||||
}
|
||||
|
||||
static void test_add_dir() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node_dir *dir;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
CU_ASSERT_PTR_NOT_NULL(root);
|
||||
dir = iso_tree_add_dir(root, "New dir name");
|
||||
CU_ASSERT_PTR_NOT_NULL(root);
|
||||
CU_ASSERT_PTR_NOT_NULL(dir);
|
||||
CU_ASSERT_PTR_EQUAL(dir->node.parent, root);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||
CU_ASSERT_PTR_EQUAL(root->children[0], (struct iso_tree_node *)dir);
|
||||
CU_ASSERT_STRING_EQUAL( dir->node.name, "New dir name");
|
||||
CU_ASSERT( S_ISDIR(dir->node.attrib.st_mode) );
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_add_file() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node_file *file;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
file = (struct iso_tree_node_file *)
|
||||
iso_tree_add_file(root, "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_PTR_NOT_NULL(root);
|
||||
CU_ASSERT_PTR_NOT_NULL(file);
|
||||
CU_ASSERT_PTR_EQUAL(file->node.parent, root);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||
CU_ASSERT_PTR_EQUAL(root->children[0], (struct iso_tree_node *)file);
|
||||
CU_ASSERT_STRING_EQUAL( file->node.name, "README" );
|
||||
CU_ASSERT_STRING_EQUAL( file->path, "/tmp/libisofs_test/README" );
|
||||
CU_ASSERT( S_ISREG(file->node.attrib.st_mode) );
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_add_symlink() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node *lnk;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
lnk = iso_tree_add_symlink(root, "read", "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_PTR_NOT_NULL(root);
|
||||
CU_ASSERT_PTR_NOT_NULL(lnk);
|
||||
CU_ASSERT_PTR_EQUAL(lnk->parent, root);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||
CU_ASSERT_PTR_EQUAL(root->children[0], (struct iso_tree_node *)lnk);
|
||||
CU_ASSERT_STRING_EQUAL( lnk->name, "read");
|
||||
CU_ASSERT_STRING_EQUAL( ((struct iso_tree_node_symlink*)lnk)->dest,
|
||||
"/tmp/libisofs_test/README" );
|
||||
CU_ASSERT( S_ISLNK(lnk->attrib.st_mode) );
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_add_node() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
|
||||
/* test addition of a dir */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_PTR_EQUAL(node->parent, root);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||
CU_ASSERT_PTR_EQUAL(root->children[0], node);
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "dir1");
|
||||
CU_ASSERT( ISO_ISDIR(node) );
|
||||
CU_ASSERT( S_ISDIR(node->attrib.st_mode) );
|
||||
|
||||
/* test addition of a link */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_PTR_EQUAL(node->parent, root);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 2);
|
||||
CU_ASSERT_PTR_EQUAL(root->children[1], node);
|
||||
CU_ASSERT( ISO_ISLNK(node) );
|
||||
CU_ASSERT( S_ISLNK(node->attrib.st_mode) );
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "link to readme");
|
||||
CU_ASSERT_STRING_EQUAL( ((struct iso_tree_node_symlink*)node)->dest,
|
||||
"/tmp/libisofs_test/README" );
|
||||
|
||||
/* test addition of a file */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_PTR_EQUAL(node->parent, root);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||
CU_ASSERT_PTR_EQUAL(root->children[2], node);
|
||||
CU_ASSERT( S_ISREG(node->attrib.st_mode) );
|
||||
CU_ASSERT( ISO_ISREG(node) );
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "README" );
|
||||
CU_ASSERT_STRING_EQUAL( ((struct iso_tree_node_file *) node)->path,
|
||||
"/tmp/libisofs_test/README" );
|
||||
|
||||
/* test no exiting file */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/THISNOTEXIST");
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
CU_ASSERT_EQUAL(libisofs_errno, NO_FILE);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||
|
||||
/* test no valid file */
|
||||
node = iso_tree_add_node(root, "/dev/zero");
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
CU_ASSERT_EQUAL(libisofs_errno, UNEXPECTED_FILE_TYPE);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||
|
||||
/* test no read perm file */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/no_read");
|
||||
CU_ASSERT_PTR_NULL(node);
|
||||
CU_ASSERT_EQUAL(libisofs_errno, NO_READ_ACCESS);
|
||||
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_radd_dir() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node_dir *child;
|
||||
struct iso_tree_node_file *file;
|
||||
struct iso_tree_radd_dir_behavior behavior = {0,0,0};
|
||||
|
||||
//TODO write really full test
|
||||
|
||||
root = iso_tree_new_root();
|
||||
CU_ASSERT_PTR_NOT_NULL(root);
|
||||
|
||||
iso_tree_radd_dir(root, "/tmp/libisofs_test", &behavior);
|
||||
|
||||
/* test _root_ children */
|
||||
/*
|
||||
child = (struct iso_tree_node_dir *)root->children[0];
|
||||
CU_ASSERT( S_ISDIR(child->node.attrib.st_mode) );
|
||||
CU_ASSERT_EQUAL( child->nchildren, 2);
|
||||
CU_ASSERT_STRING_EQUAL( child->node.name, "dir1" );
|
||||
|
||||
child = (struct iso_tree_node_dir *)root->children[1];
|
||||
CU_ASSERT( S_ISDIR(child->node.attrib.st_mode) );
|
||||
CU_ASSERT_EQUAL( child->nchildren, 0);
|
||||
CU_ASSERT_STRING_EQUAL( child->node.name, "dir2" );
|
||||
|
||||
file = (struct iso_tree_node_file *)root->children[2];
|
||||
CU_ASSERT( S_ISREG(file->node.attrib.st_mode) );
|
||||
CU_ASSERT_STRING_EQUAL( file->node.name, "README" );
|
||||
*/
|
||||
//iso_tree_print( (struct iso_tree_node *)root, 4 );
|
||||
}
|
||||
|
||||
static void test_set_name() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
|
||||
/* test on a dir */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "dir1");
|
||||
iso_tree_node_set_name(node, "newname");
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "newname");
|
||||
|
||||
/* test on a link */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "link to readme");
|
||||
iso_tree_node_set_name(node, "new link name");
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "new link name");
|
||||
|
||||
/* test on a file */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "README" );
|
||||
iso_tree_node_set_name(node, "new file name");
|
||||
CU_ASSERT_STRING_EQUAL( node->name, "new file name");
|
||||
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_set_hidden() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
|
||||
/* test on a dir */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, 0);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_JOLIET);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
|
||||
|
||||
/* test on a link */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, 0);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_JOLIET);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
|
||||
|
||||
/* test on a file */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, 0);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_JOLIET);
|
||||
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
|
||||
CU_ASSERT_EQUAL(node->hide_flags, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
|
||||
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_set_gid() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node *node;
|
||||
gid_t mygid = getgid();
|
||||
|
||||
root = iso_tree_new_root();
|
||||
|
||||
/* test on a dir */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_gid, mygid);
|
||||
iso_tree_node_set_gid(node, 1234);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_gid, 1234);
|
||||
|
||||
/* test on a link */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_gid, mygid);
|
||||
iso_tree_node_set_gid(node, 1234);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_gid, 1234);
|
||||
|
||||
/* test on a file */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_gid, mygid);
|
||||
iso_tree_node_set_gid(node, 1234);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_gid, 1234);
|
||||
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_set_uid() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node *node;
|
||||
uid_t myuid = getuid();
|
||||
|
||||
root = iso_tree_new_root();
|
||||
|
||||
/* test on a dir */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_uid, myuid);
|
||||
iso_tree_node_set_uid(node, 1234);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_uid, 1234);
|
||||
|
||||
/* test on a link */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_uid, myuid);
|
||||
iso_tree_node_set_uid(node, 1234);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_uid, 1234);
|
||||
|
||||
/* test on a file */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_uid, myuid);
|
||||
iso_tree_node_set_uid(node, 1234);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_uid, 1234);
|
||||
|
||||
//TODO
|
||||
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_set_permissions() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
|
||||
/* test on a dir */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFDIR | 0755);
|
||||
iso_tree_node_set_permissions(node, 0777);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFDIR | 0777);
|
||||
iso_tree_node_set_permissions(node, 0744);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFDIR | 0744);
|
||||
iso_tree_node_set_permissions(node, 0411);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFDIR | 0411);
|
||||
|
||||
/* test on a link */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFLNK | 0777);
|
||||
iso_tree_node_set_permissions(node, 0555);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFLNK | 0555);
|
||||
iso_tree_node_set_permissions(node, 0744);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFLNK | 0744);
|
||||
iso_tree_node_set_permissions(node, 0411);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFLNK | 0411);
|
||||
|
||||
/* test on a file */
|
||||
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_PTR_NOT_NULL(node);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFREG | 0555);
|
||||
iso_tree_node_set_permissions(node, 0777);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFREG | 0777);
|
||||
iso_tree_node_set_permissions(node, 0744);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFREG | 0744);
|
||||
iso_tree_node_set_permissions(node, 0411);
|
||||
CU_ASSERT_EQUAL(node->attrib.st_mode, S_IFREG | 0411);
|
||||
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
static void test_set_sort_weight() {
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node_dir *dir;
|
||||
struct iso_tree_node_file *file;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
|
||||
dir = iso_tree_add_dir(root, "New dir name");
|
||||
CU_ASSERT_PTR_NOT_NULL(dir);
|
||||
|
||||
file = (struct iso_tree_node_file *)
|
||||
iso_tree_add_file(dir, "/tmp/libisofs_test/README");
|
||||
CU_ASSERT_EQUAL(file->sort_weight, 0);
|
||||
iso_tree_node_set_sort_weight((struct iso_tree_node *) file, 15);
|
||||
CU_ASSERT_EQUAL(file->sort_weight, 15);
|
||||
iso_tree_node_set_sort_weight((struct iso_tree_node *) file, -15);
|
||||
CU_ASSERT_EQUAL(file->sort_weight, -15);
|
||||
|
||||
/* changes to dir involve update files inside it */
|
||||
iso_tree_node_set_sort_weight((struct iso_tree_node *) dir, 28);
|
||||
CU_ASSERT_EQUAL(file->sort_weight, 28);
|
||||
|
||||
iso_tree_free((struct iso_tree_node *)root);
|
||||
}
|
||||
|
||||
void add_tree_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("TreeSuite", NULL, NULL);
|
||||
|
||||
CU_add_test(pSuite, "test of iso_tree_new_root()", test_new_root);
|
||||
CU_add_test(pSuite, "test of iso_tree_add_dir()", test_add_dir);
|
||||
CU_add_test(pSuite, "test of iso_tree_add_file()", test_add_file);
|
||||
CU_add_test(pSuite, "test of iso_tree_add_symlink()", test_add_symlink);
|
||||
CU_add_test(pSuite, "test of iso_tree_add_node()", test_add_node);
|
||||
CU_add_test(pSuite, "test of iso_tree_radd_dir()", test_radd_dir);
|
||||
|
||||
CU_add_test(pSuite, "test of iso_tree_node_set_name()", test_set_name);
|
||||
CU_add_test(pSuite, "test of iso_tree_node_set_hidden()", test_set_hidden);
|
||||
CU_add_test(pSuite, "test of iso_tree_node_set_gid()", test_set_gid);
|
||||
CU_add_test(pSuite, "test of iso_tree_node_set_uid()", test_set_uid);
|
||||
CU_add_test(pSuite, "test of iso_tree_node_set_permissions()", test_set_permissions);
|
||||
CU_add_test(pSuite, "test of iso_tree_node_set_sort_weight()", test_set_sort_weight);
|
||||
}
|
265
libisofs/branches/ZeroTwoEight/test/test_util.c
Normal file
265
libisofs/branches/ZeroTwoEight/test/test_util.c
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Unit test for util.h
|
||||
*
|
||||
* This test utiliy functions
|
||||
*
|
||||
*/
|
||||
#include "test.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
static void test_div_up()
|
||||
{
|
||||
CU_ASSERT_EQUAL( div_up(1, 2), 1 );
|
||||
CU_ASSERT_EQUAL( div_up(2, 2), 1 );
|
||||
CU_ASSERT_EQUAL( div_up(0, 2), 0 );
|
||||
CU_ASSERT_EQUAL( div_up(-1, 2), 0 );
|
||||
CU_ASSERT_EQUAL( div_up(3, 2), 2 );
|
||||
}
|
||||
|
||||
static void test_round_up()
|
||||
{
|
||||
CU_ASSERT_EQUAL( round_up(1, 2), 2 );
|
||||
CU_ASSERT_EQUAL( round_up(2, 2), 2 );
|
||||
CU_ASSERT_EQUAL( round_up(0, 2), 0 );
|
||||
CU_ASSERT_EQUAL( round_up(-1, 2), 0 );
|
||||
CU_ASSERT_EQUAL( round_up(3, 2), 4 );
|
||||
CU_ASSERT_EQUAL( round_up(15, 7), 21 );
|
||||
CU_ASSERT_EQUAL( round_up(13, 7), 14 );
|
||||
CU_ASSERT_EQUAL( round_up(14, 7), 14 );
|
||||
}
|
||||
|
||||
static void test_iso_lsb_msb()
|
||||
{
|
||||
uint8_t buf[4];
|
||||
uint32_t num;
|
||||
|
||||
num = 0x01020304;
|
||||
iso_lsb(buf, num, 4);
|
||||
CU_ASSERT_EQUAL( buf[0], 0x04 );
|
||||
CU_ASSERT_EQUAL( buf[1], 0x03 );
|
||||
CU_ASSERT_EQUAL( buf[2], 0x02 );
|
||||
CU_ASSERT_EQUAL( buf[3], 0x01 );
|
||||
|
||||
iso_msb(buf, num, 4);
|
||||
CU_ASSERT_EQUAL( buf[0], 0x01 );
|
||||
CU_ASSERT_EQUAL( buf[1], 0x02 );
|
||||
CU_ASSERT_EQUAL( buf[2], 0x03 );
|
||||
CU_ASSERT_EQUAL( buf[3], 0x04 );
|
||||
|
||||
iso_lsb(buf, num, 2);
|
||||
CU_ASSERT_EQUAL( buf[0], 0x04 );
|
||||
CU_ASSERT_EQUAL( buf[1], 0x03 );
|
||||
|
||||
iso_msb(buf, num, 2);
|
||||
CU_ASSERT_EQUAL( buf[0], 0x03 );
|
||||
CU_ASSERT_EQUAL( buf[1], 0x04 );
|
||||
}
|
||||
|
||||
static void test_iso_1_dirid()
|
||||
{
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dir1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dIR1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("DIR1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dirwithbigname", "UTF-8"), "DIRWITHB");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dirwith8", "UTF-8"), "DIRWITH8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dir.1", "UTF-8"), "DIR_1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("4f<0KmM::xcvf", "UTF-8"), "4F_0KMM_");
|
||||
}
|
||||
|
||||
static void test_iso_2_dirid()
|
||||
{
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dir1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dIR1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("DIR1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dirwithbigname", "UTF-8"), "DIRWITHBIGNAME");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dirwith8", "UTF-8"), "DIRWITH8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dir.1", "UTF-8"), "DIR_1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("4f<0KmM::xcvf", "UTF-8"), "4F_0KMM__XCVF");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("directory with 31 characters ok", "UTF-8"), "DIRECTORY_WITH_31_CHARACTERS_OK");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("directory with more than 31 characters", "UTF-8"), "DIRECTORY_WITH_MORE_THAN_31_CHA");
|
||||
}
|
||||
|
||||
static void test_iso_r_dirid()
|
||||
{
|
||||
int flag;
|
||||
|
||||
/* 1. only ECMA119_37_CHAR_FILENAMES */
|
||||
flag = ECMA119_37_CHAR_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "DIRWITHBIGNAME");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "DIRWITH8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "DIR_1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4F_0KMM__XCVF");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "DIRECTORY_WITH_31_CHARACTERS_OK");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "DIRECTORY_WITH_MORE_THAN_37_CHARACTER");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "DIRECTORY_WITH_JUST_37_CHARACTERS__OK");
|
||||
|
||||
/* 2. only ECMA119_RELAXED_FILENAMES */
|
||||
flag = ECMA119_RELAXED_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "dir1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "dIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "dirwithbigname");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "dirwith8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "dir.1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4f<0KmM::xcvf");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "directory with 31 characters ok");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "directory with more than 37 cha");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "directory with just 37 characte");
|
||||
|
||||
/* 3. both ECMA119_RELAXED_FILENAMES and ECMA119_37_CHAR_FILENAMES */
|
||||
flag = ECMA119_RELAXED_FILENAMES | ECMA119_37_CHAR_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "dir1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "dIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "dirwithbigname");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "dirwith8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "dir.1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4f<0KmM::xcvf");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "directory with 31 characters ok");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "directory with more than 37 character");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "directory with just 37 characters ok");
|
||||
}
|
||||
|
||||
static void test_iso_1_fileid()
|
||||
{
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fILe1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("FILE1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid(".EXT", "UTF-8"), ".EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ext", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fiLE.ext", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.EXt", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("FILE.EXT", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename", "UTF-8"), "BIGFILEN.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.ext", "UTF-8"), "BIGFILEN.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.e", "UTF-8"), "BIGFILEN.E;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.bigext", "UTF-8"), "FILE.BIG;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid(".bigext", "UTF-8"), ".BIG;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.bigext", "UTF-8"), "BIGFILEN.BIG;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file<:a.ext", "UTF-8"), "FILE__A.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.<:a", "UTF-8"), "FILE.__A;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file<:a.--a", "UTF-8"), "FILE__A.__A;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ex1.ex2", "UTF-8"), "FILE_EX1.EX2;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ex1.ex2.ex3", "UTF-8"), "FILE_EX1.EX3;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fil.ex1.ex2.ex3", "UTF-8"), "FIL_EX1_.EX3;1");
|
||||
}
|
||||
|
||||
static void test_iso_2_fileid()
|
||||
{
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fILe1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("FILE1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".EXT", "UTF-8"), ".EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ext", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fiLE.ext", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.EXt", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("FILE.EXT", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename", "UTF-8"), "BIGFILENAME.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.ext", "UTF-8"), "BIGFILENAME.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.e", "UTF-8"), "BIGFILENAME.E;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("31 characters filename.extensio", "UTF-8"), "31_CHARACTERS_FILENAME.EXTENSIO;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("32 characters filename.extension", "UTF-8"), "32_CHARACTERS_FILENAME.EXTENSIO;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("more than 30 characters filename.extension", "UTF-8"), "MORE_THAN_30_CHARACTERS_FIL.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.bigext", "UTF-8"), "FILE.BIGEXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".bigext", "UTF-8"), ".BIGEXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.bigext", "UTF-8"), "BIGFILENAME.BIGEXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file<:a.ext", "UTF-8"), "FILE__A.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.<:a", "UTF-8"), "FILE.__A;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file<:a.--a", "UTF-8"), "FILE__A.__A;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ex1.ex2", "UTF-8"), "FILE_EX1.EX2;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ex1.ex2.ex3", "UTF-8"), "FILE_EX1_EX2.EX3;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fil.ex1.ex2.ex3", "UTF-8"), "FIL_EX1_EX2.EX3;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".file.bigext", "UTF-8"), "_FILE.BIGEXT;1");
|
||||
}
|
||||
|
||||
static void test_iso_r_fileid()
|
||||
{
|
||||
int flag;
|
||||
|
||||
/* 1. only ECMA119_OMIT_VERSION_NUMBERS */
|
||||
flag = ECMA119_OMIT_VERSION_NUMBERS;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31_CHARACTERS_FILENAME.EXTENSIO");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "IT_S_37_CHARACTERS_FILENAME.EXT");
|
||||
|
||||
/* 2. only ECMA119_37_CHAR_FILENAMES */
|
||||
flag = ECMA119_37_CHAR_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "BIGFILENAME.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "BIGFILENAME.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "BIGFILENAME.E");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "FILE.BIGEXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31_CHARACTERS_FILENAME.EXTENSIO");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "IT_S_37_CHARACTERS_FILENAME.EXTENSION");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("more than 37 characters filename.extension", "UTF-8", flag), "MORE_THAN_37_CHARACTERS_FILENAME.EXTE");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "FILE.THIS_IS_A_37_CHARS_LEN_EXTENSION");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a very very big extension", "UTF-8", flag), "FILE.THIS_IS_A_VERY_VERY_BIG_EXTENSIO");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "FIL_EX1_EX2.EX3");
|
||||
|
||||
/* 3. only ECMA119_RELAXED_FILENAMES */
|
||||
flag = ECMA119_RELAXED_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "file1;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "fILe1;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "file.ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "fiLE.ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "file.EXt;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "bigfilename;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "bigfilename.ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "bigfilename.e;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "file.bigext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31 characters filename.extensio;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "it's 37 characters filename.ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "file.this is a 37 chars len ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "fil.ex1.ex2.ex3;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.<:a", "UTF-8", flag), "file.<:a;1");
|
||||
|
||||
/* 3. ECMA119_RELAXED_FILENAMES and ECMA119_OMIT_VERSION_NUMBERS*/
|
||||
flag = ECMA119_RELAXED_FILENAMES | ECMA119_OMIT_VERSION_NUMBERS;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "file1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "fILe1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "file.ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "fiLE.ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "file.EXt");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "bigfilename");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "bigfilename.ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "bigfilename.e");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "file.bigext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31 characters filename.extensio");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "it's 37 characters filename.ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "file.this is a 37 chars len ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "fil.ex1.ex2.ex3");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.<:a", "UTF-8", flag), "file.<:a");
|
||||
}
|
||||
|
||||
void add_util_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("UtilSuite", NULL, NULL);
|
||||
|
||||
CU_add_test(pSuite, "test of div_up()", test_div_up);
|
||||
CU_add_test(pSuite, "test of round_up()", test_round_up);
|
||||
CU_add_test(pSuite, "test of iso_lsb_msb()", test_iso_lsb_msb);
|
||||
CU_add_test(pSuite, "test of iso_1_dirid()", test_iso_1_dirid);
|
||||
CU_add_test(pSuite, "test of iso_2_dirid()", test_iso_2_dirid);
|
||||
CU_add_test(pSuite, "test of iso_r_dirid()", test_iso_r_dirid);
|
||||
CU_add_test(pSuite, "test of iso_1_fileid()", test_iso_1_fileid);
|
||||
CU_add_test(pSuite, "test of iso_2_fileid()", test_iso_2_fileid);
|
||||
CU_add_test(pSuite, "test of iso_r_fileid()", test_iso_r_fileid);
|
||||
}
|
238
libisofs/branches/ZeroTwoEight/test/test_volume.c
Normal file
238
libisofs/branches/ZeroTwoEight/test/test_volume.c
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Unit test for volume.h
|
||||
*/
|
||||
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "tree.h"
|
||||
#include "test.h"
|
||||
#include "volume.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static void test_iso_volume_new()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NOT_NULL(volume);
|
||||
CU_ASSERT_EQUAL(volume->refcount, 1);
|
||||
/* a new root must be created */
|
||||
CU_ASSERT_PTR_NOT_NULL(volume->root);
|
||||
|
||||
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
|
||||
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
|
||||
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
|
||||
|
||||
CU_ASSERT_PTR_NULL(volume->system_id);
|
||||
CU_ASSERT_PTR_NULL(volume->application_id);
|
||||
CU_ASSERT_PTR_NULL(volume->copyright_file_id);
|
||||
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
|
||||
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
|
||||
|
||||
CU_ASSERT_PTR_NULL(volume->bootcat);
|
||||
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_new_with_root()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
struct iso_tree_node_dir *root;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
volume = iso_volume_new_with_root("volume_id", "publisher_id",
|
||||
"data_preparer_id", root);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(volume);
|
||||
CU_ASSERT_EQUAL(volume->refcount, 1);
|
||||
CU_ASSERT_PTR_NOT_NULL(volume->root);
|
||||
CU_ASSERT_PTR_EQUAL(volume->root, root);
|
||||
|
||||
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
|
||||
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
|
||||
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
|
||||
|
||||
CU_ASSERT_PTR_NULL(volume->system_id);
|
||||
CU_ASSERT_PTR_NULL(volume->application_id);
|
||||
CU_ASSERT_PTR_NULL(volume->copyright_file_id);
|
||||
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
|
||||
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
|
||||
|
||||
CU_ASSERT_PTR_NULL(volume->bootcat);
|
||||
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_get_root()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node_dir *root2;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
volume = iso_volume_new_with_root("volume_id", "publisher_id",
|
||||
"data_preparer_id", root);
|
||||
|
||||
root2 = iso_volume_get_root(volume);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(root2);
|
||||
CU_ASSERT_PTR_EQUAL(root2, volume->root);
|
||||
CU_ASSERT_PTR_EQUAL(root2, root);
|
||||
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_set_volume_id()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
|
||||
|
||||
char *volid = "new volume id";
|
||||
iso_volume_set_volume_id(volume, volid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->volume_id, "new volume id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->volume_id, volid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_set_publisher_id()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
|
||||
|
||||
char *pubid = "new publisher id";
|
||||
iso_volume_set_publisher_id(volume, pubid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "new publisher id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->publisher_id, pubid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_set_data_preparer_id()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
|
||||
|
||||
char *dpid = "new data preparer id";
|
||||
iso_volume_set_data_preparer_id(volume, dpid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "new data preparer id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->data_preparer_id, dpid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_set_system_id()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NULL(volume->system_id);
|
||||
|
||||
char *sysid = "new system id";
|
||||
iso_volume_set_system_id(volume, sysid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->system_id, "new system id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->system_id, sysid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_set_application_id()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NULL(volume->application_id);
|
||||
|
||||
char *appid = "new application id";
|
||||
iso_volume_set_application_id(volume, appid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->application_id, "new application id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->application_id, appid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_set_abstract_file_id()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
|
||||
|
||||
char *absid = "new abstract id";
|
||||
iso_volume_set_abstract_file_id(volume, absid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->abstract_file_id, "new abstract id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->abstract_file_id, absid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_set_biblio_file_id()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
|
||||
|
||||
char *bibid = "new biblio id";
|
||||
iso_volume_set_biblio_file_id(volume, bibid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->biblio_file_id, "new biblio id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->biblio_file_id, bibid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volset_new()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
struct iso_volset *volset;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
|
||||
volset = iso_volset_new(volume, "volset_id");
|
||||
CU_ASSERT_PTR_NOT_NULL(volset);
|
||||
CU_ASSERT_EQUAL(volset->refcount, 1);
|
||||
CU_ASSERT_EQUAL(volset->volset_size, 1);
|
||||
CU_ASSERT_PTR_NOT_NULL(volset->volume);
|
||||
CU_ASSERT_PTR_NOT_NULL(volset->volume[0]);
|
||||
CU_ASSERT_PTR_EQUAL(volset->volume[0], volume);
|
||||
CU_ASSERT_STRING_EQUAL( volset->volset_id, "volset_id" );
|
||||
|
||||
iso_volset_free(volset);
|
||||
}
|
||||
|
||||
void add_volume_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("VolumeSuite", NULL, NULL);
|
||||
|
||||
CU_add_test(pSuite, "test of iso_volume_new()", test_iso_volume_new);
|
||||
CU_add_test(pSuite, "test of iso_volume_new_with_root()", test_iso_volume_new_with_root);
|
||||
CU_add_test(pSuite, "test of iso_volume_get_root()", test_iso_volume_get_root);
|
||||
CU_add_test(pSuite, "test of iso_volume_set_volume_id()", test_iso_volume_set_volume_id);
|
||||
CU_add_test(pSuite, "test of iso_volume_set_publisher_id()", test_iso_volume_set_publisher_id);
|
||||
CU_add_test(pSuite, "test of iso_volume_set_data_preparer_id()", test_iso_volume_set_data_preparer_id);
|
||||
CU_add_test(pSuite, "test of iso_volume_set_system_id()", test_iso_volume_set_system_id);
|
||||
CU_add_test(pSuite, "test of iso_volume_set_application_id()", test_iso_volume_set_application_id);
|
||||
CU_add_test(pSuite, "test of iso_volume_set_abstract_file_id()", test_iso_volume_set_abstract_file_id);
|
||||
CU_add_test(pSuite, "test of iso_volume_set_biblio_file_id()", test_iso_volume_set_biblio_file_id);
|
||||
CU_add_test(pSuite, "test of iso_volset_new()", test_iso_volset_new);
|
||||
}
|
77
libisofs/branches/ZeroTwoEight/test/tree.py
Normal file
77
libisofs/branches/ZeroTwoEight/test/tree.py
Normal file
@ -0,0 +1,77 @@
|
||||
# a module to help with handling of filenames, directory trees, etc.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import stat
|
||||
|
||||
def pathsubtract(a, b):
|
||||
index = a.find(b)
|
||||
if index == -1:
|
||||
return None
|
||||
res = a[ (index + len(b)): ]
|
||||
|
||||
if res.find("/") == 0:
|
||||
res = res[1:]
|
||||
return res
|
||||
|
||||
# same as C strcmp()
|
||||
def strcmp(a, b):
|
||||
if a < b:
|
||||
return -1
|
||||
if a > b:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
class TreeNode:
|
||||
|
||||
# path is the location of the file/directory. It is either a full path or
|
||||
# a path relative to $PWD
|
||||
def __init__(self, parent, path=".", root=".", isofile=None):
|
||||
if isofile:
|
||||
self.root = os.path.abspath(isofile)
|
||||
self.path = ""
|
||||
else:
|
||||
fullpath = os.path.abspath( path )
|
||||
fullroot = os.path.abspath( root )
|
||||
self.root = fullroot
|
||||
self.path = pathsubtract( fullpath, fullroot )
|
||||
self.parent = parent
|
||||
self.children = []
|
||||
|
||||
if self.path == None:
|
||||
raise NameError, "Invalid paths %s and %s" % (fullpath, fullroot)
|
||||
|
||||
# if this is a directory, add its children recursively
|
||||
def addchildren(self):
|
||||
if not stat.S_ISDIR( os.lstat(self.root + "/" + self.path).st_mode ):
|
||||
return
|
||||
|
||||
children = os.listdir( self.root + "/" + self.path )
|
||||
for child in children:
|
||||
if self.path:
|
||||
child = self.path + "/" + child
|
||||
self.children.append( TreeNode(self, child, self.root) )
|
||||
for child in self.children:
|
||||
child.addchildren()
|
||||
|
||||
def printAll(self, spaces=0):
|
||||
print " "*spaces + self.root + "/" + self.path
|
||||
for child in self.children:
|
||||
child.printAll(spaces + 2)
|
||||
|
||||
def isValidISO1(self):
|
||||
pass
|
||||
|
||||
class Tree:
|
||||
def __init__(self, root=None, isofile=None):
|
||||
if isofile:
|
||||
self.root = TreeNode(parent=None, isofile=isofile)
|
||||
else:
|
||||
self.root = TreeNode(parent=None, path=root, root=root)
|
||||
self.root.addchildren()
|
||||
|
||||
def isValidISO1(self):
|
||||
return root.isValidISO1();
|
||||
|
||||
#t = Tree(root=".")
|
||||
#t.root.printAll()
|
3
libisofs/branches/ZeroTwoEight/version.h.in
Normal file
3
libisofs/branches/ZeroTwoEight/version.h.in
Normal file
@ -0,0 +1,3 @@
|
||||
#define BURN_MAJOR_VERSION @BURN_MAJOR_VERSION@
|
||||
#define BURN_MINOR_VERSION @BURN_MINOR_VERSION@
|
||||
#define BURN_MICRO_VERSION @BURN_MICRO_VERSION@
|
@ -18,6 +18,12 @@ static size_t calc_dirent_len(struct ecma119_tree_node *n)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the file permissions and user/group id of an ECMA-119 node.
|
||||
* This is used when a replace mode is selected, i.e., when we want to
|
||||
* create a disc where the mode of each file or directory will be
|
||||
* different than the mode in the original source.
|
||||
*/
|
||||
static void
|
||||
replace_node_mode(struct ecma119_write_target *t, struct stat *st)
|
||||
{
|
||||
@ -65,6 +71,19 @@ replace_node_mode(struct ecma119_write_target *t, struct stat *st)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ECMA-119 node from the given iso tree node, and initializes
|
||||
* the fields that are common to all kind of nodes (dir, reg file, symlink...).
|
||||
*
|
||||
* @param t
|
||||
* The options for the ECMA-119 tree that is being created
|
||||
* @param parent
|
||||
* The parent of the node, or NULL if it's the root.
|
||||
* @param iso
|
||||
* The node from which this function creates a ECMA-119 node
|
||||
* @return
|
||||
* The created node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_ecma119_node(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
@ -92,13 +111,22 @@ create_ecma119_node(struct ecma119_write_target *t,
|
||||
iso_name(iso->name, t->input_charset)
|
||||
) : NULL;
|
||||
ret->dirent_len = calc_dirent_len(ret);
|
||||
|
||||
/* iso node keeps the same file attribs as the original file. */
|
||||
ret->attrib = iso->attrib;
|
||||
|
||||
/*
|
||||
* When using RR extension and replace mode, we will replace the
|
||||
* permissions and uid/gid of each file with those previously selected
|
||||
* by the user.
|
||||
*/
|
||||
if ( t->rockridge && t->replace_mode )
|
||||
replace_node_mode(t, &ret->attrib);
|
||||
|
||||
if (!iso->name)
|
||||
ret->full_name = NULL;
|
||||
else if ( strcmp(t->input_charset,t->ouput_charset) )
|
||||
/* convert the file name charset */
|
||||
ret->full_name = convert_str(iso->name, t->input_charset,
|
||||
t->ouput_charset);
|
||||
else
|
||||
@ -108,6 +136,10 @@ create_ecma119_node(struct ecma119_write_target *t,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a directory from a iso directory
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_dir(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
@ -127,6 +159,10 @@ create_dir(struct ecma119_write_target *t,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a regular file from a iso file
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_file(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
@ -143,6 +179,10 @@ create_file(struct ecma119_write_target *t,
|
||||
/* get iso_file struct */
|
||||
file = iso_file_table_lookup(t->file_table, iso);
|
||||
if ( file == NULL ) {
|
||||
/*
|
||||
* If the file is not already added to the disc, we add it now
|
||||
* to the file table, and get a new inode number for it.
|
||||
*/
|
||||
file = iso_file_new(iso);
|
||||
iso_file_table_add_file(t->file_table, file);
|
||||
file->ino = ++t->ino;
|
||||
@ -157,6 +197,12 @@ create_file(struct ecma119_write_target *t,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a placeholder for a relocated
|
||||
* dir.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5 for details
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_placeholder(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
@ -191,6 +237,10 @@ create_placeholder(struct ecma119_write_target *t,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a symbolic link from a iso symlink
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_symlink(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
@ -212,6 +262,14 @@ create_symlink(struct ecma119_write_target *t,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a boot catalog. This is like a
|
||||
* regular file, but its contents are taken from a El-Torito boot catalog,
|
||||
* and not from a file in the local filesystem.
|
||||
*
|
||||
* See "El Torito" Bootable CD-ROM Format Specification Version 1.0 for
|
||||
* more details.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_boot_catalog(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
@ -239,6 +297,11 @@ create_boot_catalog(struct ecma119_write_target *t,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node that corresponds to the given iso tree node.
|
||||
* If that node is a dir, this function recurses over all their children,
|
||||
* thus creating a ECMA-119 tree whose root is the given iso dir.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_tree(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
@ -316,6 +379,12 @@ max_child_name_len(struct ecma119_tree_node *root)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Relocates a directory, as specified in Rock Ridge Specification
|
||||
* (see IEEE P1282, section 4.1.5). This is needed when the number of levels
|
||||
* on a directory hierarchy exceeds 8, or the length of a path is higher
|
||||
* than 255 characters, as specified in ECMA-119, section 6.8.2.1
|
||||
*/
|
||||
static void
|
||||
reparent(struct ecma119_tree_node *child,
|
||||
struct ecma119_tree_node *parent)
|
||||
@ -350,6 +419,8 @@ reparent(struct ecma119_tree_node *child,
|
||||
* Reorder the tree, if necessary, to ensure that
|
||||
* - the depth is at most 8
|
||||
* - each path length is at most 255 characters
|
||||
* This restriction is imposed by ECMA-119 specification (see ECMA-119,
|
||||
* 6.8.2.1).
|
||||
*/
|
||||
static void
|
||||
reorder_tree(struct ecma119_write_target *t,
|
||||
@ -400,6 +471,9 @@ reorder_tree(struct ecma119_write_target *t,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the iso name of two ECMA-119 nodes
|
||||
*/
|
||||
static int
|
||||
cmp_node(const void *f1, const void *f2)
|
||||
{
|
||||
@ -408,6 +482,10 @@ cmp_node(const void *f1, const void *f2)
|
||||
return strcmp(f->iso_name, g->iso_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts a the children of each directory in the ECMA-119 tree represented
|
||||
* by \p root, acording to the order specified in ECMA-119, section 9.3.
|
||||
*/
|
||||
static void
|
||||
sort_tree(struct ecma119_tree_node *root)
|
||||
{
|
||||
@ -470,6 +548,10 @@ mangle_name(char **name, int num_change, int level, int seq_num)
|
||||
sprintf(*name, fmt, base, seq_num, ext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the ISO name of each children of the given dir is unique,
|
||||
* changing some of them if needed.
|
||||
*/
|
||||
static void
|
||||
mangle_all(struct ecma119_tree_node *dir)
|
||||
{
|
||||
|
@ -14,6 +14,30 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
|
||||
void
|
||||
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||
{
|
||||
unsigned char *ER = malloc(182);
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
ER[0] = 'E';
|
||||
ER[1] = 'R';
|
||||
ER[2] = 182;
|
||||
ER[3] = 1;
|
||||
ER[4] = 9;
|
||||
ER[5] = 72;
|
||||
ER[6] = 93;
|
||||
ER[7] = 1;
|
||||
memcpy(&ER[8], "IEEE_1282", 9);
|
||||
memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
|
||||
"FILE SYSTEM SEMANTICS.", 72);
|
||||
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
|
||||
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
|
||||
susp_append(t, &dir->info.dir.self_susp, ER);
|
||||
}
|
||||
|
||||
/* create a PX field from the permissions on the current node. */
|
||||
uint8_t *rrip_make_PX(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *node)
|
||||
|
@ -1,6 +1,11 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/** Functions and structures used for Rock Ridge support. */
|
||||
/**
|
||||
* Functions and structures used for Rock Ridge support.
|
||||
*
|
||||
* See IEEE P1282, Rock Ridge Interchange Protocol, Draft Standard version
|
||||
* 1.12 for further details.
|
||||
*/
|
||||
|
||||
#ifndef ISO_ROCKRIDGE_H
|
||||
#define ISO_ROCKRIDGE_H
|
||||
@ -8,18 +13,99 @@
|
||||
struct ecma119_write_target;
|
||||
struct ecma119_tree_node;
|
||||
|
||||
/**
|
||||
* Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification.
|
||||
*
|
||||
* The "ER" System Use Entry is used to uniquely identify a specification
|
||||
* compliant with SUSP. This method adds to the given tree node "." entry
|
||||
* the "ER" corresponding to the RR protocol.
|
||||
*
|
||||
* See IEEE P1281, section 5.5 and IEEE P1282, section 4.3 for more details.
|
||||
*/
|
||||
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PX System Use Entry to the given tree node and, if that node is
|
||||
* a directory, to its "." and ".." entries. The PX System Use Entry is
|
||||
* used to add POSIX file attributes, such as access permissions or user and
|
||||
* group id, to a ECMA 119 directory record.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.1 for more details.
|
||||
*/
|
||||
void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PN System Use Entry to the given tree node.
|
||||
* The PN System Use Entry is used to store the device number, and it's
|
||||
* mandatory if the tree node corresponds to a character or block device.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.2 for more details.
|
||||
*/
|
||||
void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a SL System Use Entry to the given tree node. This is used to store
|
||||
* the content of a symbolic link, and is mandatory if the tree node
|
||||
* indicates a symbolic link.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.3 for more details.
|
||||
*/
|
||||
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a NM System Use Entry to the given tree node. The purpose of this
|
||||
* System Use Entry is to store the content of an Alternate Name to support
|
||||
* POSIX-style or other names.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.4 for more details.
|
||||
*/
|
||||
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/*
|
||||
* The next 3 System Use Entries are used to handle Deep Directory
|
||||
* Hierarchies, i.e., hierarchies where the number of directory levels
|
||||
* exceed the eight limit of ECMA-119.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add to the given tree node a CL System Use Entry, that is used to record
|
||||
* the new location of a directory which has been relocated.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.1 for more details.
|
||||
*/
|
||||
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PL System Use Entry, used to record the location of the original
|
||||
* parent directory of a directory which has been relocated.
|
||||
*
|
||||
* This is special because it doesn't modify the susp fields of the directory
|
||||
* that gets passed to it; it modifies the susp fields of the ".." entry in
|
||||
* that directory.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.2 for more details.
|
||||
*/
|
||||
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a RE System Use Entry to the given tree node. The purpose of the
|
||||
* this System Use Entry is to indicate to an RRIP-compliant receiving
|
||||
* system that the Directory Record in which an "RE" System Use Entry is
|
||||
* recorded has been relocated from another position in the original
|
||||
* Directory Hierarchy.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.3 for more details.
|
||||
*/
|
||||
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add to the given tree node a TF System Use Entry, used to record some
|
||||
* time stamps related to the file.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.6 for more details.
|
||||
*/
|
||||
void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/* This is special because it doesn't modify the susp fields of the directory
|
||||
* that gets passed to it; it modifies the susp fields of the ".." entry in
|
||||
* that directory. */
|
||||
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
|
@ -155,30 +155,6 @@ static void susp_add_ST(struct ecma119_write_target *t,
|
||||
}
|
||||
#endif
|
||||
|
||||
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
|
||||
void
|
||||
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||
{
|
||||
unsigned char *ER = malloc(182);
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
ER[0] = 'E';
|
||||
ER[1] = 'R';
|
||||
ER[2] = 182;
|
||||
ER[3] = 1;
|
||||
ER[4] = 9;
|
||||
ER[5] = 72;
|
||||
ER[6] = 93;
|
||||
ER[7] = 1;
|
||||
memcpy(&ER[8], "IEEE_1282", 9);
|
||||
memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
|
||||
"FILE SYSTEM SEMANTICS.", 72);
|
||||
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
|
||||
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
|
||||
susp_append(t, &dir->info.dir.self_susp, ER);
|
||||
}
|
||||
|
||||
/* calculate the location of the CE areas. Since CE areas don't need to be
|
||||
* aligned to a block boundary, we contatenate all CE areas from a single
|
||||
* directory and dump them immediately after all the directory records.
|
||||
|
@ -1,6 +1,10 @@
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/** Functions and structures used for SUSP (IEEE 1281).
|
||||
/**
|
||||
* Functions and structures used for SUSP (IEEE 1281).
|
||||
*
|
||||
* Please refer to IEEE P1281 System Use Sharing Protocol, draft standard
|
||||
* version 1.12 for more details.
|
||||
*/
|
||||
|
||||
#ifndef __ISO_SUSP
|
||||
@ -28,13 +32,23 @@ struct susp_info
|
||||
* will go in a CE area. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a CE System Use Entry to the given tree node. A "CE" is used to add
|
||||
* a continuation area, where additional System Use Entry can be written.
|
||||
* See IEEE P1281, section 5.1.
|
||||
*/
|
||||
void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/* these next 2 are special because they don't modify the susp fields of the
|
||||
* directory; they modify the susp fields of the
|
||||
* "." entry in the directory. */
|
||||
/**
|
||||
* Add a SP System Use Entry to the "." entry of the directory. The SP provide
|
||||
* an identifier that the SUSP is used within the volume. The SP shall be
|
||||
* recorded in the "." entry of the root directory.
|
||||
* See IEEE P1281, section 5.3 for more details.
|
||||
*
|
||||
* this is special because it doesn't modify the susp fields of the
|
||||
* directory; it modifies the susp fields of the "." entry in the directory.
|
||||
*/
|
||||
void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/** Once all the directories and files are laid out, recurse through the tree
|
||||
* and finalize all SUSP CE entries. */
|
||||
|
Loading…
Reference in New Issue
Block a user