Effective base of libisoburn+xorriso 0.1.1 2008.02.22.124732
This commit is contained in:
parent
9bd4531ed1
commit
da6e25e5c8
|
@ -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
|
|
@ -0,0 +1,19 @@
|
||||||
|
Vreixo Formoso <metalpain2002@yahoo.es>,
|
||||||
|
Mario Danic <mario.danic@gmail.com>,
|
||||||
|
Thomas Schmitt <scdbackup@gmx.net>
|
||||||
|
Copyright (C) 2007-2008 Vreixo Formoso, 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
|
|
@ -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.
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
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/builder.h \
|
||||||
|
libisofs/builder.c \
|
||||||
|
libisofs/node.h \
|
||||||
|
libisofs/node.c \
|
||||||
|
libisofs/tree.h \
|
||||||
|
libisofs/tree.c \
|
||||||
|
libisofs/image.h \
|
||||||
|
libisofs/image.c \
|
||||||
|
libisofs/fsource.h \
|
||||||
|
libisofs/fsource.c \
|
||||||
|
libisofs/fs_local.c \
|
||||||
|
libisofs/fs_image.c \
|
||||||
|
libisofs/messages.h \
|
||||||
|
libisofs/messages.c \
|
||||||
|
libisofs/libiso_msgs.h \
|
||||||
|
libisofs/libiso_msgs.c \
|
||||||
|
libisofs/stream.h \
|
||||||
|
libisofs/stream.c \
|
||||||
|
libisofs/util.h \
|
||||||
|
libisofs/util.c \
|
||||||
|
libisofs/util_rbtree.c \
|
||||||
|
libisofs/util_htable.c \
|
||||||
|
libisofs/filesrc.h \
|
||||||
|
libisofs/filesrc.c \
|
||||||
|
libisofs/ecma119.h \
|
||||||
|
libisofs/ecma119.c \
|
||||||
|
libisofs/ecma119_tree.h \
|
||||||
|
libisofs/ecma119_tree.c \
|
||||||
|
libisofs/writer.h \
|
||||||
|
libisofs/buffer.h \
|
||||||
|
libisofs/buffer.c \
|
||||||
|
libisofs/rockridge.h \
|
||||||
|
libisofs/rockridge.c \
|
||||||
|
libisofs/rockridge_read.c \
|
||||||
|
libisofs/joliet.h \
|
||||||
|
libisofs/joliet.c \
|
||||||
|
libisofs/eltorito.h \
|
||||||
|
libisofs/eltorito.c \
|
||||||
|
libisofs/iso1999.h \
|
||||||
|
libisofs/iso1999.c \
|
||||||
|
libisofs/data_source.c
|
||||||
|
libinclude_HEADERS = \
|
||||||
|
libisofs/libisofs.h
|
||||||
|
|
||||||
|
## ========================================================================= ##
|
||||||
|
|
||||||
|
## Build demo applications
|
||||||
|
noinst_PROGRAMS = \
|
||||||
|
demo/lsl \
|
||||||
|
demo/cat \
|
||||||
|
demo/catbuffer \
|
||||||
|
demo/tree \
|
||||||
|
demo/ecma119tree \
|
||||||
|
demo/iso \
|
||||||
|
demo/isoread \
|
||||||
|
demo/isocat \
|
||||||
|
demo/isomodify \
|
||||||
|
demo/isoms \
|
||||||
|
demo/isogrow
|
||||||
|
|
||||||
|
demo_lsl_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_lsl_SOURCES = demo/lsl.c
|
||||||
|
|
||||||
|
demo_cat_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_cat_SOURCES = demo/cat.c
|
||||||
|
|
||||||
|
demo_catbuffer_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_catbuffer_SOURCES = demo/cat_buffer.c
|
||||||
|
|
||||||
|
demo_tree_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_tree_SOURCES = demo/tree.c
|
||||||
|
|
||||||
|
demo_ecma119tree_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_ecma119tree_SOURCES = demo/ecma119_tree.c
|
||||||
|
|
||||||
|
demo_iso_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_iso_SOURCES = demo/iso.c
|
||||||
|
|
||||||
|
demo_isoread_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_isoread_SOURCES = demo/iso_read.c
|
||||||
|
|
||||||
|
demo_isocat_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_isocat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_isocat_SOURCES = demo/iso_cat.c
|
||||||
|
|
||||||
|
demo_isomodify_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_isomodify_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_isomodify_SOURCES = demo/iso_modify.c
|
||||||
|
|
||||||
|
demo_isoms_CPPFLAGS = -Ilibisofs
|
||||||
|
demo_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
|
||||||
|
demo_isoms_SOURCES = demo/iso_ms.c
|
||||||
|
|
||||||
|
demo_isogrow_CPPFLAGS = -Ilibisofs -Ilibburn
|
||||||
|
demo_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lburn
|
||||||
|
demo_isogrow_SOURCES = demo/iso_grow.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.h \
|
||||||
|
test/test.c \
|
||||||
|
test/test_node.c \
|
||||||
|
test/test_image.c \
|
||||||
|
test/test_tree.c \
|
||||||
|
test/test_util.c \
|
||||||
|
test/test_rockridge.c \
|
||||||
|
test/test_stream.c \
|
||||||
|
test/mocked_fsrc.h \
|
||||||
|
test/mocked_fsrc.c
|
||||||
|
|
||||||
|
## ========================================================================= ##
|
||||||
|
|
||||||
|
## Build documentation (You need Doxygen for this to work)
|
||||||
|
|
||||||
|
docdir = $(DESTDIR)$(prefix)/share/doc/$(PACKAGE)-$(VERSION)
|
||||||
|
|
||||||
|
doc: doc/html
|
||||||
|
|
||||||
|
doc/html: doc/doxygen.conf
|
||||||
|
$(RM) -r doc/html; \
|
||||||
|
doxygen doc/doxygen.conf;
|
||||||
|
|
||||||
|
install-data-local:
|
||||||
|
if [ -d doc/html ]; then \
|
||||||
|
$(mkinstalldirs) $(docdir)/html; \
|
||||||
|
$(INSTALL_DATA) doc/html/* $(docdir)/html; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
uninstall-local:
|
||||||
|
rm -rf $(docdir)
|
||||||
|
|
||||||
|
## ========================================================================= ##
|
||||||
|
|
||||||
|
# Extra things
|
||||||
|
nodist_pkgconfig_DATA = \
|
||||||
|
libisofs-1.pc
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
libisofs-1.pc.in \
|
||||||
|
version.h.in \
|
||||||
|
doc/doxygen.conf.in \
|
||||||
|
doc/Tutorial \
|
||||||
|
README \
|
||||||
|
AUTHORS \
|
||||||
|
COPYRIGHT \
|
||||||
|
COPYING \
|
||||||
|
NEWS \
|
||||||
|
INSTALL \
|
||||||
|
TODO \
|
||||||
|
ChangeLog \
|
||||||
|
Roadmap
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
== unknown ==
|
||||||
|
|
||||||
|
Libisofs v0.6.4
|
||||||
|
===============
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
== Fri Feb 22 2008 ==
|
||||||
|
|
||||||
|
Libisofs v0.6.2.1
|
||||||
|
=================
|
||||||
|
|
||||||
|
- FIX: missing buffer.h in tarball
|
||||||
|
|
||||||
|
== Thu Feb 14 2008 ==
|
||||||
|
|
||||||
|
Libisofs v0.6.2
|
||||||
|
================
|
||||||
|
|
||||||
|
- Initial release
|
|
@ -0,0 +1,341 @@
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
libisofs
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Released under GPL (see COPYING file for details).
|
||||||
|
|
||||||
|
Copyright (C) 2008 Vreixo Formoso, Mario Danic, Thomas Schmitt
|
||||||
|
|
||||||
|
libisofs is part of the libburnia project (libburnia-project.org)
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
libisofs is a library to create an ISO-9660 filesystem, and supports extensions
|
||||||
|
like RockRidge or Joliet. It is also a full featured ISO-9660 editor, allowing
|
||||||
|
you to modify an ISO image or multisession disc, including file addition and
|
||||||
|
removal, change of file names and attributes, etc
|
||||||
|
|
||||||
|
Features:
|
||||||
|
---------
|
||||||
|
|
||||||
|
- Image creation
|
||||||
|
- Creates ISO-9660 images from local files.
|
||||||
|
- Support for RockRidge and Joliet extensions.
|
||||||
|
- Support for ISO-9660:1999 (version 2)
|
||||||
|
- Support for El-Torito bootable images.
|
||||||
|
- Full featured edition of file names and attributes on the image.
|
||||||
|
- Several options to relax ISO-9660 constraints.
|
||||||
|
- Special options for images intended for distribution (suitable default
|
||||||
|
modes for files, hiding of real timestamps...)
|
||||||
|
- Multisession
|
||||||
|
- Support for growing an existing image
|
||||||
|
- Full-featured edition of the image files, including: addition of new
|
||||||
|
files, removing of existent files, moving files, renaming files,
|
||||||
|
change file attributes (permissions, timestamps...)
|
||||||
|
- Support for "emulated multisession" or image growing, suitable for non
|
||||||
|
multisession media such as DVD+RW
|
||||||
|
- Image modification
|
||||||
|
- It can create a completely new image from files on another image.
|
||||||
|
- Full-featured edition of image contents
|
||||||
|
- Others
|
||||||
|
- Handling of different input and output charset
|
||||||
|
- Good integration with libburn for image burning.
|
||||||
|
- Reliable, good handling of different kind of errors.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- libburn 0.4.2 headers must be installed at compile time. It is not required
|
||||||
|
at runtime.
|
||||||
|
|
||||||
|
Know bugs:
|
||||||
|
----------
|
||||||
|
|
||||||
|
Multisession and image growing can lead to undesired results in several cases:
|
||||||
|
|
||||||
|
a) Images with unsupported features, such as:
|
||||||
|
- UDF.
|
||||||
|
- HSF/HFS+ or other Mac extensions.
|
||||||
|
- El-Torito with multiple entries.
|
||||||
|
- ECMA-119 with extended attributes, multiple extends per file.
|
||||||
|
- Non El-Torito boot info.
|
||||||
|
- zisofs compressed images.
|
||||||
|
- ...
|
||||||
|
In all these cases, the resulting new image (or new session) could lack some
|
||||||
|
features of the original image.
|
||||||
|
In some cases libisofs will issue warning messages, or even refuse to grow
|
||||||
|
or modify the image. Others remain undetected. Images created with libisofs
|
||||||
|
do not have this problems.
|
||||||
|
|
||||||
|
b) Bootable El-Torito images may have several problems, that result in a new
|
||||||
|
image that is not bootable, or that boots from an outdated session. In many
|
||||||
|
cases it is recommended to add boot info again in the new session.
|
||||||
|
|
||||||
|
- isolinux images won't be bootable after a modify. This is because
|
||||||
|
isolinux images need to have hardcoded the root dir lba. libisofs cannot
|
||||||
|
know whether an image is an isolinux image or not, so the user is
|
||||||
|
responsible to tell libisofs that it must patch the image, with the
|
||||||
|
el_torito_patch_isolinux_image() function. This problem could also exists
|
||||||
|
on other boot images.
|
||||||
|
- Most boot images are highly dependent of the image contents, so if the
|
||||||
|
user moves or removes some files on image it is possible they won't boot
|
||||||
|
anymore.
|
||||||
|
- There is no safer way to modify hidden boot images, as the size of the
|
||||||
|
boot image can't be figured out.
|
||||||
|
|
||||||
|
c) Generated images could have different ECMA-119 low level names, due to
|
||||||
|
different way to mangle names, to new files added that force old files to
|
||||||
|
be renamed, to different relaxed contraints... This only affect the
|
||||||
|
ISO-9660 info, not the RR names, so it shouldn't be a problem in most
|
||||||
|
cases. If your app. relies on low level ISO-9660 names, you will need to
|
||||||
|
ensure all node names are valid ISO names (maybe together with some
|
||||||
|
relaxed contraints), otherwise libisofs might arbitrarily change the names.
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Download, Build and Installation
|
||||||
|
|
||||||
|
libisofs code is mantained in a Bazaar repository at Launchpad
|
||||||
|
(https://launchpad.net/libisofs/). You can download it with:
|
||||||
|
|
||||||
|
$ bzr branch lp:libisofs
|
||||||
|
|
||||||
|
Our build system is based on autotools. For preparing the build you will need
|
||||||
|
autotools of at least version 1.7. If you have download the code from the
|
||||||
|
repository, first of all you need to execute
|
||||||
|
|
||||||
|
./autogen.sh
|
||||||
|
|
||||||
|
on toplevel dir to execute autotools.
|
||||||
|
|
||||||
|
Alternatively you may unpack a release tarball for which you do not need
|
||||||
|
autotools installed.
|
||||||
|
|
||||||
|
To build libisofs it should be sufficient to go into its toplevel directory
|
||||||
|
and execute
|
||||||
|
|
||||||
|
./configure --prefix=/usr
|
||||||
|
make
|
||||||
|
|
||||||
|
To make the libraries accessible for running resp. developing applications
|
||||||
|
make install
|
||||||
|
|
||||||
|
See INSTALL file for further details.
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Overview of libburnia-project.org
|
||||||
|
|
||||||
|
libburnia-project.org is an open-source software project for reading, mastering
|
||||||
|
and writing optical discs.
|
||||||
|
For now this means only CD media and all single layer DVD media except DVD+R.
|
||||||
|
|
||||||
|
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 have a workable code base for burning CD and most single layer DVD.
|
||||||
|
The burn API is quite comprehensively documented and can be used to build a
|
||||||
|
presentable application.
|
||||||
|
We 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. Its code is
|
||||||
|
independent of cdrecord. Its DVD capabilities are learned from
|
||||||
|
studying the code of dvd+rw-tools and MMC-5 specs. No code but only
|
||||||
|
the pure SCSI knowledge has been taken from dvd+rw-tools, though.
|
||||||
|
|
||||||
|
- libisofs is the library to pack up hard disk files and directories into a
|
||||||
|
ISO 9660 disk image. This may then be brought to media 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. Additionally it
|
||||||
|
provides libburn's DVD capabilities, where only -sao is compatible
|
||||||
|
with 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 and man cdrskin/cdrskin.1 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 July 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 .
|
||||||
|
|
||||||
|
- 16th January 2007 release of libburn-0.3.0 and cdrskin-0.3.0 . Now the scope
|
||||||
|
is widened to a first class of DVD media: overwriteable single layer types
|
||||||
|
DVD-RAM, DVD+RW, DVD-RW. This is not a cdrecord emulation but rather inspired
|
||||||
|
by dvd+rw-tools' "poor man" writing facility for this class of media.
|
||||||
|
Taking a bow towards Andy Polyakov.
|
||||||
|
|
||||||
|
- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
|
||||||
|
multi-session and with DAO.
|
||||||
|
|
||||||
|
- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
|
||||||
|
DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
|
||||||
|
yet.
|
||||||
|
|
||||||
|
- 23th April 2007 version 0.3.6 follows the unanimous opinion of Linux kernel
|
||||||
|
people that one should not use /dev/sg on kernel 2.6.
|
||||||
|
|
||||||
|
- 31st July 2007 version 0.3.8 marks the first anniversary of libburn revival.
|
||||||
|
We look back on improved stability, a substantially extended list of media
|
||||||
|
and write modes, and better protection against typical user mishaps.
|
||||||
|
|
||||||
|
- 24th October 2007 version 0.4.0 is the foundation of new library libisoburn
|
||||||
|
and an upcomming integrated application for manipulating and writing
|
||||||
|
ISO 9660 + Rock Ridge images. cdrskin-0.4.0 got capabilities like growisofs
|
||||||
|
by these enhancements: growing of overwriteable media and disk files.
|
||||||
|
Taking again a bow towards Andy Polyakov.
|
||||||
|
|
||||||
|
- 26th Januar 2008 version 0.4.2 rectifies the version numbering so that we
|
||||||
|
reliably release libburn.so.4 as should have been done since libburn-0.3.2.
|
||||||
|
cdrskin now is by default linked dynamically and does a runtime check
|
||||||
|
to ensure not to be started with a libburn which is older than itself.
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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. To be exact: version 2 of that License.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
>>>>>>>>>> RELEASE 0.6.1 (development) >>>>>>>>>>>>>>>>>>>>>
|
||||||
|
|
||||||
|
- Review error severities
|
||||||
|
OK - Prepare API for stability and compatibility check
|
||||||
|
- Documentation
|
||||||
|
|
||||||
|
>>>>>>>>>> RELEASE 0.6.2 (stable) >>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||||
|
|
||||||
|
- Intensive testing and bug fixing
|
||||||
|
|
||||||
|
>>>>>>>>>> RELEASE 0.6.3 (development) >>>>>>>>>>>>>>>>>>>>>
|
||||||
|
|
||||||
|
- Improves to public tree
|
||||||
|
-> Expose node extended info. Always compile it.
|
||||||
|
(little memory cost)
|
||||||
|
-> Review builder / tree / node relation
|
||||||
|
-> Optimize storage of children in node?
|
||||||
|
-> Inode object?
|
||||||
|
- Expose Builder and Streams
|
||||||
|
- Implement filters: compression, encryption...
|
||||||
|
- Consider some kind of plugin system for Builders, Filesystems and Filters.
|
||||||
|
- ECMA-119, Joliet, and ISO-9660:1999 writers can share most of the code.
|
||||||
|
Create a new writer as a generalization of these.
|
||||||
|
- Update Java bindings
|
||||||
|
|
||||||
|
>>>>>>>>>>> ......
|
||||||
|
|
||||||
|
>>>>>>>>>>> RELEASE 1.0.0 (stable) >>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||||
|
|
||||||
|
- UDF
|
||||||
|
- HFS
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
FEATURES
|
||||||
|
========
|
||||||
|
|
||||||
|
|
||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
#00001 (node.h) -> consider adding new timestamps to IsoTreeNode
|
||||||
|
#00004 (libisofs.h) -> Add a get_mime_type() function.
|
||||||
|
#00005 (node.c) -> optimize iso_dir_iter_take.
|
||||||
|
#00006 (libisofs.h) -> define more replace values when adding a node to a dir
|
||||||
|
#00007 (libisofs.h) -> expose iso_tree_add_new_file
|
||||||
|
#00008 (data_dource.c) -> guard against partial reads
|
||||||
|
#00009 (ecma119_tree.c/h) -> add true support for harlinks and inode numbers
|
||||||
|
#00010 (buffer.c) -> optimize ring buffer
|
||||||
|
#00011 (ecma119.c) -> guard against bad path table usage with more than 65535 dirs
|
||||||
|
#00012 (fs_image.c) -> support follow symlinks on imafe filesystem
|
||||||
|
#00013 (fs_image.c) -> check for unsupported flags when reading a dir record
|
||||||
|
#00014 (fs_image.c) -> more sanity checks to ensure dir record info is valid
|
||||||
|
#00015 (fs_image.c) -> take care of CD-ROM XA discs when reading SP entry
|
||||||
|
#00016 (fs_image.c) -> handle non RR ER entries
|
||||||
|
#00017 (fs_image.c) -> take advantage of other atts of PVD
|
||||||
|
#00018 (fs_image.c) -> check if there are more entries in the boot catalog
|
||||||
|
#00019 (fs_image.c) -> set IsoImage attribs from Joliet SVD?
|
||||||
|
#00020 (fs_image.c) -> handle RR info in Joliet tree
|
||||||
|
#00021 (fs_image.c) -> handle RR info in ISO 9660:1999 tree
|
||||||
|
#00022 (joliet.c) -> support relaxed constraints in joliet filenames
|
||||||
|
#00024 (libisofs.h) -> option to convert names to lower case for iso reading
|
||||||
|
#00025 (libisofs.h) -> support for merging old image files
|
||||||
|
#00026 (libisofs.h) -> add support for "hidden" bootable images.
|
||||||
|
#00027 (iso1999.h) -> Follow ISO 9660:1999 specs when sorting files
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
=====
|
||||||
|
|
|
@ -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])
|
||||||
|
])
|
|
@ -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
|
|
@ -0,0 +1,155 @@
|
||||||
|
AC_INIT([libisofs], [0.6.3], [http://libburnia-project.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
|
||||||
|
dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
|
||||||
|
dnl
|
||||||
|
dnl CURRENT and AGE describe the binary compatibility interval of a
|
||||||
|
dnl dynamic library.
|
||||||
|
dnl See also http://www.gnu.org/software/libtool/manual.html#Interfaces
|
||||||
|
dnl
|
||||||
|
dnl The name of the library will be libisofs.so.$CURRENT-$AGE.$AGE.$REV
|
||||||
|
dnl In the terminology of this file:
|
||||||
|
dnl CURRENT = LT_CURRENT
|
||||||
|
dnl REV = LT_REVISION
|
||||||
|
dnl AGE = LT_AGE
|
||||||
|
dnl
|
||||||
|
dnl LT_CURRENT, LT_REVISION and LT_AGE get set directly now.
|
||||||
|
dnl
|
||||||
|
dnl SONAME of the emerging library is LT_CURRENT - LT_AGE.
|
||||||
|
dnl The linker will do no finer checks. Especially no age range check for
|
||||||
|
dnl the cdrskin binary. If SONAME matches, then the couple starts.
|
||||||
|
dnl
|
||||||
|
dnl Therefore a run time check is provided by libisofs function
|
||||||
|
dnl iso_lib_version(). It returns the major, minor and micro revision of the
|
||||||
|
dnl library. This means LIBISOFS_*_VERSION kept its second job which does not
|
||||||
|
dnl comply to the usual ways of configure.ac . I.e. now *officially* this is
|
||||||
|
dnl the source code release version as announced to the public. It has no
|
||||||
|
dnl conection to SONAME or libtool version numbering.
|
||||||
|
dnl It rather feeds the API function iso_lib_version().
|
||||||
|
dnl
|
||||||
|
dnl If LIBISOFS_*_VERSION changes, be sure to change AC_INIT above to match.
|
||||||
|
dnl
|
||||||
|
LIBISOFS_MAJOR_VERSION=0
|
||||||
|
LIBISOFS_MINOR_VERSION=6
|
||||||
|
LIBISOFS_MICRO_VERSION=3
|
||||||
|
LIBISOFS_VERSION=$LIBISOFS_MAJOR_VERSION.$LIBISOFS_MINOR_VERSION.$LIBISOFS_MICRO_VERSION
|
||||||
|
|
||||||
|
AC_SUBST(LIBISOFS_MAJOR_VERSION)
|
||||||
|
AC_SUBST(LIBISOFS_MINOR_VERSION)
|
||||||
|
AC_SUBST(LIBISOFS_MICRO_VERSION)
|
||||||
|
AC_SUBST(LIBISOFS_VERSION)
|
||||||
|
|
||||||
|
dnl Libtool versioning
|
||||||
|
LT_RELEASE=$LIBISOFS_MAJOR_VERSION.$LIBISOFS_MINOR_VERSION
|
||||||
|
# SONAME = 6 - 0 = 6 . Library name = libisofs.6.0.0
|
||||||
|
LT_CURRENT=6
|
||||||
|
LT_REVISION=0
|
||||||
|
LT_AGE=0
|
||||||
|
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_MSG_ERROR([Libisofs requires largefile support.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_PROG_LIBTOOL
|
||||||
|
AC_SUBST(LIBTOOL_DEPS)
|
||||||
|
LIBTOOL="$LIBTOOL --silent"
|
||||||
|
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS()
|
||||||
|
|
||||||
|
dnl Use GNU extensions if available
|
||||||
|
AC_DEFINE(_GNU_SOURCE, 1)
|
||||||
|
|
||||||
|
dnl Check for tm_gmtoff field in struct tm
|
||||||
|
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>])
|
||||||
|
|
||||||
|
dnl Check if non standard timegm() function is available
|
||||||
|
AC_CHECK_DECL([timegm],
|
||||||
|
[AC_DEFINE(HAVE_TIMEGM, 1, [Define this if timegm function is available])],
|
||||||
|
,
|
||||||
|
[#include <time.h>])
|
||||||
|
|
||||||
|
dnl Check if non standard eaccess() function is available
|
||||||
|
AC_CHECK_DECL([eaccess],
|
||||||
|
[AC_DEFINE(HAVE_EACCESS, 1, [Define this if eaccess function is available])],
|
||||||
|
,
|
||||||
|
[#include <unistd.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
|
||||||
|
|
||||||
|
dnl Verbose debug to make libisofs issue more debug messages
|
||||||
|
AC_ARG_ENABLE(verbose-debug,
|
||||||
|
[ --enable-verbose-debug Enable verbose debug messages [default=no]],
|
||||||
|
AC_DEFINE(LIBISOFS_VERBOSE_DEBUG, 1))
|
||||||
|
|
||||||
|
|
||||||
|
AC_CONFIG_FILES([
|
||||||
|
Makefile
|
||||||
|
doc/doxygen.conf
|
||||||
|
version.h
|
||||||
|
libisofs-1.pc
|
||||||
|
])
|
||||||
|
AC_OUTPUT
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "fsource.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Little test program to test filesystem implementations.
|
||||||
|
* Outputs file contents to stdout!
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
IsoFileSource *file;
|
||||||
|
struct stat info;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: cat /path/to/file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create filesystem object */
|
||||||
|
res = iso_local_filesystem_new(&fs);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't get local fs object, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = fs->get_by_path(fs, argv[1], &file);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't get file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = iso_file_source_lstat(file, &info);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't stat file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(info.st_mode)) {
|
||||||
|
fprintf(stderr, "Path refers to a directory!!\n");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
char buf[1024];
|
||||||
|
res = iso_file_source_open(file);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't open file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
while ((res = iso_file_source_read(file, buf, 1024)) > 0) {
|
||||||
|
fwrite(buf, 1, res, stdout);
|
||||||
|
}
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Error reading, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_file_source_close(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
iso_filesystem_unref(fs);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Little test program that reads a file and outputs it to stdout, using
|
||||||
|
* the libisofs ring buffer as intermediate memory
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct th_data
|
||||||
|
{
|
||||||
|
IsoRingBuffer *rbuf;
|
||||||
|
char *path;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define WRITE_CHUNK 2048
|
||||||
|
#define READ_CHUNK 2048
|
||||||
|
|
||||||
|
static
|
||||||
|
void *write_function(void *arg)
|
||||||
|
{
|
||||||
|
ssize_t bytes;
|
||||||
|
int res;
|
||||||
|
unsigned char tmp[WRITE_CHUNK];
|
||||||
|
struct th_data *data = (struct th_data *) arg;
|
||||||
|
|
||||||
|
int fd = open(data->path, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "Writer thread error: Can't open file");
|
||||||
|
iso_ring_buffer_writer_close(data->rbuf, 1);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = 1;
|
||||||
|
while ( (bytes = read(fd, tmp, WRITE_CHUNK)) > 0) {
|
||||||
|
res = iso_ring_buffer_write(data->rbuf, tmp, bytes);
|
||||||
|
if (res <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* To test premature reader exit >>>>>>>>>>>
|
||||||
|
iso_ring_buffer_writer_close(data->rbuf);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
<<<<<<<<<<<<<<<<<<<<<<<<< */
|
||||||
|
// if (rand() > 2000000000) {
|
||||||
|
// fprintf(stderr, "Writer sleeping\n");
|
||||||
|
// sleep(1);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Writer finish: %d\n", res);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
iso_ring_buffer_writer_close(data->rbuf, 0);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void *read_function(void *arg)
|
||||||
|
{
|
||||||
|
unsigned char tmp[READ_CHUNK];
|
||||||
|
int res = 1;
|
||||||
|
struct th_data *data = (struct th_data *) arg;
|
||||||
|
|
||||||
|
while ( (res = iso_ring_buffer_read(data->rbuf, tmp, READ_CHUNK)) > 0) {
|
||||||
|
write(1, tmp, READ_CHUNK);
|
||||||
|
/* To test premature reader exit >>>>>>>>>>>
|
||||||
|
iso_ring_buffer_reader_close(data->rbuf);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
<<<<<<<<<<<<<<<<<<<<<<<<< */
|
||||||
|
// if (rand() > 2000000000) {
|
||||||
|
// fprintf(stderr, "Reader sleeping\n");
|
||||||
|
// sleep(1);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Reader finish: %d\n", res);
|
||||||
|
|
||||||
|
iso_ring_buffer_reader_close(data->rbuf, 0);
|
||||||
|
|
||||||
|
pthread_exit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct th_data data;
|
||||||
|
pthread_t reader;
|
||||||
|
pthread_t writer;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: catbuffer /path/to/file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = iso_ring_buffer_new(1024, &data.rbuf);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't create buffer\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
data.path = argv[1];
|
||||||
|
|
||||||
|
res = pthread_create(&writer, NULL, write_function, (void *) &data);
|
||||||
|
res = pthread_create(&reader, NULL, read_function, (void *) &data);
|
||||||
|
|
||||||
|
pthread_join(writer, NULL);
|
||||||
|
pthread_join(reader, NULL);
|
||||||
|
|
||||||
|
fprintf(stderr, "Buffer was %d times full and %d times empty.\n",
|
||||||
|
iso_ring_buffer_get_times_full(data.rbuf),
|
||||||
|
iso_ring_buffer_get_times_empty(data.rbuf));
|
||||||
|
|
||||||
|
free(data.rbuf);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Little program that imports a directory to iso image, generates the
|
||||||
|
* ecma119 low level tree and prints it.
|
||||||
|
* Note that this is not an API example, but a little program for test
|
||||||
|
* purposes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
#include "ecma119_tree.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "filesrc.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_permissions(mode_t mode)
|
||||||
|
{
|
||||||
|
char perm[10];
|
||||||
|
|
||||||
|
//TODO suid, sticky...
|
||||||
|
|
||||||
|
perm[9] = '\0';
|
||||||
|
perm[8] = mode & S_IXOTH ? 'x' : '-';
|
||||||
|
perm[7] = mode & S_IWOTH ? 'w' : '-';
|
||||||
|
perm[6] = mode & S_IROTH ? 'r' : '-';
|
||||||
|
perm[5] = mode & S_IXGRP ? 'x' : '-';
|
||||||
|
perm[4] = mode & S_IWGRP ? 'w' : '-';
|
||||||
|
perm[3] = mode & S_IRGRP ? 'r' : '-';
|
||||||
|
perm[2] = mode & S_IXUSR ? 'x' : '-';
|
||||||
|
perm[1] = mode & S_IWUSR ? 'w' : '-';
|
||||||
|
perm[0] = mode & S_IRUSR ? 'r' : '-';
|
||||||
|
printf("[%s]",perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_dir(Ecma119Node *dir, int level)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *sp = alloca(level * 2 + 1);
|
||||||
|
|
||||||
|
for (i = 0; i < level * 2; i += 2) {
|
||||||
|
sp[i] = '|';
|
||||||
|
sp[i+1] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
sp[level * 2-1] = '-';
|
||||||
|
sp[level * 2] = '\0';
|
||||||
|
|
||||||
|
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||||
|
Ecma119Node *child = dir->info.dir->children[i];
|
||||||
|
|
||||||
|
if (child->type == ECMA119_DIR) {
|
||||||
|
printf("%s+[D] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(child->node));
|
||||||
|
printf(" %s\n", child->iso_name);
|
||||||
|
print_dir(child, level+1);
|
||||||
|
} else if (child->type == ECMA119_FILE) {
|
||||||
|
printf("%s-[F] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(child->node));
|
||||||
|
printf(" %s {%p}\n", child->iso_name, (void*)child->info.file);
|
||||||
|
} else if (child->type == ECMA119_SYMLINK) {
|
||||||
|
printf("%s-[L] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(child->node));
|
||||||
|
printf(" %s -> %s\n", child->iso_name,
|
||||||
|
((IsoSymlink*)child->node)->dest);
|
||||||
|
} else if (child->type == ECMA119_SPECIAL) {
|
||||||
|
printf("%s-[S] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(child->node));
|
||||||
|
printf(" %s\n", child->iso_name);
|
||||||
|
} else if (child->type == ECMA119_PLACEHOLDER) {
|
||||||
|
printf("%s-[RD] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(child->node));
|
||||||
|
printf(" %s\n", child->iso_name);
|
||||||
|
} else {
|
||||||
|
printf("%s-[????] ", sp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoImage *image;
|
||||||
|
Ecma119Image *ecma119;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
printf ("You need to specify a valid path\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_init();
|
||||||
|
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating image\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error adding directory %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ecma119 = calloc(1, sizeof(Ecma119Image));
|
||||||
|
iso_rbtree_new(iso_file_src_cmp, &(ecma119->files));
|
||||||
|
ecma119->iso_level = 1;
|
||||||
|
ecma119->rockridge = 1;
|
||||||
|
ecma119->image = image;
|
||||||
|
ecma119->input_charset = strdup("UTF-8");
|
||||||
|
|
||||||
|
/* create low level tree */
|
||||||
|
result = ecma119_tree_create(ecma119);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating ecma-119 tree: %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("================= ECMA-119 TREE =================\n");
|
||||||
|
print_dir(ecma119->root, 0);
|
||||||
|
printf("\n\n");
|
||||||
|
|
||||||
|
ecma119_node_free(ecma119->root);
|
||||||
|
iso_rbtree_destroy(ecma119->files, iso_file_src_free);
|
||||||
|
free(ecma119->input_charset);
|
||||||
|
free(ecma119);
|
||||||
|
iso_image_unref(image);
|
||||||
|
iso_finish();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
* Little program to show how to create an iso image from a local
|
||||||
|
* directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "libburn/libburn.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
const char * const optstring = "JRIL:b:hV:";
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind;
|
||||||
|
|
||||||
|
void usage(char **argv)
|
||||||
|
{
|
||||||
|
printf("%s [OPTIONS] DIRECTORY OUTPUT\n", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void help()
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"Options:\n"
|
||||||
|
" -J Add Joliet support\n"
|
||||||
|
" -R Add Rock Ridge support\n"
|
||||||
|
" -I Add ISO 9660:1999 support\n"
|
||||||
|
" -V label Volume Label\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 callback(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
char *path = iso_file_source_get_path(src);
|
||||||
|
printf("CALLBACK: %s\n", path);
|
||||||
|
free(path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
int c;
|
||||||
|
IsoImage *image;
|
||||||
|
struct burn_source *burn_src;
|
||||||
|
unsigned char buf[2048];
|
||||||
|
FILE *fd;
|
||||||
|
IsoWriteOpts *opts;
|
||||||
|
char *volid = "VOLID";
|
||||||
|
char *boot_img = NULL;
|
||||||
|
int rr = 0, j = 0, iso1999 = 0, level = 1;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, optstring)) != -1) {
|
||||||
|
switch(c) {
|
||||||
|
case 'h':
|
||||||
|
usage(argv);
|
||||||
|
help();
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
j = 1;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
rr = 1;
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
iso1999 = 1;
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
level = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
boot_img = optarg;
|
||||||
|
break;
|
||||||
|
case 'V':
|
||||||
|
volid = optarg;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
usage(argv);
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf ("Please pass directory from which to build ISO\n");
|
||||||
|
usage(argv);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (argc < 3) {
|
||||||
|
printf ("Please supply output file\n");
|
||||||
|
usage(argv);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = fopen(argv[optind+1], "w");
|
||||||
|
if (!fd) {
|
||||||
|
err(1, "error opening output file");
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iso_init();
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Can't initialize libisofs\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||||
|
|
||||||
|
result = iso_image_new(volid, &image);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating image\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_tree_set_follow_symlinks(image, 0);
|
||||||
|
iso_tree_set_ignore_hidden(image, 0);
|
||||||
|
iso_tree_set_ignore_special(image, 0);
|
||||||
|
iso_set_abort_severity("SORRY");
|
||||||
|
/*iso_tree_set_report_callback(image, callback);*/
|
||||||
|
|
||||||
|
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[optind]);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error adding directory %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot_img) {
|
||||||
|
/* adds El-Torito boot info. Tunned for isolinux */
|
||||||
|
ElToritoBootImage *bootimg;
|
||||||
|
result = iso_image_set_boot_image(image, boot_img, ELTORITO_NO_EMUL,
|
||||||
|
"/isolinux/boot.cat", &bootimg);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error adding boot image %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
el_torito_set_load_size(bootimg, 4);
|
||||||
|
el_torito_patch_isolinux_image(bootimg);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iso_write_opts_new(&opts, 0);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Cant create write opts, error %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_write_opts_set_iso_level(opts, level);
|
||||||
|
iso_write_opts_set_rockridge(opts, rr);
|
||||||
|
iso_write_opts_set_joliet(opts, j);
|
||||||
|
iso_write_opts_set_iso1999(opts, iso1999);
|
||||||
|
|
||||||
|
result = iso_image_create_burn_source(image, opts, &burn_src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Cant create image, error %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_write_opts_free(opts);
|
||||||
|
|
||||||
|
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
|
||||||
|
fwrite(buf, 1, 2048, fd);
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
burn_src->free_data(burn_src);
|
||||||
|
free(burn_src);
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
iso_finish();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Little test program that extracts a file form a given ISO image.
|
||||||
|
* Outputs file contents to stdout!
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
IsoFileSource *file;
|
||||||
|
struct stat info;
|
||||||
|
IsoDataSource *src;
|
||||||
|
IsoReadOpts *opts;
|
||||||
|
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: isocat /path/to/image /path/to/file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = iso_init();
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't init libisofs\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = iso_data_source_new_from_file(argv[1], &src);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Error creating data source\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = iso_read_opts_new(&opts, 0);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Error creating read options\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
res = iso_image_filesystem_new(src, opts, 1, &fs);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Error creating filesystem\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_read_opts_free(opts);
|
||||||
|
|
||||||
|
res = fs->get_by_path(fs, argv[2], &file);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't get file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = iso_file_source_lstat(file, &info);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't stat file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(info.st_mode)) {
|
||||||
|
fprintf(stderr, "Path refers to a directory!!\n");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
char buf[1024];
|
||||||
|
res = iso_file_source_open(file);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't open file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
while ((res = iso_file_source_read(file, buf, 1024)) > 0) {
|
||||||
|
fwrite(buf, 1, res, stdout);
|
||||||
|
}
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Error reading, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_file_source_close(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
iso_filesystem_unref(fs);
|
||||||
|
iso_data_source_unref(src);
|
||||||
|
iso_finish();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
/*
|
||||||
|
* Very simple program to show how to grow an iso image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "libburn/libburn.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
static IsoDataSource *libburn_data_source_new(struct burn_drive *d);
|
||||||
|
|
||||||
|
void usage(char **argv)
|
||||||
|
{
|
||||||
|
printf("%s DISC DIRECTORY\n", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoImage *image;
|
||||||
|
IsoDataSource *src;
|
||||||
|
struct burn_source *burn_src;
|
||||||
|
struct burn_drive_info *drives;
|
||||||
|
struct burn_drive *drive;
|
||||||
|
unsigned char buf[32 * 2048];
|
||||||
|
IsoWriteOpts *opts;
|
||||||
|
int ret = 0;
|
||||||
|
IsoReadImageFeatures *features;
|
||||||
|
uint32_t ms_block;
|
||||||
|
IsoReadOpts *ropts;
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
usage(argv);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_init();
|
||||||
|
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||||
|
|
||||||
|
/* create the image context */
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating image\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_tree_set_follow_symlinks(image, 0);
|
||||||
|
iso_tree_set_ignore_hidden(image, 0);
|
||||||
|
|
||||||
|
if (!burn_initialize()) {
|
||||||
|
err(1, "Can't init libburn");
|
||||||
|
}
|
||||||
|
burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
|
||||||
|
|
||||||
|
if (burn_drive_scan_and_grab(&drives, argv[1], 0) != 1) {
|
||||||
|
err(1, "Can't open device. Are you sure it is a valid drive?\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
drive = drives[0].drive;
|
||||||
|
|
||||||
|
#ifdef ISO_GROW_CHECK_MEDIA
|
||||||
|
{
|
||||||
|
/* some check before going on */
|
||||||
|
enum burn_disc_status state;
|
||||||
|
int pno;
|
||||||
|
char name[80];
|
||||||
|
|
||||||
|
state = burn_disc_get_status(drive);
|
||||||
|
burn_disc_get_profile(drive, &pno, name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* my drives report BURN_DISC_BLANK on a DVD+RW with data.
|
||||||
|
* is that correct?
|
||||||
|
*/
|
||||||
|
if ( (pno != 0x1a) /*|| (state != BURN_DISC_FULL)*/ ) {
|
||||||
|
printf("You need to insert a DVD+RW with some data.\n");
|
||||||
|
printf("Profile: %x, state: %d.\n", pno, state);
|
||||||
|
ret = 1;
|
||||||
|
goto exit_cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* create the data source to accesss previous image */
|
||||||
|
src = libburn_data_source_new(drive);
|
||||||
|
if (src == NULL) {
|
||||||
|
printf("Can't create data source.\n");
|
||||||
|
ret = 1;
|
||||||
|
goto exit_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* import previous image */
|
||||||
|
ret = iso_read_opts_new(&ropts, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error creating read options\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
result = iso_image_import(image, src, ropts, &features);
|
||||||
|
iso_data_source_unref(src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error importing previous session %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_read_opts_free(ropts);
|
||||||
|
|
||||||
|
iso_tree_set_replace_mode(image, ISO_REPLACE_IF_NEWER);
|
||||||
|
|
||||||
|
/* add new dir */
|
||||||
|
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[2]);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error adding directory %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate a multisession image with new contents */
|
||||||
|
result = iso_write_opts_new(&opts, 1);
|
||||||
|
if (result < 0) {
|
||||||
|
printf("Cant create write opts, error %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* round up to 32kb aligment = 16 block */
|
||||||
|
ms_block = ((iso_read_image_features_get_size(features) + 15) / 16 ) * 16;
|
||||||
|
iso_write_opts_set_ms_block(opts, ms_block);
|
||||||
|
iso_write_opts_set_appendable(opts, 1);
|
||||||
|
iso_write_opts_set_overwrite_buf(opts, buf);
|
||||||
|
|
||||||
|
iso_read_image_features_destroy(features);
|
||||||
|
|
||||||
|
result = iso_image_create_burn_source(image, opts, &burn_src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf("Cant create image, error %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_write_opts_free(opts);
|
||||||
|
|
||||||
|
/* a. write the new image */
|
||||||
|
printf("Adding new data...\n");
|
||||||
|
{
|
||||||
|
struct burn_disc *target_disc;
|
||||||
|
struct burn_session *session;
|
||||||
|
struct burn_write_opts *burn_options;
|
||||||
|
struct burn_track *track;
|
||||||
|
struct burn_progress progress;
|
||||||
|
char reasons[BURN_REASONS_LEN];
|
||||||
|
|
||||||
|
target_disc = burn_disc_create();
|
||||||
|
session = burn_session_create();
|
||||||
|
burn_disc_add_session(target_disc, session, BURN_POS_END);
|
||||||
|
|
||||||
|
track = burn_track_create();
|
||||||
|
burn_track_set_source(track, burn_src);
|
||||||
|
burn_session_add_track(session, track, BURN_POS_END);
|
||||||
|
|
||||||
|
burn_options = burn_write_opts_new(drive);
|
||||||
|
burn_drive_set_speed(drive, 0, 0);
|
||||||
|
burn_write_opts_set_underrun_proof(burn_options, 1);
|
||||||
|
|
||||||
|
/* mmm, check for 32K alignment? */
|
||||||
|
burn_write_opts_set_start_byte(burn_options, ms_block * 2048);
|
||||||
|
|
||||||
|
if (burn_write_opts_auto_write_type(burn_options, target_disc,
|
||||||
|
reasons, 0) == BURN_WRITE_NONE) {
|
||||||
|
printf("Failed to find a suitable write mode:\n%s\n", reasons);
|
||||||
|
ret = 1;
|
||||||
|
goto exit_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok, write the new track */
|
||||||
|
burn_disc_write(burn_options, target_disc);
|
||||||
|
burn_write_opts_free(burn_options);
|
||||||
|
|
||||||
|
while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
|
||||||
|
usleep(1002);
|
||||||
|
|
||||||
|
while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
|
||||||
|
printf("Writing: sector %d of %d\n", progress.sector, progress.sectors);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* b. write the new vol desc */
|
||||||
|
printf("Writing the new vol desc...\n");
|
||||||
|
ret = burn_random_access_write(drive, 0, (char*)buf, 32*2048, 0);
|
||||||
|
if (ret != 1) {
|
||||||
|
printf("Ups, new vol desc write failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
|
||||||
|
exit_cleanup:;
|
||||||
|
burn_drive_release(drives[0].drive, 0);
|
||||||
|
burn_finish();
|
||||||
|
iso_finish();
|
||||||
|
|
||||||
|
exit(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
libburn_ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
|
||||||
|
{
|
||||||
|
struct burn_drive *d;
|
||||||
|
off_t data_count;
|
||||||
|
|
||||||
|
d = (struct burn_drive*)src->data;
|
||||||
|
|
||||||
|
if ( burn_read_data(d, (off_t) lba * (off_t) 2048, (char*)buffer,
|
||||||
|
2048, &data_count, 0) < 0 ) {
|
||||||
|
return -1; /* error */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int libburn_ds_open(IsoDataSource *src)
|
||||||
|
{
|
||||||
|
/* nothing to do, device is always opened */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int libburn_ds_close(IsoDataSource *src)
|
||||||
|
{
|
||||||
|
/* nothing to do, device is always opened */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
libburn_ds_free_data(IsoDataSource *src)
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
static IsoDataSource *
|
||||||
|
libburn_data_source_new(struct burn_drive *d)
|
||||||
|
{
|
||||||
|
IsoDataSource *ret;
|
||||||
|
|
||||||
|
ret = malloc(sizeof(IsoDataSource));
|
||||||
|
ret->version = 0;
|
||||||
|
ret->refcount = 1;
|
||||||
|
ret->read_block = libburn_ds_read_block;
|
||||||
|
ret->open = libburn_ds_open;
|
||||||
|
ret->close = libburn_ds_close;
|
||||||
|
ret->free_data = libburn_ds_free_data;
|
||||||
|
ret->data = d;
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Little program to show how to modify an iso image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "libburn/libburn.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
void usage(char **argv)
|
||||||
|
{
|
||||||
|
printf("%s [OPTIONS] IMAGE DIRECTORY OUTPUT\n", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoImage *image;
|
||||||
|
IsoDataSource *src;
|
||||||
|
struct burn_source *burn_src;
|
||||||
|
unsigned char buf[2048];
|
||||||
|
FILE *fd;
|
||||||
|
IsoWriteOpts *opts;
|
||||||
|
IsoReadOpts *ropts;
|
||||||
|
|
||||||
|
if (argc < 4) {
|
||||||
|
usage(argv);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = fopen(argv[3], "w");
|
||||||
|
if (!fd) {
|
||||||
|
err(1, "error opening output file");
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_init();
|
||||||
|
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||||
|
|
||||||
|
/* create the data source to accesss previous image */
|
||||||
|
result = iso_data_source_new_from_file(argv[1], &src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating data source\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the image context */
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating image\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_tree_set_follow_symlinks(image, 0);
|
||||||
|
iso_tree_set_ignore_hidden(image, 0);
|
||||||
|
|
||||||
|
/* import previous image */
|
||||||
|
result = iso_read_opts_new(&ropts, 0);
|
||||||
|
if (result < 0) {
|
||||||
|
fprintf(stderr, "Error creating read options\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
result = iso_image_import(image, src, ropts, NULL);
|
||||||
|
iso_read_opts_free(ropts);
|
||||||
|
iso_data_source_unref(src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error importing previous session %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add new dir */
|
||||||
|
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[2]);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error adding directory %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate a new image with both previous and added contents */
|
||||||
|
result = iso_write_opts_new(&opts, 1);
|
||||||
|
if (result < 0) {
|
||||||
|
printf("Cant create write opts, error %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* for isolinux: iso_write_opts_set_allow_full_ascii(opts, 1); */
|
||||||
|
|
||||||
|
result = iso_image_create_burn_source(image, opts, &burn_src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Cant create image, error %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_write_opts_free(opts);
|
||||||
|
|
||||||
|
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
|
||||||
|
fwrite(buf, 1, 2048, fd);
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
burn_src->free_data(burn_src);
|
||||||
|
free(burn_src);
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
iso_finish();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* Little program to show how to create a multisession iso image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "libburn/libburn.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <err.h>
|
||||||
|
|
||||||
|
void usage(char **argv)
|
||||||
|
{
|
||||||
|
printf("%s LSS NWA DISC DIRECTORY OUTPUT\n", argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoImage *image;
|
||||||
|
IsoDataSource *src;
|
||||||
|
struct burn_source *burn_src;
|
||||||
|
unsigned char buf[2048];
|
||||||
|
FILE *fd;
|
||||||
|
IsoWriteOpts *opts;
|
||||||
|
IsoReadOpts *ropts;
|
||||||
|
uint32_t ms_block;
|
||||||
|
|
||||||
|
if (argc < 6) {
|
||||||
|
usage(argv);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = fopen(argv[5], "w");
|
||||||
|
if (!fd) {
|
||||||
|
err(1, "error opening output file");
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_init();
|
||||||
|
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||||
|
|
||||||
|
/* create the data source to accesss previous image */
|
||||||
|
result = iso_data_source_new_from_file(argv[3], &src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating data source\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the image context */
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating image\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_tree_set_follow_symlinks(image, 0);
|
||||||
|
iso_tree_set_ignore_hidden(image, 0);
|
||||||
|
|
||||||
|
/* import previous image */
|
||||||
|
result = iso_read_opts_new(&ropts, 0);
|
||||||
|
if (result < 0) {
|
||||||
|
fprintf(stderr, "Error creating read options\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_read_opts_set_start_block(ropts, atoi(argv[1]));
|
||||||
|
result = iso_image_import(image, src, ropts, NULL);
|
||||||
|
iso_read_opts_free(ropts);
|
||||||
|
iso_data_source_unref(src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error importing previous session %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add new dir */
|
||||||
|
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[4]);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error adding directory %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate a multisession image with new contents */
|
||||||
|
result = iso_write_opts_new(&opts, 1);
|
||||||
|
if (result < 0) {
|
||||||
|
printf("Cant create write opts, error %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* round up to 32kb aligment = 16 block */
|
||||||
|
ms_block = atoi(argv[2]);
|
||||||
|
iso_write_opts_set_ms_block(opts, ms_block);
|
||||||
|
iso_write_opts_set_appendable(opts, 1);
|
||||||
|
|
||||||
|
result = iso_image_create_burn_source(image, opts, &burn_src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Cant create image, error %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
iso_write_opts_free(opts);
|
||||||
|
|
||||||
|
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
|
||||||
|
fwrite(buf, 1, 2048, fd);
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
burn_src->free_data(burn_src);
|
||||||
|
free(burn_src);
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
iso_finish();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Little program to output the contents of an iso image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_permissions(mode_t mode)
|
||||||
|
{
|
||||||
|
char perm[10];
|
||||||
|
|
||||||
|
//TODO suid, sticky...
|
||||||
|
|
||||||
|
perm[9] = '\0';
|
||||||
|
perm[8] = mode & S_IXOTH ? 'x' : '-';
|
||||||
|
perm[7] = mode & S_IWOTH ? 'w' : '-';
|
||||||
|
perm[6] = mode & S_IROTH ? 'r' : '-';
|
||||||
|
perm[5] = mode & S_IXGRP ? 'x' : '-';
|
||||||
|
perm[4] = mode & S_IWGRP ? 'w' : '-';
|
||||||
|
perm[3] = mode & S_IRGRP ? 'r' : '-';
|
||||||
|
perm[2] = mode & S_IXUSR ? 'x' : '-';
|
||||||
|
perm[1] = mode & S_IWUSR ? 'w' : '-';
|
||||||
|
perm[0] = mode & S_IRUSR ? 'r' : '-';
|
||||||
|
printf(" %s ",perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_type(mode_t mode)
|
||||||
|
{
|
||||||
|
switch(mode & S_IFMT) {
|
||||||
|
case S_IFSOCK: printf("[S] "); break;
|
||||||
|
case S_IFLNK: printf("[L] "); break;
|
||||||
|
case S_IFREG: printf("[R] "); break;
|
||||||
|
case S_IFBLK: printf("[B] "); break;
|
||||||
|
case S_IFDIR: printf("[D] "); break;
|
||||||
|
case S_IFIFO: printf("[F] "); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_file_src(IsoFileSource *file)
|
||||||
|
{
|
||||||
|
struct stat info;
|
||||||
|
char *name;
|
||||||
|
iso_file_source_lstat(file, &info);
|
||||||
|
print_type(info.st_mode);
|
||||||
|
print_permissions(info.st_mode);
|
||||||
|
//printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino);
|
||||||
|
name = iso_file_source_get_name(file);
|
||||||
|
printf(" %s", name);
|
||||||
|
free(name);
|
||||||
|
if (S_ISLNK(info.st_mode)) {
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
iso_file_source_readlink(file, buf, PATH_MAX);
|
||||||
|
printf(" -> %s\n", buf);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_dir(IsoFileSource *dir, int level)
|
||||||
|
{
|
||||||
|
int ret, i;
|
||||||
|
IsoFileSource *file;
|
||||||
|
struct stat info;
|
||||||
|
char *sp = alloca(level * 2 + 1);
|
||||||
|
|
||||||
|
for (i = 0; i < level * 2; i += 2) {
|
||||||
|
sp[i] = '|';
|
||||||
|
sp[i+1] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
sp[level * 2-1] = '-';
|
||||||
|
sp[level * 2] = '\0';
|
||||||
|
|
||||||
|
ret = iso_file_source_open(dir);
|
||||||
|
if (ret < 0) {
|
||||||
|
printf ("Can't open dir %d\n", ret);
|
||||||
|
}
|
||||||
|
while ((ret = iso_file_source_readdir(dir, &file)) == 1) {
|
||||||
|
printf("%s", sp);
|
||||||
|
print_file_src(file);
|
||||||
|
ret = iso_file_source_lstat(file, &info);
|
||||||
|
if (ret < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (S_ISDIR(info.st_mode)) {
|
||||||
|
print_dir(file, level + 1);
|
||||||
|
}
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
}
|
||||||
|
iso_file_source_close(dir);
|
||||||
|
if (ret < 0) {
|
||||||
|
printf ("Can't print dir\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoImageFilesystem *fs;
|
||||||
|
IsoDataSource *src;
|
||||||
|
IsoFileSource *root;
|
||||||
|
IsoReadOpts *ropts;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
printf ("You need to specify a valid path\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_init();
|
||||||
|
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||||
|
|
||||||
|
result = iso_data_source_new_from_file(argv[1], &src);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating data source\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iso_read_opts_new(&ropts, 0);
|
||||||
|
if (result < 0) {
|
||||||
|
fprintf(stderr, "Error creating read options\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
result = iso_image_filesystem_new(src, ropts, 1, &fs);
|
||||||
|
iso_read_opts_free(ropts);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating filesystem\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nVOLUME INFORMATION\n");
|
||||||
|
printf("==================\n\n");
|
||||||
|
|
||||||
|
printf("Vol. id: %s\n", iso_image_fs_get_volume_id(fs));
|
||||||
|
printf("Publisher: %s\n", iso_image_fs_get_publisher_id(fs));
|
||||||
|
printf("Data preparer: %s\n", iso_image_fs_get_data_preparer_id(fs));
|
||||||
|
printf("System: %s\n", iso_image_fs_get_system_id(fs));
|
||||||
|
printf("Application: %s\n", iso_image_fs_get_application_id(fs));
|
||||||
|
printf("Copyright: %s\n", iso_image_fs_get_copyright_file_id(fs));
|
||||||
|
printf("Abstract: %s\n", iso_image_fs_get_abstract_file_id(fs));
|
||||||
|
printf("Biblio: %s\n", iso_image_fs_get_biblio_file_id(fs));
|
||||||
|
|
||||||
|
printf("\nDIRECTORY TREE\n");
|
||||||
|
printf("==============\n");
|
||||||
|
|
||||||
|
result = fs->get_root(fs, &root);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Can't get root %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
//print_file_src(root);
|
||||||
|
print_dir(root, 0);
|
||||||
|
iso_file_source_unref(root);
|
||||||
|
|
||||||
|
fs->close(fs);
|
||||||
|
iso_filesystem_unref((IsoFilesystem*)fs);
|
||||||
|
iso_data_source_unref(src);
|
||||||
|
iso_finish();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "fsource.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Little test program to test filesystem implementations.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_permissions(mode_t mode)
|
||||||
|
{
|
||||||
|
char perm[10];
|
||||||
|
|
||||||
|
//TODO suid, sticky...
|
||||||
|
|
||||||
|
perm[9] = '\0';
|
||||||
|
perm[8] = mode & S_IXOTH ? 'x' : '-';
|
||||||
|
perm[7] = mode & S_IWOTH ? 'w' : '-';
|
||||||
|
perm[6] = mode & S_IROTH ? 'r' : '-';
|
||||||
|
perm[5] = mode & S_IXGRP ? 'x' : '-';
|
||||||
|
perm[4] = mode & S_IWGRP ? 'w' : '-';
|
||||||
|
perm[3] = mode & S_IRGRP ? 'r' : '-';
|
||||||
|
perm[2] = mode & S_IXUSR ? 'x' : '-';
|
||||||
|
perm[1] = mode & S_IWUSR ? 'w' : '-';
|
||||||
|
perm[0] = mode & S_IRUSR ? 'r' : '-';
|
||||||
|
printf(" %s ",perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_type(mode_t mode)
|
||||||
|
{
|
||||||
|
switch(mode & S_IFMT) {
|
||||||
|
case S_IFSOCK: printf("[S] "); break;
|
||||||
|
case S_IFLNK: printf("[L] "); break;
|
||||||
|
case S_IFREG: printf("[R] "); break;
|
||||||
|
case S_IFBLK: printf("[B] "); break;
|
||||||
|
case S_IFDIR: printf("[D] "); break;
|
||||||
|
case S_IFIFO: printf("[F] "); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_file_src(IsoFileSource *file)
|
||||||
|
{
|
||||||
|
struct stat info;
|
||||||
|
char *name;
|
||||||
|
iso_file_source_lstat(file, &info);
|
||||||
|
print_type(info.st_mode);
|
||||||
|
print_permissions(info.st_mode);
|
||||||
|
printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino);
|
||||||
|
name = iso_file_source_get_name(file);
|
||||||
|
printf(" %s", name);
|
||||||
|
free(name);
|
||||||
|
if (S_ISLNK(info.st_mode)) {
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
iso_file_source_readlink(file, buf, PATH_MAX);
|
||||||
|
printf(" -> %s\n", buf);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
IsoFileSource *dir;
|
||||||
|
IsoFileSource *file;
|
||||||
|
struct stat info;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: lsl /path/to/file\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create filesystem object */
|
||||||
|
res = iso_local_filesystem_new(&fs);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't get local fs object, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = fs->get_by_path(fs, argv[1], &dir);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't get file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = iso_file_source_lstat(dir, &info);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't stat file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISDIR(info.st_mode)) {
|
||||||
|
res = iso_file_source_open(dir);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't open file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (iso_file_source_readdir(dir, &file) == 1) {
|
||||||
|
print_file_src(file);
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = iso_file_source_close(dir);
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr, "Can't close file, err = %d\n", res);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print_file_src(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_file_source_unref(dir);
|
||||||
|
iso_filesystem_unref(fs);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Little program that import a directory and prints the resulting iso tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_permissions(mode_t mode)
|
||||||
|
{
|
||||||
|
char perm[10];
|
||||||
|
|
||||||
|
//TODO suid, sticky...
|
||||||
|
|
||||||
|
perm[9] = '\0';
|
||||||
|
perm[8] = mode & S_IXOTH ? 'x' : '-';
|
||||||
|
perm[7] = mode & S_IWOTH ? 'w' : '-';
|
||||||
|
perm[6] = mode & S_IROTH ? 'r' : '-';
|
||||||
|
perm[5] = mode & S_IXGRP ? 'x' : '-';
|
||||||
|
perm[4] = mode & S_IWGRP ? 'w' : '-';
|
||||||
|
perm[3] = mode & S_IRGRP ? 'r' : '-';
|
||||||
|
perm[2] = mode & S_IXUSR ? 'x' : '-';
|
||||||
|
perm[1] = mode & S_IWUSR ? 'w' : '-';
|
||||||
|
perm[0] = mode & S_IRUSR ? 'r' : '-';
|
||||||
|
printf("[%s]",perm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_dir(IsoDir *dir, int level)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
IsoDirIter *iter;
|
||||||
|
IsoNode *node;
|
||||||
|
char *sp = alloca(level * 2 + 1);
|
||||||
|
|
||||||
|
for (i = 0; i < level * 2; i += 2) {
|
||||||
|
sp[i] = '|';
|
||||||
|
sp[i+1] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
sp[level * 2-1] = '-';
|
||||||
|
sp[level * 2] = '\0';
|
||||||
|
|
||||||
|
iso_dir_get_children(dir, &iter);
|
||||||
|
while (iso_dir_iter_next(iter, &node) == 1) {
|
||||||
|
|
||||||
|
if (ISO_NODE_IS_DIR(node)) {
|
||||||
|
printf("%s+[D] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(node));
|
||||||
|
printf(" %s\n", iso_node_get_name(node));
|
||||||
|
print_dir(ISO_DIR(node), level+1);
|
||||||
|
} else if (ISO_NODE_IS_FILE(node)) {
|
||||||
|
printf("%s-[F] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(node));
|
||||||
|
printf(" %s\n", iso_node_get_name(node) );
|
||||||
|
} else if (ISO_NODE_IS_SYMLINK(node)) {
|
||||||
|
printf("%s-[L] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(node));
|
||||||
|
printf(" %s -> %s \n", iso_node_get_name(node),
|
||||||
|
iso_symlink_get_dest(ISO_SYMLINK(node)) );
|
||||||
|
} else {
|
||||||
|
printf("%s-[C] ", sp);
|
||||||
|
print_permissions(iso_node_get_permissions(node));
|
||||||
|
printf(" %s\n", iso_node_get_name(node) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iso_dir_iter_free(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoImage *image;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
printf ("You need to specify a valid path\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_init();
|
||||||
|
iso_set_msgs_severities("NEVER", "ALL", "");
|
||||||
|
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error creating image\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]);
|
||||||
|
if (result < 0) {
|
||||||
|
printf ("Error adding directory %d\n", result);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("================= IMAGE =================\n");
|
||||||
|
print_dir(iso_image_get_root(image), 0);
|
||||||
|
printf("\n\n");
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
iso_finish();
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,506 @@
|
||||||
|
===============================================================================
|
||||||
|
LIBISOFS DEVELOPMENT TUTORIAL
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
Creation date: 2008-Jan-27
|
||||||
|
Author: Vreixo Formoso
|
||||||
|
_______________________________________________________________________________
|
||||||
|
|
||||||
|
This is a little tutorial of how to use libisofs library for application
|
||||||
|
development.
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
---------
|
||||||
|
|
||||||
|
1. Introduction
|
||||||
|
1.1 Library initialization
|
||||||
|
1.2 Image context
|
||||||
|
1.3 Error reporting
|
||||||
|
2. Creating an image
|
||||||
|
2.1 Image tree manipulation
|
||||||
|
2.2 Set the write options
|
||||||
|
2.3 Obtaining a burn_source
|
||||||
|
3. Image growing and modification
|
||||||
|
3.1 Growing vs Modification
|
||||||
|
3.2 Image import
|
||||||
|
3.3 Generating a new image
|
||||||
|
4. Bootable images
|
||||||
|
5. Advanced features
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
1. Introduction
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[TODO some lines about refcounts]
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
1.1. Library initialization
|
||||||
|
|
||||||
|
Before any usage of the library, you have to call
|
||||||
|
|
||||||
|
iso_init()
|
||||||
|
|
||||||
|
in the same way, when you have finished using the library, you should call
|
||||||
|
|
||||||
|
iso_finish()
|
||||||
|
|
||||||
|
to free all resources reserved by the library.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
1.2. Image context
|
||||||
|
|
||||||
|
Libisofs is image-oriented, the core of libisofs usage is the IsoImage object.
|
||||||
|
Thus, the first you need to do is to get your own IsoImage object:
|
||||||
|
|
||||||
|
IsoImage *my_image;
|
||||||
|
iso_image_new("NEW DISC", &my_image);
|
||||||
|
|
||||||
|
An IsoImage is a context for image creation. It holds the files that will be
|
||||||
|
added to image, other related information and several options to customize
|
||||||
|
the behavior of libisofs when working with such Image. i.e., an IsoImage is
|
||||||
|
a context for libisofs operations. As such, you can work with several image
|
||||||
|
contexts at a time.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
1.3. Error reporting
|
||||||
|
|
||||||
|
In libisofs error reporting is done in two ways: with the return value of
|
||||||
|
the functions and with the message queue.
|
||||||
|
|
||||||
|
Error codes are negative numbers, defined in "libisofs.h" header. An
|
||||||
|
error code is associated with a given severity, either "DEBUG", "UPDATE",
|
||||||
|
"NOTE", "HINT", "WARNING", "SORRY", "FAILURE" and "FATAL". For the meaning
|
||||||
|
of each severity take a look at private header "libiso_msgs.h". Errors
|
||||||
|
reported by function return value are always "FAILURE" or "FATAL". Other kind
|
||||||
|
of errors are only reported with the message queue. You can get the severity
|
||||||
|
of any error message with iso_error_get_severity() function.
|
||||||
|
|
||||||
|
First of all, most libisofs functions return an integer. If such integer is
|
||||||
|
a negative number, it means the function has returned an error. The error code
|
||||||
|
and its severity is encoded in the return value (take a look at error codes in
|
||||||
|
libisofs.h header).
|
||||||
|
|
||||||
|
Additionally, libisofs reports most of its errors in a message queue. Error
|
||||||
|
messages on that queue can be printed directly to stderr or programmatically
|
||||||
|
retrieved. First of all, you should set the severity threshold over which an
|
||||||
|
error is printed or enqueued, with function:
|
||||||
|
|
||||||
|
iso_set_msgs_severities()
|
||||||
|
|
||||||
|
Errors enqueued can be retrieved with function:
|
||||||
|
|
||||||
|
iso_obtain_msgs()
|
||||||
|
|
||||||
|
Together with the code error, a text message and its severity, this function
|
||||||
|
also returns the image id. This is an identifier that uniquely identifies a
|
||||||
|
given image context. You can get the identifier of each IsoImage with the
|
||||||
|
|
||||||
|
iso_image_get_msg_id()
|
||||||
|
|
||||||
|
and that way distinguish what image has issued the message.
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
2. Creating an Image
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
An image is built from a set of files that you want to store together in an
|
||||||
|
ISO-9660 volume. We call the "iso tree" to the file hierarchy that will be
|
||||||
|
written to image. The image context, IsoImage, holds that tree, together with
|
||||||
|
configuration options and other properties of the image, that provide info
|
||||||
|
about the volume (such as the identifier, author, etc...).
|
||||||
|
|
||||||
|
All configuration options and volume properties are set by its corresponding
|
||||||
|
setters (iso_image_set_volset_id(), iso_image_set_publisher_id()...)
|
||||||
|
|
||||||
|
To create an image, you have to follow the following steps:
|
||||||
|
|
||||||
|
* Obtain the image context.
|
||||||
|
See "1.2 Image context" for details of how to obtain the IsoImage.
|
||||||
|
* Set the desired properties
|
||||||
|
* Prepare the iso tree with the files you want to add to image.
|
||||||
|
See "2.1 Image tree manipulation" for details
|
||||||
|
* Select the options for image generation.
|
||||||
|
See "2.2 Set the write options"
|
||||||
|
* Get the burn_source used to actually write the image.
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
2.1 Image tree manipulation
|
||||||
|
|
||||||
|
libisofs maintains in memory a file tree (usually called the iso tree), that
|
||||||
|
represents the files and directories that will be written later to image. You
|
||||||
|
are allowed to make whatever changes you want to that tree, just like you do
|
||||||
|
to any "real" filesystem, before actually write it to image.
|
||||||
|
|
||||||
|
Unlike other ISO-9660 mastering tools, you have full control over the file
|
||||||
|
hierarchy that will be written to image, via the libisofs API. You can add
|
||||||
|
new files, create any file in image, change its name, attributes, etc The iso
|
||||||
|
tree behaves just like any other POSIX filesystem.
|
||||||
|
|
||||||
|
The root of the iso tree is created automatically when the IsoImage is
|
||||||
|
allocated, and you can't replace it. To get a reference to it you can use the
|
||||||
|
function:
|
||||||
|
|
||||||
|
iso_image_get_root()
|
||||||
|
|
||||||
|
* Iso tree objects
|
||||||
|
|
||||||
|
Each file in the image or iso tree is represented by an IsoNode instance. In
|
||||||
|
the same way a POSIX filesystem has several file types (regular files,
|
||||||
|
directories, symlinks...), the IsoNode has several subtypes:
|
||||||
|
|
||||||
|
IsoNode
|
||||||
|
|
|
||||||
|
---------------------------------
|
||||||
|
| | | |
|
||||||
|
IsoDir IsoFile IsoSymlink IsoSpecial
|
||||||
|
|
||||||
|
where
|
||||||
|
|
||||||
|
- IsoDir represents a directory
|
||||||
|
- IsoFile represents a regular file
|
||||||
|
- IsoSymlink represents a symbolic linke
|
||||||
|
- IsoSpecial represents any other POSIX file, i.e. block and character
|
||||||
|
devices, FIFOs, sockets.
|
||||||
|
|
||||||
|
You can obtain the concrete type of an IsoNode with the iso_node_get_type()
|
||||||
|
function.
|
||||||
|
|
||||||
|
Many libisofs functions take or return an IsoNode. Many others, however,
|
||||||
|
require an specific type. You can safety cast any subtype to an IsoNode
|
||||||
|
object. In the same way, after ensuring you are dealing with the correct
|
||||||
|
subtype, you can downcast a given IsoNode to the specific subtype.
|
||||||
|
|
||||||
|
IsoDir *dir;
|
||||||
|
IsoNode *node;
|
||||||
|
|
||||||
|
node = (IsoNode*) dir;
|
||||||
|
|
||||||
|
if (iso_node_get_type(node) == LIBISO_DIR) {
|
||||||
|
dir = (IsoDir*) node;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
or with the provided macros:
|
||||||
|
|
||||||
|
IsoDir *dir;
|
||||||
|
IsoNode *node;
|
||||||
|
|
||||||
|
node = ISO_NODE(dir);
|
||||||
|
|
||||||
|
if (ISO_NODE_IS_DIR(node)) {
|
||||||
|
dir = ISO_DIR(node);
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
* Adding files to the image
|
||||||
|
|
||||||
|
Files can be added to the image or iso tree either as new files or as files
|
||||||
|
from the filesystem.
|
||||||
|
|
||||||
|
In the first case, files are created directly on the image. They do not
|
||||||
|
correspond to any file in the filesystem. Provided functions are:
|
||||||
|
|
||||||
|
- iso_tree_add_new_dir()
|
||||||
|
- iso_tree_add_new_symlink()
|
||||||
|
- iso_tree_add_new_special()
|
||||||
|
|
||||||
|
On the other side, you can add local files to the image, either with the
|
||||||
|
|
||||||
|
iso_tree_add_node()
|
||||||
|
|
||||||
|
or with
|
||||||
|
|
||||||
|
iso_tree_add_dir_rec().
|
||||||
|
|
||||||
|
The first is intended to add a single file, while the last can be used to add,
|
||||||
|
recursively, a full directory (see below for details).
|
||||||
|
|
||||||
|
It is important to note that libisofs doesn't store any kind of link between
|
||||||
|
the IsoNode and the filesystem file it was created from. The above functions
|
||||||
|
just initialize a newly created IsoNode with the attributes of a given file in
|
||||||
|
the filesystem. After that, you can move the original file, change its
|
||||||
|
attributes or even delete it. The IsoNode in the image tree remains with the
|
||||||
|
original attributes. One exception to this rule are the contents of a regular
|
||||||
|
file. Libisofs does not make any copy of those contents until they're actually
|
||||||
|
written to image. Thus, you shouldn't modify, move or delete regular files
|
||||||
|
after adding them to the IsoImage.
|
||||||
|
|
||||||
|
|
||||||
|
* Recursive directory addition.
|
||||||
|
|
||||||
|
One common use case is to add a local directory to the image. While this can
|
||||||
|
be done with iso_tree_add_node(), handling the addition of directory children
|
||||||
|
in the application, libisofs provides a function suitable for this case:
|
||||||
|
|
||||||
|
iso_tree_add_dir_rec()
|
||||||
|
|
||||||
|
that takes care of adding all files inside a directory, recursing on directory
|
||||||
|
children. By default, this function adds all children. However, it is usual
|
||||||
|
that you don't want really this. For example, you may want to exclude some
|
||||||
|
kind of files (backup files, application sockets,...). Libisofs provides
|
||||||
|
several functions to customize the behavior of that function:
|
||||||
|
|
||||||
|
- iso_tree_set_follow_symlinks()
|
||||||
|
- iso_tree_set_ignore_hidden()
|
||||||
|
- iso_tree_set_ignore_special()
|
||||||
|
- iso_tree_add_exclude()
|
||||||
|
|
||||||
|
* Operations on iso tree
|
||||||
|
|
||||||
|
[TODO briefly explain how to add node, change attributes, ...]
|
||||||
|
|
||||||
|
* Replace mode
|
||||||
|
|
||||||
|
[TODO]
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
2.2 Set the write options
|
||||||
|
|
||||||
|
Once you have prepared the iso tree, it is time to select the options for the
|
||||||
|
image writing.
|
||||||
|
|
||||||
|
These options affect the characteristics of the filesystem to create in the
|
||||||
|
image, but also can control how libisofs generates the image.
|
||||||
|
|
||||||
|
First of all you have to get an instance of IsoWriteOpts, with the function
|
||||||
|
|
||||||
|
iso_write_opts_new()
|
||||||
|
|
||||||
|
The several options available can be classified in:
|
||||||
|
|
||||||
|
- Extensions to add to the ISO-9660 image:
|
||||||
|
|
||||||
|
iso_write_opts_set_rockridge()
|
||||||
|
iso_write_opts_set_joliet()
|
||||||
|
iso_write_opts_set_iso1999()
|
||||||
|
|
||||||
|
RockRidge is highly recommended, in fact you should use it in all image. Joliet
|
||||||
|
is needed if you want to use your images in Windows system. Nowadays,
|
||||||
|
ISO-9660:1999 is no much useful, so in most cases you don't want such
|
||||||
|
extension.
|
||||||
|
|
||||||
|
- ISO-9660 options:
|
||||||
|
|
||||||
|
iso_write_opts_set_iso_level()
|
||||||
|
iso_write_opts_set_omit_version_numbers()
|
||||||
|
iso_write_opts_set_allow_deep_paths()
|
||||||
|
iso_write_opts_set_allow_longer_paths()
|
||||||
|
iso_write_opts_set_max_37_char_filenames()
|
||||||
|
iso_write_opts_set_no_force_dots()
|
||||||
|
iso_write_opts_set_allow_lowercase()
|
||||||
|
iso_write_opts_set_allow_full_ascii()
|
||||||
|
|
||||||
|
These control the options for the ISO-9660 filesystem. In most cases you won't
|
||||||
|
care about them, as it is the RockRidge or Joliet extensions what determine the
|
||||||
|
properties of the files once the image is mounted.
|
||||||
|
|
||||||
|
- File attributes options
|
||||||
|
|
||||||
|
iso_write_opts_set_replace_mode()
|
||||||
|
iso_write_opts_set_default_dir_mode()
|
||||||
|
iso_write_opts_set_default_file_mode()
|
||||||
|
iso_write_opts_set_default_uid()
|
||||||
|
iso_write_opts_set_default_gid()
|
||||||
|
iso_write_opts_set_replace_timestamps()
|
||||||
|
iso_write_opts_set_default_timestamp()
|
||||||
|
iso_write_opts_set_always_gmt()
|
||||||
|
|
||||||
|
They allow to set default attributes for files in image, despite of the real
|
||||||
|
attributes of the file on the local filesystem.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
2.3 Obtaining a burn_source
|
||||||
|
|
||||||
|
Finally, you get the burn_source used to write the image with the function:
|
||||||
|
|
||||||
|
iso_image_create_burn_source()
|
||||||
|
|
||||||
|
The returned burn_source is suitable for using with libburn, to directly burn
|
||||||
|
the image to a disc. Alternatively, you can use burn_source read() to get
|
||||||
|
the image contents (for example, to write them to a file, pipe...).
|
||||||
|
|
||||||
|
Before creating the burn_source, libisofs computes the size of the image, so
|
||||||
|
the get_size() function of the burn_source always returns the final image
|
||||||
|
size. It also starts a writing thread. All the operations needed to generate
|
||||||
|
the image are done by this thread, including read the original files contents.
|
||||||
|
The image is writing to a FIFO buffer, from which the burn_source will read.
|
||||||
|
The size of the buffer can be set in advanced with a property of the
|
||||||
|
IsoWriteOpts struct:
|
||||||
|
|
||||||
|
iso_write_opts_set_fifo_size()
|
||||||
|
|
||||||
|
You can get the state of the buffer in any moment, with the function:
|
||||||
|
|
||||||
|
iso_ring_buffer_get_status()
|
||||||
|
|
||||||
|
You can also cancel the writer thread at any time, with the cancel() function
|
||||||
|
of the burn_source.
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
3. Image growing and modification
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
3.1 Growing vs Modification
|
||||||
|
|
||||||
|
Libisofs is not restricted only to create new images. It can also be used to
|
||||||
|
modify existing images. It supports two kind of image modifications, that we
|
||||||
|
have called image growing and image modification:
|
||||||
|
|
||||||
|
Image modification consists in generating a new image, based on the contents
|
||||||
|
of an existing image. In this mode, libisofs takes an image, the users modifies
|
||||||
|
its contents (adding new files, removing files, changing their names...), and
|
||||||
|
finally libisofs generates a completely new image.
|
||||||
|
|
||||||
|
On the other side, image growing is similar, with the difference that the new
|
||||||
|
image is dependent on the other, i.e., it refers to files of the other image.
|
||||||
|
Thus, it can't be mounted without the old image. The purpose of this kind of
|
||||||
|
images is to increment or add files to a multisession disc. The new image only
|
||||||
|
contains the new files. Old files are just references to the old image blocks.
|
||||||
|
|
||||||
|
The advantage of the growing approach is that the generated image is smaller,
|
||||||
|
as only the new files are written. This mode is suitable when you just want to
|
||||||
|
add some files to a very big image, or when dealing with write-once media, such
|
||||||
|
as CD-R. Both the time and space needed for the modification is much less than
|
||||||
|
with normal image modify.
|
||||||
|
|
||||||
|
The main problem of growing is that the new image needs to be recorded together
|
||||||
|
with the old image, in order to be mountable. The total size of the image
|
||||||
|
(old + new) is bigger (even much bigger) than a completely new image. So, if
|
||||||
|
you plan to distribute an image on Internet, or burn it to a disc, generate a
|
||||||
|
completely new image is usually a better alternative.
|
||||||
|
|
||||||
|
To be able to mount a grown image, the OS needs to now you have appended new
|
||||||
|
data to the original image. In multisession media (such as CD-R), the new data
|
||||||
|
is appended as a new session, so the OS can identify this and mount the image
|
||||||
|
propertly. However, when dealing with non-multisession media (such as DVD+RW)
|
||||||
|
or plain .iso files, the new data is just appended at the end of the old image,
|
||||||
|
and the OS has no way to know that the appended data is in fact a "new
|
||||||
|
session". The method introduced by Andy Polyakov in growisofs can be used in
|
||||||
|
those cases. It consists in overwrite the volume descriptors of the old image
|
||||||
|
with a new ones that refer to the newly appended contents.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
3.2 Image import
|
||||||
|
|
||||||
|
The first thing you need to do in order to modify or grow an image is to import
|
||||||
|
it, with the function:
|
||||||
|
|
||||||
|
iso_image_import()
|
||||||
|
|
||||||
|
It takes several arguments.
|
||||||
|
|
||||||
|
First, the image context, an IsoImage previously obtained with iso_image_new().
|
||||||
|
In most cases you will want to use an empty image. However, if you have already
|
||||||
|
added files to the image, they will be removed and replaced with the contents
|
||||||
|
of the image being imported.
|
||||||
|
|
||||||
|
The second parameter is an IsoDataSource instance. It abstracts the original
|
||||||
|
image, and it is used by libisofs to access its contents. You are free to
|
||||||
|
implement your own data source to access image contents. However, libisofs has
|
||||||
|
a simple implementation suitable for reading images on the local filesystem,
|
||||||
|
that can be used for import both .iso files and inserted media, via the block
|
||||||
|
device and POSIX functions. You can get it with
|
||||||
|
|
||||||
|
iso_data_source_new_from_file()
|
||||||
|
|
||||||
|
The third parameter of iso_image_import() is a pointer to an IsoReadOpts
|
||||||
|
struct. It holds the options for image reading. You get it with:
|
||||||
|
|
||||||
|
iso_read_opts_new()
|
||||||
|
|
||||||
|
and after calling iso_image_import() you should free it with
|
||||||
|
|
||||||
|
iso_read_opts_free()
|
||||||
|
|
||||||
|
Some options are related to select what extensions to read. Default options
|
||||||
|
are suitable for most users.
|
||||||
|
|
||||||
|
iso_read_opts_set_no_rockridge()
|
||||||
|
iso_read_opts_set_no_joliet()
|
||||||
|
iso_read_opts_set_no_iso1999()
|
||||||
|
iso_read_opts_set_preferjoliet()
|
||||||
|
|
||||||
|
If RockRidge extensions are not present, many files attributes can't be
|
||||||
|
obtained. In those cases libisofs uses default values. You have options to
|
||||||
|
configure what default values to use.
|
||||||
|
|
||||||
|
iso_read_opts_set_default_uid()
|
||||||
|
iso_read_opts_set_default_gid()
|
||||||
|
iso_read_opts_set_default_permissions()
|
||||||
|
|
||||||
|
If the original image has been created in another system with a different
|
||||||
|
charset, you may want to use:
|
||||||
|
|
||||||
|
iso_read_opts_set_input_charset()
|
||||||
|
|
||||||
|
to specify the encoding of the file names on image.
|
||||||
|
|
||||||
|
Finally, to import multisession images, you should tell libisofs that it must
|
||||||
|
read the last session. For that, you must set the block where the last session
|
||||||
|
starts:
|
||||||
|
|
||||||
|
iso_read_opts_set_start_block()
|
||||||
|
|
||||||
|
The last parameter for iso_image_import(), optional, is a pointer that will
|
||||||
|
be filled with a library-allocated IsoReadImageFeatures, that lets you access
|
||||||
|
some information about the image: size, extensions used,...
|
||||||
|
|
||||||
|
[TODO: explain that iso_image_import uses dir rec options]
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
3.3 Generating a new image
|
||||||
|
|
||||||
|
After importing the image, the old image tree gets loaded. You are free to
|
||||||
|
make any changes to it: add new files, remove files, change names or
|
||||||
|
attributes... Refer to "2.1 Image tree manipulation" for details.
|
||||||
|
|
||||||
|
When it is ready, you can now create the new image. The process is the same as
|
||||||
|
explained in "2.2 Set the write options" and "2.3 Obtaining a burn_source".
|
||||||
|
However, there are some write options that should be taken into account.
|
||||||
|
|
||||||
|
First of all, you must select whether you want to grow or modify the image
|
||||||
|
(read "3.1 Growing vs Modification" for details). You must call
|
||||||
|
|
||||||
|
iso_write_opts_set_appendable()
|
||||||
|
|
||||||
|
An appendable image leads to image growing, and a non-appendable image leads
|
||||||
|
to a completelly new image (modification). An appendable image will be appended
|
||||||
|
after the old image (in a new session, for example). Thus, in those cases, the
|
||||||
|
first block of the image is not 0. You should set the correct lba of the first
|
||||||
|
block with:
|
||||||
|
|
||||||
|
iso_write_opts_set_ms_block()
|
||||||
|
|
||||||
|
That is usually the "Next Writable Address" on a multisession media, and a
|
||||||
|
value slightly greater than the old image size on .iso files or DVD+RW media.
|
||||||
|
You can obtain the old image size with the iso_read_image_features_get_size()
|
||||||
|
function.
|
||||||
|
|
||||||
|
In this last case (i.e., on a non multisession media), you will need to
|
||||||
|
overwrite the volume descriptors of the old image with the new ones. To do
|
||||||
|
this you need:
|
||||||
|
|
||||||
|
- Allocate a buffer of at least 64 KiBs.
|
||||||
|
- Initialize it with the first 64 KiBs of the original image.
|
||||||
|
- Pass the buffer to libisofs with the iso_write_opts_set_overwrite_buf()
|
||||||
|
option.
|
||||||
|
- After appending the new image, you have to overwrite the first 64 KiBs of
|
||||||
|
the original image with the new content of the buffer.
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
4. Bootable images
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
5. Advanced features
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
= libisofs =
|
||||||
|
|
||||||
|
libisofs is a library to create an ISO-9660 filesystem, and supports extensions like RockRidge and Joliet. It is also a full featured ISO-9660 editor, allowing you to modify an ISO image or multisession disc, including file addition/removal, change of file names and attributes, and similar.
|
||||||
|
|
||||||
|
The old libisofs.so.5 has been declarated deprecated and frozen, leaving it unmaintained. A full refactoring of the design has been done during the last months, and the next generation libisofs.so.6 of the library will be released in the following days.
|
||||||
|
|
||||||
|
== Source Code ==
|
||||||
|
|
||||||
|
The code is maintained in a [http://bazaar-vcs.org/ Bazaar] repository at Launchpad (https://launchpad.net/libisofs/). You can download it with:
|
||||||
|
|
||||||
|
{{{
|
||||||
|
$ bzr branch lp:libisofs
|
||||||
|
}}}
|
||||||
|
|
||||||
|
|
||||||
|
To report any bug or suggest enchantments, [http://libburnia-project.org/register register] yourself and submit a new ticket. Bug and enchantments reports for nglibisofs can be found at http://libburnia-project.org/report/9.
|
||||||
|
|
||||||
|
== Usage tutorial ==
|
||||||
|
|
||||||
|
Coming soon... For now check [http://codebrowse.launchpad.net/~mario-danic/libisofs/mainline/annotate/metalpain2002%40yahoo.es-20080201154704-xqyzc57vki97iv3y?file_id=tutorial-20080127170757-cwmomu7oz9eh7fcz-1 "doc/Tutorial"] in the source tree.
|
||||||
|
|
||||||
|
|
||||||
|
=== Applications ===
|
||||||
|
|
||||||
|
Comming soon:
|
||||||
|
|
||||||
|
[http://libburnia-project.org/browser/libisoburn/trunk libisoburn]:
|
||||||
|
emulates ISO 9660 multi-session on overwriteable media, coordinates libisofs and libburn.
|
||||||
|
|
||||||
|
[http://libburnia-project.org/browser/libisoburn/trunk/xorriso/xorriso_eng.html?format=raw xorriso]:
|
||||||
|
creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions.
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
FEATURES
|
||||||
|
========
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
|
||||||
|
2.0 Operations on image tree
|
||||||
|
2.1 ECMA-119
|
||||||
|
2.2 Rock Ridge
|
||||||
|
2.3 Joliet
|
||||||
|
2.4 El-Torito
|
||||||
|
2.5 UDF
|
||||||
|
2.6 HFS/HFS+
|
||||||
|
2.7 Others
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
2.0 Operations on image tree
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Basic:
|
||||||
|
- We HAVE TO Support addition of directories
|
||||||
|
- From filesystem
|
||||||
|
- From filesystem recursively
|
||||||
|
- New on image
|
||||||
|
- We HAVE TO support addition of files
|
||||||
|
- From local filesystem
|
||||||
|
- From previous/ms images
|
||||||
|
- We HAVE TO support addition of other POSIX file types
|
||||||
|
- From filesystem
|
||||||
|
- New on image
|
||||||
|
- Types: symlinks, block/char devices, fifos, sockets...
|
||||||
|
- We HAVE TO support modification of file names on image
|
||||||
|
- We HAVE TO support modification of POSIX attributes:
|
||||||
|
- Uid/Gid
|
||||||
|
- Permissions (we DON'T HAVE TO support full mode modification,
|
||||||
|
as we don't want a dir to be changed to a reg file!!)
|
||||||
|
- Timestamps
|
||||||
|
- We HAVE TO support deletion of nodes.
|
||||||
|
- We HAVE TO support iteration of directory tree.
|
||||||
|
- We WANT TO support direct getting (without iteration) of the number of
|
||||||
|
nodes in a directory.
|
||||||
|
|
||||||
|
Extras:
|
||||||
|
- We WANT TO support on-the-fly modification of file contents, to
|
||||||
|
allow things like compression and encryption.
|
||||||
|
|
||||||
|
Notes: many operations will need RR extensions to be actually reflected on
|
||||||
|
the image.
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
2.1 ECMA-119
|
||||||
|
------------
|
||||||
|
|
||||||
|
Support for ECMA-119 (ISO-9660) specification.
|
||||||
|
|
||||||
|
2.1.1 Creation
|
||||||
|
--------------
|
||||||
|
|
||||||
|
We HAVE TO support creation of new images.
|
||||||
|
|
||||||
|
General:
|
||||||
|
- We HAVE TO support single volume images
|
||||||
|
- We DON'T NEED TO support multiple volume images.
|
||||||
|
It seems multiple volume images are not used.
|
||||||
|
- We HAVE TO support bootable volumes (see 2.4 in this doc)
|
||||||
|
Conformance:
|
||||||
|
- We HAVE TO support Level 1 restrictions (ECMA-119 10.1)
|
||||||
|
- We HAVE TO support Level 2 restrictions (ECMA-119 10.2)
|
||||||
|
Single Section files have a theoric size limit of 4GB (data length
|
||||||
|
is a 32-bit number, see ECMA-119 9.1.4). However I think I have
|
||||||
|
read that only files up to 2GB are supported.
|
||||||
|
- We MAY support full Level 3 (ECMA-119 10.3)
|
||||||
|
Multiple file sections are useful to support files higher than
|
||||||
|
level 2 limit. However, it seems it's a feature not supported in
|
||||||
|
most O.S. nowadays, so it's not very useful.
|
||||||
|
- We DON'T WANT TO support files recording in interleaved mode
|
||||||
|
(ECMA-119 6.4.3)
|
||||||
|
It seems a feature that it's not used.
|
||||||
|
- We DON'T WANT TO support associated files (ECMA-119 6.5.4)
|
||||||
|
What is that? Is it used?
|
||||||
|
- We DON'T WANT TO support Volume Partitions (ECMA-119 8.6)
|
||||||
|
What is that? Is it used?
|
||||||
|
- We DON'T WANT TO support extended attribute records (ECMA-119 9.5)
|
||||||
|
It seems an unused feature. RR is a better alternative.
|
||||||
|
- We DON'T NEED TO support file versions other than 1.
|
||||||
|
Restrictions:
|
||||||
|
- We HAVE TO provide a way to relax iso restrictions related to
|
||||||
|
filenames, allowing:
|
||||||
|
- Higher filename length, up to 37 chars (ECMA-119 7.5.1/7.6.3)
|
||||||
|
- Omit version number (ECMA-119 7.5.1)
|
||||||
|
- Directory hierarchy deeper than 8 levels / 255 path length
|
||||||
|
(ECMA-119 6.8.2.1)
|
||||||
|
- More characters in filenames, not only d-characters
|
||||||
|
|
||||||
|
|
||||||
|
2.2.2 Reading
|
||||||
|
-------------
|
||||||
|
|
||||||
|
General
|
||||||
|
- We HAVE TO support the reading of iso images
|
||||||
|
- We DON'T NEED TO support reading of features we don't support in
|
||||||
|
creation (see 2.2.1 above)
|
||||||
|
- We HAVE TO support reading arbitray file contents inside image
|
||||||
|
|
||||||
|
2.2.3 Modification/growing
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
General
|
||||||
|
- We HAVE TO support creation of new images from the contents of
|
||||||
|
an existing image
|
||||||
|
- We HAVE TO support multissession images
|
||||||
|
- We HAVE TO support growing of images
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
2.2 Rock Ridge
|
||||||
|
--------------
|
||||||
|
|
||||||
|
- We HAVE TO support ALL Rock Ridge features, with these exceptions:
|
||||||
|
- We DON'T NEED TO support SF System User Entry (RRIP 4.1.7), used to
|
||||||
|
encode sparse files.
|
||||||
|
- We MIGHT support BACKUP timestamp (RRIP 4.1.6)
|
||||||
|
- We HAVE TO support any charset in RR filenames, and not only POSIX portable
|
||||||
|
filename character set (RRIP 3.4.1). Namely, UTF-8 SHOULD BE the default for
|
||||||
|
RR filenames.
|
||||||
|
- We MIGHT support Linux specific ZF extension, to allow transparent
|
||||||
|
compression.
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
2.3 Joliet
|
||||||
|
----------
|
||||||
|
|
||||||
|
- We HAVE TO support ALL Joliet features, with these exceptions:
|
||||||
|
- We DON'T KNOW what to do with UCS-2 conformance level 1 and 2 (scape
|
||||||
|
sequences '%\@' and '%\C'). What's this???????
|
||||||
|
- We DON'T KNOW what to do with CD-XA extensions.
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
2.4 El-Torito
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- We HAVE TO El-Torito standard with a single boot image.
|
||||||
|
- We MAY support multiple boot images and boot entry selection.
|
||||||
|
- El Torito standard is not very clear about how to do that.
|
||||||
|
- We HAVE TO support both emulation and not emulation mode.
|
||||||
|
- We HAVE TO support 80x86 platform. We MAY support Power PC and Mac platforms.
|
||||||
|
- We HAVE TO provide improved support for isolinux boot images, namely patching
|
||||||
|
features.
|
||||||
|
- We HAVE TO support El-Torito in ms images.
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
2.5 UDF
|
||||||
|
-------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
2.6 HFS/HFS+
|
||||||
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
2.7 Others
|
||||||
|
----------
|
||||||
|
|
||||||
|
- We HAVE TO support sorting of file contents on image
|
||||||
|
- We HAVE TO support inode caching to prevent the same file to be written
|
||||||
|
several times into the image
|
||||||
|
- We DON'T NEED TO support TRANS.TBL files
|
||||||
|
- We DON'T NEED TO support padding of images
|
||||||
|
- Padding should be part of the burning process
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
USE CASES FOR NG LIBISOFS
|
||||||
|
=========================
|
||||||
|
|
||||||
|
3.1 General Operations
|
||||||
|
======================
|
||||||
|
|
||||||
|
3.1.1 Creation of a new image
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Desc: Creation of a new ISO image from files on the local filesystem
|
||||||
|
Phases:
|
||||||
|
- User creates a new image context
|
||||||
|
- User get the root (empty) of the image
|
||||||
|
- User adds files to the image root (see 3.2.)
|
||||||
|
- User sets the options for the the new image (extension to use...)
|
||||||
|
- User gets a burn_source to write the image.
|
||||||
|
- The burn_source can be used by libburn to write the new image.
|
||||||
|
|
||||||
|
3.1.2 Image growing (multisession)
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
Desc: An existing image can be grown with new files. New content is added
|
||||||
|
incrementally. Suitable for multisession. Growing support for
|
||||||
|
overwritteable media.
|
||||||
|
Phases:
|
||||||
|
- Uses reads an existing image to get the image context.
|
||||||
|
- User get the root of the image
|
||||||
|
- User modifies the image tree (see 3.2.)
|
||||||
|
- User sets the options for the the new image (extension to use...)
|
||||||
|
A required option will be the nwa for the image.
|
||||||
|
Optionally it can pass a pointer to a 64K buffer, that will be filled
|
||||||
|
with suitable volume descriptors to be used with overwrieable media.
|
||||||
|
- User gets a burn_source to write the image.
|
||||||
|
- The burn_source can be used by libburn to write an image that should be
|
||||||
|
appended to the previous image.
|
||||||
|
|
||||||
|
|
||||||
|
3.1.3 Image modification
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Desc: Creation of a new image from the contents of a previous image.
|
||||||
|
Phases:
|
||||||
|
- Uses reads an existing image to get the image context.
|
||||||
|
- User get the root of the image
|
||||||
|
- User modifies the image tree (see 3.2.)
|
||||||
|
- User sets the options for the the new image (extension to use...)
|
||||||
|
- User gets a burn_source to write the image.
|
||||||
|
- The burn_source can be used by libburn to write the image to another
|
||||||
|
device or file.
|
||||||
|
|
||||||
|
3.2 Tree operations
|
||||||
|
===================
|
||||||
|
|
||||||
|
3.2.1 Addition of contents
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
All addition operations take a parent dir. The functions check that the
|
||||||
|
node name is unique among all children. Image context options determine
|
||||||
|
what to do if a file with such name already exist.
|
||||||
|
|
||||||
|
3.2.1.1 Directories
|
||||||
|
--------------------
|
||||||
|
- Creation of new directories in image, given a parent dir. and a name.
|
||||||
|
Attributes are initialized to default values
|
||||||
|
- Addition of a dir from the filesystem, given a parent.
|
||||||
|
Dir contents are not added. Name and other attributes taken from
|
||||||
|
the dir on filesystem
|
||||||
|
- Recursive addition of a dir, given a parent. Directory contents are
|
||||||
|
recursivelly added to image.
|
||||||
|
|
||||||
|
3.2.1.2 Regular files
|
||||||
|
----------------------
|
||||||
|
- Addition of a local filesystem file. Name, attributes and contents to
|
||||||
|
be written taken from the filesystem file.
|
||||||
|
- Addition of files from the previous image. Files are automatically
|
||||||
|
added to the tree when the image is read. Name and attrbs taken from
|
||||||
|
previous image. When the image has no RR extensions, unavailable atts
|
||||||
|
are initialized to default values. The contents are only written to
|
||||||
|
img if we choose image modification.
|
||||||
|
- Addition of filtered files. Name and atts taken from the local
|
||||||
|
filesystem. A filter (see 3.3) is applied to the file contents before
|
||||||
|
written to image.
|
||||||
|
- Addition of splitted files. Like local filesystem files, but the file
|
||||||
|
is splitted in several files on a given size. Suitable for big (> 2GB)
|
||||||
|
files. Name of the splitted files automatically generated.
|
||||||
|
|
||||||
|
3.2.1.3 Symbolic links
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Simbolic links are only written to image if RR extensions are enabled.
|
||||||
|
|
||||||
|
- Addition of a simbolic link from local filesystem. Name, atts and
|
||||||
|
dest of a path are taken from the simbolic link.
|
||||||
|
- Addition of new link on image to a path. Name and dest specified,
|
||||||
|
the destination is specified as a path. Attributes initialized to
|
||||||
|
default values.
|
||||||
|
- Addition of new link on image to another node. Name and dest
|
||||||
|
specified, the dest is set to a node previously added to image.
|
||||||
|
When written, the destination path is computed as the relative path
|
||||||
|
from the link to the destination node. Attributes initialized to
|
||||||
|
default values.
|
||||||
|
|
||||||
|
3.2.1.4 Special files (block devices, fifos...)
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
Special files are only written to image if RR extensions are enabled.
|
||||||
|
|
||||||
|
- Addition of special files from filesystem.
|
||||||
|
- Creation of new special files on image.
|
||||||
|
|
||||||
|
|
||||||
|
3.2.2 Modification of contents
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
3.2.2.1 Deletion of nodes
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- Any node can be deleted. When a dir is remove, all its contents
|
||||||
|
are also removed.
|
||||||
|
|
||||||
|
3.2.2.2 Move
|
||||||
|
------------
|
||||||
|
|
||||||
|
- Any node can be move to another dir..
|
||||||
|
|
||||||
|
3.2.2.3 Rename
|
||||||
|
--------------
|
||||||
|
|
||||||
|
- You can change the name of any node
|
||||||
|
|
||||||
|
3.2.2.4 Change of POSIX attributes
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
- Following POSIX atts can be changed: owner (uid/gid), permissions,
|
||||||
|
timestamps.
|
||||||
|
|
||||||
|
3.2.3 Bootable information
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Addition of a boot image to a volume.
|
||||||
|
- In most cases, the catalog and the boot image itself is added to the
|
||||||
|
iso tree.
|
||||||
|
- Alternatively, user can select to add a hidden images, i.e., images
|
||||||
|
that don't appear in the iso tree.
|
||||||
|
- Modification of boot image attributes:
|
||||||
|
- bootable flag
|
||||||
|
- load segment
|
||||||
|
- load size
|
||||||
|
- Automatic patching of isolinux images. User needs to set whether to apply
|
||||||
|
this.
|
||||||
|
- Reading of El-Torito info from multisession images. Modification of its
|
||||||
|
attributes.
|
||||||
|
- Removing of El-Torito images
|
||||||
|
|
||||||
|
|
||||||
|
3.2.4 Other operations
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
3.2.4.1 Set file sort weight
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
- Any file can have a sort weight, that will determine the order in
|
||||||
|
which the files are written to image
|
||||||
|
|
||||||
|
3.2.4.2 Hidding of nodes
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
- Files can be hidden in the RR or Joliet tree
|
||||||
|
|
||||||
|
|
||||||
|
3.3 Filters
|
||||||
|
===========
|
||||||
|
|
||||||
|
[TODO]
|
||||||
|
|
||||||
|
Support for:
|
||||||
|
- compression filter
|
||||||
|
- encryption filter
|
||||||
|
- external process filter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
Index
|
||||||
|
=====
|
||||||
|
|
||||||
|
1. Overview
|
||||||
|
2. Features
|
||||||
|
3. Design
|
||||||
|
4. Implementation
|
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1,821 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<java version="1.6.0" class="java.beans.XMLDecoder">
|
||||||
|
<object class="com.horstmann.violet.SequenceDiagramGraph">
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="LifelineNode0" class="com.horstmann.violet.ImplicitParameterNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>fs:Filesystem</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>160.0</double>
|
||||||
|
<double>73.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ActivationBarNode0" class="com.horstmann.violet.CallNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="LifelineNode1" class="com.horstmann.violet.ImplicitParameterNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>file:FileSource</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="implicitParameter">
|
||||||
|
<object idref="LifelineNode0"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>192.0</double>
|
||||||
|
<double>209.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="LifelineNode1"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>274.0</double>
|
||||||
|
<double>202.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="LifelineNode2" class="com.horstmann.violet.ImplicitParameterNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>User</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>34.86475730998367</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ActivationBarNode1" class="com.horstmann.violet.CallNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object idref="LifelineNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="LifelineNode3" class="com.horstmann.violet.ImplicitParameterNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>b:TNBuilder</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object idref="ActivationBarNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ActivationBarNode2" class="com.horstmann.violet.CallNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ActivationBarNode3" class="com.horstmann.violet.CallNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ActivationBarNode4" class="com.horstmann.violet.CallNode">
|
||||||
|
<void property="implicitParameter">
|
||||||
|
<object idref="LifelineNode1"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="LifelineNode4" class="com.horstmann.violet.ImplicitParameterNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>ftn:FileTN</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ActivationBarNode5" class="com.horstmann.violet.CallNode">
|
||||||
|
<void property="implicitParameter">
|
||||||
|
<object idref="LifelineNode4"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="LifelineNode5" class="com.horstmann.violet.ImplicitParameterNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>fs:FileStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ActivationBarNode6" class="com.horstmann.violet.CallNode">
|
||||||
|
<void property="implicitParameter">
|
||||||
|
<object idref="LifelineNode4"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="implicitParameter">
|
||||||
|
<object idref="LifelineNode3"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="implicitParameter">
|
||||||
|
<object id="LifelineNode6" class="com.horstmann.violet.ImplicitParameterNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>d:DirTreeNode</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ActivationBarNode7" class="com.horstmann.violet.CallNode">
|
||||||
|
<void property="implicitParameter">
|
||||||
|
<object idref="LifelineNode4"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="implicitParameter">
|
||||||
|
<object idref="LifelineNode2"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>66.86475730998367</double>
|
||||||
|
<double>80.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="LifelineNode3"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>539.756828460011</double>
|
||||||
|
<double>126.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="LifelineNode6"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>651.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ActivationBarNode2"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>683.0</double>
|
||||||
|
<double>305.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>571.756828460011</double>
|
||||||
|
<double>328.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ActivationBarNode4"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>306.0</double>
|
||||||
|
<double>351.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="LifelineNode4"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>331.97135964975513</double>
|
||||||
|
<double>374.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ActivationBarNode5"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>363.97135964975513</double>
|
||||||
|
<double>457.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="LifelineNode5"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>418.8259109283281</double>
|
||||||
|
<double>480.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ActivationBarNode6"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>363.97135964975513</double>
|
||||||
|
<double>563.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>1. User wants to add a file to a dir in the iso node</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>143.89406091532933</double>
|
||||||
|
<double>16.868736840587744</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>2. It creates the source filesystem and the
|
||||||
|
custom builder</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>317.51829970572646</double>
|
||||||
|
<double>74.92004824517142</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode0" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double0" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>570.819415201306</double>
|
||||||
|
<double>142.7048538003265</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double0"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>570.819415201306</double>
|
||||||
|
<double>142.7048538003265</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode1" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double1" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>218.81410916050066</double>
|
||||||
|
<double>114.16388304026121</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double1"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>218.81410916050066</double>
|
||||||
|
<double>114.16388304026121</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>3. It gets the file from the filesystem
|
||||||
|
and add it to parent dir</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>379.1320632384976</double>
|
||||||
|
<double>217.4323774110454</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode2" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double2" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>327.03195662574825</double>
|
||||||
|
<double>218.46075295682857</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double2"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>327.03195662574825</double>
|
||||||
|
<double>218.46075295682857</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>4. The dir delegates in the builder.
|
||||||
|
5. The builder stat's the source file. In
|
||||||
|
this example it's a reg. file</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>767.038589176755</double>
|
||||||
|
<double>206.92203801047344</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode3" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double3" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>694.4969551615891</double>
|
||||||
|
<double>312.7614712457156</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double3"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>694.4969551615891</double>
|
||||||
|
<double>312.7614712457156</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode4" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double4" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>314.9148790283507</double>
|
||||||
|
<double>359.23720542189034</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double4"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>314.9148790283507</double>
|
||||||
|
<double>359.23720542189034</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>6. The conversion is not needed, so
|
||||||
|
the builder just creates a FileTreeNode</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>762.2817607167442</double>
|
||||||
|
<double>335.3564064307673</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode5" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double5" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>522.2869299335649</double>
|
||||||
|
<double>399.9594286575042</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double5"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>522.2869299335649</double>
|
||||||
|
<double>399.9594286575042</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode4" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>7. Sets the attributes from source</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>774.1738318667714</double>
|
||||||
|
<double>413.8440760209469</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode5" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>8 ...and a FileStream to read contents
|
||||||
|
from the FileSource</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>762.2817607167442</double>
|
||||||
|
<double>478.0612602310938</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode6" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double6" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>534.9181953038541</double>
|
||||||
|
<double>453.1845675071054</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double6"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>534.9181953038541</double>
|
||||||
|
<double>453.1845675071054</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode7" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double7" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>482.368075796364</double>
|
||||||
|
<double>524.8261757327898</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double7"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>482.368075796364</double>
|
||||||
|
<double>524.8261757327898</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode6" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>9. Finally, the FileTreeNode is added to
|
||||||
|
the parent dir, and returned to the user</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>757.5249322567332</double>
|
||||||
|
<double>556.5489298212734</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode8" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double8" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>689.7401267015781</double>
|
||||||
|
<double>614.8200784564067</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double8"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>689.7401267015781</double>
|
||||||
|
<double>614.8200784564067</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ActivationBarNode7"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>363.97135964975513</double>
|
||||||
|
<double>656.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode7" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>10. The user can change any attribute
|
||||||
|
on the FileTreeNode</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>735.3910524340093</double>
|
||||||
|
<double>659.0235200658623</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="PointNode9" class="com.horstmann.violet.PointNode">
|
||||||
|
<void id="Rectangle2D$Double9" property="bounds">
|
||||||
|
<void method="setRect">
|
||||||
|
<double>373.3523804664971</double>
|
||||||
|
<double>666.0945878777277</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
<double>0.0</double>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="bounds">
|
||||||
|
<object idref="Rectangle2D$Double9"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>373.3523804664971</double>
|
||||||
|
<double>666.0945878777277</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>«create»</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode0"/>
|
||||||
|
<object idref="LifelineNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>«create»</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode1"/>
|
||||||
|
<object idref="LifelineNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ReturnEdge">
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="SOLID"/>
|
||||||
|
</void>
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>file</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode0"/>
|
||||||
|
<object idref="ActivationBarNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>add_file(file,b)</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode1"/>
|
||||||
|
<object idref="ActivationBarNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>create_file(file)</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode2"/>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>lstat()</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
<object idref="ActivationBarNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ReturnEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>S_IFREG</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode4"/>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>«create»</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
<object idref="LifelineNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>set attributes</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
<object idref="ActivationBarNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ReturnEdge"/>
|
||||||
|
<object idref="ActivationBarNode5"/>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ReturnEdge">
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="SOLID"/>
|
||||||
|
</void>
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>ftn</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
<object idref="ActivationBarNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>«create»</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
<object idref="LifelineNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>set stream (fs)</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
<object idref="ActivationBarNode6"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ReturnEdge"/>
|
||||||
|
<object idref="ActivationBarNode6"/>
|
||||||
|
<object idref="ActivationBarNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ReturnEdge">
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="SOLID"/>
|
||||||
|
</void>
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>ftn</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode2"/>
|
||||||
|
<object idref="ActivationBarNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>«create»</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode1"/>
|
||||||
|
<object idref="LifelineNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>get(path)</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode1"/>
|
||||||
|
<object idref="ActivationBarNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode0"/>
|
||||||
|
<object idref="PointNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode0"/>
|
||||||
|
<object idref="PointNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode1"/>
|
||||||
|
<object idref="PointNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
<object idref="PointNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
<object idref="PointNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode3"/>
|
||||||
|
<object idref="PointNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode4"/>
|
||||||
|
<object idref="PointNode6"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode5"/>
|
||||||
|
<object idref="PointNode7"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode6"/>
|
||||||
|
<object idref="PointNode8"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.CallEdge">
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>set_permission()</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ActivationBarNode1"/>
|
||||||
|
<object idref="ActivationBarNode7"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ReturnEdge"/>
|
||||||
|
<object idref="ActivationBarNode7"/>
|
||||||
|
<object idref="ActivationBarNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="NoteNode7"/>
|
||||||
|
<object idref="PointNode9"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</java>
|
|
@ -0,0 +1,884 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<java version="1.6.0" class="java.beans.XMLDecoder">
|
||||||
|
<object class="com.horstmann.violet.ClassDiagramGraph">
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>get_root()
|
||||||
|
get_from_path(char *)</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Filesystem</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>159.04005306497305</double>
|
||||||
|
<double>489.4913761627291</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>MountedFilesytem</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>56.38849919058573</double>
|
||||||
|
<double>630.9884605487425</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>IsoImage</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>258.8562868808994</double>
|
||||||
|
<double>766.3563832139356</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode1" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>lstat()
|
||||||
|
read()
|
||||||
|
close()
|
||||||
|
open()
|
||||||
|
readdir()</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
SourceFile</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>481.55979910778467</double>
|
||||||
|
<double>464.84194569982117</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TarFile</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>176.58261638364775</double>
|
||||||
|
<double>701.0593878047844</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode2" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>read()
|
||||||
|
size()
|
||||||
|
open()
|
||||||
|
close()</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Stream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>779.894860994415</double>
|
||||||
|
<double>340.36024540554786</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FdStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>907.9433913981195</double>
|
||||||
|
<double>505.6600343909271</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FileStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>646.2536512193697</double>
|
||||||
|
<double>514.5953286599063</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TransformStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>774.6238447615127</double>
|
||||||
|
<double>513.9203093177954</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode3" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>create_file()
|
||||||
|
create_symlink()
|
||||||
|
create_dir()</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
TreeNodeBuilder</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>469.51180397870456</double>
|
||||||
|
<double>119.92057094444797</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TreeNode</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>777.5164467644091</double>
|
||||||
|
<double>137.7586776694888</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>File</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>776.3272396494064</double>
|
||||||
|
<double>235.11044131455145</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode8" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Dir</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>899.7797731623193</double>
|
||||||
|
<double>242.40651557378732</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode9" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Symlink</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>658.5957352641371</double>
|
||||||
|
<double>237.4888555445569</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode4" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
FileBuilder</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>68.74900622278733</double>
|
||||||
|
<double>236.29964842955417</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode5" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
DirBuilder</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>190.04813195306485</double>
|
||||||
|
<double>236.2996484295542</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode6" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
SymlinkBuilder</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>304.21201499332614</double>
|
||||||
|
<double>236.29964842955417</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>POSIX inspired interface to files on different filesystems.
|
||||||
|
open/close act as a opendir/closedir if the file is a dir,
|
||||||
|
I think we don't need different function to open a dir.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>154.8805850420814</double>
|
||||||
|
<double>333.9382491299707</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>"Sources" for file contents</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>587.0127806828101</double>
|
||||||
|
<double>358.755499461917</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode10" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>CutOutStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>845.6997102991108</double>
|
||||||
|
<double>605.2834046956852</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode11" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FilterStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>721.2489168102784</double>
|
||||||
|
<double>605.2834046956852</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode7" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Filter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>715.5920625607861</double>
|
||||||
|
<double>705.6925676241749</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>Used for arbitray streams, not related to
|
||||||
|
filesystem high-level idea. Also used for
|
||||||
|
files like fifos, that can't be added directly as
|
||||||
|
regulat files via de Builder, because its size is
|
||||||
|
unknown. The need to be added as new_files
|
||||||
|
on image</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>906.5108934811542</double>
|
||||||
|
<double>328.0975464705584</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>Create the user-specified TreeNode from the
|
||||||
|
user-specified source. If the source type differs the
|
||||||
|
TreeNode type the use wants to create, it makes
|
||||||
|
the needed conversion, if possible. Each builder
|
||||||
|
implementation can do different conversions.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>654.7808793787427</double>
|
||||||
|
<double>20.610173055266337</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode4" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>Together with the SourceFile encapsulates the
|
||||||
|
access to a given filesystem and abstracts it to
|
||||||
|
a POSIX interface.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>20.610173055266422</double>
|
||||||
|
<double>403.050865276332</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode5" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>The TreeNodeBuilder can be created with
|
||||||
|
the combination of different interfaces for
|
||||||
|
each factory method</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>149.90663761154804</double>
|
||||||
|
<double>57.982756057296896</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode12" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>MountedSrc</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>373.3523804664971</double>
|
||||||
|
<double>634.9818895055197</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode13" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TarSrc</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>479.4183976444791</double>
|
||||||
|
<double>695.7930726875627</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode14" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>IsoSrc</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>578.4133470105959</double>
|
||||||
|
<double>773.574818618083</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>{{create}}</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode9"/>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
<object idref="InterfaceNode6"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
<object idref="InterfaceNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
<object idref="InterfaceNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
<object idref="NoteNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
<object idref="NoteNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode11"/>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode10"/>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode11"/>
|
||||||
|
<object idref="InterfaceNode7"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
<object idref="NoteNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
<object idref="NoteNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode4"/>
|
||||||
|
<object idref="NoteNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode5"/>
|
||||||
|
<object idref="NoteNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode6"/>
|
||||||
|
<object idref="NoteNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode12"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode13"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode14"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode12"/>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode13"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode14"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</java>
|
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
|
@ -0,0 +1,634 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<java version="1.6.0" class="java.beans.XMLDecoder">
|
||||||
|
<object class="com.horstmann.violet.ClassDiagramGraph">
|
||||||
|
<void method="addNode">
|
||||||
|
<object class="com.horstmann.violet.PackageNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
BurnSource</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<string>libburn</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>600.0</double>
|
||||||
|
<double>50.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>612.4370214406964</double>
|
||||||
|
<double>81.3237865499184</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Ecma119Source</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>604.1172144213822</double>
|
||||||
|
<double>242.59825146055505</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>WriterState</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>861.1034292438676</double>
|
||||||
|
<double>244.31119796826698</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FilesWriterSt</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>984.2531292100068</double>
|
||||||
|
<double>359.95094883087904</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>VolDescWriterSt</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>717.2457054234224</double>
|
||||||
|
<double>357.4185959653686</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>DirInfoWriterSt</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>854.6043620021998</double>
|
||||||
|
<double>355.85097462036043</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Ecma119Image</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>392.3294860655768</double>
|
||||||
|
<double>240.39714472372754</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>The context data for image burn sources, contains
|
||||||
|
references to the tree, creation options...</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>261.45257180386454</double>
|
||||||
|
<double>85.80450046553075</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Ecma119Node</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>291.8219414851778</double>
|
||||||
|
<double>612.806815288254</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode1" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>init()
|
||||||
|
write_voldesc()
|
||||||
|
write_dir_info()</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
ImageWriter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>401.9520048709197</double>
|
||||||
|
<double>344.8700633507891</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>JolietNode</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>409.0872475609359</double>
|
||||||
|
<double>614.8200784564067</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode8" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FileRegistry</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>718.2810974616434</double>
|
||||||
|
<double>459.0339463910502</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode9" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Ecma119Writer</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>273.51763645062584</double>
|
||||||
|
<double>489.95333138112096</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode10" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>JolietWriter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>404.3304191009253</double>
|
||||||
|
<double>485.1965029211101</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode11" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>ElToritoWriter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>512.5482665661723</double>
|
||||||
|
<double>485.19650292111</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode12" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>size : off_t
|
||||||
|
block : uint32_t</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>IsoFile</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>720.659511691649</double>
|
||||||
|
<double>568.4410009713001</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode2" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Stream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>909.7434429770816</double>
|
||||||
|
<double>580.3330721213274</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>ImageWriter goal is to encapsulate the output
|
||||||
|
of image blocks related to one "specification",
|
||||||
|
i.e. we will have an implementation for ECMA-119/RR,
|
||||||
|
other for Joliet...
|
||||||
|
|
||||||
|
Note that having different implementations for things that
|
||||||
|
need to be written in the same block has no utility, i.e. RR
|
||||||
|
and ECMA-119 must share its Writer implementation.
|
||||||
|
|
||||||
|
Note also that while this provides considerable encapsulation
|
||||||
|
the provided abstraction is really partial: In the relation
|
||||||
|
with WriterState the encapsulation is quite good, each
|
||||||
|
concrete state know what method to call here (notice that
|
||||||
|
this interface is also quite coupled with state). However,
|
||||||
|
with respect to Ecma119Image the abstration only refers
|
||||||
|
to implementation, as the Ecma119Image needs to know
|
||||||
|
about the ImageWriter implementations. This can't be
|
||||||
|
avoided, as Ecma119Image has to be responsible of the
|
||||||
|
instantation in the correct order and following the user
|
||||||
|
needs.
|
||||||
|
|
||||||
|
</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>2.3784142300054896</double>
|
||||||
|
<double>160.54296052536733</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>The files are registered into the file registry, that will take care
|
||||||
|
about the written of content.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>286.59891471565567</double>
|
||||||
|
<double>708.7674405416217</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>Each state will invoque property method in each of
|
||||||
|
the ImageWriters. Some writers can return without
|
||||||
|
outputting anything. It is possible that when dealing
|
||||||
|
with UDF or other specification we would need new
|
||||||
|
states and methods in ImageWriter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>765.8493820617523</double>
|
||||||
|
<double>132.001989765302</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="NoteNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode10"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode9"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode11"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>*</string>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode9"/>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode10"/>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>*</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
<object idref="ClassNode12"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode12"/>
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
<object idref="NoteNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="NoteNode3"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</java>
|
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
|
@ -0,0 +1,552 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<java version="1.6.0" class="java.beans.XMLDecoder">
|
||||||
|
<object class="com.horstmann.violet.ClassDiagramGraph">
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Volume</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>479.2699858975891</double>
|
||||||
|
<double>226.94112549695433</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>block : uint32_t</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>ElToritoCatalog</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>472.58578643762684</double>
|
||||||
|
<double>344.73506473629425</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>bootable : bool
|
||||||
|
type : enum
|
||||||
|
partition_type : enum
|
||||||
|
load_seg : uint16
|
||||||
|
load_size : uint16
|
||||||
|
patch_isolinux : bool
|
||||||
|
block: uint32_t</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>BootImage</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>470.4142135623731</double>
|
||||||
|
<double>487.3919189857866</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>In a future we can support several boot
|
||||||
|
images</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>251.63542622468316</double>
|
||||||
|
<double>429.69343417595167</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>img : boolean</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>BootNode</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>193.07106781186545</double>
|
||||||
|
<double>334.49242404917493</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object class="com.horstmann.violet.PackageNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TreeNode</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<string>iso_tree</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>180.0</double>
|
||||||
|
<double>40.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>193.0</double>
|
||||||
|
<double>69.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>The img field is an implementation detail, used
|
||||||
|
to distinguish between the catalog node and the image
|
||||||
|
node. This is needed when the image is written.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>57.81118318204312</double>
|
||||||
|
<double>584.0458146424488</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>The support for growing or modify El-Torito images
|
||||||
|
is really hard to implement. The reason: when the
|
||||||
|
image is hidden, we don't know its size, so the best we
|
||||||
|
can do is just refer to the old image. When modify, all
|
||||||
|
we can do may be wrong.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>748.978906441031</double>
|
||||||
|
<double>574.8973495522459</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>The block in both Catalog and BootImage is needed
|
||||||
|
for multissession images</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>629.3242465083424</double>
|
||||||
|
<double>441.1316647878586</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>File</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>188.09040379562163</double>
|
||||||
|
<double>172.5340546095176</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>CatalogStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>851.105100475371</double>
|
||||||
|
<double>283.5127233261827</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FileStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>743.4055403867466</double>
|
||||||
|
<double>284.4253525880894</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode8" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TransformStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>958.5987801403015</double>
|
||||||
|
<double>279.8322618091961</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Stream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>847.6728065449973</double>
|
||||||
|
<double>157.05765855361264</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode9" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>IsoLinuxPatch</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>968.73629022557</double>
|
||||||
|
<double>384.6660889654818</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode4" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>Generates the content of the catalog on-the-fly</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>517.6021638285529</double>
|
||||||
|
<double>107.48023074035522</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode5" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>To apply the needed patch to isolinux
|
||||||
|
images</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>923.4814562296309</double>
|
||||||
|
<double>509.1168824543143</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>1 image</string>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="NoteNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>0..1 boot_cat</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>0..1 node</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object idref="NoteNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>0..1 node</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>1</string>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="NoteNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="NoteNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode9"/>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="NoteNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode9"/>
|
||||||
|
<object idref="NoteNode5"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</java>
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -0,0 +1,748 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<java version="1.6.0" class="java.beans.XMLDecoder">
|
||||||
|
<object class="com.horstmann.violet.ClassDiagramGraph">
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>volume_id : char*
|
||||||
|
publisher_id : char*
|
||||||
|
data_preparer_id : char*
|
||||||
|
system_id : char*
|
||||||
|
application_id : char*
|
||||||
|
copyright_file_id : char*
|
||||||
|
abstract_file_id : char*
|
||||||
|
biblio_file_id : char*</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Volume</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>1160.4799402311673</double>
|
||||||
|
<double>240.649943764645</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>sort_weight : int
|
||||||
|
block : uint32_t</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>File</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>687.5479565719912</double>
|
||||||
|
<double>269.2931470368318</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>name : char *
|
||||||
|
attribs : struct stat
|
||||||
|
hidden : enum</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TreeNode</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>706.83671056434</double>
|
||||||
|
<double>108.4726745515399</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>add(XXX)
|
||||||
|
remove(Node)
|
||||||
|
children()</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Directory</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>986.1687535943008</double>
|
||||||
|
<double>267.29314703683184</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>dest : char*</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Symlink</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>571.9364350336367</double>
|
||||||
|
<double>273.31078127658077</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Special</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>813.0651280884073</double>
|
||||||
|
<double>272.20749521231266</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>name : char*</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string><<static>>new(id)
|
||||||
|
<<static>>read(src, opts)
|
||||||
|
create()
|
||||||
|
grow()</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Image</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>1149.1980515339465</double>
|
||||||
|
<double>455.5218613006981</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>In addition to the dest as a path, it could
|
||||||
|
be a good idea to have a ref to tree node.
|
||||||
|
That way we can compute the dest on creation
|
||||||
|
time, and thus links to files on image are also valid
|
||||||
|
after moving or renaming those files</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>322.02220861890066</double>
|
||||||
|
<double>362.2044136147912</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>Image is a context for the creation of images. Its "static"
|
||||||
|
methods, new() and read() are used to create a new
|
||||||
|
image context, either from scratch or from an existing
|
||||||
|
image (for example, a ms disc). The methods create() and
|
||||||
|
grow() return an BurnSource suitable for libburn.
|
||||||
|
create() writes a full image, grow() only add to the image
|
||||||
|
the new files, thus it is suitable for a new session
|
||||||
|
</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>1212.7956394939486</double>
|
||||||
|
<double>697.0920982847697</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>Ecma119Source</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>1423.5617211564486</double>
|
||||||
|
<double>483.61244144432396</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object class="com.horstmann.violet.PackageNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
BurnSource</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<string>Libburn</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>1420.0</double>
|
||||||
|
<double>280.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>1431.4906533445824</double>
|
||||||
|
<double>311.35760744838467</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>Class diagram for the public tree. Note that getters and setters are not shown,
|
||||||
|
to improve readability. Note also that not all the attributes will have public getters
|
||||||
|
or/and setters.
|
||||||
|
El-Torito related information is shown in another diagram.
|
||||||
|
We don't show the several functions in Dir to manage the tree.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>290.59037712396525</double>
|
||||||
|
<double>9.859316379054544</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode1" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
DataSource</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>1192.781692587207</double>
|
||||||
|
<double>608.8954677283948</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object class="com.horstmann.violet.PackageNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="InterfaceNode2" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Filters</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<string>filters</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>260.0</double>
|
||||||
|
<double>710.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>265.45434264405947</double>
|
||||||
|
<double>743.9994422711634</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode8" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TransformStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>486.9335577265969</double>
|
||||||
|
<double>640.636302316303</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode9" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>CutOutStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>555.9916340674516</double>
|
||||||
|
<double>750.220757440409</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode3" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>get_size()
|
||||||
|
read()
|
||||||
|
open()
|
||||||
|
close()
|
||||||
|
is_repeatable()</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Stream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>688.5487814157467</double>
|
||||||
|
<double>437.25152600545294</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode10" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FdStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>680.6673668471356</double>
|
||||||
|
<double>637.245696021424</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode11" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FileStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>828.9404615480411</double>
|
||||||
|
<double>642.40096597045</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode12" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FilteredStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>428.449880813367</double>
|
||||||
|
<double>747.5389646099015</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode4" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
SourceFile</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>1000.6667341519202</double>
|
||||||
|
<double>639.0812755928229</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>For files, we need to know whethe they come
|
||||||
|
from a previous session. That's the purpose of
|
||||||
|
the block field</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>818.829652614022</double>
|
||||||
|
<double>414.36457377531684</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>1 volume</string>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
<object idref="NoteNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="NoteNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
<void property="middleLabel">
|
||||||
|
<string>{create}</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>0..1</string>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>* children</string>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>1 root</string>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>1 parent</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode11"/>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>1</string>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode10"/>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode9"/>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode12"/>
|
||||||
|
<object idref="ClassNode8"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode12"/>
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode11"/>
|
||||||
|
<object idref="InterfaceNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>1 src</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="InterfaceNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</java>
|
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,492 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<java version="1.6.0" class="java.beans.XMLDecoder">
|
||||||
|
<object class="com.horstmann.violet.ClassDiagramGraph">
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>TransformStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>374.71280028618764</double>
|
||||||
|
<double>246.7337520453866</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>get_size()
|
||||||
|
read()
|
||||||
|
open()
|
||||||
|
close()
|
||||||
|
is_repeatable()</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Stream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>576.3280239753375</double>
|
||||||
|
<double>43.34897573453627</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FileStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>741.9465965652432</double>
|
||||||
|
<double>246.8166228690261</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object class="com.horstmann.violet.PackageNode">
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>CompressionFilter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>EncryptionFilter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>ExtAppFilter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addChild">
|
||||||
|
<object id="InterfaceNode1" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="methods">
|
||||||
|
<void property="text">
|
||||||
|
<string>filter(in, out)</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
Filter</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<string>Filters</string>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>270.0</double>
|
||||||
|
<double>480.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>A Stream to read data from an abstract
|
||||||
|
file represented by a SourceFile</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>781.6101730552666</double>
|
||||||
|
<double>137.2161620284267</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>A stream to get data from an arbitrary file
|
||||||
|
descritor. size must be know in advance.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>580.8730162779191</double>
|
||||||
|
<double>392.3137084989848</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>fd : int
|
||||||
|
size : off_t</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FdStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>565.61818228198</double>
|
||||||
|
<double>253.24264068711926</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>281.2426406871193</double>
|
||||||
|
<double>620.6274169979695</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>429.51546936508925</double>
|
||||||
|
<double>624.9910026589843</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>568.2426406871186</double>
|
||||||
|
<double>624.6274169979695</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>A Filter do a tranformation on a stream of data.
|
||||||
|
The main difference with TransformSources is that
|
||||||
|
a Filter can be applied to several sources.
|
||||||
|
NOTES:
|
||||||
|
- filter() method still to define
|
||||||
|
- A filter_changes_size() method can be useful
|
||||||
|
</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>724.6274169979696</double>
|
||||||
|
<double>510.3015151901651</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>FilteredStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>439.0</double>
|
||||||
|
<double>357.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
|
||||||
|
<void property="attributes">
|
||||||
|
<void property="text">
|
||||||
|
<string>size : off_t
|
||||||
|
lba: off_t</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>CutOutStream</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>321.0</double>
|
||||||
|
<double>358.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>This can be implemented as a Filter, but
|
||||||
|
it has no sense to have the same cut out
|
||||||
|
filter to several sources, so this is a better
|
||||||
|
place.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>67.0</double>
|
||||||
|
<double>276.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="NoteNode4" class="com.horstmann.violet.NoteNode">
|
||||||
|
<void property="text">
|
||||||
|
<void property="text">
|
||||||
|
<string>A stream that applies some transformation
|
||||||
|
to the contents of another stream.</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>122.0</double>
|
||||||
|
<double>183.0</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>437.57046683437824</double>
|
||||||
|
<double>509.23933115391503</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="addNode">
|
||||||
|
<object id="InterfaceNode2" class="com.horstmann.violet.InterfaceNode">
|
||||||
|
<void property="name">
|
||||||
|
<void property="text">
|
||||||
|
<string>«interface»
|
||||||
|
SourceFile</string>
|
||||||
|
</void>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object class="java.awt.geom.Point2D$Double">
|
||||||
|
<void method="setLocation">
|
||||||
|
<double>920.6530291048848</double>
|
||||||
|
<double>248.90158697766475</double>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
<void property="endLabel">
|
||||||
|
<string>1</string>
|
||||||
|
</void>
|
||||||
|
<void property="startArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="InterfaceNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode5"/>
|
||||||
|
<object idref="NoteNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode7"/>
|
||||||
|
<object idref="NoteNode3"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode0"/>
|
||||||
|
<object idref="NoteNode4"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode2"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode3"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
|
||||||
|
</void>
|
||||||
|
<void property="lineStyle">
|
||||||
|
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode4"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode6"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="InterfaceNode1"/>
|
||||||
|
<object idref="NoteNode2"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.NoteEdge"/>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="NoteNode0"/>
|
||||||
|
</void>
|
||||||
|
<void method="connect">
|
||||||
|
<object class="com.horstmann.violet.ClassRelationshipEdge">
|
||||||
|
<void property="bentStyle">
|
||||||
|
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
|
||||||
|
</void>
|
||||||
|
<void property="endArrowHead">
|
||||||
|
<object class="com.horstmann.violet.ArrowHead" field="V"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
<object idref="ClassNode1"/>
|
||||||
|
<object idref="InterfaceNode2"/>
|
||||||
|
</void>
|
||||||
|
</object>
|
||||||
|
</java>
|
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
|
@ -0,0 +1,91 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<profiles version="1">
|
||||||
|
<profile kind="CodeFormatterProfile" name="nglibisofs" version="1">
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.continuation_indentation" value="2"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.lineSplit" value="80"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression" value="16"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier" value="true"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.tabulation.size" value="4"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_empty_lines" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.tabulation.char" value="space"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block_in_case" value="next_line_shifted"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.compact_else_if" value="true"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation" value="18"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration" value="18"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.indentation.size" value="4"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
|
@ -0,0 +1,119 @@
|
||||||
|
===============================================================================
|
||||||
|
ISO/IEC 9660:1999 Cookbook
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
Creation date: 2008-Jan-14
|
||||||
|
Author: Vreixo Formoso
|
||||||
|
_______________________________________________________________________________
|
||||||
|
|
||||||
|
Contents:
|
||||||
|
---------
|
||||||
|
|
||||||
|
1. References
|
||||||
|
2. General
|
||||||
|
3. Features
|
||||||
|
4. Implementation
|
||||||
|
5. Known implementation bugs and specification ambiguities/problems
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
1. References:
|
||||||
|
|
||||||
|
ISO/IEC DIS 9660:1999(E) "Information processing. Volume and file structure of
|
||||||
|
CD-ROM for Information Interchange"
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
2. General
|
||||||
|
|
||||||
|
ISO 9660:1999, also known as ISO-9660 version 2 is an update of the old
|
||||||
|
ISO 9660:1988 standard for writing data images for CD.
|
||||||
|
|
||||||
|
In the same way Joliet does, it is based on a Secondary Volume Descriptor (that
|
||||||
|
is called Enhanced Volume Descriptor), that provides a second tree where the
|
||||||
|
new file information is recorded.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
3. Features
|
||||||
|
|
||||||
|
It makes some improvements with respect to ECMA-119, mainly related to relax
|
||||||
|
the constraints imposed by its predecessor.
|
||||||
|
|
||||||
|
- It removes the limit to the deep of the directory hierarchy (6.8.2.1).
|
||||||
|
However, it still keep a limit to the path length, of 255 characters as in
|
||||||
|
ECMA-119.
|
||||||
|
|
||||||
|
- File names don't need the version number (;1) anymore, and the "." and ";",
|
||||||
|
used as SEPARATORS for extension and version number, have no special meaning
|
||||||
|
now.
|
||||||
|
|
||||||
|
- The file name max length is incremented to 207 bytes.
|
||||||
|
|
||||||
|
- The file name is not restricted to d-characters.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
4. Implementation
|
||||||
|
|
||||||
|
ISO 9660:1999 is very similar to old ISO 9660:1988 (ECMA-119). It needs two
|
||||||
|
tree hierarchies: one, identified by the Primary Volume Descriptor, is recorded
|
||||||
|
in the same way that an ECMA-119 structure.
|
||||||
|
|
||||||
|
The second structure is identified by a Enhanced Volume Descriptor (8.5). The
|
||||||
|
structure is exactly like defined in ECMA-119, with the exceptions named above.
|
||||||
|
|
||||||
|
Thus, to write an ISO 9660:1999:
|
||||||
|
|
||||||
|
- First 16 blocks are set to 0.
|
||||||
|
- Block 16 identifies a PVD (8.4), associated with a directory structure
|
||||||
|
written following ECMA-119.
|
||||||
|
- It is needed a Enhanced Volume descriptor to describe the additional
|
||||||
|
structure. It is much like a SVD, with version number set to 2 to identify
|
||||||
|
this new version.
|
||||||
|
- We can also write boot records (El-Torito) and additional SVD (Joliet).
|
||||||
|
- We write a Volume Descriptor Set Terminator (8.3)
|
||||||
|
- We write directory structure and path tables (L and M) for both ECMA-119
|
||||||
|
tree and enhanced tree. Path table record and directory record format is
|
||||||
|
the same in both structures. However, ECMA-119 is constrained by the usual
|
||||||
|
restrictions.
|
||||||
|
- And write the contents of the files.
|
||||||
|
|
||||||
|
Interchange levels 1, 2 and 3 are also defined. For PVD tree, they have the
|
||||||
|
same meaning as in ECMA-119. For EVD tree, in levels 1 and 2 files are
|
||||||
|
restricted to one file section (i.e., 4 GB filesize limit). In level 3 we can
|
||||||
|
have more than one section per file. Level 1 does not impose other
|
||||||
|
restrictions than that in the EVD tree.
|
||||||
|
|
||||||
|
It seems that both El-Torito and Joliet can coexist in a ISO 9660:1999 image.
|
||||||
|
However, Joliet has no utility at all in this kind of images, as it has no
|
||||||
|
benefit over ISO 9660:1999, and it is more restrictive in filename length.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
5. Known implementation bugs and specification ambiguities/problems
|
||||||
|
|
||||||
|
- While the specification clearly states that the tree speficied by the Primary
|
||||||
|
Volume Descriptor should remain compatible with ISO-9660 (ECMA-119), i.e., it
|
||||||
|
should be constrained by ECMA-119 restrictions, some image generation
|
||||||
|
applications out there just make both Primary and Enhanced Volume Descriptors
|
||||||
|
to point to the same directory structure. That is a specification violation, as
|
||||||
|
for a) the directory hierarchy specified in the Primary Volume Descriptor
|
||||||
|
doesn't follow the restrictions specified in the specs, and b) the same
|
||||||
|
directories are part of two different hiearchies (6.8.3 "A directory shall not
|
||||||
|
be a part of more than one Directory Hierarchy.").
|
||||||
|
Thus, we should keep two trees as we do with Joliet. Or are there strong
|
||||||
|
reasons against this?
|
||||||
|
|
||||||
|
- It's not very clear what characters are allowed for files and dir names. For
|
||||||
|
the tree identified in the Enhanced Volume Descriptor, it seems that a
|
||||||
|
"sequence of characters rather than d-characters or d1-characters" is allowed.
|
||||||
|
It also seems that the charset is determined by the escape sequence in the
|
||||||
|
EVD. Anyway, leaving escape sequence to 0 and use any user-specified sequence
|
||||||
|
(such as UTF-8) seems a good solution and is what many other applications do.
|
||||||
|
Linux correctly mounts the images in this case.
|
||||||
|
|
||||||
|
- It is not clear if RR extensions are allowed in the tree identified by the
|
||||||
|
Enhanced Volume Descriptor. However, it seems not a good idea. With 207 bytes
|
||||||
|
filenames and XA extensions, there is no place for RR entries in the directory
|
||||||
|
records of the enhanced tree. In my opinion, RR extension should be attached to
|
||||||
|
the ECMA-119 tree that must also be written to image.
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -0,0 +1,328 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synchronized ring buffer, works with a writer thread and a read thread.
|
||||||
|
*
|
||||||
|
* TODO #00010 : optimize ring buffer
|
||||||
|
* - write/read at the end of buffer requires a second mutex_lock, even if
|
||||||
|
* there's enought space/data at the beginning
|
||||||
|
* - pre-buffer for writes < BLOCK_SIZE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "libburn/libburn.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct iso_ring_buffer
|
||||||
|
{
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Max number of bytes in buffer
|
||||||
|
*/
|
||||||
|
size_t cap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of bytes available.
|
||||||
|
*/
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/* position for reading and writing, offset from buf */
|
||||||
|
size_t rpos;
|
||||||
|
size_t wpos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flags to report if read or writer threads ends execution
|
||||||
|
* 0 not finished, 1 finished ok, 2 finish with error
|
||||||
|
*/
|
||||||
|
unsigned int rend :2;
|
||||||
|
unsigned int wend :2;
|
||||||
|
|
||||||
|
/* just for statistical purposes */
|
||||||
|
unsigned int times_full;
|
||||||
|
unsigned int times_empty;
|
||||||
|
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
pthread_cond_t empty;
|
||||||
|
pthread_cond_t full;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer.
|
||||||
|
*
|
||||||
|
* The created buffer should be freed with iso_ring_buffer_free()
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* Number of blocks in buffer. You should supply a number >= 32, otherwise
|
||||||
|
* size will be ignored and 32 will be used by default, which leads to a
|
||||||
|
* 64 KiB buffer.
|
||||||
|
* @return
|
||||||
|
* 1 success, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_ring_buffer_new(size_t size, IsoRingBuffer **rbuf)
|
||||||
|
{
|
||||||
|
IsoRingBuffer *buffer;
|
||||||
|
|
||||||
|
if (rbuf == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = malloc(sizeof(IsoRingBuffer));
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->cap = (size > 32 ? size : 32) * BLOCK_SIZE;
|
||||||
|
buffer->buf = malloc(buffer->cap);
|
||||||
|
if (buffer->buf == NULL) {
|
||||||
|
free(buffer);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->size = 0;
|
||||||
|
buffer->wpos = 0;
|
||||||
|
buffer->rpos = 0;
|
||||||
|
|
||||||
|
buffer->times_full = 0;
|
||||||
|
buffer->times_empty = 0;
|
||||||
|
|
||||||
|
buffer->rend = buffer->wend = 0;
|
||||||
|
|
||||||
|
/* init mutex and waiting queues */
|
||||||
|
pthread_mutex_init(&buffer->mutex, NULL);
|
||||||
|
pthread_cond_init(&buffer->empty, NULL);
|
||||||
|
pthread_cond_init(&buffer->full, NULL);
|
||||||
|
|
||||||
|
*rbuf = buffer;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_ring_buffer_free(IsoRingBuffer *buf)
|
||||||
|
{
|
||||||
|
if (buf == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(buf->buf);
|
||||||
|
pthread_mutex_destroy(&buf->mutex);
|
||||||
|
pthread_cond_destroy(&buf->empty);
|
||||||
|
pthread_cond_destroy(&buf->full);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write count bytes into buffer. It blocks until all bytes where written or
|
||||||
|
* reader close the buffer.
|
||||||
|
*
|
||||||
|
* @param buf
|
||||||
|
* the buffer
|
||||||
|
* @param data
|
||||||
|
* pointer to a memory region of at least coun bytes, from which data
|
||||||
|
* will be read.
|
||||||
|
* @param
|
||||||
|
* Number of bytes to write
|
||||||
|
* @return
|
||||||
|
* 1 succes, 0 read finished, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
int bytes_write = 0;
|
||||||
|
|
||||||
|
if (buf == NULL || data == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bytes_write < count) {
|
||||||
|
|
||||||
|
pthread_mutex_lock(&buf->mutex);
|
||||||
|
|
||||||
|
while (buf->size == buf->cap) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note. There's only a writer, so we have no race conditions.
|
||||||
|
* Thus, the while(buf->size == buf->cap) is used here
|
||||||
|
* only to propertly detect the reader has been cancelled
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (buf->rend) {
|
||||||
|
/* the read procces has been finished */
|
||||||
|
pthread_mutex_unlock(&buf->mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
buf->times_full++;
|
||||||
|
/* wait until space available */
|
||||||
|
pthread_cond_wait(&buf->full, &buf->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
len = MIN(count - bytes_write, buf->cap - buf->size);
|
||||||
|
if (buf->wpos + len > buf->cap) {
|
||||||
|
len = buf->cap - buf->wpos;
|
||||||
|
}
|
||||||
|
memcpy(buf->buf + buf->wpos, data + bytes_write, len);
|
||||||
|
buf->wpos = (buf->wpos + len) % (buf->cap);
|
||||||
|
bytes_write += len;
|
||||||
|
buf->size += len;
|
||||||
|
|
||||||
|
/* wake up reader */
|
||||||
|
pthread_cond_signal(&buf->empty);
|
||||||
|
pthread_mutex_unlock(&buf->mutex);
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read count bytes from the buffer into dest. It blocks until the desired
|
||||||
|
* bytes has been read. If the writer finishes before outputting enought
|
||||||
|
* bytes, 0 (EOF) is returned, the number of bytes already read remains
|
||||||
|
* unknown.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 EOF, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_ring_buffer_read(IsoRingBuffer *buf, uint8_t *dest, size_t count)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
int bytes_read = 0;
|
||||||
|
|
||||||
|
if (buf == NULL || dest == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bytes_read < count) {
|
||||||
|
pthread_mutex_lock(&buf->mutex);
|
||||||
|
|
||||||
|
while (buf->size == 0) {
|
||||||
|
/*
|
||||||
|
* Note. There's only a reader, so we have no race conditions.
|
||||||
|
* Thus, the while(buf->size == 0) is used here just to ensure
|
||||||
|
* a reader detects the EOF propertly if the writer has been
|
||||||
|
* canceled while the reader was waiting
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (buf->wend) {
|
||||||
|
/* the writer procces has been finished */
|
||||||
|
pthread_mutex_unlock(&buf->mutex);
|
||||||
|
return 0; /* EOF */
|
||||||
|
}
|
||||||
|
buf->times_empty++;
|
||||||
|
/* wait until data available */
|
||||||
|
pthread_cond_wait(&buf->empty, &buf->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
len = MIN(count - bytes_read, buf->size);
|
||||||
|
if (buf->rpos + len > buf->cap) {
|
||||||
|
len = buf->cap - buf->rpos;
|
||||||
|
}
|
||||||
|
memcpy(dest + bytes_read, buf->buf + buf->rpos, len);
|
||||||
|
buf->rpos = (buf->rpos + len) % (buf->cap);
|
||||||
|
bytes_read += len;
|
||||||
|
buf->size -= len;
|
||||||
|
|
||||||
|
/* wake up the writer */
|
||||||
|
pthread_cond_signal(&buf->full);
|
||||||
|
pthread_mutex_unlock(&buf->mutex);
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_ring_buffer_writer_close(IsoRingBuffer *buf, int error)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&buf->mutex);
|
||||||
|
buf->wend = error ? 2 : 1;
|
||||||
|
|
||||||
|
/* ensure no reader is waiting */
|
||||||
|
pthread_cond_signal(&buf->empty);
|
||||||
|
pthread_mutex_unlock(&buf->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_ring_buffer_reader_close(IsoRingBuffer *buf, int error)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&buf->mutex);
|
||||||
|
|
||||||
|
if (buf->rend) {
|
||||||
|
/* reader already closed */
|
||||||
|
pthread_mutex_unlock(&buf->mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->rend = error ? 2 : 1;
|
||||||
|
|
||||||
|
/* ensure no writer is waiting */
|
||||||
|
pthread_cond_signal(&buf->full);
|
||||||
|
pthread_mutex_unlock(&buf->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the times the buffer was full.
|
||||||
|
*/
|
||||||
|
unsigned int iso_ring_buffer_get_times_full(IsoRingBuffer *buf)
|
||||||
|
{
|
||||||
|
return buf->times_full;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the times the buffer was empty.
|
||||||
|
*/
|
||||||
|
unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
|
||||||
|
{
|
||||||
|
return buf->times_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the status of the buffer used by a burn_source.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* A burn_source previously obtained with
|
||||||
|
* iso_image_create_burn_source().
|
||||||
|
* @param size
|
||||||
|
* Will be filled with the total size of the buffer, in bytes
|
||||||
|
* @param free_bytes
|
||||||
|
* Will be filled with the bytes currently available in buffer
|
||||||
|
* @return
|
||||||
|
* < 0 error, > 0 state:
|
||||||
|
* 1="active" : input and consumption are active
|
||||||
|
* 2="ending" : input has ended without error
|
||||||
|
* 3="failing" : input had error and ended,
|
||||||
|
* 5="abandoned" : consumption has ended prematurely
|
||||||
|
* 6="ended" : consumption has ended without input error
|
||||||
|
* 7="aborted" : consumption has ended after input error
|
||||||
|
*/
|
||||||
|
int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
|
||||||
|
size_t *free_bytes)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoRingBuffer *buf;
|
||||||
|
if (b == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
buf = ((Ecma119Image*)(b->data))->buffer;
|
||||||
|
|
||||||
|
/* get mutex */
|
||||||
|
pthread_mutex_lock(&buf->mutex);
|
||||||
|
if (size) {
|
||||||
|
*size = buf->cap;
|
||||||
|
}
|
||||||
|
if (free_bytes) {
|
||||||
|
*free_bytes = buf->cap - buf->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = (buf->rend ? 4 : 0) + (buf->wend + 1);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&buf->mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_BUFFER_H_
|
||||||
|
#define LIBISO_BUFFER_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define BLOCK_SIZE 2048
|
||||||
|
|
||||||
|
typedef struct iso_ring_buffer IsoRingBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new buffer.
|
||||||
|
*
|
||||||
|
* The created buffer should be freed with iso_ring_buffer_free()
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* Number of blocks in buffer. You should supply a number >= 32, otherwise
|
||||||
|
* size will be ignored and 32 will be used by default, which leads to a
|
||||||
|
* 64 KiB buffer.
|
||||||
|
* @return
|
||||||
|
* 1 success, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_ring_buffer_new(size_t size, IsoRingBuffer **rbuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a given buffer
|
||||||
|
*/
|
||||||
|
void iso_ring_buffer_free(IsoRingBuffer *buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write count bytes into buffer. It blocks until all bytes where written or
|
||||||
|
* reader close the buffer.
|
||||||
|
*
|
||||||
|
* @param buf
|
||||||
|
* the buffer
|
||||||
|
* @param data
|
||||||
|
* pointer to a memory region of at least coun bytes, from which data
|
||||||
|
* will be read.
|
||||||
|
* @param
|
||||||
|
* Number of bytes to write
|
||||||
|
* @return
|
||||||
|
* 1 succes, 0 read finished, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read count bytes from the buffer into dest. It blocks until the desired
|
||||||
|
* bytes has been read. If the writer finishes before outputting enought
|
||||||
|
* bytes, 0 (EOF) is returned, the number of bytes already read remains
|
||||||
|
* unknown.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 EOF, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_ring_buffer_read(IsoRingBuffer *buf, uint8_t *dest, size_t count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the buffer (to be called by the writer).
|
||||||
|
* You have to explicity close the buffer when you don't have more data to
|
||||||
|
* write, otherwise reader will be waiting forever.
|
||||||
|
*
|
||||||
|
* @param error
|
||||||
|
* Writer has finished prematurely due to an error
|
||||||
|
*/
|
||||||
|
void iso_ring_buffer_writer_close(IsoRingBuffer *buf, int error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the buffer (to be called by the reader).
|
||||||
|
* If for any reason you don't want to read more data, you need to call this
|
||||||
|
* to let the writer thread finish.
|
||||||
|
*
|
||||||
|
* @param error
|
||||||
|
* Reader has finished prematurely due to an error
|
||||||
|
*/
|
||||||
|
void iso_ring_buffer_reader_close(IsoRingBuffer *buf, int error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the times the buffer was full.
|
||||||
|
*/
|
||||||
|
unsigned int iso_ring_buffer_get_times_full(IsoRingBuffer *buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the times the buffer was empty.
|
||||||
|
*/
|
||||||
|
unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf);
|
||||||
|
|
||||||
|
#endif /*LIBISO_BUFFER_H_*/
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "builder.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "fsource.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
void iso_node_builder_ref(IsoNodeBuilder *builder)
|
||||||
|
{
|
||||||
|
++builder->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_node_builder_unref(IsoNodeBuilder *builder)
|
||||||
|
{
|
||||||
|
if (--builder->refcount == 0) {
|
||||||
|
/* free private data */
|
||||||
|
builder->free(builder);
|
||||||
|
free(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int default_create_file(IsoNodeBuilder *builder, IsoImage *image,
|
||||||
|
IsoFileSource *src, IsoFile **file)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct stat info;
|
||||||
|
IsoStream *stream;
|
||||||
|
IsoFile *node;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
if (builder == NULL || src == NULL || file == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = iso_file_source_stat(src, &info);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this will fail if src is a dir, is not accessible... */
|
||||||
|
ret = iso_file_source_stream_new(src, &stream);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = iso_file_source_get_name(src);
|
||||||
|
ret = iso_node_new_file(name, stream, &node);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* the stream has taken our ref to src, so we need to add one */
|
||||||
|
iso_file_source_ref(src);
|
||||||
|
iso_stream_unref(stream);
|
||||||
|
free(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill node fields */
|
||||||
|
iso_node_set_permissions((IsoNode*)node, info.st_mode);
|
||||||
|
iso_node_set_uid((IsoNode*)node, info.st_uid);
|
||||||
|
iso_node_set_gid((IsoNode*)node, info.st_gid);
|
||||||
|
iso_node_set_atime((IsoNode*)node, info.st_atime);
|
||||||
|
iso_node_set_mtime((IsoNode*)node, info.st_mtime);
|
||||||
|
iso_node_set_ctime((IsoNode*)node, info.st_ctime);
|
||||||
|
iso_node_set_uid((IsoNode*)node, info.st_uid);
|
||||||
|
|
||||||
|
*file = node;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
|
||||||
|
IsoFileSource *src, IsoNode **node)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct stat info;
|
||||||
|
IsoNode *new;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
if (builder == NULL || src == NULL || node == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get info about source */
|
||||||
|
if (iso_tree_get_follow_symlinks(image)) {
|
||||||
|
ret = iso_file_source_stat(src, &info);
|
||||||
|
} else {
|
||||||
|
ret = iso_file_source_lstat(src, &info);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = iso_file_source_get_name(src);
|
||||||
|
new = NULL;
|
||||||
|
|
||||||
|
switch (info.st_mode & S_IFMT) {
|
||||||
|
case S_IFREG:
|
||||||
|
{
|
||||||
|
/* source is a regular file */
|
||||||
|
IsoStream *stream;
|
||||||
|
IsoFile *file;
|
||||||
|
ret = iso_file_source_stream_new(src, &stream);
|
||||||
|
if (ret < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* take a ref to the src, as stream has taken our ref */
|
||||||
|
iso_file_source_ref(src);
|
||||||
|
|
||||||
|
/* create the file */
|
||||||
|
ret = iso_node_new_file(name, stream, &file);
|
||||||
|
if (ret < 0) {
|
||||||
|
iso_stream_unref(stream);
|
||||||
|
}
|
||||||
|
new = (IsoNode*) file;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case S_IFDIR:
|
||||||
|
{
|
||||||
|
/* source is a directory */
|
||||||
|
IsoDir *dir;
|
||||||
|
ret = iso_node_new_dir(name, &dir);
|
||||||
|
new = (IsoNode*)dir;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case S_IFLNK:
|
||||||
|
{
|
||||||
|
/* source is a symbolic link */
|
||||||
|
char dest[PATH_MAX];
|
||||||
|
IsoSymlink *link;
|
||||||
|
|
||||||
|
ret = iso_file_source_readlink(src, dest, PATH_MAX);
|
||||||
|
if (ret < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = iso_node_new_symlink(name, strdup(dest), &link);
|
||||||
|
new = (IsoNode*) link;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case S_IFSOCK:
|
||||||
|
case S_IFBLK:
|
||||||
|
case S_IFCHR:
|
||||||
|
case S_IFIFO:
|
||||||
|
{
|
||||||
|
/* source is an special file */
|
||||||
|
IsoSpecial *special;
|
||||||
|
ret = iso_node_new_special(name, info.st_mode, info.st_rdev,
|
||||||
|
&special);
|
||||||
|
new = (IsoNode*) special;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
free(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill fields */
|
||||||
|
iso_node_set_permissions(new, info.st_mode);
|
||||||
|
iso_node_set_uid(new, info.st_uid);
|
||||||
|
iso_node_set_gid(new, info.st_gid);
|
||||||
|
iso_node_set_atime(new, info.st_atime);
|
||||||
|
iso_node_set_mtime(new, info.st_mtime);
|
||||||
|
iso_node_set_ctime(new, info.st_ctime);
|
||||||
|
iso_node_set_uid(new, info.st_uid);
|
||||||
|
|
||||||
|
*node = new;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void default_free(IsoNodeBuilder *builder)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_node_basic_builder_new(IsoNodeBuilder **builder)
|
||||||
|
{
|
||||||
|
IsoNodeBuilder *b;
|
||||||
|
|
||||||
|
if (builder == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
b = malloc(sizeof(IsoNodeBuilder));
|
||||||
|
if (b == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->refcount = 1;
|
||||||
|
b->create_file_data = NULL;
|
||||||
|
b->create_node_data = NULL;
|
||||||
|
b->create_file = default_create_file;
|
||||||
|
b->create_node = default_create_node;
|
||||||
|
b->free = default_free;
|
||||||
|
|
||||||
|
*builder = b;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_BUILDER_H_
|
||||||
|
#define LIBISO_BUILDER_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for IsoNode builders.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some functions here will be moved to libisofs.h when we expose
|
||||||
|
* Builder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "fsource.h"
|
||||||
|
|
||||||
|
typedef struct Iso_Node_Builder IsoNodeBuilder;
|
||||||
|
|
||||||
|
struct Iso_Node_Builder
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IsoFile from an IsoFileSource. Name, permissions
|
||||||
|
* and other attributes are taken from src, but a regular file will
|
||||||
|
* always be created, even if src is another kind of file.
|
||||||
|
*
|
||||||
|
* In that case, if the implementation can't do the conversion, it
|
||||||
|
* should fail propertly.
|
||||||
|
*
|
||||||
|
* On sucess, the ref. to src will be owned by file, so you musn't
|
||||||
|
* unref it.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int (*create_file)(IsoNodeBuilder *builder, IsoImage *image,
|
||||||
|
IsoFileSource *src, IsoFile **file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IsoNode from a IsoFileSource. The type of the node to be
|
||||||
|
* created is determined from the type of the file source. Name,
|
||||||
|
* permissions and other attributes are taken from source file.
|
||||||
|
*
|
||||||
|
* Note that the src is never unref, so you need to free it.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int (*create_node)(IsoNodeBuilder *builder, IsoImage *image,
|
||||||
|
IsoFileSource *src, IsoNode **node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free implementation specific data. Should never be called by user.
|
||||||
|
* Use iso_node_builder_unref() instead.
|
||||||
|
*/
|
||||||
|
void (*free)(IsoNodeBuilder *builder);
|
||||||
|
|
||||||
|
int refcount;
|
||||||
|
void *create_file_data;
|
||||||
|
void *create_node_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void iso_node_builder_ref(IsoNodeBuilder *builder);
|
||||||
|
void iso_node_builder_unref(IsoNodeBuilder *builder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new basic builder ...
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 success, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_node_basic_builder_new(IsoNodeBuilder **builder);
|
||||||
|
|
||||||
|
#endif /*LIBISO_BUILDER_H_*/
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private data for File IsoDataSource
|
||||||
|
*/
|
||||||
|
struct file_data_src
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the reference counting of the given IsoDataSource.
|
||||||
|
*/
|
||||||
|
void iso_data_source_ref(IsoDataSource *src)
|
||||||
|
{
|
||||||
|
src->refcount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements the reference counting of the given IsoDataSource, freeing it
|
||||||
|
* if refcount reach 0.
|
||||||
|
*/
|
||||||
|
void iso_data_source_unref(IsoDataSource *src)
|
||||||
|
{
|
||||||
|
if (--src->refcount == 0) {
|
||||||
|
src->free_data(src);
|
||||||
|
free(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int ds_open(IsoDataSource *src)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct file_data_src *data;
|
||||||
|
|
||||||
|
if (src == NULL || src->data == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = (struct file_data_src*) src->data;
|
||||||
|
if (data->fd != -1) {
|
||||||
|
return ISO_FILE_ALREADY_OPENNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(data->path, O_RDONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
return ISO_FILE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->fd = fd;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int ds_close(IsoDataSource *src)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct file_data_src *data;
|
||||||
|
|
||||||
|
if (src == NULL || src->data == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = (struct file_data_src*) src->data;
|
||||||
|
if (data->fd == -1) {
|
||||||
|
return ISO_FILE_NOT_OPENNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close can fail if fd is not valid, but that should never happen */
|
||||||
|
ret = close(data->fd);
|
||||||
|
|
||||||
|
/* in any case we mark file as closed */
|
||||||
|
data->fd = -1;
|
||||||
|
return ret == 0 ? ISO_SUCCESS : ISO_FILE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
|
||||||
|
{
|
||||||
|
struct file_data_src *data;
|
||||||
|
|
||||||
|
if (src == NULL || src->data == NULL || buffer == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = (struct file_data_src*) src->data;
|
||||||
|
if (data->fd == -1) {
|
||||||
|
return ISO_FILE_NOT_OPENNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* goes to requested block */
|
||||||
|
if (lseek(data->fd, (off_t)lba * (off_t)2048, SEEK_SET) == (off_t) -1) {
|
||||||
|
return ISO_FILE_SEEK_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO #00008 : guard against partial reads. */
|
||||||
|
if (read(data->fd, buffer, 2048) != 2048) {
|
||||||
|
return ISO_FILE_READ_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void ds_free_data(IsoDataSource *src)
|
||||||
|
{
|
||||||
|
struct file_data_src *data;
|
||||||
|
|
||||||
|
data = (struct file_data_src*)src->data;
|
||||||
|
|
||||||
|
/* close the file if needed */
|
||||||
|
if (data->fd != -1) {
|
||||||
|
close(data->fd);
|
||||||
|
}
|
||||||
|
free(data->path);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IsoDataSource from a local file. This is suitable for
|
||||||
|
* accessing regular .iso images, or to acces drives via its block device
|
||||||
|
* and standard POSIX I/O calls.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* The path of the file
|
||||||
|
* @param src
|
||||||
|
* Will be filled with the pointer to the newly created data source.
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error.
|
||||||
|
*/
|
||||||
|
int iso_data_source_new_from_file(const char *path, IsoDataSource **src)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct file_data_src *data;
|
||||||
|
IsoDataSource *ds;
|
||||||
|
|
||||||
|
if (path == NULL || src == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ensure we have read access to the file */
|
||||||
|
ret = iso_eaccess(path);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = malloc(sizeof(struct file_data_src));
|
||||||
|
if (data == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ds = malloc(sizeof(IsoDataSource));
|
||||||
|
if (ds == NULL) {
|
||||||
|
free(data);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill data fields */
|
||||||
|
data->path = strdup(path);
|
||||||
|
if (data->path == NULL) {
|
||||||
|
free(data);
|
||||||
|
free(ds);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->fd = -1;
|
||||||
|
ds->version = 0;
|
||||||
|
ds->refcount = 1;
|
||||||
|
ds->data = data;
|
||||||
|
|
||||||
|
ds->open = ds_open;
|
||||||
|
ds->close = ds_close;
|
||||||
|
ds->read_block = ds_read_block;
|
||||||
|
ds->free_data = ds_free_data;
|
||||||
|
|
||||||
|
*src = ds;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,476 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_ECMA119_H_
|
||||||
|
#define LIBISO_ECMA119_H_
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define BLOCK_SIZE 2048
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the options for the image generation.
|
||||||
|
*/
|
||||||
|
struct iso_write_opts {
|
||||||
|
|
||||||
|
int level; /**< ISO level to write at. (ECMA-119, 10) */
|
||||||
|
|
||||||
|
/** Which extensions to support. */
|
||||||
|
unsigned int rockridge :1;
|
||||||
|
unsigned int joliet :1;
|
||||||
|
unsigned int iso1999 :1;
|
||||||
|
|
||||||
|
/* allways write timestamps in GMT */
|
||||||
|
unsigned int always_gmt :1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Relaxed constraints. Setting any of these to 1 break the specifications,
|
||||||
|
* but it is supposed to work on most moderns systems. Use with caution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Omit the version number (";1") at the end of the ISO-9660 identifiers.
|
||||||
|
* Version numbers are usually not used.
|
||||||
|
*/
|
||||||
|
unsigned int omit_version_numbers :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow ISO-9660 directory hierarchy to be deeper than 8 levels.
|
||||||
|
*/
|
||||||
|
unsigned int allow_deep_paths :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow path in the ISO-9660 tree to have more than 255 characters.
|
||||||
|
*/
|
||||||
|
unsigned int allow_longer_paths :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow a single file or directory hierarchy to have up to 37 characters.
|
||||||
|
* This is larger than the 31 characters allowed by ISO level 2, and the
|
||||||
|
* extra space is taken from the version number, so this also forces
|
||||||
|
* omit_version_numbers.
|
||||||
|
*/
|
||||||
|
unsigned int max_37_char_filenames :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISO-9660 forces filenames to have a ".", that separates file name from
|
||||||
|
* extension. libisofs adds it if original filename doesn't has one. Set
|
||||||
|
* this to 1 to prevent this behavior
|
||||||
|
*/
|
||||||
|
unsigned int no_force_dots :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow lowercase characters in ISO-9660 filenames. By default, only
|
||||||
|
* uppercase characters, numbers and a few other characters are allowed.
|
||||||
|
*/
|
||||||
|
unsigned int allow_lowercase :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow all ASCII characters to be appear on an ISO-9660 filename. Note
|
||||||
|
* that "/" and "\0" characters are never allowed, even in RR names.
|
||||||
|
*/
|
||||||
|
unsigned int allow_full_ascii :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow all characters to be part of Volume and Volset identifiers on
|
||||||
|
* the Primary Volume Descriptor. This breaks ISO-9660 contraints, but
|
||||||
|
* should work on modern systems.
|
||||||
|
*/
|
||||||
|
unsigned int relaxed_vol_atts :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow paths in the Joliet tree to have more than 240 characters.
|
||||||
|
*/
|
||||||
|
unsigned int joliet_longer_paths :1;
|
||||||
|
|
||||||
|
/** If files should be sorted based on their weight. */
|
||||||
|
unsigned int sort_files :1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following options set the default values for files and directory
|
||||||
|
* permissions, gid and uid. All these take one of three values: 0, 1 or 2.
|
||||||
|
* If 0, the corresponding attribute will be kept as setted in the IsoNode.
|
||||||
|
* Unless you have changed it, it corresponds to the value on disc, so it
|
||||||
|
* is suitable for backup purposes. If set to 1, the corresponding attrib.
|
||||||
|
* will be changed by a default suitable value. Finally, if you set it to
|
||||||
|
* 2, the attrib. will be changed with the value specified in the options
|
||||||
|
* below. Note that for mode attributes, only the permissions are set, the
|
||||||
|
* file type remains unchanged.
|
||||||
|
*/
|
||||||
|
unsigned int replace_dir_mode :2;
|
||||||
|
unsigned int replace_file_mode :2;
|
||||||
|
unsigned int replace_uid :2;
|
||||||
|
unsigned int replace_gid :2;
|
||||||
|
|
||||||
|
mode_t dir_mode; /** Mode to use on dirs when replace_dir_mode == 2. */
|
||||||
|
mode_t file_mode; /** Mode to use on files when replace_file_mode == 2. */
|
||||||
|
uid_t uid; /** uid to use when replace_uid == 2. */
|
||||||
|
gid_t gid; /** gid to use when replace_gid == 2. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 to use IsoNode timestamps, 1 to use recording time, 2 to use
|
||||||
|
* values from timestamp field. This has only meaning if RR extensions
|
||||||
|
* are enabled.
|
||||||
|
*/
|
||||||
|
unsigned int replace_timestamps :2;
|
||||||
|
time_t timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charset for the RR filenames that will be created.
|
||||||
|
* NULL to use default charset, the locale one.
|
||||||
|
*/
|
||||||
|
char *output_charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flags control the type of the image to create. Libisofs support
|
||||||
|
* two kind of images: stand-alone and appendable.
|
||||||
|
*
|
||||||
|
* A stand-alone image is an image that is valid alone, and that can be
|
||||||
|
* mounted by its own. This is the kind of image you will want to create
|
||||||
|
* in most cases. A stand-alone image can be burned in an empty CD or DVD,
|
||||||
|
* or write to an .iso file for future burning or distribution.
|
||||||
|
*
|
||||||
|
* On the other side, an appendable image is not self contained, it refers
|
||||||
|
* to serveral files that are stored outside the image. Its usage is for
|
||||||
|
* multisession discs, where you add data in a new session, while the
|
||||||
|
* previous session data can still be accessed. In those cases, the old
|
||||||
|
* data is not written again. Instead, the new image refers to it, and thus
|
||||||
|
* it's only valid when appended to the original. Note that in those cases
|
||||||
|
* the image will be written after the original, and thus you will want
|
||||||
|
* to use a ms_block greater than 0.
|
||||||
|
*
|
||||||
|
* Note that if you haven't import a previous image (by means of
|
||||||
|
* iso_image_import()), the image will always be a stand-alone image, as
|
||||||
|
* there is no previous data to refer to.
|
||||||
|
*/
|
||||||
|
unsigned int appendable : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start block of the image. It is supposed to be the lba where the first
|
||||||
|
* block of the image will be written on disc. All references inside the
|
||||||
|
* ISO image will take this into account, thus providing a mountable image.
|
||||||
|
*
|
||||||
|
* For appendable images, that are written to a new session, you should
|
||||||
|
* pass here the lba of the next writable address on disc.
|
||||||
|
*
|
||||||
|
* In stand alone images this is usually 0. However, you may want to
|
||||||
|
* provide a different ms_block if you don't plan to burn the image in the
|
||||||
|
* first session on disc, such as in some CD-Extra disc whether the data
|
||||||
|
* image is written in a new session after some audio tracks.
|
||||||
|
*/
|
||||||
|
uint32_t ms_block;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When not NULL, it should point to a buffer of at least 64KiB, where
|
||||||
|
* libisofs will write the contents that should be written at the beginning
|
||||||
|
* of a overwriteable media, to grow the image. The growing of an image is
|
||||||
|
* a way, used by first time in growisofs by Andy Polyakov, to allow the
|
||||||
|
* appending of new data to non-multisession media, such as DVD+RW, in the
|
||||||
|
* same way you append a new session to a multisession disc, i.e., without
|
||||||
|
* need to write again the contents of the previous image.
|
||||||
|
*
|
||||||
|
* Note that if you want this kind of image growing, you will also need to
|
||||||
|
* set appendable to "1" and provide a valid ms_block after the previous
|
||||||
|
* image.
|
||||||
|
*
|
||||||
|
* You should initialize the buffer either with 0s, or with the contents of
|
||||||
|
* the first blocks of the image you're growing. In most cases, 0 is good
|
||||||
|
* enought.
|
||||||
|
*/
|
||||||
|
uint8_t *overwrite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size, in number of blocks, of the FIFO buffer used between the writer
|
||||||
|
* thread and the burn_source. You have to provide at least a 32 blocks
|
||||||
|
* buffer.
|
||||||
|
*/
|
||||||
|
size_t fifo_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ecma119_image Ecma119Image;
|
||||||
|
typedef struct ecma119_node Ecma119Node;
|
||||||
|
typedef struct joliet_node JolietNode;
|
||||||
|
typedef struct iso1999_node Iso1999Node;
|
||||||
|
typedef struct Iso_File_Src IsoFileSrc;
|
||||||
|
typedef struct Iso_Image_Writer IsoImageWriter;
|
||||||
|
|
||||||
|
struct ecma119_image
|
||||||
|
{
|
||||||
|
IsoImage *image;
|
||||||
|
Ecma119Node *root;
|
||||||
|
|
||||||
|
unsigned int iso_level :2;
|
||||||
|
|
||||||
|
/* extensions */
|
||||||
|
unsigned int rockridge :1;
|
||||||
|
unsigned int joliet :1;
|
||||||
|
unsigned int eltorito :1;
|
||||||
|
unsigned int iso1999 :1;
|
||||||
|
|
||||||
|
/* allways write timestamps in GMT */
|
||||||
|
unsigned int always_gmt :1;
|
||||||
|
|
||||||
|
/* relaxed constraints */
|
||||||
|
unsigned int omit_version_numbers :1;
|
||||||
|
unsigned int allow_deep_paths :1;
|
||||||
|
unsigned int allow_longer_paths :1;
|
||||||
|
unsigned int max_37_char_filenames :1;
|
||||||
|
unsigned int no_force_dots :1;
|
||||||
|
unsigned int allow_lowercase :1;
|
||||||
|
unsigned int allow_full_ascii :1;
|
||||||
|
|
||||||
|
unsigned int relaxed_vol_atts : 1;
|
||||||
|
|
||||||
|
/** Allow paths on Joliet tree to be larger than 240 bytes */
|
||||||
|
unsigned int joliet_longer_paths :1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mode replace. If one of these flags is set, the correspodent values are
|
||||||
|
* replaced with values below.
|
||||||
|
*/
|
||||||
|
unsigned int replace_uid :1;
|
||||||
|
unsigned int replace_gid :1;
|
||||||
|
unsigned int replace_file_mode :1;
|
||||||
|
unsigned int replace_dir_mode :1;
|
||||||
|
unsigned int replace_timestamps :1;
|
||||||
|
|
||||||
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
mode_t file_mode;
|
||||||
|
mode_t dir_mode;
|
||||||
|
time_t timestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if sort files or not. Sorting is based of the weight of each file
|
||||||
|
*/
|
||||||
|
int sort_files;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
char *input_charset;
|
||||||
|
char *output_charset;
|
||||||
|
|
||||||
|
unsigned int appendable : 1;
|
||||||
|
uint32_t ms_block; /**< start block for a ms image */
|
||||||
|
time_t now; /**< Time at which writing began. */
|
||||||
|
|
||||||
|
/** Total size of the output. This only includes the current volume. */
|
||||||
|
off_t total_size;
|
||||||
|
uint32_t vol_space_size;
|
||||||
|
|
||||||
|
/* Bytes already written, just for progress notification */
|
||||||
|
off_t bytes_written;
|
||||||
|
int percent_written;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Block being processed, either during image writing or structure
|
||||||
|
* size calculation.
|
||||||
|
*/
|
||||||
|
uint32_t curblock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* number of dirs in ECMA-119 tree, computed together with dir position,
|
||||||
|
* and needed for path table computation in a efficient way
|
||||||
|
*/
|
||||||
|
size_t ndirs;
|
||||||
|
uint32_t path_table_size;
|
||||||
|
uint32_t l_path_table_pos;
|
||||||
|
uint32_t m_path_table_pos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Joliet related information
|
||||||
|
*/
|
||||||
|
JolietNode *joliet_root;
|
||||||
|
size_t joliet_ndirs;
|
||||||
|
uint32_t joliet_path_table_size;
|
||||||
|
uint32_t joliet_l_path_table_pos;
|
||||||
|
uint32_t joliet_m_path_table_pos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ISO 9660:1999 related information
|
||||||
|
*/
|
||||||
|
Iso1999Node *iso1999_root;
|
||||||
|
size_t iso1999_ndirs;
|
||||||
|
uint32_t iso1999_path_table_size;
|
||||||
|
uint32_t iso1999_l_path_table_pos;
|
||||||
|
uint32_t iso1999_m_path_table_pos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* El-Torito related information
|
||||||
|
*/
|
||||||
|
struct el_torito_boot_catalog *catalog;
|
||||||
|
IsoFileSrc *cat; /**< location of the boot catalog in the new image */
|
||||||
|
IsoFileSrc *bootimg; /**< location of the boot image in the new image */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of pad blocks that we need to write. Padding blocks are blocks
|
||||||
|
* filled by 0s that we put between the directory structures and the file
|
||||||
|
* data. These padding blocks are added by libisofs to improve the handling
|
||||||
|
* of image growing. The idea is that the first blocks in the image are
|
||||||
|
* overwritten with the volume descriptors of the new image. These first
|
||||||
|
* blocks usually correspond to the volume descriptors and directory
|
||||||
|
* structure of the old image, and can be safety overwritten. However,
|
||||||
|
* with very small images they might correspond to valid data. To ensure
|
||||||
|
* this never happens, what we do is to add padding bytes, to ensure no
|
||||||
|
* file data is written in the first 64 KiB, that are the bytes we usually
|
||||||
|
* overwrite.
|
||||||
|
*/
|
||||||
|
uint32_t pad_blocks;
|
||||||
|
|
||||||
|
size_t nwriters;
|
||||||
|
IsoImageWriter **writers;
|
||||||
|
|
||||||
|
/* tree of files sources */
|
||||||
|
IsoRBTree *files;
|
||||||
|
|
||||||
|
/* Buffer for communication between burn_source and writer thread */
|
||||||
|
IsoRingBuffer *buffer;
|
||||||
|
|
||||||
|
/* writer thread descriptor */
|
||||||
|
pthread_t wthread;
|
||||||
|
pthread_attr_t th_attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BP(a,b) [(b) - (a) + 1]
|
||||||
|
|
||||||
|
/* ECMA-119, 8.4 */
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ECMA-119, 8.5 */
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ECMA-119, 8.2 */
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ECMA-119, 9.1 */
|
||||||
|
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) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ECMA-119, 9.4 */
|
||||||
|
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) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ECMA-119, 8.3 */
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /*LIBISO_ECMA119_H_*/
|
|
@ -0,0 +1,846 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ecma119_tree.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "filesrc.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "stream.h"
|
||||||
|
#include "eltorito.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
|
||||||
|
{
|
||||||
|
int ret, relaxed;
|
||||||
|
char *ascii_name;
|
||||||
|
char *isoname= NULL;
|
||||||
|
|
||||||
|
if (iso->name == NULL) {
|
||||||
|
/* it is not necessarily an error, it can be the root */
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = str2ascii(img->input_charset, iso->name, &ascii_name);
|
||||||
|
if (ret < 0) {
|
||||||
|
iso_msg_submit(img->image->id, ret, 0, "Can't convert %s", iso->name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img->allow_full_ascii) {
|
||||||
|
relaxed = 2;
|
||||||
|
} else {
|
||||||
|
relaxed = (int)img->allow_lowercase;
|
||||||
|
}
|
||||||
|
if (iso->type == LIBISO_DIR) {
|
||||||
|
if (img->max_37_char_filenames) {
|
||||||
|
isoname = iso_r_dirid(ascii_name, 37, relaxed);
|
||||||
|
} else if (img->iso_level == 1) {
|
||||||
|
if (relaxed) {
|
||||||
|
isoname = iso_r_dirid(ascii_name, 8, relaxed);
|
||||||
|
} else {
|
||||||
|
isoname = iso_1_dirid(ascii_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (relaxed) {
|
||||||
|
isoname = iso_r_dirid(ascii_name, 8, relaxed);
|
||||||
|
} else {
|
||||||
|
isoname = iso_2_dirid(ascii_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (img->max_37_char_filenames) {
|
||||||
|
isoname = iso_r_fileid(ascii_name, 36, relaxed,
|
||||||
|
img->no_force_dots ? 0 : 1);
|
||||||
|
} else if (img->iso_level == 1) {
|
||||||
|
if (relaxed) {
|
||||||
|
isoname = iso_r_fileid(ascii_name, 11, relaxed,
|
||||||
|
img->no_force_dots ? 0 : 1);
|
||||||
|
} else {
|
||||||
|
isoname = iso_1_fileid(ascii_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (relaxed) {
|
||||||
|
isoname = iso_r_fileid(ascii_name, 30, relaxed,
|
||||||
|
img->no_force_dots ? 0 : 1);
|
||||||
|
} else {
|
||||||
|
isoname = iso_2_fileid(ascii_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(ascii_name);
|
||||||
|
if (isoname != NULL) {
|
||||||
|
*name = isoname;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* only possible if mem error, as check for empty names is done
|
||||||
|
* in public tree
|
||||||
|
*/
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int create_ecma119_node(Ecma119Image *img, IsoNode *iso, Ecma119Node **node)
|
||||||
|
{
|
||||||
|
Ecma119Node *ecma;
|
||||||
|
|
||||||
|
ecma = calloc(1, sizeof(Ecma119Node));
|
||||||
|
if (ecma == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* take a ref to the IsoNode */
|
||||||
|
ecma->node = iso;
|
||||||
|
iso_node_ref(iso);
|
||||||
|
|
||||||
|
/* TODO #00009 : add true support for harlinks and inode numbers */
|
||||||
|
ecma->nlink = 1;
|
||||||
|
ecma->ino = ++img->ino;
|
||||||
|
|
||||||
|
*node = ecma;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ECMA-119 node representing a directory from a iso directory
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int create_dir(Ecma119Image *img, IsoDir *iso, Ecma119Node **node)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
Ecma119Node **children;
|
||||||
|
struct ecma119_dir_info *dir_info;
|
||||||
|
|
||||||
|
children = calloc(1, sizeof(void*) * iso->nchildren);
|
||||||
|
if (children == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_info = calloc(1, sizeof(struct ecma119_dir_info));
|
||||||
|
if (dir_info == NULL) {
|
||||||
|
free(children);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = create_ecma119_node(img, (IsoNode*)iso, node);
|
||||||
|
if (ret < 0) {
|
||||||
|
free(children);
|
||||||
|
free(dir_info);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
(*node)->type = ECMA119_DIR;
|
||||||
|
(*node)->info.dir = dir_info;
|
||||||
|
(*node)->info.dir->nchildren = 0;
|
||||||
|
(*node)->info.dir->children = children;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ECMA-119 node representing a regular file from a iso file
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoFileSrc *src;
|
||||||
|
off_t size;
|
||||||
|
|
||||||
|
size = iso_stream_get_size(iso->stream);
|
||||||
|
if (size > (off_t)0xffffffff) {
|
||||||
|
return iso_msg_submit(img->image->id, ISO_FILE_TOO_BIG, 0,
|
||||||
|
"File \"%s\" can't be added to image because "
|
||||||
|
"is greater than 4GB", iso->node.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = iso_file_src_create(img, iso, &src);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = create_ecma119_node(img, (IsoNode*)iso, node);
|
||||||
|
if (ret < 0) {
|
||||||
|
/*
|
||||||
|
* the src doesn't need to be freed, it is free together with
|
||||||
|
* the Ecma119Image
|
||||||
|
*/
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
(*node)->type = ECMA119_FILE;
|
||||||
|
(*node)->info.file = src;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ECMA-119 node representing a regular file from an El-Torito
|
||||||
|
* boot catalog
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int create_boot_cat(Ecma119Image *img, IsoBoot *iso, Ecma119Node **node)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoFileSrc *src;
|
||||||
|
|
||||||
|
ret = el_torito_catalog_file_src_create(img, &src);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = create_ecma119_node(img, (IsoNode*)iso, node);
|
||||||
|
if (ret < 0) {
|
||||||
|
/*
|
||||||
|
* the src doesn't need to be freed, it is free together with
|
||||||
|
* the Ecma119Image
|
||||||
|
*/
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
(*node)->type = ECMA119_FILE;
|
||||||
|
(*node)->info.file = src;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ECMA-119 node representing a symbolic link from a iso symlink
|
||||||
|
* node.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int create_symlink(Ecma119Image *img, IsoSymlink *iso, Ecma119Node **node)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = create_ecma119_node(img, (IsoNode*)iso, node);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
(*node)->type = ECMA119_SYMLINK;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ECMA-119 node representing a special file.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int create_special(Ecma119Image *img, IsoSpecial *iso, Ecma119Node **node)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = create_ecma119_node(img, (IsoNode*)iso, node);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
(*node)->type = ECMA119_SPECIAL;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ecma119_node_free(Ecma119Node *node)
|
||||||
|
{
|
||||||
|
if (node == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node->type == ECMA119_DIR) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < node->info.dir->nchildren; i++) {
|
||||||
|
ecma119_node_free(node->info.dir->children[i]);
|
||||||
|
}
|
||||||
|
free(node->info.dir->children);
|
||||||
|
free(node->info.dir);
|
||||||
|
}
|
||||||
|
free(node->iso_name);
|
||||||
|
iso_node_unref(node->node);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 node ignored, < 0 error
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
|
||||||
|
int depth, int pathlen)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
Ecma119Node *node;
|
||||||
|
int max_path;
|
||||||
|
char *iso_name= NULL;
|
||||||
|
|
||||||
|
if (image == NULL || iso == NULL || tree == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iso->hidden & LIBISO_HIDE_ON_RR) {
|
||||||
|
/* file will be ignored */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret = get_iso_name(image, iso, &iso_name);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
max_path = pathlen + 1 + (iso_name ? strlen(iso_name) : 0);
|
||||||
|
if (!image->rockridge) {
|
||||||
|
if ((iso->type == LIBISO_DIR && depth > 8) && !image->allow_deep_paths) {
|
||||||
|
free(iso_name);
|
||||||
|
return iso_msg_submit(image->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||||
|
"File \"%s\" can't be added, because directory depth "
|
||||||
|
"is greater than 8.", iso->name);
|
||||||
|
} else if (max_path > 255 && !image->allow_longer_paths) {
|
||||||
|
free(iso_name);
|
||||||
|
return iso_msg_submit(image->image->id, ISO_FILE_IMGPATH_WRONG, 0,
|
||||||
|
"File \"%s\" can't be added, because path length "
|
||||||
|
"is greater than 255 characters", iso->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (iso->type) {
|
||||||
|
case LIBISO_FILE:
|
||||||
|
ret = create_file(image, (IsoFile*)iso, &node);
|
||||||
|
break;
|
||||||
|
case LIBISO_SYMLINK:
|
||||||
|
if (image->rockridge) {
|
||||||
|
ret = create_symlink(image, (IsoSymlink*)iso, &node);
|
||||||
|
} else {
|
||||||
|
/* symlinks are only supported when RR is enabled */
|
||||||
|
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
|
||||||
|
"File \"%s\" ignored. Symlinks need RockRidge extensions.",
|
||||||
|
iso->name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIBISO_SPECIAL:
|
||||||
|
if (image->rockridge) {
|
||||||
|
ret = create_special(image, (IsoSpecial*)iso, &node);
|
||||||
|
} else {
|
||||||
|
/* symlinks are only supported when RR is enabled */
|
||||||
|
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
|
||||||
|
"File \"%s\" ignored. Special files need RockRidge extensions.",
|
||||||
|
iso->name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIBISO_BOOT:
|
||||||
|
if (image->eltorito) {
|
||||||
|
ret = create_boot_cat(image, (IsoBoot*)iso, &node);
|
||||||
|
} else {
|
||||||
|
/* log and ignore */
|
||||||
|
ret = iso_msg_submit(image->image->id, ISO_FILE_IGNORED, 0,
|
||||||
|
"El-Torito catalog found on a image without El-Torito.",
|
||||||
|
iso->name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIBISO_DIR:
|
||||||
|
{
|
||||||
|
IsoNode *pos;
|
||||||
|
IsoDir *dir = (IsoDir*)iso;
|
||||||
|
ret = create_dir(image, dir, &node);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
pos = dir->children;
|
||||||
|
while (pos) {
|
||||||
|
int cret;
|
||||||
|
Ecma119Node *child;
|
||||||
|
cret = create_tree(image, pos, &child, depth + 1, max_path);
|
||||||
|
if (cret < 0) {
|
||||||
|
/* error */
|
||||||
|
ecma119_node_free(node);
|
||||||
|
ret = cret;
|
||||||
|
break;
|
||||||
|
} else if (cret == ISO_SUCCESS) {
|
||||||
|
/* add child to this node */
|
||||||
|
int nchildren = node->info.dir->nchildren++;
|
||||||
|
node->info.dir->children[nchildren] = child;
|
||||||
|
child->parent = node;
|
||||||
|
}
|
||||||
|
pos = pos->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* should never happen */
|
||||||
|
return ISO_ASSERT_FAILURE;
|
||||||
|
}
|
||||||
|
if (ret <= 0) {
|
||||||
|
free(iso_name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
node->iso_name = iso_name;
|
||||||
|
*tree = node;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the iso name of two ECMA-119 nodes
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int cmp_node_name(const void *f1, const void *f2)
|
||||||
|
{
|
||||||
|
Ecma119Node *f = *((Ecma119Node**)f1);
|
||||||
|
Ecma119Node *g = *((Ecma119Node**)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(Ecma119Node *root)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
qsort(root->info.dir->children, root->info.dir->nchildren, sizeof(void*),
|
||||||
|
cmp_node_name);
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the ISO name of each children of the given dir is unique,
|
||||||
|
* changing some of them if needed.
|
||||||
|
* It also ensures that resulting filename is always <= than given
|
||||||
|
* max_name_len, including extension. If needed, the extension will be reduced,
|
||||||
|
* but never under 3 characters.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||||
|
int max_dir_len)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
int i, nchildren;
|
||||||
|
Ecma119Node **children;
|
||||||
|
IsoHTable *table;
|
||||||
|
int need_sort = 0;
|
||||||
|
|
||||||
|
nchildren = dir->info.dir->nchildren;
|
||||||
|
children = dir->info.dir->children;
|
||||||
|
|
||||||
|
/* a hash table will temporary hold the names, for fast searching */
|
||||||
|
ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash,
|
||||||
|
(compare_function_t)strcmp, &table);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
for (i = 0; i < nchildren; ++i) {
|
||||||
|
char *name = children[i]->iso_name;
|
||||||
|
ret = iso_htable_add(table, name, name);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto mangle_cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nchildren; ++i) {
|
||||||
|
char *name, *ext;
|
||||||
|
char full_name[40];
|
||||||
|
int max; /* computed max len for name, without extension */
|
||||||
|
int j = i;
|
||||||
|
int digits = 1; /* characters to change per name */
|
||||||
|
|
||||||
|
/* first, find all child with same name */
|
||||||
|
while (j + 1 < nchildren && !cmp_node_name(children + i, children + j
|
||||||
|
+ 1)) {
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
if (j == i) {
|
||||||
|
/* name is unique */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A max of 7 characters is good enought, it allows handling up to
|
||||||
|
* 9,999,999 files with same name. We can increment this to
|
||||||
|
* max_name_len, but the int_pow() function must then be modified
|
||||||
|
* to return a bigger integer.
|
||||||
|
*/
|
||||||
|
while (digits < 8) {
|
||||||
|
int ok, k;
|
||||||
|
char *dot;
|
||||||
|
int change = 0; /* number to be written */
|
||||||
|
|
||||||
|
/* copy name to buffer */
|
||||||
|
strcpy(full_name, children[i]->iso_name);
|
||||||
|
|
||||||
|
/* compute name and extension */
|
||||||
|
dot = strrchr(full_name, '.');
|
||||||
|
if (dot != NULL && children[i]->type != ECMA119_DIR) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File (not dir) with extension
|
||||||
|
* Note that we don't need to check for placeholders, as
|
||||||
|
* tree reparent happens later, so no placeholders can be
|
||||||
|
* here at this time.
|
||||||
|
*/
|
||||||
|
int extlen;
|
||||||
|
full_name[dot - full_name] = '\0';
|
||||||
|
name = full_name;
|
||||||
|
ext = dot + 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For iso level 1 we force ext len to be 3, as name
|
||||||
|
* can't grow on the extension space
|
||||||
|
*/
|
||||||
|
extlen = (max_file_len == 12) ? 3 : strlen(ext);
|
||||||
|
max = max_file_len - extlen - 1 - digits;
|
||||||
|
if (max <= 0) {
|
||||||
|
/* this can happen if extension is too long */
|
||||||
|
if (extlen + max > 3) {
|
||||||
|
/*
|
||||||
|
* reduce extension len, to give name an extra char
|
||||||
|
* note that max is negative or 0
|
||||||
|
*/
|
||||||
|
extlen = extlen + max - 1;
|
||||||
|
ext[extlen] = '\0';
|
||||||
|
max = max_file_len - extlen - 1 - digits;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* error, we don't support extensions < 3
|
||||||
|
* This can't happen with current limit of digits.
|
||||||
|
*/
|
||||||
|
ret = ISO_ERROR;
|
||||||
|
goto mangle_cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ok, reduce name by digits */
|
||||||
|
if (name + max < dot) {
|
||||||
|
name[max] = '\0';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Directory, or file without extension */
|
||||||
|
if (children[i]->type == ECMA119_DIR) {
|
||||||
|
max = max_dir_len - digits;
|
||||||
|
dot = NULL; /* dots have no meaning in dirs */
|
||||||
|
} else {
|
||||||
|
max = max_file_len - digits;
|
||||||
|
}
|
||||||
|
name = full_name;
|
||||||
|
if (max < strlen(name)) {
|
||||||
|
name[max] = '\0';
|
||||||
|
}
|
||||||
|
/* let ext be an empty string */
|
||||||
|
ext = name + strlen(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = 1;
|
||||||
|
/* change name of each file */
|
||||||
|
for (k = i; k <= j; ++k) {
|
||||||
|
char tmp[40];
|
||||||
|
char fmt[16];
|
||||||
|
if (dot != NULL) {
|
||||||
|
sprintf(fmt, "%%s%%0%dd.%%s", digits);
|
||||||
|
} else {
|
||||||
|
sprintf(fmt, "%%s%%0%dd%%s", digits);
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
sprintf(tmp, fmt, name, change, ext);
|
||||||
|
++change;
|
||||||
|
if (change > int_pow(10, digits)) {
|
||||||
|
ok = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!iso_htable_get(table, tmp, NULL)) {
|
||||||
|
/* the name is unique, so it can be used */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
char *new = strdup(tmp);
|
||||||
|
if (new == NULL) {
|
||||||
|
ret = ISO_OUT_OF_MEM;
|
||||||
|
goto mangle_cleanup;
|
||||||
|
}
|
||||||
|
iso_msg_debug(img->image->id, "\"%s\" renamed to \"%s\"",
|
||||||
|
children[k]->iso_name, new);
|
||||||
|
|
||||||
|
iso_htable_remove_ptr(table, children[k]->iso_name, NULL);
|
||||||
|
free(children[k]->iso_name);
|
||||||
|
children[k]->iso_name = new;
|
||||||
|
iso_htable_add(table, new, new);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we change a name we need to sort again children
|
||||||
|
* at the end
|
||||||
|
*/
|
||||||
|
need_sort = 1;
|
||||||
|
} else {
|
||||||
|
/* we need to increment digits */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
++digits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (digits == 8) {
|
||||||
|
ret = ISO_MANGLE_TOO_MUCH_FILES;
|
||||||
|
goto mangle_cleanup;
|
||||||
|
}
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If needed, sort again the files inside dir
|
||||||
|
*/
|
||||||
|
if (need_sort) {
|
||||||
|
qsort(children, nchildren, sizeof(void*), cmp_node_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ISO_SUCCESS;
|
||||||
|
|
||||||
|
mangle_cleanup : ;
|
||||||
|
iso_htable_destroy(table, NULL);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mangle_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
|
||||||
|
int max_dir_len)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
ret = mangle_single_dir(img, dir, max_file_len, max_dir_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* recurse */
|
||||||
|
for (i = 0; i < dir->info.dir->nchildren; ++i) {
|
||||||
|
if (dir->info.dir->children[i]->type == ECMA119_DIR) {
|
||||||
|
ret = mangle_dir(img, dir->info.dir->children[i], max_file_len,
|
||||||
|
max_dir_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* error */
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mangle_tree(Ecma119Image *img, int recurse)
|
||||||
|
{
|
||||||
|
int max_file, max_dir;
|
||||||
|
|
||||||
|
if (img->max_37_char_filenames) {
|
||||||
|
max_file = max_dir = 37;
|
||||||
|
} else if (img->iso_level == 1) {
|
||||||
|
max_file = 12; /* 8 + 3 + 1 */
|
||||||
|
max_dir = 8;
|
||||||
|
} else {
|
||||||
|
max_file = max_dir = 31;
|
||||||
|
}
|
||||||
|
if (recurse) {
|
||||||
|
return mangle_dir(img, img->root, max_file, max_dir);
|
||||||
|
} else {
|
||||||
|
return mangle_single_dir(img, img->root, max_file, max_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ECMA-119 node representing a placeholder for a relocated
|
||||||
|
* dir.
|
||||||
|
*
|
||||||
|
* See IEEE P1282, section 4.1.5 for details
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int create_placeholder(Ecma119Node *parent, Ecma119Node *real,
|
||||||
|
Ecma119Node **node)
|
||||||
|
{
|
||||||
|
Ecma119Node *ret;
|
||||||
|
|
||||||
|
ret = calloc(1, sizeof(Ecma119Node));
|
||||||
|
if (ret == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO
|
||||||
|
* If real is a dir, while placeholder is a file, ISO name restricctions
|
||||||
|
* are different, what to do?
|
||||||
|
*/
|
||||||
|
ret->iso_name = strdup(real->iso_name);
|
||||||
|
if (ret->iso_name == NULL) {
|
||||||
|
free(ret);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* take a ref to the IsoNode */
|
||||||
|
ret->node = real->node;
|
||||||
|
iso_node_ref(real->node);
|
||||||
|
ret->parent = parent;
|
||||||
|
ret->type = ECMA119_PLACEHOLDER;
|
||||||
|
ret->info.real_me = real;
|
||||||
|
ret->ino = real->ino;
|
||||||
|
ret->nlink = real->nlink;
|
||||||
|
|
||||||
|
*node = ret;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
size_t max_child_name_len(Ecma119Node *dir)
|
||||||
|
{
|
||||||
|
size_t ret = 0, i;
|
||||||
|
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||||
|
size_t len = strlen(dir->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
|
||||||
|
int reparent(Ecma119Node *child, Ecma119Node *parent)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t i;
|
||||||
|
Ecma119Node *placeholder;
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
ret = create_placeholder(child->parent, child, &placeholder);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
child->parent->info.dir->children[i] = placeholder;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* just for debug, this should never happen... */
|
||||||
|
if (i == child->parent->info.dir->nchildren) {
|
||||||
|
return ISO_ASSERT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep track of the real parent */
|
||||||
|
child->info.dir->real_parent = child->parent;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 (ECMA-119, 6.8.2.1).
|
||||||
|
*
|
||||||
|
* @param dir
|
||||||
|
* Dir we are currently processing
|
||||||
|
* @param level
|
||||||
|
* Level of the directory in the hierarchy
|
||||||
|
* @param pathlen
|
||||||
|
* Length of the path until dir, including it
|
||||||
|
* @return
|
||||||
|
* 1 success, < 0 error
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int reorder_tree(Ecma119Image *img, Ecma119Node *dir, int level, int pathlen)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t max_path;
|
||||||
|
|
||||||
|
max_path = pathlen + 1 + max_child_name_len(dir);
|
||||||
|
|
||||||
|
if (level > 8 || max_path > 255) {
|
||||||
|
ret = reparent(dir, img->root);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we are appended to the root's children now, so there is no
|
||||||
|
* need to recurse (the root will hit us again)
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
||||||
|
Ecma119Node *child = dir->info.dir->children[i];
|
||||||
|
if (child->type == ECMA119_DIR) {
|
||||||
|
int newpathlen = pathlen + 1 + strlen(child->iso_name);
|
||||||
|
ret = reorder_tree(img, child, level + 1, newpathlen);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ecma119_tree_create(Ecma119Image *img)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
Ecma119Node *root;
|
||||||
|
|
||||||
|
ret = create_tree(img, (IsoNode*)img->image->root, &root, 1, 0);
|
||||||
|
if (ret <= 0) {
|
||||||
|
if (ret == 0) {
|
||||||
|
/* unexpected error, root ignored!! This can't happen */
|
||||||
|
ret = ISO_ASSERT_FAILURE;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
img->root = root;
|
||||||
|
|
||||||
|
iso_msg_debug(img->image->id, "Sorting the low level tree...");
|
||||||
|
sort_tree(root);
|
||||||
|
|
||||||
|
iso_msg_debug(img->image->id, "Mangling names...");
|
||||||
|
ret = mangle_tree(img, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img->rockridge && !img->allow_deep_paths) {
|
||||||
|
|
||||||
|
/* reorder the tree, acording to RRIP, 4.1.5 */
|
||||||
|
ret = reorder_tree(img, img->root, 1, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* and we need to remangle the root directory, as the function
|
||||||
|
* above could insert new directories into the root.
|
||||||
|
* Note that recurse = 0, as we don't need to recurse.
|
||||||
|
*/
|
||||||
|
ret = mangle_tree(img, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_ECMA119_TREE_H_
|
||||||
|
#define LIBISO_ECMA119_TREE_H_
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
|
||||||
|
enum ecma119_node_type {
|
||||||
|
ECMA119_FILE,
|
||||||
|
ECMA119_DIR,
|
||||||
|
ECMA119_SYMLINK,
|
||||||
|
ECMA119_SPECIAL,
|
||||||
|
ECMA119_PLACEHOLDER
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct with info about a node representing a directory
|
||||||
|
*/
|
||||||
|
struct ecma119_dir_info
|
||||||
|
{
|
||||||
|
/* Block where the directory entries will be written on image */
|
||||||
|
size_t block;
|
||||||
|
|
||||||
|
size_t nchildren;
|
||||||
|
Ecma119Node **children;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size of the dir, i.e., sum of the lengths of all directory records.
|
||||||
|
* It is computed by calc_dir_size() [ecma119.c].
|
||||||
|
* Note that this don't include the length of any SUSP Continuation
|
||||||
|
* Area needed by the dir, but it includes the size of the SUSP entries
|
||||||
|
* than fit in the directory records System Use Field.
|
||||||
|
*/
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Real parent if the dir has been reallocated. NULL otherwise.
|
||||||
|
*/
|
||||||
|
Ecma119Node *real_parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node for a tree containing all the information necessary for writing
|
||||||
|
* an ISO9660 volume.
|
||||||
|
*/
|
||||||
|
struct ecma119_node
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Name in ASCII, conforming to selected ISO level.
|
||||||
|
* Version number is not include, it is added on the fly
|
||||||
|
*/
|
||||||
|
char *iso_name;
|
||||||
|
|
||||||
|
Ecma119Node *parent;
|
||||||
|
|
||||||
|
IsoNode *node; /*< reference to the iso node */
|
||||||
|
|
||||||
|
/* TODO #00009 : add true support for harlinks and inode numbers */
|
||||||
|
ino_t ino;
|
||||||
|
nlink_t nlink;
|
||||||
|
|
||||||
|
/**< file, symlink, special, directory or placeholder */
|
||||||
|
enum ecma119_node_type type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
IsoFileSrc *file;
|
||||||
|
struct ecma119_dir_info *dir;
|
||||||
|
/** this field points to the relocated directory. */
|
||||||
|
Ecma119Node *real_me;
|
||||||
|
} info;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int ecma119_tree_create(Ecma119Image *img);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free an Ecma119Node, and its children if node is a dir
|
||||||
|
*/
|
||||||
|
void ecma119_node_free(Ecma119Node *node);
|
||||||
|
|
||||||
|
#endif /*LIBISO_ECMA119_TREE_H_*/
|
|
@ -0,0 +1,913 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "eltorito.h"
|
||||||
|
#include "stream.h"
|
||||||
|
#include "fsource.h"
|
||||||
|
#include "filesrc.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "writer.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure for each one of the four entries in a partition table on a
|
||||||
|
* hard disk image.
|
||||||
|
*/
|
||||||
|
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];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structures for a Master Boot Record of a hard disk image.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(ElToritoBootImage *bootimg, short segment)
|
||||||
|
{
|
||||||
|
if (bootimg->type != ELTORITO_NO_EMUL)
|
||||||
|
return;
|
||||||
|
bootimg->load_seg = 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(ElToritoBootImage *bootimg, short sectors)
|
||||||
|
{
|
||||||
|
if (bootimg->type != ELTORITO_NO_EMUL)
|
||||||
|
return;
|
||||||
|
bootimg->load_size = sectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the specified boot image as not bootable
|
||||||
|
*/
|
||||||
|
void el_torito_set_no_bootable(ElToritoBootImage *bootimg)
|
||||||
|
{
|
||||||
|
bootimg->bootable = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* The original boot image file won't be modified.
|
||||||
|
* This is needed for isolinux boot images.
|
||||||
|
*/
|
||||||
|
void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg)
|
||||||
|
{
|
||||||
|
bootimg->isolinux = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int iso_tree_add_boot_node(IsoDir *parent, const char *name, IsoBoot **boot)
|
||||||
|
{
|
||||||
|
IsoBoot *node;
|
||||||
|
IsoNode **pos;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if (parent == NULL || name == NULL || boot == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (boot) {
|
||||||
|
*boot = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if the name is valid */
|
||||||
|
if (!iso_node_is_valid_name(name)) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find place where to insert */
|
||||||
|
pos = &(parent->children);
|
||||||
|
while (*pos != NULL && strcmp((*pos)->name, name) < 0) {
|
||||||
|
pos = &((*pos)->next);
|
||||||
|
}
|
||||||
|
if (*pos != NULL && !strcmp((*pos)->name, name)) {
|
||||||
|
/* a node with same name already exists */
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = calloc(1, sizeof(IsoBoot));
|
||||||
|
if (node == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->node.refcount = 1;
|
||||||
|
node->node.type = LIBISO_BOOT;
|
||||||
|
node->node.name = strdup(name);
|
||||||
|
if (node->node.name == NULL) {
|
||||||
|
free(node);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* atributes from parent */
|
||||||
|
node->node.mode = S_IFREG | (parent->node.mode & 0444);
|
||||||
|
node->node.uid = parent->node.uid;
|
||||||
|
node->node.gid = parent->node.gid;
|
||||||
|
node->node.hidden = parent->node.hidden;
|
||||||
|
|
||||||
|
/* current time */
|
||||||
|
now = time(NULL);
|
||||||
|
node->node.atime = now;
|
||||||
|
node->node.ctime = now;
|
||||||
|
node->node.mtime = now;
|
||||||
|
|
||||||
|
/* add to dir */
|
||||||
|
node->node.parent = parent;
|
||||||
|
node->node.next = *pos;
|
||||||
|
*pos = (IsoNode*)node;
|
||||||
|
|
||||||
|
if (boot) {
|
||||||
|
*boot = node;
|
||||||
|
}
|
||||||
|
return ++parent->nchildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
int create_image(IsoImage *image, const char *image_path,
|
||||||
|
enum eltorito_boot_media_type type,
|
||||||
|
struct el_torito_boot_image **bootimg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
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;
|
||||||
|
IsoNode *imgfile;
|
||||||
|
IsoStream *stream;
|
||||||
|
|
||||||
|
ret = iso_tree_path_to_node(image, image_path, &imgfile);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
return ISO_NODE_DOESNT_EXIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imgfile->type != LIBISO_FILE) {
|
||||||
|
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = ((IsoFile*)imgfile)->stream;
|
||||||
|
|
||||||
|
/* we need to read the image at least two times */
|
||||||
|
if (!iso_stream_is_repeatable(stream)) {
|
||||||
|
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ELTORITO_FLOPPY_EMUL:
|
||||||
|
switch (iso_stream_get_size(stream)) {
|
||||||
|
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:
|
||||||
|
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||||
|
"Invalid image size %d Kb. Must be one of 1.2, 1.44"
|
||||||
|
"or 2.88 Mb", iso_stream_get_size(stream) / 1024);
|
||||||
|
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||||
|
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;
|
||||||
|
struct hard_disc_mbr mbr;
|
||||||
|
int used_partition;
|
||||||
|
|
||||||
|
/* read the MBR on disc and get the type of the partition */
|
||||||
|
ret = iso_stream_open(stream);
|
||||||
|
if (ret < 0) {
|
||||||
|
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, ret,
|
||||||
|
"Can't open image file.");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = iso_stream_read(stream, &mbr, sizeof(mbr));
|
||||||
|
iso_stream_close(stream);
|
||||||
|
if (ret != sizeof(mbr)) {
|
||||||
|
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||||
|
"Can't read MBR from image file.");
|
||||||
|
return ret < 0 ? ret : ISO_FILE_READ_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check valid MBR signature */
|
||||||
|
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
|
||||||
|
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||||
|
"Invalid MBR. Wrong signature.");
|
||||||
|
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
iso_msg_submit(image->id, ISO_BOOT_IMAGE_NOT_VALID, 0,
|
||||||
|
"Invalid MBR. At least 2 partitions: %d and "
|
||||||
|
"%d, are being used\n", used_partition, i);
|
||||||
|
return ISO_BOOT_IMAGE_NOT_VALID;
|
||||||
|
} 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));
|
||||||
|
if (boot == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
boot->image = (IsoFile*)imgfile;
|
||||||
|
iso_node_ref(imgfile); /* get our ref */
|
||||||
|
boot->bootable = 1;
|
||||||
|
boot->type = boot_media_type;
|
||||||
|
boot->load_size = load_sectors;
|
||||||
|
boot->partition_type = partition_type;
|
||||||
|
|
||||||
|
if (bootimg) {
|
||||||
|
*bootimg = boot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_image_set_boot_image(IsoImage *image, const char *image_path,
|
||||||
|
enum eltorito_boot_media_type type,
|
||||||
|
const char *catalog_path,
|
||||||
|
ElToritoBootImage **boot)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct el_torito_boot_catalog *catalog;
|
||||||
|
ElToritoBootImage *boot_image= NULL;
|
||||||
|
IsoBoot *cat_node= NULL;
|
||||||
|
|
||||||
|
if (image == NULL || image_path == NULL || catalog_path == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (image->bootcat != NULL) {
|
||||||
|
return ISO_IMAGE_ALREADY_BOOTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the node for the catalog */
|
||||||
|
{
|
||||||
|
IsoDir *parent;
|
||||||
|
char *catdir = NULL, *catname = NULL;
|
||||||
|
catdir = strdup(catalog_path);
|
||||||
|
if (catdir == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get both the dir and the name */
|
||||||
|
catname = strrchr(catdir, '/');
|
||||||
|
if (catname == NULL) {
|
||||||
|
free(catdir);
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
if (catname == catdir) {
|
||||||
|
/* we are apending catalog to root node */
|
||||||
|
parent = image->root;
|
||||||
|
} else {
|
||||||
|
IsoNode *p;
|
||||||
|
catname[0] = '\0';
|
||||||
|
ret = iso_tree_path_to_node(image, catdir, &p);
|
||||||
|
if (ret <= 0) {
|
||||||
|
free(catdir);
|
||||||
|
return ret < 0 ? ret : ISO_NODE_DOESNT_EXIST;
|
||||||
|
}
|
||||||
|
if (p->type != LIBISO_DIR) {
|
||||||
|
free(catdir);
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
parent = (IsoDir*)p;
|
||||||
|
}
|
||||||
|
catname++;
|
||||||
|
ret = iso_tree_add_boot_node(parent, catname, &cat_node);
|
||||||
|
free(catdir);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the boot image */
|
||||||
|
ret = create_image(image, image_path, type, &boot_image);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto boot_image_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* creates the catalog with the given image */
|
||||||
|
catalog = malloc(sizeof(struct el_torito_boot_catalog));
|
||||||
|
if (catalog == NULL) {
|
||||||
|
ret = ISO_OUT_OF_MEM;
|
||||||
|
goto boot_image_cleanup;
|
||||||
|
}
|
||||||
|
catalog->image = boot_image;
|
||||||
|
catalog->node = cat_node;
|
||||||
|
iso_node_ref((IsoNode*)cat_node);
|
||||||
|
image->bootcat = catalog;
|
||||||
|
|
||||||
|
if (boot) {
|
||||||
|
*boot = boot_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
|
||||||
|
boot_image_cleanup:;
|
||||||
|
if (cat_node) {
|
||||||
|
iso_node_take((IsoNode*)cat_node);
|
||||||
|
iso_node_unref((IsoNode*)cat_node);
|
||||||
|
}
|
||||||
|
if (boot_image) {
|
||||||
|
iso_node_unref((IsoNode*)boot_image->image);
|
||||||
|
free(boot_image);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get El-Torito boot image of an ISO image, if any.
|
||||||
|
*
|
||||||
|
* This can be useful, for example, to check if a volume read from a previous
|
||||||
|
* session or an existing image is bootable. It can also be useful to get
|
||||||
|
* the image and catalog tree nodes. An application would want those, for
|
||||||
|
* example, to prevent the user removing it.
|
||||||
|
*
|
||||||
|
* Both nodes are owned by libisofs and should not be freed. You can get your
|
||||||
|
* own ref with iso_node_ref(). You can can also check if the node is already
|
||||||
|
* on the tree by getting its parent (note that when reading El-Torito info
|
||||||
|
* from a previous image, the nodes might not be on the tree even if you haven't
|
||||||
|
* removed them). Remember that you'll need to get a new ref
|
||||||
|
* (with iso_node_ref()) before inserting them again to the tree, and probably
|
||||||
|
* you will also need to set the name or permissions.
|
||||||
|
*
|
||||||
|
* @param image
|
||||||
|
* The image from which to get the boot image.
|
||||||
|
* @param boot
|
||||||
|
* If not NULL, it will be filled with a pointer to the boot image, if
|
||||||
|
* any. That object is owned by the IsoImage and should not be freed by
|
||||||
|
* the user, nor dereferenced once the last reference to the IsoImage was
|
||||||
|
* disposed via iso_image_unref().
|
||||||
|
* @param imgnode
|
||||||
|
* When not NULL, it will be filled with the image tree node. No extra ref
|
||||||
|
* is added, you can use iso_node_ref() to get one if you need it.
|
||||||
|
* @param catnode
|
||||||
|
* When not NULL, it will be filled with the catnode tree node. No extra
|
||||||
|
* ref is added, you can use iso_node_ref() to get one if you need it.
|
||||||
|
* @return
|
||||||
|
* 1 on success, 0 is the image is not bootable (i.e., it has no El-Torito
|
||||||
|
* image), < 0 error.
|
||||||
|
*/
|
||||||
|
int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
|
||||||
|
IsoFile **imgnode, IsoBoot **catnode)
|
||||||
|
{
|
||||||
|
if (image == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (image->bootcat == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok, image is bootable */
|
||||||
|
if (boot) {
|
||||||
|
*boot = image->bootcat->image;
|
||||||
|
}
|
||||||
|
if (imgnode) {
|
||||||
|
*imgnode = image->bootcat->image->image;
|
||||||
|
}
|
||||||
|
if (catnode) {
|
||||||
|
*catnode = image->bootcat->node;
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the El-Torito bootable image.
|
||||||
|
*
|
||||||
|
* The IsoBoot node that acts as placeholder for the catalog is also removed
|
||||||
|
* for the image tree, if there.
|
||||||
|
* If the image is not bootable (don't have el-torito boot image) this function
|
||||||
|
* just returns.
|
||||||
|
*/
|
||||||
|
void iso_image_remove_boot_image(IsoImage *image)
|
||||||
|
{
|
||||||
|
if (image == NULL || image->bootcat == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remove catalog node from its parent
|
||||||
|
* (the reference will be disposed next)
|
||||||
|
*/
|
||||||
|
iso_node_take((IsoNode*)image->bootcat->node);
|
||||||
|
|
||||||
|
/* free boot catalog and image, including references to nodes */
|
||||||
|
el_torito_boot_catalog_free(image->bootcat);
|
||||||
|
image->bootcat = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
|
||||||
|
{
|
||||||
|
struct el_torito_boot_image *image;
|
||||||
|
|
||||||
|
if (cat == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
image = cat->image;
|
||||||
|
iso_node_unref((IsoNode*)image->image);
|
||||||
|
free(image);
|
||||||
|
iso_node_unref((IsoNode*)cat->node);
|
||||||
|
free(cat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream that generates the contents of a El-Torito catalog.
|
||||||
|
*/
|
||||||
|
struct catalog_stream
|
||||||
|
{
|
||||||
|
Ecma119Image *target;
|
||||||
|
uint8_t buffer[BLOCK_SIZE];
|
||||||
|
int offset; /* -1 if stream is not openned */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
write_validation_entry(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 -= (int16_t) ((buf[i+1] << 8) | buf[i]);
|
||||||
|
}
|
||||||
|
iso_lsb(ve->checksum, checksum, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write one section entry.
|
||||||
|
* Currently this is used only for default image (the only supported just now)
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
write_section_entry(uint8_t *buf, Ecma119Image *t)
|
||||||
|
{
|
||||||
|
struct el_torito_boot_image *img;
|
||||||
|
struct el_torito_section_entry *se =
|
||||||
|
(struct el_torito_section_entry*)buf;
|
||||||
|
|
||||||
|
img = t->catalog->image;
|
||||||
|
|
||||||
|
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] = img->partition_type;
|
||||||
|
iso_lsb(se->sec_count, img->load_size, 2);
|
||||||
|
iso_lsb(se->block, t->bootimg->block, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int catalog_open(IsoStream *stream)
|
||||||
|
{
|
||||||
|
struct catalog_stream *data;
|
||||||
|
if (stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = stream->data;
|
||||||
|
|
||||||
|
if (data->offset != -1) {
|
||||||
|
return ISO_FILE_ALREADY_OPENNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(data->buffer, 0, BLOCK_SIZE);
|
||||||
|
|
||||||
|
/* fill the buffer with the catalog contents */
|
||||||
|
write_validation_entry(data->buffer);
|
||||||
|
|
||||||
|
/* write default entry */
|
||||||
|
write_section_entry(data->buffer + 32, data->target);
|
||||||
|
|
||||||
|
data->offset = 0;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int catalog_close(IsoStream *stream)
|
||||||
|
{
|
||||||
|
struct catalog_stream *data;
|
||||||
|
if (stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = stream->data;
|
||||||
|
|
||||||
|
if (data->offset == -1) {
|
||||||
|
return ISO_FILE_NOT_OPENNED;
|
||||||
|
}
|
||||||
|
data->offset = -1;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
off_t catalog_get_size(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int catalog_read(IsoStream *stream, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
struct catalog_stream *data;
|
||||||
|
if (stream == NULL || buf == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
data = stream->data;
|
||||||
|
|
||||||
|
if (data->offset == -1) {
|
||||||
|
return ISO_FILE_NOT_OPENNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = MIN(count, BLOCK_SIZE - data->offset);
|
||||||
|
memcpy(buf, data->buffer + data->offset, len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int catalog_is_repeatable(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fs_id will be the id reserved for El-Torito
|
||||||
|
* dev_id will be 0 for catalog, 1 for boot image (if needed)
|
||||||
|
* we leave ino_id for future use when we support multiple boot images
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void catalog_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||||
|
ino_t *ino_id)
|
||||||
|
{
|
||||||
|
*fs_id = ISO_ELTORITO_FS_ID;
|
||||||
|
*dev_id = 0;
|
||||||
|
*ino_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
char *catalog_get_name(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return strdup("El-Torito Boot Catalog");
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void catalog_free(IsoStream *stream)
|
||||||
|
{
|
||||||
|
free(stream->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
IsoStreamIface catalog_stream_class = {
|
||||||
|
catalog_open,
|
||||||
|
catalog_close,
|
||||||
|
catalog_get_size,
|
||||||
|
catalog_read,
|
||||||
|
catalog_is_repeatable,
|
||||||
|
catalog_get_id,
|
||||||
|
catalog_get_name,
|
||||||
|
catalog_free
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an IsoStream for writing El-Torito catalog for a given target.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int catalog_stream_new(Ecma119Image *target, IsoStream **stream)
|
||||||
|
{
|
||||||
|
IsoStream *str;
|
||||||
|
struct catalog_stream *data;
|
||||||
|
|
||||||
|
if (target == NULL || stream == NULL || target->catalog == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = malloc(sizeof(IsoStream));
|
||||||
|
if (str == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
data = malloc(sizeof(struct catalog_stream));
|
||||||
|
if (str == NULL) {
|
||||||
|
free(str);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill data */
|
||||||
|
data->target = target;
|
||||||
|
data->offset = -1;
|
||||||
|
|
||||||
|
str->refcount = 1;
|
||||||
|
str->data = data;
|
||||||
|
str->class = &catalog_stream_class;
|
||||||
|
|
||||||
|
*stream = str;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoFileSrc *file;
|
||||||
|
IsoStream *stream;
|
||||||
|
|
||||||
|
if (target == NULL || src == NULL || target->catalog == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target->cat != NULL) {
|
||||||
|
/* catalog file src already created */
|
||||||
|
*src = target->cat;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = malloc(sizeof(IsoFileSrc));
|
||||||
|
if (file == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = catalog_stream_new(target, &stream);
|
||||||
|
if (ret < 0) {
|
||||||
|
free(file);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill fields */
|
||||||
|
file->prev_img = 0; /* TODO allow copy of old img catalog???? */
|
||||||
|
file->block = 0; /* to be filled later */
|
||||||
|
file->sort_weight = 1000; /* slightly high */
|
||||||
|
file->stream = stream;
|
||||||
|
|
||||||
|
ret = iso_file_src_add(target, file, src);
|
||||||
|
if (ret <= 0) {
|
||||||
|
iso_stream_unref(stream);
|
||||||
|
free(file);
|
||||||
|
} else {
|
||||||
|
target->cat = *src;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************* EL-TORITO WRITER *******************************/
|
||||||
|
|
||||||
|
static
|
||||||
|
int eltorito_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||||
|
{
|
||||||
|
/* nothing to do, the files are written by the file writer */
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the Boot Record Volume Descriptor (ECMA-119, 8.2)
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int eltorito_writer_write_vol_desc(IsoImageWriter *writer)
|
||||||
|
{
|
||||||
|
Ecma119Image *t;
|
||||||
|
struct el_torito_boot_catalog *cat;
|
||||||
|
struct ecma119_boot_rec_vol_desc vol;
|
||||||
|
|
||||||
|
if (writer == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = writer->target;
|
||||||
|
cat = t->catalog;
|
||||||
|
|
||||||
|
iso_msg_debug(t->image->id, "Write El-Torito boot record");
|
||||||
|
|
||||||
|
memset(&vol, 0, sizeof(struct ecma119_boot_rec_vol_desc));
|
||||||
|
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, t->cat->block, 4);
|
||||||
|
|
||||||
|
return iso_write(t, &vol, sizeof(struct ecma119_boot_rec_vol_desc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Patch an isolinux boot image.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, 0 error (but continue), < 0 error
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int patch_boot_image(uint8_t *buf, Ecma119Image *t, size_t imgsize)
|
||||||
|
{
|
||||||
|
struct boot_info_table *info;
|
||||||
|
uint32_t checksum;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (imgsize < 64) {
|
||||||
|
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
|
||||||
|
"Isolinux image too small. We won't patch it.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute checksum, as the the sum of all 32 bit words in boot image
|
||||||
|
* from offset 64 */
|
||||||
|
checksum = 0;
|
||||||
|
offset = (size_t) 64;
|
||||||
|
|
||||||
|
while (offset <= imgsize - 4) {
|
||||||
|
checksum += iso_read_lsb(buf + offset, 4);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
if (offset != imgsize) {
|
||||||
|
/* file length not multiple of 4 */
|
||||||
|
return iso_msg_submit(t->image->id, ISO_ISOLINUX_CANT_PATCH, 0,
|
||||||
|
"Unexpected isolinux image length. Patch might not work.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* patch boot info table */
|
||||||
|
info = (struct boot_info_table*)(buf + 8);
|
||||||
|
/*memset(info, 0, sizeof(struct boot_info_table));*/
|
||||||
|
iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
|
||||||
|
iso_lsb(info->bi_file, t->bootimg->block, 4);
|
||||||
|
iso_lsb(info->bi_length, imgsize, 4);
|
||||||
|
iso_lsb(info->bi_csum, checksum, 4);
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int eltorito_writer_write_data(IsoImageWriter *writer)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We have nothing to write, but if we need to patch an isolinux image,
|
||||||
|
* this is a good place to do so.
|
||||||
|
*/
|
||||||
|
Ecma119Image *t;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (writer == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = writer->target;
|
||||||
|
|
||||||
|
if (t->catalog->image->isolinux) {
|
||||||
|
/* we need to patch the image */
|
||||||
|
size_t size;
|
||||||
|
uint8_t *buf;
|
||||||
|
IsoStream *new = NULL;
|
||||||
|
IsoStream *original = t->bootimg->stream;
|
||||||
|
size = (size_t) iso_stream_get_size(original);
|
||||||
|
buf = malloc(size);
|
||||||
|
if (buf == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
ret = iso_stream_open(original);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = iso_stream_read(original, buf, size);
|
||||||
|
iso_stream_close(original);
|
||||||
|
if (ret != size) {
|
||||||
|
return (ret < 0) ? ret : ISO_FILE_READ_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok, patch the read buffer */
|
||||||
|
ret = patch_boot_image(buf, t, size);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replace the original stream with a memory stream that reads from
|
||||||
|
* the patched buffer */
|
||||||
|
ret = iso_memory_stream_new(buf, size, &new);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
t->bootimg->stream = new;
|
||||||
|
iso_stream_unref(original);
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int eltorito_writer_free_data(IsoImageWriter *writer)
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int eltorito_writer_create(Ecma119Image *target)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImageWriter *writer;
|
||||||
|
IsoFile *bootimg;
|
||||||
|
IsoFileSrc *src;
|
||||||
|
|
||||||
|
writer = malloc(sizeof(IsoImageWriter));
|
||||||
|
if (writer == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer->compute_data_blocks = eltorito_writer_compute_data_blocks;
|
||||||
|
writer->write_vol_desc = eltorito_writer_write_vol_desc;
|
||||||
|
writer->write_data = eltorito_writer_write_data;
|
||||||
|
writer->free_data = eltorito_writer_free_data;
|
||||||
|
writer->data = NULL;
|
||||||
|
writer->target = target;
|
||||||
|
|
||||||
|
/* add this writer to image */
|
||||||
|
target->writers[target->nwriters++] = writer;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get catalog and image file sources.
|
||||||
|
* Note that the catalog may be already added, when creating the low
|
||||||
|
* level ECMA-119 tree.
|
||||||
|
*/
|
||||||
|
if (target->cat == NULL) {
|
||||||
|
ret = el_torito_catalog_file_src_create(target, &src);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bootimg = target->catalog->image->image;
|
||||||
|
ret = iso_file_src_create(target, bootimg, &src);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
target->bootimg = src;
|
||||||
|
|
||||||
|
/* if we have selected to patch the image, it needs to be copied always */
|
||||||
|
if (target->catalog->image->isolinux) {
|
||||||
|
src->prev_img = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we need the bootable volume descriptor */
|
||||||
|
target->curblock++;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare El-Torito related structures.
|
||||||
|
* References:
|
||||||
|
* "El Torito" Bootable CD-ROM Format Specification Version 1.0 (1995)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_ELTORITO_H
|
||||||
|
#define LIBISO_ELTORITO_H
|
||||||
|
|
||||||
|
#include "ecma119.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A node that acts as a placeholder for an El-Torito catalog.
|
||||||
|
*/
|
||||||
|
struct Iso_Boot
|
||||||
|
{
|
||||||
|
IsoNode node;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct el_torito_boot_catalog {
|
||||||
|
IsoBoot *node; /* node of the catalog */
|
||||||
|
struct el_torito_boot_image *image; /* default boot image */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct el_torito_boot_image {
|
||||||
|
IsoFile *image;
|
||||||
|
|
||||||
|
unsigned int bootable:1; /**< If the entry is bootable. */
|
||||||
|
unsigned int isolinux:1; /**< 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 sectors to load. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** El-Torito, 2.1 */
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** El-Torito, 2.2 */
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** El-Torito, 2.3 */
|
||||||
|
struct el_torito_section_header {
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** El-Torito, 2.4 */
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a IsoFileSrc for writing the el-torito catalog for the given
|
||||||
|
* target, and add it to target. If the target already has a src for the
|
||||||
|
* catalog, it just returns.
|
||||||
|
*/
|
||||||
|
int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a writer for el-torito information.
|
||||||
|
*/
|
||||||
|
int eltorito_writer_create(Ecma119Image *target);
|
||||||
|
|
||||||
|
#endif /* LIBISO_ELTORITO_H */
|
|
@ -0,0 +1,393 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "filesrc.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "writer.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int iso_file_src_cmp(const void *n1, const void *n2)
|
||||||
|
{
|
||||||
|
const IsoFileSrc *f1, *f2;
|
||||||
|
unsigned int fs_id1, fs_id2;
|
||||||
|
dev_t dev_id1, dev_id2;
|
||||||
|
ino_t ino_id1, ino_id2;
|
||||||
|
|
||||||
|
f1 = (const IsoFileSrc *)n1;
|
||||||
|
f2 = (const IsoFileSrc *)n2;
|
||||||
|
|
||||||
|
iso_stream_get_id(f1->stream, &fs_id1, &dev_id1, &ino_id1);
|
||||||
|
iso_stream_get_id(f2->stream, &fs_id2, &dev_id2, &ino_id2);
|
||||||
|
|
||||||
|
if (fs_id1 < fs_id2) {
|
||||||
|
return -1;
|
||||||
|
} else if (fs_id1 > fs_id2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
/* files belong to the same fs */
|
||||||
|
if (dev_id1 > dev_id2) {
|
||||||
|
return -1;
|
||||||
|
} else if (dev_id1 < dev_id2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
/* files belong to same device in same fs */
|
||||||
|
return (ino_id1 < ino_id2) ? -1 : (ino_id1 > ino_id2) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoFileSrc *fsrc;
|
||||||
|
unsigned int fs_id;
|
||||||
|
dev_t dev_id;
|
||||||
|
ino_t ino_id;
|
||||||
|
|
||||||
|
if (img == NULL || file == NULL || src == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_stream_get_id(file->stream, &fs_id, &dev_id, &ino_id);
|
||||||
|
|
||||||
|
fsrc = malloc(sizeof(IsoFileSrc));
|
||||||
|
if (fsrc == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill key and other atts */
|
||||||
|
fsrc->prev_img = file->msblock ? 1 : 0;
|
||||||
|
fsrc->block = file->msblock;
|
||||||
|
fsrc->sort_weight = file->sort_weight;
|
||||||
|
fsrc->stream = file->stream;
|
||||||
|
|
||||||
|
/* insert the filesrc in the tree */
|
||||||
|
ret = iso_rbtree_insert(img->files, fsrc, (void**)src);
|
||||||
|
if (ret <= 0) {
|
||||||
|
free(fsrc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
iso_stream_ref(fsrc->stream);
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a given IsoFileSrc to the given image target.
|
||||||
|
*
|
||||||
|
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||||
|
* being written several times to image. If you call again this function
|
||||||
|
* with a node that refers to the same source file, the previously
|
||||||
|
* created one will be returned.
|
||||||
|
*
|
||||||
|
* @param img
|
||||||
|
* The image where this file is to be written
|
||||||
|
* @param new
|
||||||
|
* The IsoFileSrc to add
|
||||||
|
* @param src
|
||||||
|
* Will be filled with a pointer to the IsoFileSrc really present in
|
||||||
|
* the tree. It could be different than new if the same file already
|
||||||
|
* exists in the tree.
|
||||||
|
* @return
|
||||||
|
* 1 on success, 0 if file already exists on tree, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (img == NULL || new == NULL || src == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* insert the filesrc in the tree */
|
||||||
|
ret = iso_rbtree_insert(img->files, new, (void**)src);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_file_src_free(void *node)
|
||||||
|
{
|
||||||
|
iso_stream_unref(((IsoFileSrc*)node)->stream);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t iso_file_src_get_size(IsoFileSrc *file)
|
||||||
|
{
|
||||||
|
return iso_stream_get_size(file->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp_by_weight(const void *f1, const void *f2)
|
||||||
|
{
|
||||||
|
IsoFileSrc *f = *((IsoFileSrc**)f1);
|
||||||
|
IsoFileSrc *g = *((IsoFileSrc**)f2);
|
||||||
|
/* higher weighted first */
|
||||||
|
return g->sort_weight - f->sort_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int is_ms_file(void *arg)
|
||||||
|
{
|
||||||
|
IsoFileSrc *f = (IsoFileSrc *)arg;
|
||||||
|
return f->prev_img ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||||
|
{
|
||||||
|
size_t i, size;
|
||||||
|
Ecma119Image *t;
|
||||||
|
IsoFileSrc **filelist;
|
||||||
|
int (*inc_item)(void *);
|
||||||
|
|
||||||
|
if (writer == NULL) {
|
||||||
|
return ISO_ASSERT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = writer->target;
|
||||||
|
|
||||||
|
/* on appendable images, ms files shouldn't be included */
|
||||||
|
if (t->appendable) {
|
||||||
|
inc_item = is_ms_file;
|
||||||
|
} else {
|
||||||
|
inc_item = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store the filesrcs in a array */
|
||||||
|
filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files, inc_item, &size);
|
||||||
|
if (filelist == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sort files by weight, if needed */
|
||||||
|
if (t->sort_files) {
|
||||||
|
qsort(filelist, size, sizeof(void*), cmp_by_weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill block value */
|
||||||
|
for (i = 0; i < size; ++i) {
|
||||||
|
IsoFileSrc *file = filelist[i];
|
||||||
|
file->block = t->curblock;
|
||||||
|
t->curblock += DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the list is only needed by this writer, store locally */
|
||||||
|
writer->data = filelist;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int filesrc_writer_write_vol_desc(IsoImageWriter *writer)
|
||||||
|
{
|
||||||
|
/* nothing needed */
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open a file, i.e., its Stream */
|
||||||
|
static inline
|
||||||
|
int filesrc_open(IsoFileSrc *file)
|
||||||
|
{
|
||||||
|
return iso_stream_open(file->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int filesrc_close(IsoFileSrc *file)
|
||||||
|
{
|
||||||
|
return iso_stream_close(file->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
* 1 ok, 0 EOF, < 0 error
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int filesrc_read(IsoFileSrc *file, char *buf, size_t count)
|
||||||
|
{
|
||||||
|
size_t bytes = 0;
|
||||||
|
|
||||||
|
/* loop to ensure the full buffer is filled */
|
||||||
|
do {
|
||||||
|
ssize_t result;
|
||||||
|
result = iso_stream_read(file->stream, buf + bytes, count - bytes);
|
||||||
|
if (result < 0) {
|
||||||
|
/* fill buffer with 0s and return */
|
||||||
|
memset(buf + bytes, 0, count - bytes);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (result == 0)
|
||||||
|
break;
|
||||||
|
bytes += result;
|
||||||
|
} while (bytes < count);
|
||||||
|
|
||||||
|
if (bytes < count) {
|
||||||
|
/* eof */
|
||||||
|
memset(buf + bytes, 0, count - bytes);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int filesrc_writer_write_data(IsoImageWriter *writer)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
size_t i, b;
|
||||||
|
Ecma119Image *t;
|
||||||
|
IsoFileSrc *file;
|
||||||
|
IsoFileSrc **filelist;
|
||||||
|
char *name;
|
||||||
|
char buffer[BLOCK_SIZE];
|
||||||
|
|
||||||
|
if (writer == NULL) {
|
||||||
|
return ISO_ASSERT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = writer->target;
|
||||||
|
filelist = writer->data;
|
||||||
|
|
||||||
|
iso_msg_debug(t->image->id, "Writing Files...");
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while ((file = filelist[i++]) != NULL) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO WARNING
|
||||||
|
* when we allow files greater than 4GB, current DIV_UP implementation
|
||||||
|
* can overflow!!
|
||||||
|
*/
|
||||||
|
uint32_t nblocks = DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
|
||||||
|
|
||||||
|
res = filesrc_open(file);
|
||||||
|
if (res < 0) {
|
||||||
|
/*
|
||||||
|
* UPS, very ugly error, the best we can do is just to write
|
||||||
|
* 0's to image
|
||||||
|
*/
|
||||||
|
name = iso_stream_get_name(file->stream);
|
||||||
|
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||||
|
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
|
||||||
|
"File \"%s\" can't be opened. Filling with 0s.", name);
|
||||||
|
free(name);
|
||||||
|
if (res < 0) {
|
||||||
|
return res; /* aborted due to error severity */
|
||||||
|
}
|
||||||
|
memset(buffer, 0, BLOCK_SIZE);
|
||||||
|
for (b = 0; b < nblocks; ++b) {
|
||||||
|
res = iso_write(t, buffer, BLOCK_SIZE);
|
||||||
|
if (res < 0) {
|
||||||
|
/* ko, writer error, we need to go out! */
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (res > 1) {
|
||||||
|
name = iso_stream_get_name(file->stream);
|
||||||
|
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||||
|
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||||
|
"Size of file \"%s\" has changed. It will be %s", name,
|
||||||
|
(res == 2 ? "truncated" : "padded with 0's"));
|
||||||
|
free(name);
|
||||||
|
if (res < 0) {
|
||||||
|
filesrc_close(file);
|
||||||
|
return res; /* aborted due to error severity */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef LIBISOFS_VERBOSE_DEBUG
|
||||||
|
else {
|
||||||
|
name = iso_stream_get_name(file->stream);
|
||||||
|
iso_msg_debug(t->image->id, "Writing file %s", name);
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* write file contents to image */
|
||||||
|
for (b = 0; b < nblocks; ++b) {
|
||||||
|
int wres;
|
||||||
|
res = filesrc_read(file, buffer, BLOCK_SIZE);
|
||||||
|
if (res < 0) {
|
||||||
|
/* read error */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wres = iso_write(t, buffer, BLOCK_SIZE);
|
||||||
|
if (wres < 0) {
|
||||||
|
/* ko, writer error, we need to go out! */
|
||||||
|
filesrc_close(file);
|
||||||
|
return wres;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filesrc_close(file);
|
||||||
|
|
||||||
|
if (b < nblocks) {
|
||||||
|
/* premature end of file, due to error or eof */
|
||||||
|
char *name = iso_stream_get_name(file->stream);
|
||||||
|
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||||
|
if (res < 0) {
|
||||||
|
/* error */
|
||||||
|
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
|
||||||
|
"Read error in file %s.", name);
|
||||||
|
} else {
|
||||||
|
/* eof */
|
||||||
|
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||||
|
"Premature end of file %s.", name);
|
||||||
|
}
|
||||||
|
free(name);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
return res; /* aborted due error severity */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill with 0s */
|
||||||
|
iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||||
|
"Filling with 0");
|
||||||
|
memset(buffer, 0, BLOCK_SIZE);
|
||||||
|
while (b++ < nblocks) {
|
||||||
|
res = iso_write(t, buffer, BLOCK_SIZE);
|
||||||
|
if (res < 0) {
|
||||||
|
/* ko, writer error, we need to go out! */
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int filesrc_writer_free_data(IsoImageWriter *writer)
|
||||||
|
{
|
||||||
|
/* free the list of files (contents are free together with the tree) */
|
||||||
|
free(writer->data);
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_file_src_writer_create(Ecma119Image *target)
|
||||||
|
{
|
||||||
|
IsoImageWriter *writer;
|
||||||
|
|
||||||
|
writer = malloc(sizeof(IsoImageWriter));
|
||||||
|
if (writer == NULL) {
|
||||||
|
return ISO_ASSERT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer->compute_data_blocks = filesrc_writer_compute_data_blocks;
|
||||||
|
writer->write_vol_desc = filesrc_writer_write_vol_desc;
|
||||||
|
writer->write_data = filesrc_writer_write_data;
|
||||||
|
writer->free_data = filesrc_writer_free_data;
|
||||||
|
writer->data = NULL;
|
||||||
|
writer->target = target;
|
||||||
|
|
||||||
|
/* add this writer to image */
|
||||||
|
target->writers[target->nwriters++] = writer;
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBISO_FILESRC_H_
|
||||||
|
#define LIBISO_FILESRC_H_
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "stream.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct Iso_File_Src
|
||||||
|
{
|
||||||
|
unsigned int prev_img :1; /**< if the file comes from a previous image */
|
||||||
|
uint32_t block; /**< Block where this file will be written on image */
|
||||||
|
int sort_weight;
|
||||||
|
IsoStream *stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
int iso_file_src_cmp(const void *n1, const void *n2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IsoFileSrc to get data from a specific IsoFile.
|
||||||
|
*
|
||||||
|
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||||
|
* being written several times to image. If you call again this function
|
||||||
|
* with a node that refers to the same source file, the previously
|
||||||
|
* created one will be returned. No new IsoFileSrc is created in that case.
|
||||||
|
*
|
||||||
|
* @param img
|
||||||
|
* The image where this file is to be written
|
||||||
|
* @param file
|
||||||
|
* The IsoNode we want to write
|
||||||
|
* @param src
|
||||||
|
* Will be filled with a pointer to the IsoFileSrc
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a given IsoFileSrc to the given image target.
|
||||||
|
*
|
||||||
|
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||||
|
* being written several times to image. If you call again this function
|
||||||
|
* with a node that refers to the same source file, the previously
|
||||||
|
* created one will be returned.
|
||||||
|
*
|
||||||
|
* @param img
|
||||||
|
* The image where this file is to be written
|
||||||
|
* @param new
|
||||||
|
* The IsoFileSrc to add
|
||||||
|
* @param src
|
||||||
|
* Will be filled with a pointer to the IsoFileSrc really present in
|
||||||
|
* the tree. It could be different than new if the same file already
|
||||||
|
* exists in the tree.
|
||||||
|
* @return
|
||||||
|
* 1 on success, 0 if file already exists on tree, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the IsoFileSrc especific data
|
||||||
|
*/
|
||||||
|
void iso_file_src_free(void *node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the file this IsoFileSrc represents
|
||||||
|
*/
|
||||||
|
off_t iso_file_src_get_size(IsoFileSrc *file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Writer for file contents.
|
||||||
|
*
|
||||||
|
* It takes care of written the files in the correct order.
|
||||||
|
*/
|
||||||
|
int iso_file_src_writer_create(Ecma119Image *target);
|
||||||
|
|
||||||
|
#endif /*LIBISO_FILESRC_H_*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,645 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filesystem/FileSource implementation to access the local filesystem.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fsource.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
int iso_file_source_new_lfs(IsoFileSource *parent, const char *name,
|
||||||
|
IsoFileSource **src);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can share a local filesystem object, as it has no private atts.
|
||||||
|
*/
|
||||||
|
IsoFilesystem *lfs= NULL;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/** reference to the parent (if root it points to itself) */
|
||||||
|
IsoFileSource *parent;
|
||||||
|
char *name;
|
||||||
|
unsigned int openned :2; /* 0: not openned, 1: file, 2:dir */
|
||||||
|
union
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
DIR *dir;
|
||||||
|
} info;
|
||||||
|
} _LocalFsFileSource;
|
||||||
|
|
||||||
|
static
|
||||||
|
char* lfs_get_path(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
data = src->data;
|
||||||
|
|
||||||
|
if (data->parent == src) {
|
||||||
|
return strdup("/");
|
||||||
|
} else {
|
||||||
|
char *path = lfs_get_path(data->parent);
|
||||||
|
int pathlen = strlen(path);
|
||||||
|
path = realloc(path, pathlen + strlen(data->name) + 2);
|
||||||
|
if (pathlen != 1) {
|
||||||
|
/* pathlen can only be 1 for root */
|
||||||
|
path[pathlen] = '/';
|
||||||
|
path[pathlen + 1] = '\0';
|
||||||
|
}
|
||||||
|
return strcat(path, data->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
char* lfs_get_name(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
data = src->data;
|
||||||
|
return strdup(data->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_lstat(IsoFileSource *src, struct stat *info)
|
||||||
|
{
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (src == NULL || info == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = src->data;
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
|
||||||
|
if (lstat(path, info) != 0) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* error, choose an appropriate return code */
|
||||||
|
switch (errno) {
|
||||||
|
case EACCES:
|
||||||
|
err = ISO_FILE_ACCESS_DENIED;
|
||||||
|
break;
|
||||||
|
case ENOTDIR:
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
case ELOOP:
|
||||||
|
err = ISO_FILE_BAD_PATH;
|
||||||
|
break;
|
||||||
|
case ENOENT:
|
||||||
|
err = ISO_FILE_DOESNT_EXIST;
|
||||||
|
break;
|
||||||
|
case EFAULT:
|
||||||
|
case ENOMEM:
|
||||||
|
err = ISO_OUT_OF_MEM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = ISO_FILE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_stat(IsoFileSource *src, struct stat *info)
|
||||||
|
{
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (src == NULL || info == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = src->data;
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
|
||||||
|
if (stat(path, info) != 0) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* error, choose an appropriate return code */
|
||||||
|
switch (errno) {
|
||||||
|
case EACCES:
|
||||||
|
err = ISO_FILE_ACCESS_DENIED;
|
||||||
|
break;
|
||||||
|
case ENOTDIR:
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
case ELOOP:
|
||||||
|
err = ISO_FILE_BAD_PATH;
|
||||||
|
break;
|
||||||
|
case ENOENT:
|
||||||
|
err = ISO_FILE_DOESNT_EXIST;
|
||||||
|
break;
|
||||||
|
case EFAULT:
|
||||||
|
case ENOMEM:
|
||||||
|
err = ISO_OUT_OF_MEM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = ISO_FILE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_access(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (src == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = src->data;
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
|
||||||
|
ret = iso_eaccess(path);
|
||||||
|
free(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_open(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct stat info;
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (src == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = src->data;
|
||||||
|
if (data->openned) {
|
||||||
|
return ISO_FILE_ALREADY_OPENNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is a file or a dir ? */
|
||||||
|
err = lfs_stat(src, &info);
|
||||||
|
if (err < 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
if (S_ISDIR(info.st_mode)) {
|
||||||
|
data->info.dir = opendir(path);
|
||||||
|
data->openned = data->info.dir ? 2 : 0;
|
||||||
|
} else {
|
||||||
|
data->info.fd = open(path, O_RDONLY);
|
||||||
|
data->openned = data->info.fd != -1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check for possible errors, note that many of possible ones are
|
||||||
|
* parsed in the lstat call above
|
||||||
|
*/
|
||||||
|
if (data->openned == 0) {
|
||||||
|
switch (errno) {
|
||||||
|
case EACCES:
|
||||||
|
err = ISO_FILE_ACCESS_DENIED;
|
||||||
|
break;
|
||||||
|
case EFAULT:
|
||||||
|
case ENOMEM:
|
||||||
|
err = ISO_OUT_OF_MEM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = ISO_FILE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_close(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
|
||||||
|
if (src == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = src->data;
|
||||||
|
switch (data->openned) {
|
||||||
|
case 1: /* not dir */
|
||||||
|
ret = close(data->info.fd) == 0 ? ISO_SUCCESS : ISO_FILE_ERROR;
|
||||||
|
break;
|
||||||
|
case 2: /* directory */
|
||||||
|
ret = closedir(data->info.dir) == 0 ? ISO_SUCCESS : ISO_FILE_ERROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = ISO_FILE_NOT_OPENNED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret == ISO_SUCCESS) {
|
||||||
|
data->openned = 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_read(IsoFileSource *src, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
|
||||||
|
if (src == NULL || buf == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = src->data;
|
||||||
|
switch (data->openned) {
|
||||||
|
case 1: /* not dir */
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = read(data->info.fd, buf, count);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* error on read */
|
||||||
|
switch (errno) {
|
||||||
|
case EINTR:
|
||||||
|
ret = ISO_INTERRUPTED;
|
||||||
|
break;
|
||||||
|
case EFAULT:
|
||||||
|
ret = ISO_OUT_OF_MEM;
|
||||||
|
break;
|
||||||
|
case EIO:
|
||||||
|
ret = ISO_FILE_READ_ERROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = ISO_FILE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case 2: /* directory */
|
||||||
|
return ISO_FILE_IS_DIR;
|
||||||
|
default:
|
||||||
|
return ISO_FILE_NOT_OPENNED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||||
|
{
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
|
||||||
|
if (src == NULL || child == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = src->data;
|
||||||
|
switch (data->openned) {
|
||||||
|
case 1: /* not dir */
|
||||||
|
return ISO_FILE_IS_NOT_DIR;
|
||||||
|
case 2: /* directory */
|
||||||
|
{
|
||||||
|
struct dirent *entry;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* while to skip "." and ".." dirs */
|
||||||
|
while (1) {
|
||||||
|
entry = readdir(data->info.dir);
|
||||||
|
if (entry == NULL) {
|
||||||
|
if (errno == EBADF)
|
||||||
|
return ISO_FILE_ERROR;
|
||||||
|
else
|
||||||
|
return 0; /* EOF */
|
||||||
|
}
|
||||||
|
if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create the new FileSrc */
|
||||||
|
ret = iso_file_source_new_lfs(src, entry->d_name, child);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ISO_FILE_NOT_OPENNED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
if (src == NULL || buf == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufsiz <= 0) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = src->data;
|
||||||
|
path = lfs_get_path(src);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* invoke readlink, with bufsiz -1 to reserve an space for
|
||||||
|
* the NULL character
|
||||||
|
*/
|
||||||
|
size = readlink(path, buf, bufsiz - 1);
|
||||||
|
free(path);
|
||||||
|
if (size < 0) {
|
||||||
|
/* error */
|
||||||
|
switch (errno) {
|
||||||
|
case EACCES:
|
||||||
|
return ISO_FILE_ACCESS_DENIED;
|
||||||
|
case ENOTDIR:
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
case ELOOP:
|
||||||
|
return ISO_FILE_BAD_PATH;
|
||||||
|
case ENOENT:
|
||||||
|
return ISO_FILE_DOESNT_EXIST;
|
||||||
|
case EINVAL:
|
||||||
|
return ISO_FILE_IS_NOT_SYMLINK;
|
||||||
|
case EFAULT:
|
||||||
|
case ENOMEM:
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
default:
|
||||||
|
return ISO_FILE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NULL-terminate the buf */
|
||||||
|
buf[size] = '\0';
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
IsoFilesystem* lfs_get_filesystem(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
return src == NULL ? NULL : lfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void lfs_free(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
|
||||||
|
data = src->data;
|
||||||
|
|
||||||
|
/* close the file if it is already openned */
|
||||||
|
if (data->openned) {
|
||||||
|
src->class->close(src);
|
||||||
|
}
|
||||||
|
if (data->parent != src) {
|
||||||
|
iso_file_source_unref(data->parent);
|
||||||
|
}
|
||||||
|
free(data->name);
|
||||||
|
free(data);
|
||||||
|
iso_filesystem_unref(lfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
IsoFileSourceIface lfs_class = {
|
||||||
|
0, /* version */
|
||||||
|
lfs_get_path,
|
||||||
|
lfs_get_name,
|
||||||
|
lfs_lstat,
|
||||||
|
lfs_stat,
|
||||||
|
lfs_access,
|
||||||
|
lfs_open,
|
||||||
|
lfs_close,
|
||||||
|
lfs_read,
|
||||||
|
lfs_readdir,
|
||||||
|
lfs_readlink,
|
||||||
|
lfs_get_filesystem,
|
||||||
|
lfs_free
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 success, < 0 error
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int iso_file_source_new_lfs(IsoFileSource *parent, const char *name,
|
||||||
|
IsoFileSource **src)
|
||||||
|
{
|
||||||
|
IsoFileSource *lfs_src;
|
||||||
|
_LocalFsFileSource *data;
|
||||||
|
|
||||||
|
if (src == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lfs == NULL) {
|
||||||
|
/* this should never happen */
|
||||||
|
return ISO_ASSERT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate memory */
|
||||||
|
data = malloc(sizeof(_LocalFsFileSource));
|
||||||
|
if (data == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
lfs_src = malloc(sizeof(IsoFileSource));
|
||||||
|
if (lfs_src == NULL) {
|
||||||
|
free(data);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill struct */
|
||||||
|
data->name = name ? strdup(name) : NULL;
|
||||||
|
data->openned = 0;
|
||||||
|
if (parent) {
|
||||||
|
data->parent = parent;
|
||||||
|
iso_file_source_ref(parent);
|
||||||
|
} else {
|
||||||
|
data->parent = lfs_src;
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_src->refcount = 1;
|
||||||
|
lfs_src->data = data;
|
||||||
|
lfs_src->class = &lfs_class;
|
||||||
|
|
||||||
|
/* take a ref to local filesystem */
|
||||||
|
iso_filesystem_ref(lfs);
|
||||||
|
|
||||||
|
/* return */
|
||||||
|
*src = lfs_src;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_get_root(IsoFilesystem *fs, IsoFileSource **root)
|
||||||
|
{
|
||||||
|
if (fs == NULL || root == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
return iso_file_source_new_lfs(NULL, NULL, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoFileSource *src;
|
||||||
|
struct stat info;
|
||||||
|
char *ptr, *brk_info, *component;
|
||||||
|
|
||||||
|
if (fs == NULL || path == NULL || file == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* first of all check that it is a valid path.
|
||||||
|
*/
|
||||||
|
if (lstat(path, &info) != 0) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* error, choose an appropriate return code */
|
||||||
|
switch (errno) {
|
||||||
|
case EACCES:
|
||||||
|
err = ISO_FILE_ACCESS_DENIED;
|
||||||
|
break;
|
||||||
|
case ENOTDIR:
|
||||||
|
case ENAMETOOLONG:
|
||||||
|
case ELOOP:
|
||||||
|
err = ISO_FILE_BAD_PATH;
|
||||||
|
break;
|
||||||
|
case ENOENT:
|
||||||
|
err = ISO_FILE_DOESNT_EXIST;
|
||||||
|
break;
|
||||||
|
case EFAULT:
|
||||||
|
case ENOMEM:
|
||||||
|
err = ISO_OUT_OF_MEM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = ISO_FILE_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok, path is valid. create the file source */
|
||||||
|
ret = lfs_get_root(fs, &src);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!strcmp(path, "/")) {
|
||||||
|
/* we are looking for root */
|
||||||
|
*file = src;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = strdup(path);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
iso_file_source_unref(src);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
component = strtok_r(ptr, "/", &brk_info);
|
||||||
|
while (component) {
|
||||||
|
IsoFileSource *child = NULL;
|
||||||
|
if (!strcmp(component, ".")) {
|
||||||
|
child = src;
|
||||||
|
} else if (!strcmp(component, "..")) {
|
||||||
|
child = ((_LocalFsFileSource*)src->data)->parent;
|
||||||
|
iso_file_source_ref(child);
|
||||||
|
iso_file_source_unref(src);
|
||||||
|
} else {
|
||||||
|
ret = iso_file_source_new_lfs(src, component, &child);
|
||||||
|
iso_file_source_unref(src);
|
||||||
|
if (ret < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
src = child;
|
||||||
|
component = strtok_r(NULL, "/", &brk_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ptr);
|
||||||
|
if (ret > 0) {
|
||||||
|
*file = src;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
unsigned int lfs_get_id(IsoFilesystem *fs)
|
||||||
|
{
|
||||||
|
return ISO_LOCAL_FS_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_fs_open(IsoFilesystem *fs)
|
||||||
|
{
|
||||||
|
/* open() operation is not needed */
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int lfs_fs_close(IsoFilesystem *fs)
|
||||||
|
{
|
||||||
|
/* close() operation is not needed */
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void lfs_fs_free(IsoFilesystem *fs)
|
||||||
|
{
|
||||||
|
lfs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_local_filesystem_new(IsoFilesystem **fs)
|
||||||
|
{
|
||||||
|
if (fs == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lfs != NULL) {
|
||||||
|
/* just take a new ref */
|
||||||
|
iso_filesystem_ref(lfs);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
lfs = malloc(sizeof(IsoFilesystem));
|
||||||
|
if (lfs == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill struct */
|
||||||
|
strncpy(lfs->type, "file", 4);
|
||||||
|
lfs->refcount = 1;
|
||||||
|
lfs->version = 0;
|
||||||
|
lfs->data = NULL; /* we don't need private data */
|
||||||
|
lfs->get_root = lfs_get_root;
|
||||||
|
lfs->get_by_path = lfs_get_by_path;
|
||||||
|
lfs->get_id = lfs_get_id;
|
||||||
|
lfs->open = lfs_fs_open;
|
||||||
|
lfs->close = lfs_fs_close;
|
||||||
|
lfs->free = lfs_fs_free;
|
||||||
|
}
|
||||||
|
*fs = lfs;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fsource.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Values belong 1000 are reserved for libisofs usage
|
||||||
|
*/
|
||||||
|
unsigned int iso_fs_global_id = 1000;
|
||||||
|
|
||||||
|
void iso_file_source_ref(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
++src->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_file_source_unref(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
if (--src->refcount == 0) {
|
||||||
|
src->class->free(src);
|
||||||
|
free(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_filesystem_ref(IsoFilesystem *fs)
|
||||||
|
{
|
||||||
|
++fs->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_filesystem_unref(IsoFilesystem *fs)
|
||||||
|
{
|
||||||
|
if (--fs->refcount == 0) {
|
||||||
|
fs->free(fs);
|
||||||
|
free(fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this are just helpers to invoque methods in class
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline
|
||||||
|
char* iso_file_source_get_path(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
return src->class->get_path(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
char* iso_file_source_get_name(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
return src->class->get_name(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_file_source_lstat(IsoFileSource *src, struct stat *info)
|
||||||
|
{
|
||||||
|
return src->class->lstat(src, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_file_source_access(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
return src->class->access(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_file_source_stat(IsoFileSource *src, struct stat *info)
|
||||||
|
{
|
||||||
|
return src->class->stat(src, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_file_source_open(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
return src->class->open(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_file_source_close(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
return src->class->close(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_file_source_read(IsoFileSource *src, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
return src->class->read(src, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||||
|
{
|
||||||
|
return src->class->readdir(src, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_file_source_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
|
||||||
|
{
|
||||||
|
return src->class->readlink(src, buf, bufsiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
IsoFilesystem* iso_file_source_get_filesystem(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
return src->class->get_filesystem(src);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_FSOURCE_H_
|
||||||
|
#define LIBISO_FSOURCE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for the file sources. Most functions/structures related with
|
||||||
|
* this were moved to libisofs.h.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
|
||||||
|
#define ISO_LOCAL_FS_ID 1
|
||||||
|
#define ISO_IMAGE_FS_ID 2
|
||||||
|
#define ISO_ELTORITO_FS_ID 3
|
||||||
|
#define ISO_MEM_FS_ID 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IsoFilesystem to deal with local filesystem.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 sucess, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_local_filesystem_new(IsoFilesystem **fs);
|
||||||
|
|
||||||
|
#endif /*LIBISO_FSOURCE_H_*/
|
|
@ -0,0 +1,277 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "eltorito.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new image, empty.
|
||||||
|
*
|
||||||
|
* The image will be owned by you and should be unref() when no more needed.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* Name of the image. This will be used as volset_id and volume_id.
|
||||||
|
* @param image
|
||||||
|
* Location where the image pointer will be stored.
|
||||||
|
* @return
|
||||||
|
* 1 sucess, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_image_new(const char *name, IsoImage **image)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
IsoImage *img;
|
||||||
|
|
||||||
|
if (image == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
img = calloc(1, sizeof(IsoImage));
|
||||||
|
if (img == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* local filesystem will be used by default */
|
||||||
|
res = iso_local_filesystem_new(&(img->fs));
|
||||||
|
if (res < 0) {
|
||||||
|
free(img);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use basic builder as default */
|
||||||
|
res = iso_node_basic_builder_new(&(img->builder));
|
||||||
|
if (res < 0) {
|
||||||
|
iso_filesystem_unref(img->fs);
|
||||||
|
free(img);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill image fields */
|
||||||
|
res = iso_node_new_root(&img->root);
|
||||||
|
if (res < 0) {
|
||||||
|
iso_node_builder_unref(img->builder);
|
||||||
|
iso_filesystem_unref(img->fs);
|
||||||
|
free(img);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
img->refcount = 1;
|
||||||
|
img->id = iso_message_id++;
|
||||||
|
|
||||||
|
if (name != NULL) {
|
||||||
|
img->volset_id = strdup(name);
|
||||||
|
img->volume_id = strdup(name);
|
||||||
|
}
|
||||||
|
*image = img;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the reference counting of the given image.
|
||||||
|
*/
|
||||||
|
void iso_image_ref(IsoImage *image)
|
||||||
|
{
|
||||||
|
++image->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements the reference couting of the given image.
|
||||||
|
* If it reaches 0, the image is free, together with its tree nodes (whether
|
||||||
|
* their refcount reach 0 too, of course).
|
||||||
|
*/
|
||||||
|
void iso_image_unref(IsoImage *image)
|
||||||
|
{
|
||||||
|
if (--image->refcount == 0) {
|
||||||
|
int nexcl;
|
||||||
|
|
||||||
|
/* we need to free the image */
|
||||||
|
if (image->user_data_free != NULL) {
|
||||||
|
/* free attached data */
|
||||||
|
image->user_data_free(image->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (nexcl = 0; nexcl < image->nexcludes; ++nexcl) {
|
||||||
|
free(image->excludes[nexcl]);
|
||||||
|
}
|
||||||
|
free(image->excludes);
|
||||||
|
|
||||||
|
iso_node_unref((IsoNode*)image->root);
|
||||||
|
iso_node_builder_unref(image->builder);
|
||||||
|
iso_filesystem_unref(image->fs);
|
||||||
|
el_torito_boot_catalog_free(image->bootcat);
|
||||||
|
free(image->volset_id);
|
||||||
|
free(image->volume_id);
|
||||||
|
free(image->publisher_id);
|
||||||
|
free(image->data_preparer_id);
|
||||||
|
free(image->system_id);
|
||||||
|
free(image->application_id);
|
||||||
|
free(image->copyright_file_id);
|
||||||
|
free(image->abstract_file_id);
|
||||||
|
free(image->biblio_file_id);
|
||||||
|
free(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach user defined data to the image. Use this if your application needs
|
||||||
|
* to store addition info together with the IsoImage. If the image already
|
||||||
|
* has data attached, the old data will be freed.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* Pointer to application defined data that will be attached to the
|
||||||
|
* image. You can pass NULL to remove any already attached data.
|
||||||
|
* @param give_up
|
||||||
|
* Function that will be called when the image does not need the data
|
||||||
|
* any more. It receives the data pointer as an argumente, and eventually
|
||||||
|
* causes data to be free. It can be NULL if you don't need it.
|
||||||
|
*/
|
||||||
|
int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*))
|
||||||
|
{
|
||||||
|
if (image == NULL || (data != NULL && free == NULL)) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image->user_data != NULL) {
|
||||||
|
/* free previously attached data */
|
||||||
|
if (image->user_data_free) {
|
||||||
|
image->user_data_free(image->user_data);
|
||||||
|
}
|
||||||
|
image->user_data = NULL;
|
||||||
|
image->user_data_free = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data != NULL) {
|
||||||
|
image->user_data = data;
|
||||||
|
image->user_data_free = give_up;
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The the data previously attached with iso_image_attach_data()
|
||||||
|
*/
|
||||||
|
void *iso_image_get_attached_data(IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->user_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsoDir *iso_image_get_root(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_volset_id(IsoImage *image, const char *volset_id)
|
||||||
|
{
|
||||||
|
free(image->volset_id);
|
||||||
|
image->volset_id = strdup(volset_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_volset_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->volset_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_volume_id(IsoImage *image, const char *volume_id)
|
||||||
|
{
|
||||||
|
free(image->volume_id);
|
||||||
|
image->volume_id = strdup(volume_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_volume_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->volume_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_publisher_id(IsoImage *image, const char *publisher_id)
|
||||||
|
{
|
||||||
|
free(image->publisher_id);
|
||||||
|
image->publisher_id = strdup(publisher_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_publisher_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->publisher_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_data_preparer_id(IsoImage *image,
|
||||||
|
const char *data_preparer_id)
|
||||||
|
{
|
||||||
|
free(image->data_preparer_id);
|
||||||
|
image->data_preparer_id = strdup(data_preparer_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_data_preparer_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->data_preparer_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_system_id(IsoImage *image, const char *system_id)
|
||||||
|
{
|
||||||
|
free(image->system_id);
|
||||||
|
image->system_id = strdup(system_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_system_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->system_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_application_id(IsoImage *image, const char *application_id)
|
||||||
|
{
|
||||||
|
free(image->application_id);
|
||||||
|
image->application_id = strdup(application_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_application_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->application_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_copyright_file_id(IsoImage *image,
|
||||||
|
const char *copyright_file_id)
|
||||||
|
{
|
||||||
|
free(image->copyright_file_id);
|
||||||
|
image->copyright_file_id = strdup(copyright_file_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_copyright_file_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->copyright_file_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_abstract_file_id(IsoImage *image,
|
||||||
|
const char *abstract_file_id)
|
||||||
|
{
|
||||||
|
free(image->abstract_file_id);
|
||||||
|
image->abstract_file_id = strdup(abstract_file_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_abstract_file_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->abstract_file_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_image_set_biblio_file_id(IsoImage *image, const char *biblio_file_id)
|
||||||
|
{
|
||||||
|
free(image->biblio_file_id);
|
||||||
|
image->biblio_file_id = strdup(biblio_file_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_image_get_biblio_file_id(const IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->biblio_file_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_image_get_msg_id(IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->id;
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBISO_IMAGE_H_
|
||||||
|
#define LIBISO_IMAGE_H_
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "fsource.h"
|
||||||
|
#include "builder.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Image is a context for image manipulation.
|
||||||
|
* Global objects such as the message_queues must belogn to that
|
||||||
|
* context. Thus we will have, for example, a msg queue per image,
|
||||||
|
* so images are completelly independent and can be managed together.
|
||||||
|
* (Usefull, for example, in Multiple-Document-Interface GUI apps.
|
||||||
|
* [The stuff we have in init belongs really to image!]
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Iso_Image
|
||||||
|
{
|
||||||
|
|
||||||
|
int refcount;
|
||||||
|
|
||||||
|
IsoDir *root;
|
||||||
|
|
||||||
|
char *volset_id;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* el-torito boot catalog */
|
||||||
|
struct el_torito_boot_catalog *bootcat;
|
||||||
|
|
||||||
|
/* image identifier, for message origin identifier */
|
||||||
|
int id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default filesystem to use when adding files to the image tree.
|
||||||
|
*/
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default builder to use when adding files to the image tree.
|
||||||
|
*/
|
||||||
|
IsoNodeBuilder *builder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to follow symlinks or just add them as symlinks
|
||||||
|
*/
|
||||||
|
unsigned int follow_symlinks : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to skip hidden files
|
||||||
|
*/
|
||||||
|
unsigned int ignore_hidden : 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags that determine what special files should be ignore. It is a
|
||||||
|
* bitmask:
|
||||||
|
* bit0: ignore FIFOs
|
||||||
|
* bit1: ignore Sockets
|
||||||
|
* bit2: ignore char devices
|
||||||
|
* bit3: ignore block devices
|
||||||
|
*/
|
||||||
|
int ignore_special;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Files to exclude. Wildcard support is included.
|
||||||
|
*/
|
||||||
|
char** excludes;
|
||||||
|
int nexcludes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if the dir already contains a node with the same name, whether to
|
||||||
|
* replace or not the old node with the new.
|
||||||
|
*/
|
||||||
|
enum iso_replace_mode replace;
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
enum iso_replace_mode (*confirm_replace)(IsoFileSource *src, IsoNode *node);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When this is not NULL, it is a pointer to a function that will
|
||||||
|
* be called just before a file will be added. You can control where
|
||||||
|
* the file will be in fact added or ignored.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 add, 0 ignore, < 0 cancel
|
||||||
|
*/
|
||||||
|
int (*report)(IsoImage *image, IsoFileSource *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User supplied data
|
||||||
|
*/
|
||||||
|
void *user_data;
|
||||||
|
void (*user_data_free)(void *ptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /*LIBISO_IMAGE_H_*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structures related to ISO/IEC 9660:1999, that is version 2 of ISO-9660
|
||||||
|
* "See doc/devel/cookbook/ISO 9660-1999" and
|
||||||
|
* ISO/IEC DIS 9660:1999(E) "Information processing. Volume and file structure
|
||||||
|
* of CD-ROM for Information Interchange"
|
||||||
|
* for further details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_ISO1999_H
|
||||||
|
#define LIBISO_ISO1999_H
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
|
||||||
|
enum iso1999_node_type {
|
||||||
|
ISO1999_FILE,
|
||||||
|
ISO1999_DIR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iso1999_dir_info {
|
||||||
|
Iso1999Node **children;
|
||||||
|
size_t nchildren;
|
||||||
|
size_t len;
|
||||||
|
size_t block;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iso1999_node
|
||||||
|
{
|
||||||
|
char *name; /**< Name chosen output charset. */
|
||||||
|
|
||||||
|
Iso1999Node *parent;
|
||||||
|
|
||||||
|
IsoNode *node; /*< reference to the iso node */
|
||||||
|
|
||||||
|
enum iso1999_node_type type;
|
||||||
|
union {
|
||||||
|
IsoFileSrc *file;
|
||||||
|
struct iso1999_dir_info *dir;
|
||||||
|
} info;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a IsoWriter to deal with ISO 9660:1999 estructures, and add it to
|
||||||
|
* the given target.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int iso1999_writer_create(Ecma119Image *target);
|
||||||
|
|
||||||
|
#endif /* LIBISO_ISO1999_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
* Copyright (c) 2007 Mario Danic
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare Joliet related structures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_JOLIET_H
|
||||||
|
#define LIBISO_JOLIET_H
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
|
||||||
|
enum joliet_node_type {
|
||||||
|
JOLIET_FILE,
|
||||||
|
JOLIET_DIR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct joliet_dir_info {
|
||||||
|
JolietNode **children;
|
||||||
|
size_t nchildren;
|
||||||
|
size_t len;
|
||||||
|
size_t block;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct joliet_node
|
||||||
|
{
|
||||||
|
uint16_t *name; /**< Name in UCS-2BE. */
|
||||||
|
|
||||||
|
JolietNode *parent;
|
||||||
|
|
||||||
|
IsoNode *node; /*< reference to the iso node */
|
||||||
|
|
||||||
|
enum joliet_node_type type;
|
||||||
|
union {
|
||||||
|
IsoFileSrc *file;
|
||||||
|
struct joliet_dir_info *dir;
|
||||||
|
} info;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a IsoWriter to deal with Joliet estructures, and add it to the given
|
||||||
|
* target.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int joliet_writer_create(Ecma119Image *target);
|
||||||
|
|
||||||
|
#endif /* LIBISO_JOLIET_H */
|
|
@ -0,0 +1,439 @@
|
||||||
|
|
||||||
|
/* libiso_msgs (generated from libdax_msgs : Fri Feb 22 19:42:52 CET 2008)
|
||||||
|
Message handling facility of libisofs.
|
||||||
|
Copyright (C) 2006 - 2008 Thomas Schmitt <scdbackup@gmx.net>,
|
||||||
|
provided under GPL version 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
/* Only this single source module is entitled to do this */
|
||||||
|
#define LIBISO_MSGS_H_INTERNAL 1
|
||||||
|
|
||||||
|
/* All participants in the messaging system must do this */
|
||||||
|
#include "libiso_msgs.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------- libiso_msgs_item ------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
static int libiso_msgs_item_new(struct libiso_msgs_item **item,
|
||||||
|
struct libiso_msgs_item *link, int flag)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct libiso_msgs_item *o;
|
||||||
|
struct timeval tv;
|
||||||
|
struct timezone tz;
|
||||||
|
|
||||||
|
(*item)= o=
|
||||||
|
(struct libiso_msgs_item *) malloc(sizeof(struct libiso_msgs_item));
|
||||||
|
if(o==NULL)
|
||||||
|
return(-1);
|
||||||
|
o->timestamp= 0.0;
|
||||||
|
ret= gettimeofday(&tv,&tz);
|
||||||
|
if(ret==0)
|
||||||
|
o->timestamp= tv.tv_sec+0.000001*tv.tv_usec;
|
||||||
|
o->process_id= getpid();
|
||||||
|
o->origin= -1;
|
||||||
|
o->severity= LIBISO_MSGS_SEV_ALL;
|
||||||
|
o->priority= LIBISO_MSGS_PRIO_ZERO;
|
||||||
|
o->error_code= 0;
|
||||||
|
o->msg_text= NULL;
|
||||||
|
o->os_errno= 0;
|
||||||
|
o->prev= link;
|
||||||
|
o->next= NULL;
|
||||||
|
if(link!=NULL) {
|
||||||
|
if(link->next!=NULL) {
|
||||||
|
link->next->prev= o;
|
||||||
|
o->next= link->next;
|
||||||
|
}
|
||||||
|
link->next= o;
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Detaches item from its queue and eventually readjusts start, end pointers
|
||||||
|
of the queue */
|
||||||
|
int libiso_msgs_item_unlink(struct libiso_msgs_item *o,
|
||||||
|
struct libiso_msgs_item **chain_start,
|
||||||
|
struct libiso_msgs_item **chain_end, int flag)
|
||||||
|
{
|
||||||
|
if(o->prev!=NULL)
|
||||||
|
o->prev->next= o->next;
|
||||||
|
if(o->next!=NULL)
|
||||||
|
o->next->prev= o->prev;
|
||||||
|
if(chain_start!=NULL)
|
||||||
|
if(*chain_start == o)
|
||||||
|
*chain_start= o->next;
|
||||||
|
if(chain_end!=NULL)
|
||||||
|
if(*chain_end == o)
|
||||||
|
*chain_end= o->prev;
|
||||||
|
o->next= o->prev= NULL;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_item_destroy(struct libiso_msgs_item **item,
|
||||||
|
int flag)
|
||||||
|
{
|
||||||
|
struct libiso_msgs_item *o;
|
||||||
|
|
||||||
|
o= *item;
|
||||||
|
if(o==NULL)
|
||||||
|
return(0);
|
||||||
|
libiso_msgs_item_unlink(o,NULL,NULL,0);
|
||||||
|
if(o->msg_text!=NULL)
|
||||||
|
free((char *) o->msg_text);
|
||||||
|
free((char *) o);
|
||||||
|
*item= NULL;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_item_get_msg(struct libiso_msgs_item *item,
|
||||||
|
int *error_code, char **msg_text, int *os_errno,
|
||||||
|
int flag)
|
||||||
|
{
|
||||||
|
*error_code= item->error_code;
|
||||||
|
*msg_text= item->msg_text;
|
||||||
|
*os_errno= item->os_errno;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_item_get_origin(struct libiso_msgs_item *item,
|
||||||
|
double *timestamp, pid_t *process_id, int *origin,
|
||||||
|
int flag)
|
||||||
|
{
|
||||||
|
*timestamp= item->timestamp;
|
||||||
|
*process_id= item->process_id;
|
||||||
|
*origin= item->origin;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_item_get_rank(struct libiso_msgs_item *item,
|
||||||
|
int *severity, int *priority, int flag)
|
||||||
|
{
|
||||||
|
*severity= item->severity;
|
||||||
|
*priority= item->priority;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------- libiso_msgs ---------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_new(struct libiso_msgs **m, int flag)
|
||||||
|
{
|
||||||
|
struct libiso_msgs *o;
|
||||||
|
|
||||||
|
(*m)= o= (struct libiso_msgs *) malloc(sizeof(struct libiso_msgs));
|
||||||
|
if(o==NULL)
|
||||||
|
return(-1);
|
||||||
|
o->refcount= 1;
|
||||||
|
o->oldest= NULL;
|
||||||
|
o->youngest= NULL;
|
||||||
|
o->count= 0;
|
||||||
|
o->queue_severity= LIBISO_MSGS_SEV_ALL;
|
||||||
|
o->print_severity= LIBISO_MSGS_SEV_NEVER;
|
||||||
|
strcpy(o->print_id,"libiso: ");
|
||||||
|
|
||||||
|
#ifndef LIBISO_MSGS_SINGLE_THREADED
|
||||||
|
pthread_mutex_init(&(o->lock_mutex),NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int libiso_msgs_lock(struct libiso_msgs *m, int flag)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifndef LIBISO_MSGS_SINGLE_THREADED
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret= pthread_mutex_lock(&(m->lock_mutex));
|
||||||
|
if(ret!=0)
|
||||||
|
return(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int libiso_msgs_unlock(struct libiso_msgs *m, int flag)
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifndef LIBISO_MSGS_SINGLE_THREADED
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret= pthread_mutex_unlock(&(m->lock_mutex));
|
||||||
|
if(ret!=0)
|
||||||
|
return(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_destroy(struct libiso_msgs **m, int flag)
|
||||||
|
{
|
||||||
|
struct libiso_msgs *o;
|
||||||
|
struct libiso_msgs_item *item, *next_item;
|
||||||
|
|
||||||
|
o= *m;
|
||||||
|
if(o==NULL)
|
||||||
|
return(0);
|
||||||
|
if(o->refcount > 1) {
|
||||||
|
if(libiso_msgs_lock(*m,0)<=0)
|
||||||
|
return(-1);
|
||||||
|
o->refcount--;
|
||||||
|
libiso_msgs_unlock(*m,0);
|
||||||
|
*m= NULL;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef LIBISO_MSGS_SINGLE_THREADED
|
||||||
|
if(pthread_mutex_destroy(&(o->lock_mutex))!=0) {
|
||||||
|
pthread_mutex_unlock(&(o->lock_mutex));
|
||||||
|
pthread_mutex_destroy(&(o->lock_mutex));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for(item= o->oldest; item!=NULL; item= next_item) {
|
||||||
|
next_item= item->next;
|
||||||
|
libiso_msgs_item_destroy(&item,0);
|
||||||
|
}
|
||||||
|
free((char *) o);
|
||||||
|
*m= NULL;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_refer(struct libiso_msgs **pt, struct libiso_msgs *m, int flag)
|
||||||
|
{
|
||||||
|
if(libiso_msgs_lock(m,0)<=0)
|
||||||
|
return(0);
|
||||||
|
m->refcount++;
|
||||||
|
*pt= m;
|
||||||
|
libiso_msgs_unlock(m,0);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_set_severities(struct libiso_msgs *m, int queue_severity,
|
||||||
|
int print_severity, char *print_id, int flag)
|
||||||
|
{
|
||||||
|
if(libiso_msgs_lock(m,0)<=0)
|
||||||
|
return(0);
|
||||||
|
m->queue_severity= queue_severity;
|
||||||
|
m->print_severity= print_severity;
|
||||||
|
strncpy(m->print_id,print_id,80);
|
||||||
|
m->print_id[80]= 0;
|
||||||
|
libiso_msgs_unlock(m,0);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs__text_to_sev(char *severity_name, int *severity,
|
||||||
|
int flag)
|
||||||
|
{
|
||||||
|
if(strncmp(severity_name,"NEVER",5)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_NEVER;
|
||||||
|
else if(strncmp(severity_name,"ABORT",5)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_ABORT;
|
||||||
|
else if(strncmp(severity_name,"FATAL",5)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_FATAL;
|
||||||
|
else if(strncmp(severity_name,"FAILURE",7)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_FAILURE;
|
||||||
|
else if(strncmp(severity_name,"MISHAP",6)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_MISHAP;
|
||||||
|
else if(strncmp(severity_name,"SORRY",5)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_SORRY;
|
||||||
|
else if(strncmp(severity_name,"WARNING",7)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_WARNING;
|
||||||
|
else if(strncmp(severity_name,"HINT",4)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_HINT;
|
||||||
|
else if(strncmp(severity_name,"NOTE",4)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_NOTE;
|
||||||
|
else if(strncmp(severity_name,"UPDATE",6)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_UPDATE;
|
||||||
|
else if(strncmp(severity_name,"DEBUG",5)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_DEBUG;
|
||||||
|
else if(strncmp(severity_name,"ERRFILE",7)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_ERRFILE;
|
||||||
|
else if(strncmp(severity_name,"ALL",3)==0)
|
||||||
|
*severity= LIBISO_MSGS_SEV_ALL;
|
||||||
|
else {
|
||||||
|
*severity= LIBISO_MSGS_SEV_ALL;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs__sev_to_text(int severity, char **severity_name,
|
||||||
|
int flag)
|
||||||
|
{
|
||||||
|
if(flag&1) {
|
||||||
|
*severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nMISHAP\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL";
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
*severity_name= "";
|
||||||
|
if(severity>=LIBISO_MSGS_SEV_NEVER)
|
||||||
|
*severity_name= "NEVER";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_ABORT)
|
||||||
|
*severity_name= "ABORT";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_FATAL)
|
||||||
|
*severity_name= "FATAL";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_FAILURE)
|
||||||
|
*severity_name= "FAILURE";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_MISHAP)
|
||||||
|
*severity_name= "MISHAP";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_SORRY)
|
||||||
|
*severity_name= "SORRY";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_WARNING)
|
||||||
|
*severity_name= "WARNING";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_HINT)
|
||||||
|
*severity_name= "HINT";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_NOTE)
|
||||||
|
*severity_name= "NOTE";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_UPDATE)
|
||||||
|
*severity_name= "UPDATE";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_DEBUG)
|
||||||
|
*severity_name= "DEBUG";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_ERRFILE)
|
||||||
|
*severity_name= "ERRFILE";
|
||||||
|
else if(severity>=LIBISO_MSGS_SEV_ALL)
|
||||||
|
*severity_name= "ALL";
|
||||||
|
else {
|
||||||
|
*severity_name= "";
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_submit(struct libiso_msgs *m, int origin, int error_code,
|
||||||
|
int severity, int priority, char *msg_text,
|
||||||
|
int os_errno, int flag)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *textpt,*sev_name,sev_text[81];
|
||||||
|
struct libiso_msgs_item *item= NULL;
|
||||||
|
|
||||||
|
if(severity >= m->print_severity) {
|
||||||
|
if(msg_text==NULL)
|
||||||
|
textpt= "";
|
||||||
|
else
|
||||||
|
textpt= msg_text;
|
||||||
|
sev_text[0]= 0;
|
||||||
|
ret= libiso_msgs__sev_to_text(severity,&sev_name,0);
|
||||||
|
if(ret>0)
|
||||||
|
sprintf(sev_text,"%s : ",sev_name);
|
||||||
|
|
||||||
|
fprintf(stderr,"%s%s%s\n",m->print_id,sev_text,textpt);
|
||||||
|
if(os_errno!=0) {
|
||||||
|
ret= libiso_msgs_lock(m,0);
|
||||||
|
if(ret<=0)
|
||||||
|
return(-1);
|
||||||
|
fprintf(stderr,"%s( Most recent system error: %d '%s' )\n",
|
||||||
|
m->print_id,os_errno,strerror(os_errno));
|
||||||
|
libiso_msgs_unlock(m,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(severity < m->queue_severity)
|
||||||
|
return(0);
|
||||||
|
|
||||||
|
ret= libiso_msgs_lock(m,0);
|
||||||
|
if(ret<=0)
|
||||||
|
return(-1);
|
||||||
|
ret= libiso_msgs_item_new(&item,m->youngest,0);
|
||||||
|
if(ret<=0)
|
||||||
|
goto failed;
|
||||||
|
item->origin= origin;
|
||||||
|
item->error_code= error_code;
|
||||||
|
item->severity= severity;
|
||||||
|
item->priority= priority;
|
||||||
|
if(msg_text!=NULL) {
|
||||||
|
item->msg_text= malloc(strlen(msg_text)+1);
|
||||||
|
if(item->msg_text==NULL)
|
||||||
|
goto failed;
|
||||||
|
strcpy(item->msg_text,msg_text);
|
||||||
|
}
|
||||||
|
item->os_errno= os_errno;
|
||||||
|
if(m->oldest==NULL)
|
||||||
|
m->oldest= item;
|
||||||
|
m->youngest= item;
|
||||||
|
m->count++;
|
||||||
|
libiso_msgs_unlock(m,0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
fprintf(stderr,"libiso_experimental: message submitted to queue (now %d)\n",
|
||||||
|
m->count);
|
||||||
|
*/
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
failed:;
|
||||||
|
libiso_msgs_item_destroy(&item,0);
|
||||||
|
libiso_msgs_unlock(m,0);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_obtain(struct libiso_msgs *m, struct libiso_msgs_item **item,
|
||||||
|
int severity, int priority, int flag)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct libiso_msgs_item *im, *next_im= NULL;
|
||||||
|
|
||||||
|
*item= NULL;
|
||||||
|
ret= libiso_msgs_lock(m,0);
|
||||||
|
if(ret<=0)
|
||||||
|
return(-1);
|
||||||
|
for(im= m->oldest; im!=NULL; im= next_im) {
|
||||||
|
for(; im!=NULL; im= next_im) {
|
||||||
|
next_im= im->next;
|
||||||
|
if(im->severity>=severity)
|
||||||
|
break;
|
||||||
|
libiso_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
|
||||||
|
libiso_msgs_item_destroy(&im,0); /* severity too low: delete */
|
||||||
|
}
|
||||||
|
if(im==NULL)
|
||||||
|
break;
|
||||||
|
if(im->priority>=priority)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(im==NULL)
|
||||||
|
{ret= 0; goto ex;}
|
||||||
|
libiso_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
|
||||||
|
*item= im;
|
||||||
|
ret= 1;
|
||||||
|
ex:;
|
||||||
|
libiso_msgs_unlock(m,0);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int libiso_msgs_destroy_item(struct libiso_msgs *m,
|
||||||
|
struct libiso_msgs_item **item, int flag)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret= libiso_msgs_lock(m,0);
|
||||||
|
if(ret<=0)
|
||||||
|
return(-1);
|
||||||
|
ret= libiso_msgs_item_destroy(item,0);
|
||||||
|
libiso_msgs_unlock(m,0);
|
||||||
|
return(ret);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,682 @@
|
||||||
|
|
||||||
|
/* libiso_msgs (generated from libdax_msgs : Fri Feb 22 19:42:52 CET 2008)
|
||||||
|
Message handling facility of libisofs.
|
||||||
|
Copyright (C) 2006-2008 Thomas Schmitt <scdbackup@gmx.net>,
|
||||||
|
provided under GPL version 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*Never* set this macro outside libiso_msgs.c !
|
||||||
|
The entrails of the message handling facility are not to be seen by
|
||||||
|
the other library components or the applications.
|
||||||
|
*/
|
||||||
|
#ifdef LIBISO_MSGS_H_INTERNAL
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LIBISO_MSGS_SINGLE_THREADED
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct libiso_msgs_item {
|
||||||
|
|
||||||
|
double timestamp;
|
||||||
|
pid_t process_id;
|
||||||
|
int origin;
|
||||||
|
|
||||||
|
int severity;
|
||||||
|
int priority;
|
||||||
|
|
||||||
|
/* Apply for your developer's error code range at
|
||||||
|
libburn-hackers@pykix.org
|
||||||
|
Report introduced codes in the list below. */
|
||||||
|
int error_code;
|
||||||
|
|
||||||
|
char *msg_text;
|
||||||
|
int os_errno;
|
||||||
|
|
||||||
|
struct libiso_msgs_item *prev,*next;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct libiso_msgs {
|
||||||
|
|
||||||
|
int refcount;
|
||||||
|
|
||||||
|
struct libiso_msgs_item *oldest;
|
||||||
|
struct libiso_msgs_item *youngest;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
int queue_severity;
|
||||||
|
int print_severity;
|
||||||
|
char print_id[81];
|
||||||
|
|
||||||
|
#ifndef LIBISO_MSGS_SINGLE_THREADED
|
||||||
|
pthread_mutex_t lock_mutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* LIBISO_MSGS_H_INTERNAL */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LIBISO_MSGS_H_INCLUDED
|
||||||
|
#define LIBISO_MSGS_H_INCLUDED 1
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef LIBISO_MSGS_H_INTERNAL
|
||||||
|
|
||||||
|
|
||||||
|
/* Architectural aspects */
|
||||||
|
/*
|
||||||
|
libdax_msgs is designed to serve in libraries which want to offer their
|
||||||
|
applications a way to control the output of library messages. It shall be
|
||||||
|
incorporated by an owner, i.e. a software entity which encloses the code
|
||||||
|
of the .c file.
|
||||||
|
|
||||||
|
Owner of libdax_msgs is libburn. A fully compatible variant named libiso_msgs
|
||||||
|
is owned by libisofs and can get generated by a script of the libburn
|
||||||
|
project: libburn/libiso_msgs_to_xyz_msgs.sh .
|
||||||
|
|
||||||
|
Reason: One cannot link two owners of the same variant together because
|
||||||
|
both would offer the same functions to the linker. For that situation one
|
||||||
|
has to create a compatible variant as it is done for libisofs.
|
||||||
|
|
||||||
|
Compatible variants may get plugged together by call combinations like
|
||||||
|
burn_set_messenger(iso_get_messenger());
|
||||||
|
A new variant would demand a _set_messenger() function if it has to work
|
||||||
|
with libisofs. If only libburn is planned as link partner then a simple
|
||||||
|
_get_messenger() does suffice.
|
||||||
|
Take care to shutdown libburn before its provider of the *_msgs object
|
||||||
|
gets shut down.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Public Opaque Handles */
|
||||||
|
|
||||||
|
/** A pointer to this is a opaque handle to a message handling facility */
|
||||||
|
struct libiso_msgs;
|
||||||
|
|
||||||
|
/** A pointer to this is a opaque handle to a single message item */
|
||||||
|
struct libiso_msgs_item;
|
||||||
|
|
||||||
|
#endif /* ! LIBISO_MSGS_H_INTERNAL */
|
||||||
|
|
||||||
|
|
||||||
|
/* Public Macros */
|
||||||
|
|
||||||
|
|
||||||
|
/* Registered Severities */
|
||||||
|
|
||||||
|
/* It is well advisable to let applications select severities via strings and
|
||||||
|
forwarded functions libiso_msgs__text_to_sev(), libiso_msgs__sev_to_text().
|
||||||
|
These macros are for use by the owner of libiso_msgs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Use this to get messages of any severity. Do not use for submitting.
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_ALL 0x00000000
|
||||||
|
|
||||||
|
|
||||||
|
/** Messages of this severity shall transport plain disk file paths
|
||||||
|
whenever an event of severity SORRY or above is related with an
|
||||||
|
individual disk file.
|
||||||
|
No message text shall be added to the file path. The ERRFILE message
|
||||||
|
shall be issued before the human readable message which carries the
|
||||||
|
true event severity. That message should contain the file path so it
|
||||||
|
can be found by strstr(message, path)!=NULL.
|
||||||
|
The error code shall be the same as with the human readable message.
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_ERRFILE 0x08000000
|
||||||
|
|
||||||
|
|
||||||
|
/** Debugging messages not to be visible to normal users by default
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_DEBUG 0x10000000
|
||||||
|
|
||||||
|
/** Update of a progress report about long running actions
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_UPDATE 0x20000000
|
||||||
|
|
||||||
|
/** Not so usual events which were gracefully handled
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_NOTE 0x30000000
|
||||||
|
|
||||||
|
/** Possibilities to achieve a better result
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_HINT 0x40000000
|
||||||
|
|
||||||
|
/** Warnings about problems which could not be handled optimally
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_WARNING 0x50000000
|
||||||
|
|
||||||
|
|
||||||
|
/** Non-fatal error messages indicating that parts of an action failed but
|
||||||
|
processing may go on if one accepts deviations from the desired result.
|
||||||
|
|
||||||
|
SORRY may also be the severity for incidents which are severe enough
|
||||||
|
for FAILURE but happen within already started irrevocable actions,
|
||||||
|
like ISO image generation. A precondition for such a severity ease is
|
||||||
|
that the action can be continued after the incident.
|
||||||
|
See below MISHAP for what xorriso would need instead of this kind of SORRY
|
||||||
|
and generates for itself in case of libisofs image generation.
|
||||||
|
|
||||||
|
E.g.: A pattern yields no result.
|
||||||
|
A speed setting cannot be made.
|
||||||
|
A libisofs input file is inaccessible during image generation.
|
||||||
|
|
||||||
|
After SORRY a function should try to go on if that makes any sense
|
||||||
|
and if no threshold prescribes abort on SORRY. The function should
|
||||||
|
nevertheless indicate some failure in its return value.
|
||||||
|
It should - but it does not have to.
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_SORRY 0x60000000
|
||||||
|
|
||||||
|
|
||||||
|
/** A FAILURE (see below) which can be tolerated during long lasting
|
||||||
|
operations just because they cannot simply be stopped or revoked.
|
||||||
|
|
||||||
|
xorriso converts libisofs SORRY messages issued during image generation
|
||||||
|
into MISHAP messages in order to allow its evaluators to distinguish
|
||||||
|
image generation problems from minor image composition problems.
|
||||||
|
E.g.:
|
||||||
|
A libisofs input file is inaccessible during image generation.
|
||||||
|
|
||||||
|
After a MISHAP a function should behave like after SORRY.
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_MISHAP 0x64000000
|
||||||
|
|
||||||
|
|
||||||
|
/** Non-fatal error indicating that an important part of an action failed and
|
||||||
|
that only a new setup of preconditions will give hope for sufficient
|
||||||
|
success.
|
||||||
|
|
||||||
|
E.g.: No media is inserted in the output drive.
|
||||||
|
No write mode can be found for inserted media.
|
||||||
|
A libisofs input file is inaccessible during grafting.
|
||||||
|
|
||||||
|
After FAILURE a function should end with a return value indicating failure.
|
||||||
|
It is at the discretion of the function whether it ends immediately in any
|
||||||
|
case or whether it tries to go on if the eventual threshold allows.
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_FAILURE 0x68000000
|
||||||
|
|
||||||
|
|
||||||
|
/** An error message which puts the whole operation of the program in question
|
||||||
|
|
||||||
|
E.g.: Not enough memory for essential temporary objects.
|
||||||
|
Irregular errors from resources.
|
||||||
|
Programming errors (soft assert).
|
||||||
|
|
||||||
|
After FATAL a function should end very soon with a return value
|
||||||
|
indicating severe failure.
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_FATAL 0x70000000
|
||||||
|
|
||||||
|
|
||||||
|
/** A message from an abort handler which will finally finish libburn
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_ABORT 0x71000000
|
||||||
|
|
||||||
|
/** A severity to exclude resp. discard any possible message.
|
||||||
|
Do not use this severity for submitting.
|
||||||
|
*/
|
||||||
|
#define LIBISO_MSGS_SEV_NEVER 0x7fffffff
|
||||||
|
|
||||||
|
|
||||||
|
/* Registered Priorities */
|
||||||
|
|
||||||
|
/* Priorities are to be selected by the programmers and not by the user. */
|
||||||
|
|
||||||
|
#define LIBISO_MSGS_PRIO_ZERO 0x00000000
|
||||||
|
#define LIBISO_MSGS_PRIO_LOW 0x10000000
|
||||||
|
#define LIBISO_MSGS_PRIO_MEDIUM 0x20000000
|
||||||
|
#define LIBISO_MSGS_PRIO_HIGH 0x30000000
|
||||||
|
#define LIBISO_MSGS_PRIO_TOP 0x7ffffffe
|
||||||
|
|
||||||
|
/* Do not use this priority for submitting */
|
||||||
|
#define LIBISO_MSGS_PRIO_NEVER 0x7fffffff
|
||||||
|
|
||||||
|
|
||||||
|
/* Origin numbers of libburn drives may range from 0 to 1048575 */
|
||||||
|
#define LIBISO_MSGS_ORIGIN_DRIVE_BASE 0
|
||||||
|
#define LIBISO_MSGS_ORIGIN_DRIVE_TOP 0xfffff
|
||||||
|
|
||||||
|
/* Origin numbers of libisofs images may range from 1048575 to 2097152 */
|
||||||
|
#define LIBISO_MSGS_ORIGIN_IMAGE_BASE 0x100000
|
||||||
|
#define LIBISO_MSGS_ORIGIN_IMAGE_TOP 0x1fffff
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Public Functions */
|
||||||
|
|
||||||
|
/* Calls initiated from inside the direct owner (e.g. from libburn) */
|
||||||
|
|
||||||
|
|
||||||
|
/** Create new empty message handling facility with queue and issue a first
|
||||||
|
official reference to it.
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return >0 success, <=0 failure
|
||||||
|
*/
|
||||||
|
int libiso_msgs_new(struct libiso_msgs **m, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Destroy a message handling facility and all its eventual messages.
|
||||||
|
The submitted pointer gets set to NULL.
|
||||||
|
Actually only the last destroy call of all offical references to the object
|
||||||
|
will really dispose it. All others just decrement the reference counter.
|
||||||
|
Call this function only with official reference pointers obtained by
|
||||||
|
libiso_msgs_new() or libiso_msgs_refer(), and only once per such pointer.
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 for success, 0 for pointer to NULL, -1 for fatal error
|
||||||
|
*/
|
||||||
|
int libiso_msgs_destroy(struct libiso_msgs **m, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Create an official reference to an existing libiso_msgs object. The
|
||||||
|
references keep the object alive at least until it is released by
|
||||||
|
a matching number of destroy calls. So each reference MUST be revoked
|
||||||
|
by exactly one call to libiso_msgs_destroy().
|
||||||
|
@param pt The pointer to be set and registered
|
||||||
|
@param m A pointer to the existing object
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 for success, 0 for failure
|
||||||
|
*/
|
||||||
|
int libiso_msgs_refer(struct libiso_msgs **pt, struct libiso_msgs *o, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Submit a message to a message handling facility.
|
||||||
|
@param origin program specific identification number of the originator of
|
||||||
|
a message. E.g. drive number. Programs should have an own
|
||||||
|
range of origin numbers. See above LIBISO_MSGS_ORIGIN_*_BASE
|
||||||
|
Use -1 if no number is known.
|
||||||
|
@param error_code Unique error code. Use only registered codes. See below.
|
||||||
|
The same unique error_code may be issued at different
|
||||||
|
occasions but those should be equivalent out of the view
|
||||||
|
of a libiso_msgs application. (E.g. "cannot open ATA drive"
|
||||||
|
versus "cannot open SCSI drive" would be equivalent.)
|
||||||
|
@param severity The LIBISO_MSGS_SEV_* of the event.
|
||||||
|
@param priority The LIBISO_MSGS_PRIO_* number of the event.
|
||||||
|
@param msg_text Printable and human readable message text.
|
||||||
|
@param os_errno Eventual error code from operating system (0 if none)
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 on success, 0 on rejection, <0 for severe errors
|
||||||
|
*/
|
||||||
|
int libiso_msgs_submit(struct libiso_msgs *m, int origin, int error_code,
|
||||||
|
int severity, int priority, char *msg_text,
|
||||||
|
int os_errno, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Calls from applications (to be forwarded by direct owner) */
|
||||||
|
|
||||||
|
|
||||||
|
/** Convert a registered severity number into a severity name
|
||||||
|
@param flag Bitfield for control purposes:
|
||||||
|
bit0= list all severity names in a newline separated string
|
||||||
|
@return >0 success, <=0 failure
|
||||||
|
*/
|
||||||
|
int libiso_msgs__sev_to_text(int severity, char **severity_name,
|
||||||
|
int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Convert a severity name into a severity number,
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return >0 success, <=0 failure
|
||||||
|
*/
|
||||||
|
int libiso_msgs__text_to_sev(char *severity_name, int *severity,
|
||||||
|
int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Set minimum severity for messages to be queued (default
|
||||||
|
LIBISO_MSGS_SEV_ALL) and for messages to be printed directly to stderr
|
||||||
|
(default LIBISO_MSGS_SEV_NEVER).
|
||||||
|
@param print_id A text of at most 80 characters to be printed before
|
||||||
|
any eventually printed message (default is "libiso: ").
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return always 1 for now
|
||||||
|
*/
|
||||||
|
int libiso_msgs_set_severities(struct libiso_msgs *m, int queue_severity,
|
||||||
|
int print_severity, char *print_id, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Obtain a message item that has at least the given severity and priority.
|
||||||
|
Usually all older messages of lower severity are discarded then. If no
|
||||||
|
item of sufficient severity was found, all others are discarded from the
|
||||||
|
queue.
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 if a matching item was found, 0 if not, <0 for severe errors
|
||||||
|
*/
|
||||||
|
int libiso_msgs_obtain(struct libiso_msgs *m, struct libiso_msgs_item **item,
|
||||||
|
int severity, int priority, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Destroy a message item obtained by libiso_msgs_obtain(). The submitted
|
||||||
|
pointer gets set to NULL.
|
||||||
|
Caution: Copy eventually obtained msg_text before destroying the item,
|
||||||
|
if you want to use it further.
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 for success, 0 for pointer to NULL, <0 for severe errors
|
||||||
|
*/
|
||||||
|
int libiso_msgs_destroy_item(struct libiso_msgs *m,
|
||||||
|
struct libiso_msgs_item **item, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Obtain from a message item the three application oriented components as
|
||||||
|
submitted with the originating call of libiso_msgs_submit().
|
||||||
|
Caution: msg_text becomes a pointer into item, not a copy.
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 on success, 0 on invalid item, <0 for servere errors
|
||||||
|
*/
|
||||||
|
int libiso_msgs_item_get_msg(struct libiso_msgs_item *item,
|
||||||
|
int *error_code, char **msg_text, int *os_errno,
|
||||||
|
int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Obtain from a message item the submitter identification submitted
|
||||||
|
with the originating call of libiso_msgs_submit().
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 on success, 0 on invalid item, <0 for servere errors
|
||||||
|
*/
|
||||||
|
int libiso_msgs_item_get_origin(struct libiso_msgs_item *item,
|
||||||
|
double *timestamp, pid_t *process_id, int *origin,
|
||||||
|
int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Obtain from a message item severity and priority as submitted
|
||||||
|
with the originating call of libiso_msgs_submit().
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 on success, 0 on invalid item, <0 for servere errors
|
||||||
|
*/
|
||||||
|
int libiso_msgs_item_get_rank(struct libiso_msgs_item *item,
|
||||||
|
int *severity, int *priority, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LIDBAX_MSGS_________________
|
||||||
|
|
||||||
|
|
||||||
|
/* Registered Error Codes */
|
||||||
|
|
||||||
|
|
||||||
|
Format: error_code (LIBISO_MSGS_SEV_*,LIBISO_MSGS_PRIO_*) = explanation
|
||||||
|
If no severity or priority are fixely associated, use "(,)".
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Range "libiso_msgs" : 0x00000000 to 0x0000ffff
|
||||||
|
|
||||||
|
0x00000000 (ALL,ZERO) = Initial setting in new libiso_msgs_item
|
||||||
|
0x00000001 (DEBUG,ZERO) = Test error message
|
||||||
|
0x00000002 (DEBUG,ZERO) = Debugging message
|
||||||
|
0x00000003 (FATAL,HIGH) = Out of virtual memory
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Range "elmom" : 0x00010000 to 0x0001ffff
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||||
|
|
||||||
|
Acessing and defending drives:
|
||||||
|
|
||||||
|
0x00020001 (SORRY,LOW) = Cannot open busy device
|
||||||
|
0x00020002 (SORRY,HIGH) = Encountered error when closing drive
|
||||||
|
0x00020003 (SORRY,HIGH) = Could not grab drive
|
||||||
|
0x00020004 (NOTE,HIGH) = Opened O_EXCL scsi sibling
|
||||||
|
0x00020005 (SORRY,HIGH) = Failed to open device
|
||||||
|
0x00020006 (FATAL,HIGH) = Too many scsi siblings
|
||||||
|
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
|
||||||
|
0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock
|
||||||
|
0x00020009 (SORRY,HIGH) = Neither stdio-path nor its directory exist
|
||||||
|
|
||||||
|
General library operations:
|
||||||
|
|
||||||
|
0x00020101 (WARNING,HIGH) = Cannot find given worker item
|
||||||
|
0x00020102 (SORRY,HIGH) = A drive operation is still going on
|
||||||
|
0x00020103 (WARNING,HIGH) = After scan a drive operation is still going on
|
||||||
|
0x00020104 (SORRY,HIGH) = NULL pointer caught
|
||||||
|
0x00020105 (SORRY,HIGH) = Drive is already released
|
||||||
|
0x00020106 (SORRY,HIGH) = Drive is busy on attempt to close
|
||||||
|
0x00020107 (WARNING,HIGH) = A drive is still busy on shutdown of library
|
||||||
|
0x00020108 (SORRY,HIGH) = Drive is not grabbed on disc status inquiry
|
||||||
|
0x00020108 (FATAL,HIGH) = Could not allocate new drive object
|
||||||
|
0x00020109 (FATAL,HIGH) = Library not running
|
||||||
|
0x0002010a (FATAL,HIGH) = Unsuitable track mode
|
||||||
|
0x0002010b (FATAL,HIGH) = Burn run failed
|
||||||
|
0x0002010c (FATAL,HIGH) = Failed to transfer command to drive
|
||||||
|
0x0002010d (DEBUG,HIGH) = Could not inquire TOC
|
||||||
|
0x0002010e (FATAL,HIGH) = Attempt to read ATIP from ungrabbed drive
|
||||||
|
0x0002010f (DEBUG,HIGH) = SCSI error condition on command
|
||||||
|
0x00020110 (FATAL,HIGH) = Persistent drive address too long
|
||||||
|
0x00020111 (FATAL,HIGH) = Could not allocate new auxiliary object
|
||||||
|
0x00020112 (SORRY,HIGH) = Bad combination of write_type and block_type
|
||||||
|
0x00020113 (FATAL,HIGH) = Drive capabilities not inquired yet
|
||||||
|
0x00020114 (SORRY,HIGH) = Attempt to set ISRC with bad data
|
||||||
|
0x00020115 (SORRY,HIGH) = Attempt to set track mode to unusable value
|
||||||
|
0x00020116 (FATAL,HIGH) = Track mode has unusable value
|
||||||
|
0x00020117 (FATAL,HIGH) = toc_entry of drive is already in use
|
||||||
|
0x00020118 (DEBUG,HIGH) = Closing track
|
||||||
|
0x00020119 (DEBUG,HIGH) = Closing session
|
||||||
|
0x0002011a (NOTE,HIGH) = Padding up track to minimum size
|
||||||
|
0x0002011b (FATAL,HIGH) = Attempt to read track info from ungrabbed drive
|
||||||
|
0x0002011c (FATAL,HIGH) = Attempt to read track info from busy drive
|
||||||
|
0x0002011d (FATAL,HIGH) = SCSI error on write
|
||||||
|
0x0002011e (SORRY,HIGH) = Unsuitable media detected
|
||||||
|
0x0002011f (SORRY,HIGH) = Burning is restricted to a single track
|
||||||
|
0x00020120 (NOTE,HIGH) = FORMAT UNIT ignored
|
||||||
|
0x00020121 (FATAL,HIGH) = Write preparation setup failed
|
||||||
|
0x00020122 (FATAL,HIGH) = SCSI error on format_unit
|
||||||
|
0x00020123 (SORRY,HIGH) = DVD Media are unsuitable for desired track type
|
||||||
|
0x00020124 (SORRY,HIGH) = SCSI error on set_streaming
|
||||||
|
0x00020125 (SORRY,HIGH) = Write start address not supported
|
||||||
|
0x00020126 (SORRY,HIGH) = Write start address not properly aligned
|
||||||
|
0x00020127 (NOTE,HIGH) = Write start address is ...
|
||||||
|
0x00020128 (FATAL,HIGH) = Unsupported inquiry_type with mmc_get_performance
|
||||||
|
0x00020129 (SORRY,HIGH) = Will not format media type
|
||||||
|
0x0002012a (FATAL,HIGH) = Cannot inquire write mode capabilities
|
||||||
|
0x0002012b (FATAL,HIGH) = Drive offers no suitable write mode with this job
|
||||||
|
0x0002012c (SORRY,HIGH) = Too many logical tracks recorded
|
||||||
|
0x0002012d (FATAL,HIGH) = Exceeding range of permissible write addresses
|
||||||
|
0x0002012e (NOTE,HIGH) = Activated track default size
|
||||||
|
0x0002012f (SORRY,HIGH) = SAO is restricted to single fixed size session
|
||||||
|
0x00020130 (SORRY,HIGH) = Drive and media state unsuitable for blanking
|
||||||
|
0x00020131 (SORRY,HIGH) = No suitable formatting type offered by drive
|
||||||
|
0x00020132 (SORRY,HIGH) = Selected format is not suitable for libburn
|
||||||
|
0x00020133 (SORRY,HIGH) = Cannot mix data and audio in SAO mode
|
||||||
|
0x00020134 (NOTE,HIGH) = Defaulted TAO to DAO
|
||||||
|
0x00020135 (SORRY,HIGH) = Cannot perform TAO, job unsuitable for DAO
|
||||||
|
0x00020136 (SORRY,HIGH) = DAO burning restricted to single fixed size track
|
||||||
|
0x00020137 (HINT,HIGH) = TAO would be possible
|
||||||
|
0x00020138 (FATAL,HIGH) = Cannot reserve track
|
||||||
|
0x00020139 (SORRY,HIGH) = Write job parameters are unsuitable
|
||||||
|
0x0002013a (FATAL,HIGH) = No suitable media detected
|
||||||
|
0x0002013b (DEBUG,HIGH) = SCSI command indicates host or driver error
|
||||||
|
0x0002013c (SORRY,HIGH) = Malformed capabilities page 2Ah received
|
||||||
|
0x0002013d (DEBUG,LOW) = Waiting for free buffer space takes long time
|
||||||
|
0x0002013e (SORRY,HIGH) = Timeout with waiting for free buffer. Now disabled
|
||||||
|
0x0002013f (DEBUG,LOW) = Reporting total time spent with waiting for buffer
|
||||||
|
0x00020140 (FATAL,HIGH) = Drive is busy on attempt to write random access
|
||||||
|
0x00020141 (SORRY,HIGH) = Write data count not properly aligned
|
||||||
|
0x00020142 (FATAL,HIGH) = Drive is not grabbed on random access write
|
||||||
|
0x00020143 (SORRY,HIGH) = Read start address not properly aligned
|
||||||
|
0x00020144 (SORRY,HIGH) = SCSI error on read
|
||||||
|
0x00020145 (FATAL,HIGH) = Drive is busy on attempt to read data
|
||||||
|
0x00020146 (FATAL,HIGH) = Drive is a virtual placeholder
|
||||||
|
0x00020147 (SORRY,HIGH) = Cannot address start byte
|
||||||
|
0x00020148 (SORRY,HIGH) = Cannot write desired amount of data
|
||||||
|
0x00020149 (SORRY,HIGH) = Unsuitable filetype for pseudo-drive
|
||||||
|
0x0002014a (SORRY,HIGH) = Cannot read desired amount of data
|
||||||
|
0x0002014b (SORRY,HIGH) = Drive is already registered resp. scanned
|
||||||
|
0x0002014c (FATAL,HIGH) = Emulated drive caught in SCSI function
|
||||||
|
0x0002014d (SORRY,HIGH) = Asynchromous SCSI error
|
||||||
|
0x0002014f (SORRY,HIGH) = Timeout with asynchromous SCSI command
|
||||||
|
0x00020150 (DEBUG,LOW) = Reporting asynchronous waiting time
|
||||||
|
0x00020151 (FATAL,HIGH) = Read attempt on write-only drive
|
||||||
|
0x00020152 (FATAL,HIGH) = Cannot start fifo thread
|
||||||
|
0x00020153 (SORRY,HIGH) = Read error on fifo input
|
||||||
|
0x00020154 (NOTE,HIGH) = Forwarded input error ends output
|
||||||
|
0x00020155 (SORRY,HIGH) = Desired fifo buffer too large
|
||||||
|
0x00020156 (SORRY,HIGH) = Desired fifo buffer too small
|
||||||
|
0x00020157 (FATAL,HIGH) = burn_source is not a fifo object
|
||||||
|
0x00020158 (DEBUG,LOW) = Reporting thread disposal precautions
|
||||||
|
0x00020159 (DEBUG,HIGH) = TOC Format 0 returns inconsistent data
|
||||||
|
|
||||||
|
libiso_audioxtr:
|
||||||
|
0x00020200 (SORRY,HIGH) = Cannot open audio source file
|
||||||
|
0x00020201 (SORRY,HIGH) = Audio source file has unsuitable format
|
||||||
|
0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Range "vreixo" : 0x00030000 to 0x0003ffff
|
||||||
|
|
||||||
|
0x0003ffff (FAILURE,HIGH) = Operation canceled
|
||||||
|
0x0003fffe (FATAL,HIGH) = Unknown or unexpected fatal error
|
||||||
|
0x0003fffd (FAILURE,HIGH) = Unknown or unexpected error
|
||||||
|
0x0003fffc (FATAL,HIGH) = Internal programming error
|
||||||
|
0x0003fffb (FAILURE,HIGH) = NULL pointer where NULL not allowed
|
||||||
|
0x0003fffa (FATAL,HIGH) = Memory allocation error
|
||||||
|
0x0003fff9 (FATAL,HIGH) = Interrupted by a signal
|
||||||
|
0x0003fff8 (FAILURE,HIGH) = Invalid parameter value
|
||||||
|
0x0003fff7 (FATAL,HIGH) = Cannot create a needed thread
|
||||||
|
0x0003fff6 (FAILURE,HIGH) = Write error
|
||||||
|
0x0003fff5 (FAILURE,HIGH) = Buffer read error
|
||||||
|
0x0003ffc0 (FAILURE,HIGH) = Trying to add a node already added to another dir
|
||||||
|
0x0003ffbf (FAILURE,HIGH) = Node with same name already exist
|
||||||
|
0x0003ffbe (FAILURE,HIGH) = Trying to remove a node that was not added to dir
|
||||||
|
0x0003ffbd (FAILURE,HIGH) = A requested node does not exist
|
||||||
|
0x0003ffbc (FAILURE,HIGH) = Image already bootable
|
||||||
|
0x0003ffbb (FAILURE,HIGH) = Trying to use an invalid file as boot image
|
||||||
|
0x0003ff80 (FAILURE,HIGH) = Error on file operation
|
||||||
|
0x0003ff7f (FAILURE,HIGH) = Trying to open an already openned file
|
||||||
|
0x0003ff7e (FAILURE,HIGH) = Access to file is not allowed
|
||||||
|
0x0003ff7d (FAILURE,HIGH) = Incorrect path to file
|
||||||
|
0x0003ff7c (FAILURE,HIGH) = The file does not exist in the filesystem
|
||||||
|
0x0003ff7b (FAILURE,HIGH) = Trying to read or close a file not openned
|
||||||
|
0x0003ff7a (FAILURE,HIGH) = Directory used where no dir is expected
|
||||||
|
0x0003ff79 (FAILURE,HIGH) = File read error
|
||||||
|
0x0003ff78 (FAILURE,HIGH) = Not dir used where a dir is expected
|
||||||
|
0x0003ff77 (FAILURE,HIGH) = Not symlink used where a symlink is expected
|
||||||
|
0x0003ff76 (FAILURE,HIGH) = Cannot seek to specified location
|
||||||
|
0x0003ff75 (HINT,MEDIUM) = File not supported in ECMA-119 tree and ignored
|
||||||
|
0x0003ff74 (HINT,MEDIUM) = File bigger than supported by used standard
|
||||||
|
0x0003ff73 (MISHAP,HIGH) = File read error during image creation
|
||||||
|
0x0003ff72 (HINT,MEDIUM) = Cannot convert filename to requested charset
|
||||||
|
0x0003ff71 (SORRY,HIGH) = File cannot be added to the tree
|
||||||
|
0x0003ff70 (HINT,MEDIUM) = File path breaks specification constraints
|
||||||
|
0x0003ff00 (FAILURE,HIGH) = Charset conversion error
|
||||||
|
0x0003feff (FAILURE,HIGH) = Too much files to mangle
|
||||||
|
0x0003fec0 (FAILURE,HIGH) = Wrong or damaged Primary Volume Descriptor
|
||||||
|
0x0003febf (SORRY,HIGH) = Wrong or damaged RR entry
|
||||||
|
0x0003febe (SORRY,HIGH) = Unsupported RR feature
|
||||||
|
0x0003febd (FAILURE,HIGH) = Wrong or damaged ECMA-119
|
||||||
|
0x0003febc (FAILURE,HIGH) = Unsupported ECMA-119 feature
|
||||||
|
0x0003febb (SORRY,HIGH) = Wrong or damaged El-Torito catalog
|
||||||
|
0x0003feba (SORRY,HIGH) = Unsupported El-Torito feature
|
||||||
|
0x0003feb9 (SORRY,HIGH) = Cannot patch isolinux boot image
|
||||||
|
0x0003feb8 (SORRY,HIGH) = Unsupported SUSP feature
|
||||||
|
0x0003feb7 (WARNING,HIGH) = Error on a RR entry that can be ignored
|
||||||
|
0x0003feb6 (HINT,MEDIUM) = Error on a RR entry that can be ignored
|
||||||
|
0x0003feb5 (WARNING,HIGH) = Multiple ER SUSP entries found
|
||||||
|
0x0003feb4 (HINT,MEDIUM) = Unsupported volume descriptor found
|
||||||
|
0x0003feb3 (WARNING,HIGH) = El-Torito related warning
|
||||||
|
0x0003feb2 (MISHAP,HIGH) = Image write cancelled
|
||||||
|
0x0003feb1 (WARNING,HIGH) = El-Torito image is hidden
|
||||||
|
|
||||||
|
Outdated codes which may not be re-used for other purposes than
|
||||||
|
re-instating them, if ever:
|
||||||
|
|
||||||
|
X 0x00031001 (SORRY,HIGH) = Cannot read file (ignored)
|
||||||
|
X 0x00031002 (FATAL,HIGH) = Cannot read file (operation canceled)
|
||||||
|
X 0x00031000 (FATAL,HIGH) = Unsupported ISO-9660 image
|
||||||
|
X 0x00031001 (HINT,MEDIUM) = Unsupported Vol Desc that will be ignored
|
||||||
|
X 0x00031002 (FATAL,HIGH) = Damaged ISO-9660 image
|
||||||
|
X 0x00031003 (SORRY,HIGH) = Cannot read previous image file
|
||||||
|
X 0x00030101 (HINT,MEDIUM) = Unsupported SUSP entry that will be ignored
|
||||||
|
X 0x00030102 (SORRY,HIGH) = Wrong/damaged SUSP entry
|
||||||
|
X 0x00030103 (WARNING,MEDIUM)= Multiple SUSP ER entries where found
|
||||||
|
X 0x00030111 (SORRY,HIGH) = Unsupported RR feature
|
||||||
|
X 0x00030112 (SORRY,HIGH) = Error in a Rock Ridge entry
|
||||||
|
X 0x00030201 (HINT,MEDIUM) = Unsupported Boot Vol Desc that will be ignored
|
||||||
|
X 0x00030202 (SORRY,HIGH) = Wrong El-Torito catalog
|
||||||
|
X 0x00030203 (HINT,MEDIUM) = Unsupported El-Torito feature
|
||||||
|
X 0x00030204 (SORRY,HIGH) = Invalid file to be an El-Torito image
|
||||||
|
X 0x00030205 (WARNING,MEDIUM)= Cannot properly patch isolinux image
|
||||||
|
X 0x00030206 (WARNING,MEDIUM)= Copying El-Torito from a previous image without
|
||||||
|
X enought info about it
|
||||||
|
X 0x00030301 (NOTE,MEDIUM) = Unsupported file type for Joliet tree
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Range "application" : 0x00040000 to 0x0004ffff
|
||||||
|
|
||||||
|
0x00040000 (ABORT,HIGH) : Application supplied message
|
||||||
|
0x00040001 (FATAL,HIGH) : Application supplied message
|
||||||
|
0x00040002 (SORRY,HIGH) : Application supplied message
|
||||||
|
0x00040003 (WARNING,HIGH) : Application supplied message
|
||||||
|
0x00040004 (HINT,HIGH) : Application supplied message
|
||||||
|
0x00040005 (NOTE,HIGH) : Application supplied message
|
||||||
|
0x00040006 (UPDATE,HIGH) : Application supplied message
|
||||||
|
0x00040007 (DEBUG,HIGH) : Application supplied message
|
||||||
|
0x00040008 (*,HIGH) : Application supplied message
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Range "libisofs-xorriso" : 0x00050000 to 0x0005ffff
|
||||||
|
|
||||||
|
This is an alternative representation of libisofs.so.6 error codes in xorriso.
|
||||||
|
If values returned by iso_error_get_code() do not fit into 0x30000 to 0x3ffff
|
||||||
|
then they get truncated to 16 bit and mapped into this range.
|
||||||
|
(This should never need to happen, of course.)
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
Range "libisoburn" : 0x00060000 to 0x00006ffff
|
||||||
|
|
||||||
|
0x00060000 (*,*) : Message which shall be attributed to libisoburn
|
||||||
|
|
||||||
|
>>> the messages of libisoburn need to be registered individually
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif /* LIDBAX_MSGS_________________ */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LIBISO_MSGS_H_INTERNAL
|
||||||
|
|
||||||
|
/* Internal Functions */
|
||||||
|
|
||||||
|
|
||||||
|
/** Lock before doing side effect operations on m */
|
||||||
|
static int libiso_msgs_lock(struct libiso_msgs *m, int flag);
|
||||||
|
|
||||||
|
/** Unlock after effect operations on m are done */
|
||||||
|
static int libiso_msgs_unlock(struct libiso_msgs *m, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
/** Create new empty message item.
|
||||||
|
@param link Previous item in queue
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return >0 success, <=0 failure
|
||||||
|
*/
|
||||||
|
static int libiso_msgs_item_new(struct libiso_msgs_item **item,
|
||||||
|
struct libiso_msgs_item *link, int flag);
|
||||||
|
|
||||||
|
/** Destroy a message item obtained by libiso_msgs_obtain(). The submitted
|
||||||
|
pointer gets set to NULL.
|
||||||
|
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||||
|
@return 1 for success, 0 for pointer to NULL
|
||||||
|
*/
|
||||||
|
static int libiso_msgs_item_destroy(struct libiso_msgs_item **item, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* LIBISO_MSGS_H_INTERNAL */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ! LIBISO_MSGS_H_INCLUDED */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,428 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "libiso_msgs.h"
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "messages.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* error codes are 32 bit numbers, that follow the following conventions:
|
||||||
|
*
|
||||||
|
* bit 31 (MSB) -> 1 (to make the value always negative)
|
||||||
|
* bits 30-24 -> Encoded severity (Use ISO_ERR_SEV to translate an error code
|
||||||
|
* to a LIBISO_MSGS_SEV_* constant)
|
||||||
|
* = 0x10 -> DEBUG
|
||||||
|
* = 0x20 -> UPDATE
|
||||||
|
* = 0x30 -> NOTE
|
||||||
|
* = 0x40 -> HINT
|
||||||
|
* = 0x50 -> WARNING
|
||||||
|
* = 0x60 -> SORRY
|
||||||
|
* = 0x64 -> MISHAP
|
||||||
|
* = 0x68 -> FAILURE
|
||||||
|
* = 0x70 -> FATAL
|
||||||
|
* = 0x71 -> ABORT
|
||||||
|
* bits 23-20 -> Encoded priority (Use ISO_ERR_PRIO to translate an error code
|
||||||
|
* to a LIBISO_MSGS_PRIO_* constant)
|
||||||
|
* = 0x0 -> ZERO
|
||||||
|
* = 0x1 -> LOW
|
||||||
|
* = 0x2 -> MEDIUM
|
||||||
|
* = 0x3 -> HIGH
|
||||||
|
* bits 19-16 -> Reserved for future usage (maybe message ranges)
|
||||||
|
* bits 15-0 -> Error code
|
||||||
|
*/
|
||||||
|
#define ISO_ERR_SEV(e) (e & 0x7F000000)
|
||||||
|
#define ISO_ERR_PRIO(e) ((e & 0x00F00000) << 8)
|
||||||
|
#define ISO_ERR_CODE(e) ((e & 0x0000FFFF) | 0x00030000)
|
||||||
|
|
||||||
|
int iso_message_id = LIBISO_MSGS_ORIGIN_IMAGE_BASE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Threshold for aborting.
|
||||||
|
*/
|
||||||
|
int abort_threshold = LIBISO_MSGS_SEV_FAILURE;
|
||||||
|
|
||||||
|
#define MAX_MSG_LEN 4096
|
||||||
|
|
||||||
|
struct libiso_msgs *libiso_msgr = NULL;
|
||||||
|
|
||||||
|
int iso_init()
|
||||||
|
{
|
||||||
|
if (libiso_msgr == NULL) {
|
||||||
|
if (libiso_msgs_new(&libiso_msgr, 0) <= 0)
|
||||||
|
return ISO_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
libiso_msgs_set_severities(libiso_msgr, LIBISO_MSGS_SEV_NEVER,
|
||||||
|
LIBISO_MSGS_SEV_FATAL, "libisofs: ", 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_finish()
|
||||||
|
{
|
||||||
|
libiso_msgs_destroy(&libiso_msgr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_set_abort_severity(char *severity)
|
||||||
|
{
|
||||||
|
int ret, sevno;
|
||||||
|
|
||||||
|
ret = libiso_msgs__text_to_sev(severity, &sevno, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
if (sevno > LIBISO_MSGS_SEV_FAILURE || sevno < LIBISO_MSGS_SEV_NOTE)
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
ret = abort_threshold;
|
||||||
|
abort_threshold = sevno;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_msg_debug(int imgid, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char msg[MAX_MSG_LEN];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(msg, MAX_MSG_LEN, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
libiso_msgs_submit(libiso_msgr, imgid, 0x00000002, LIBISO_MSGS_SEV_DEBUG,
|
||||||
|
LIBISO_MSGS_PRIO_ZERO, msg, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *iso_error_to_msg(int errcode)
|
||||||
|
{
|
||||||
|
switch(errcode) {
|
||||||
|
case ISO_CANCELED:
|
||||||
|
return "Operation canceled";
|
||||||
|
case ISO_FATAL_ERROR:
|
||||||
|
return "Unknown or unexpected fatal error";
|
||||||
|
case ISO_ERROR:
|
||||||
|
return "Unknown or unexpected error";
|
||||||
|
case ISO_ASSERT_FAILURE:
|
||||||
|
return "Internal programming error. Please report this bug";
|
||||||
|
case ISO_NULL_POINTER:
|
||||||
|
return "NULL pointer as value for an arg. that doesn't allow NULL";
|
||||||
|
case ISO_OUT_OF_MEM:
|
||||||
|
return "Memory allocation error";
|
||||||
|
case ISO_INTERRUPTED:
|
||||||
|
return "Interrupted by a signal";
|
||||||
|
case ISO_WRONG_ARG_VALUE:
|
||||||
|
return "Invalid parameter value";
|
||||||
|
case ISO_THREAD_ERROR:
|
||||||
|
return "Can't create a needed thread";
|
||||||
|
case ISO_WRITE_ERROR:
|
||||||
|
return "Write error";
|
||||||
|
case ISO_BUF_READ_ERROR:
|
||||||
|
return "Buffer read error";
|
||||||
|
case ISO_NODE_ALREADY_ADDED:
|
||||||
|
return "Trying to add to a dir a node already added to a dir";
|
||||||
|
case ISO_NODE_NAME_NOT_UNIQUE:
|
||||||
|
return "Node with same name already exists";
|
||||||
|
case ISO_NODE_NOT_ADDED_TO_DIR:
|
||||||
|
return "Trying to remove a node that was not added to dir";
|
||||||
|
case ISO_NODE_DOESNT_EXIST:
|
||||||
|
return "A requested node does not exist";
|
||||||
|
case ISO_IMAGE_ALREADY_BOOTABLE:
|
||||||
|
return "Try to set the boot image of an already bootable image";
|
||||||
|
case ISO_BOOT_IMAGE_NOT_VALID:
|
||||||
|
return "Trying to use an invalid file as boot image";
|
||||||
|
case ISO_FILE_ERROR:
|
||||||
|
return "Error on file operation";
|
||||||
|
case ISO_FILE_ALREADY_OPENNED:
|
||||||
|
return "Trying to open an already openned file";
|
||||||
|
case ISO_FILE_ACCESS_DENIED:
|
||||||
|
return "Access to file is not allowed";
|
||||||
|
case ISO_FILE_BAD_PATH:
|
||||||
|
return "Incorrect path to file";
|
||||||
|
case ISO_FILE_DOESNT_EXIST:
|
||||||
|
return "The file does not exist in the filesystem";
|
||||||
|
case ISO_FILE_NOT_OPENNED:
|
||||||
|
return "Trying to read or close a file not openned";
|
||||||
|
case ISO_FILE_IS_DIR:
|
||||||
|
return "Directory used where no dir is expected";
|
||||||
|
case ISO_FILE_READ_ERROR:
|
||||||
|
return "Read error";
|
||||||
|
case ISO_FILE_IS_NOT_DIR:
|
||||||
|
return "Not dir used where a dir is expected";
|
||||||
|
case ISO_FILE_IS_NOT_SYMLINK:
|
||||||
|
return "Not symlink used where a symlink is expected";
|
||||||
|
case ISO_FILE_SEEK_ERROR:
|
||||||
|
return "Can't seek to specified location";
|
||||||
|
case ISO_FILE_IGNORED:
|
||||||
|
return "File not supported in ECMA-119 tree and thus ignored";
|
||||||
|
case ISO_FILE_TOO_BIG:
|
||||||
|
return "A file is bigger than supported by used standard";
|
||||||
|
case ISO_FILE_CANT_WRITE:
|
||||||
|
return "File read error during image creation";
|
||||||
|
case ISO_FILENAME_WRONG_CHARSET:
|
||||||
|
return "Can't convert filename to requested charset";
|
||||||
|
case ISO_FILE_CANT_ADD:
|
||||||
|
return "File can't be added to the tree";
|
||||||
|
case ISO_FILE_IMGPATH_WRONG:
|
||||||
|
return "File path break specification constraints and will be ignored";
|
||||||
|
case ISO_CHARSET_CONV_ERROR:
|
||||||
|
return "Charset conversion error";
|
||||||
|
case ISO_MANGLE_TOO_MUCH_FILES:
|
||||||
|
return "Too much files to mangle, can't guarantee unique file names";
|
||||||
|
case ISO_WRONG_PVD:
|
||||||
|
return "Wrong or damaged Primary Volume Descriptor";
|
||||||
|
case ISO_WRONG_RR:
|
||||||
|
return "Wrong or damaged RR entry";
|
||||||
|
case ISO_UNSUPPORTED_RR:
|
||||||
|
return "Unsupported RR feature";
|
||||||
|
case ISO_WRONG_ECMA119:
|
||||||
|
return "Wrong or damaged ECMA-119";
|
||||||
|
case ISO_UNSUPPORTED_ECMA119:
|
||||||
|
return "Unsupported ECMA-119 feature";
|
||||||
|
case ISO_WRONG_EL_TORITO:
|
||||||
|
return "Wrong or damaged El-Torito catalog";
|
||||||
|
case ISO_UNSUPPORTED_EL_TORITO:
|
||||||
|
return "Unsupported El-Torito feature";
|
||||||
|
case ISO_ISOLINUX_CANT_PATCH:
|
||||||
|
return "Can't patch isolinux boot image";
|
||||||
|
case ISO_UNSUPPORTED_SUSP:
|
||||||
|
return "Unsupported SUSP feature";
|
||||||
|
case ISO_WRONG_RR_WARN:
|
||||||
|
return "Error on a RR entry that can be ignored";
|
||||||
|
case ISO_SUSP_UNHANDLED:
|
||||||
|
return "Error on a RR entry that can be ignored";
|
||||||
|
case ISO_SUSP_MULTIPLE_ER:
|
||||||
|
return "Multiple ER SUSP entries found";
|
||||||
|
case ISO_UNSUPPORTED_VD:
|
||||||
|
return "Unsupported volume descriptor found";
|
||||||
|
case ISO_EL_TORITO_WARN:
|
||||||
|
return "El-Torito related warning";
|
||||||
|
case ISO_IMAGE_WRITE_CANCELED:
|
||||||
|
return "Image write cancelled";
|
||||||
|
case ISO_EL_TORITO_HIDDEN:
|
||||||
|
return "El-Torito image is hidden";
|
||||||
|
default:
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char msg[MAX_MSG_LEN];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* when called with ISO_CANCELED, we don't need to submit any message */
|
||||||
|
if (errcode == ISO_CANCELED && fmt == NULL) {
|
||||||
|
return ISO_CANCELED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fmt) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(msg, MAX_MSG_LEN, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
} else {
|
||||||
|
strncpy(msg, iso_error_to_msg(errcode), MAX_MSG_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(errcode),
|
||||||
|
ISO_ERR_SEV(errcode), ISO_ERR_PRIO(errcode), msg, 0, 0);
|
||||||
|
if (causedby != 0) {
|
||||||
|
snprintf(msg, MAX_MSG_LEN, " > Caused by: %s",
|
||||||
|
iso_error_to_msg(causedby));
|
||||||
|
libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(causedby),
|
||||||
|
LIBISO_MSGS_SEV_NOTE, LIBISO_MSGS_PRIO_LOW, msg, 0, 0);
|
||||||
|
if (ISO_ERR_SEV(causedby) == LIBISO_MSGS_SEV_FATAL) {
|
||||||
|
return ISO_CANCELED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ISO_ERR_SEV(errcode) >= abort_threshold) {
|
||||||
|
return ISO_CANCELED;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control queueing and stderr printing of messages from libisofs.
|
||||||
|
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||||
|
* "NOTE", "UPDATE", "DEBUG", "ALL".
|
||||||
|
*
|
||||||
|
* @param queue_severity Gives the minimum limit for messages to be queued.
|
||||||
|
* Default: "NEVER". If you queue messages then you
|
||||||
|
* must consume them by iso_msgs_obtain().
|
||||||
|
* @param print_severity Does the same for messages to be printed directly
|
||||||
|
* to stderr.
|
||||||
|
* @param print_id A text prefix to be printed before the message.
|
||||||
|
* @return >0 for success, <=0 for error
|
||||||
|
*/
|
||||||
|
int iso_set_msgs_severities(char *queue_severity, char *print_severity,
|
||||||
|
char *print_id)
|
||||||
|
{
|
||||||
|
int ret, queue_sevno, print_sevno;
|
||||||
|
|
||||||
|
ret = libiso_msgs__text_to_sev(queue_severity, &queue_sevno, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
return 0;
|
||||||
|
ret = libiso_msgs__text_to_sev(print_severity, &print_sevno, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
return 0;
|
||||||
|
ret = libiso_msgs_set_severities(libiso_msgr, queue_sevno, print_sevno,
|
||||||
|
print_id, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain the oldest pending libisofs message from the queue which has at
|
||||||
|
* least the given minimum_severity. This message and any older message of
|
||||||
|
* lower severity will get discarded from the queue and is then lost forever.
|
||||||
|
*
|
||||||
|
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||||
|
* "NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
|
||||||
|
* will discard the whole queue.
|
||||||
|
*
|
||||||
|
* @param error_code Will become a unique error code as listed in messages.h
|
||||||
|
* @param imgid Id of the image that was issued the message.
|
||||||
|
* @param msg_text Must provide at least ISO_MSGS_MESSAGE_LEN bytes.
|
||||||
|
* @param severity Will become the severity related to the message and
|
||||||
|
* should provide at least 80 bytes.
|
||||||
|
* @return 1 if a matching item was found, 0 if not, <0 for severe errors
|
||||||
|
*/
|
||||||
|
int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
|
||||||
|
char msg_text[], char severity[])
|
||||||
|
{
|
||||||
|
int ret, minimum_sevno, sevno, priority, os_errno;
|
||||||
|
double timestamp;
|
||||||
|
pid_t pid;
|
||||||
|
char *textpt, *sev_name;
|
||||||
|
struct libiso_msgs_item *item= NULL;
|
||||||
|
|
||||||
|
ret = libiso_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
return 0;
|
||||||
|
ret = libiso_msgs_obtain(libiso_msgr, &item, minimum_sevno,
|
||||||
|
LIBISO_MSGS_PRIO_ZERO, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = libiso_msgs_item_get_msg(item, error_code, &textpt, &os_errno, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
strncpy(msg_text, textpt, ISO_MSGS_MESSAGE_LEN-1);
|
||||||
|
if (strlen(textpt) >= ISO_MSGS_MESSAGE_LEN)
|
||||||
|
msg_text[ISO_MSGS_MESSAGE_LEN-1] = 0;
|
||||||
|
|
||||||
|
ret = libiso_msgs_item_get_origin(item, ×tamp, &pid, imgid, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
|
||||||
|
severity[0]= 0;
|
||||||
|
ret = libiso_msgs_item_get_rank(item, &sevno, &priority, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
ret = libiso_msgs__sev_to_text(sevno, &sev_name, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
goto ex;
|
||||||
|
strcpy(severity, sev_name);
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
ex: ;
|
||||||
|
libiso_msgs_destroy_item(libiso_msgr, &item, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A80222 : derived from libburn/init.c:burn_msgs_submit()
|
||||||
|
*/
|
||||||
|
int iso_msgs_submit(int error_code, char msg_text[], int os_errno,
|
||||||
|
char severity[], int origin)
|
||||||
|
{
|
||||||
|
int ret, sevno;
|
||||||
|
|
||||||
|
ret = libiso_msgs__text_to_sev(severity, &sevno, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
sevno = LIBISO_MSGS_SEV_ALL;
|
||||||
|
if (error_code <= 0) {
|
||||||
|
switch(sevno) {
|
||||||
|
case LIBISO_MSGS_SEV_ABORT: error_code = 0x00040000;
|
||||||
|
break; case LIBISO_MSGS_SEV_FATAL: error_code = 0x00040001;
|
||||||
|
break; case LIBISO_MSGS_SEV_SORRY: error_code = 0x00040002;
|
||||||
|
break; case LIBISO_MSGS_SEV_WARNING: error_code = 0x00040003;
|
||||||
|
break; case LIBISO_MSGS_SEV_HINT: error_code = 0x00040004;
|
||||||
|
break; case LIBISO_MSGS_SEV_NOTE: error_code = 0x00040005;
|
||||||
|
break; case LIBISO_MSGS_SEV_UPDATE: error_code = 0x00040006;
|
||||||
|
break; case LIBISO_MSGS_SEV_DEBUG: error_code = 0x00040007;
|
||||||
|
break; default: error_code = 0x00040008;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = libiso_msgs_submit(libiso_msgr, origin, error_code,
|
||||||
|
sevno, LIBISO_MSGS_PRIO_HIGH, msg_text, os_errno, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A80222 : derived from libburn/init.c:burn_text_to_sev()
|
||||||
|
*/
|
||||||
|
int iso_text_to_sev(char *severity_name, int *sevno, int flag)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = libiso_msgs__text_to_sev(severity_name, sevno, 0);
|
||||||
|
if (ret <= 0)
|
||||||
|
*sevno = LIBISO_MSGS_SEV_FATAL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A80222 : derived from libburn/init.c:burn_sev_to_text()
|
||||||
|
*/
|
||||||
|
int iso_sev_to_text(int severity_number, char **severity_name, int flag)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = libiso_msgs__sev_to_text(severity_number, severity_name, 0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the messenger object handle used by libisofs. This handle
|
||||||
|
* may be used by related libraries to their own compatible
|
||||||
|
* messenger objects and thus to direct their messages to the libisofs
|
||||||
|
* message queue. See also: libburn, API function burn_set_messenger().
|
||||||
|
*
|
||||||
|
* @return the handle. Do only use with compatible
|
||||||
|
*/
|
||||||
|
void *iso_get_messenger()
|
||||||
|
{
|
||||||
|
return libiso_msgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_error_get_severity(int e)
|
||||||
|
{
|
||||||
|
return ISO_ERR_SEV(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_error_get_priority(int e)
|
||||||
|
{
|
||||||
|
return ISO_ERR_PRIO(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_error_get_code(int e)
|
||||||
|
{
|
||||||
|
return ISO_ERR_CODE(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A80222 */
|
||||||
|
int iso_report_errfile(char *path, int error_code, int os_errno, int flag)
|
||||||
|
{
|
||||||
|
libiso_msgs_submit(libiso_msgr, 0, error_code,
|
||||||
|
LIBISO_MSGS_SEV_ERRFILE, LIBISO_MSGS_PRIO_HIGH,
|
||||||
|
path, os_errno, 0);
|
||||||
|
return(1);
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Message handling for libisofs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MESSAGES_H_
|
||||||
|
#define MESSAGES_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take and increment this variable to get a valid identifier for message
|
||||||
|
* origin.
|
||||||
|
*/
|
||||||
|
extern int iso_message_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a debug message.
|
||||||
|
*/
|
||||||
|
void iso_msg_debug(int imgid, const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param errcode
|
||||||
|
* The error code.
|
||||||
|
* @param causedby
|
||||||
|
* Error that was caused the errcode. If this error is a FATAL error,
|
||||||
|
* < 0 will be returned in any case. Use 0 if there is no previous
|
||||||
|
* cause for the error.
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 if function must abort asap.
|
||||||
|
*/
|
||||||
|
int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
|
/* ts A80222 */
|
||||||
|
/* To be called with events which report incidents with individual input
|
||||||
|
files from the local filesystem. Not with image nodes, files containing an
|
||||||
|
image or similar file-like objects.
|
||||||
|
*/
|
||||||
|
int iso_report_errfile(char *path, int error_code, int os_errno, int flag);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*MESSAGES_H_*/
|
|
@ -0,0 +1,884 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the reference counting of the given node.
|
||||||
|
*/
|
||||||
|
void iso_node_ref(IsoNode *node)
|
||||||
|
{
|
||||||
|
++node->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrements the reference couting of the given node.
|
||||||
|
* If it reach 0, the node is free, and, if the node is a directory,
|
||||||
|
* its children will be unref() too.
|
||||||
|
*/
|
||||||
|
void iso_node_unref(IsoNode *node)
|
||||||
|
{
|
||||||
|
if (--node->refcount == 0) {
|
||||||
|
switch (node->type) {
|
||||||
|
case LIBISO_DIR:
|
||||||
|
{
|
||||||
|
IsoNode *child = ((IsoDir*)node)->children;
|
||||||
|
while (child != NULL) {
|
||||||
|
IsoNode *tmp = child->next;
|
||||||
|
child->parent = NULL;
|
||||||
|
iso_node_unref(child);
|
||||||
|
child = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIBISO_FILE:
|
||||||
|
{
|
||||||
|
IsoFile *file = (IsoFile*) node;
|
||||||
|
iso_stream_unref(file->stream);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIBISO_SYMLINK:
|
||||||
|
{
|
||||||
|
IsoSymlink *link = (IsoSymlink*) node;
|
||||||
|
free(link->dest);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/* other kind of nodes does not need to delete anything here */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||||
|
if (node->xinfo) {
|
||||||
|
/* free extended info */
|
||||||
|
node->xinfo->process(node->xinfo->data, 1);
|
||||||
|
free(node->xinfo);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
free(node->name);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the type of an IsoNode.
|
||||||
|
*/
|
||||||
|
enum IsoNodeType iso_node_get_type(IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the name of a node.
|
||||||
|
*
|
||||||
|
* @param name The name in UTF-8 encoding
|
||||||
|
*/
|
||||||
|
int iso_node_set_name(IsoNode *node, const char *name)
|
||||||
|
{
|
||||||
|
char *new;
|
||||||
|
|
||||||
|
if ((IsoNode*)node->parent == node) {
|
||||||
|
/* you can't change name of the root node */
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if the name is valid */
|
||||||
|
if (!iso_node_is_valid_name(name)) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->parent != NULL) {
|
||||||
|
/* check if parent already has a node with same name */
|
||||||
|
if (iso_dir_get_node(node->parent, name, NULL) == 1) {
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new = strdup(name);
|
||||||
|
if (new == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
free(node->name);
|
||||||
|
node->name = new;
|
||||||
|
if (node->parent != NULL) {
|
||||||
|
IsoDir *parent;
|
||||||
|
int res;
|
||||||
|
/* take and add again to ensure correct children order */
|
||||||
|
parent = node->parent;
|
||||||
|
iso_node_take(node);
|
||||||
|
res = iso_dir_add_node(parent, node, 0);
|
||||||
|
if (res < 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of a node (in UTF-8).
|
||||||
|
* The returned string belongs to the node and should not be modified nor
|
||||||
|
* freed. Use strdup if you really need your own copy.
|
||||||
|
*/
|
||||||
|
const char *iso_node_get_name(const IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_node_set_permissions(IsoNode *node, mode_t mode)
|
||||||
|
{
|
||||||
|
node->mode = (node->mode & S_IFMT) | (mode & ~S_IFMT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the permissions for the node
|
||||||
|
*/
|
||||||
|
mode_t iso_node_get_permissions(const IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->mode & ~S_IFMT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mode of the node, both permissions and file type, as specified in
|
||||||
|
* 'man 2 stat'.
|
||||||
|
*/
|
||||||
|
mode_t iso_node_get_mode(const IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the user id for the node. This attribute is only useful when
|
||||||
|
* Rock Ridge extensions are enabled.
|
||||||
|
*/
|
||||||
|
void iso_node_set_uid(IsoNode *node, uid_t uid)
|
||||||
|
{
|
||||||
|
node->uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user id of the node.
|
||||||
|
*/
|
||||||
|
uid_t iso_node_get_uid(const IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the group id for the node. This attribute is only useful when
|
||||||
|
* Rock Ridge extensions are enabled.
|
||||||
|
*/
|
||||||
|
void iso_node_set_gid(IsoNode *node, gid_t gid)
|
||||||
|
{
|
||||||
|
node->gid = gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the group id of the node.
|
||||||
|
*/
|
||||||
|
gid_t iso_node_get_gid(const IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the time of last modification of the file
|
||||||
|
*/
|
||||||
|
void iso_node_set_mtime(IsoNode *node, time_t time)
|
||||||
|
{
|
||||||
|
node->mtime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the time of last modification of the file
|
||||||
|
*/
|
||||||
|
time_t iso_node_get_mtime(const IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->mtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the time of last access to the file
|
||||||
|
*/
|
||||||
|
void iso_node_set_atime(IsoNode *node, time_t time)
|
||||||
|
{
|
||||||
|
node->atime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the time of last access to the file
|
||||||
|
*/
|
||||||
|
time_t iso_node_get_atime(const IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->atime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the time of last status change of the file
|
||||||
|
*/
|
||||||
|
void iso_node_set_ctime(IsoNode *node, time_t time)
|
||||||
|
{
|
||||||
|
node->ctime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the time of last status change of the file
|
||||||
|
*/
|
||||||
|
time_t iso_node_get_ctime(const IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->ctime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_node_set_hidden(IsoNode *node, int hide_attrs)
|
||||||
|
{
|
||||||
|
/* you can't hide root node */
|
||||||
|
if ((IsoNode*)node->parent != node) {
|
||||||
|
node->hidden = hide_attrs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new node to a dir. Note that this function don't add a new ref to
|
||||||
|
* the node, so you don't need to free it, it will be automatically freed
|
||||||
|
* when the dir is deleted. Of course, if you want to keep using the node
|
||||||
|
* after the dir life, you need to iso_node_ref() it.
|
||||||
|
*
|
||||||
|
* @param dir
|
||||||
|
* the dir where to add the node
|
||||||
|
* @param child
|
||||||
|
* the node to add. You must ensure that the node hasn't previously added
|
||||||
|
* to other dir, and that the node name is unique inside the child.
|
||||||
|
* Otherwise this function will return a failure, and the child won't be
|
||||||
|
* inserted.
|
||||||
|
* @param replace
|
||||||
|
* if the dir already contains a node with the same name, whether to
|
||||||
|
* replace or not the old node with this.
|
||||||
|
* @return
|
||||||
|
* number of nodes in dir if succes, < 0 otherwise
|
||||||
|
*/
|
||||||
|
int iso_dir_add_node(IsoDir *dir, IsoNode *child,
|
||||||
|
enum iso_replace_mode replace)
|
||||||
|
{
|
||||||
|
IsoNode **pos;
|
||||||
|
|
||||||
|
if (dir == NULL || child == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if ((IsoNode*)dir == child) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check if child is already added to another dir, or if child
|
||||||
|
* is the root node, where parent == itself
|
||||||
|
*/
|
||||||
|
if (child->parent != NULL || child->parent == (IsoDir*)child) {
|
||||||
|
return ISO_NODE_ALREADY_ADDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
iso_dir_find(dir, child->name, &pos);
|
||||||
|
return iso_dir_insert(dir, child, pos, replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate a node inside a given dir.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* The name of the node
|
||||||
|
* @param node
|
||||||
|
* Location for a pointer to the node, it will filled with NULL if the dir
|
||||||
|
* doesn't have a child with the given name.
|
||||||
|
* The node will be owned by the dir and shouldn't be unref(). Just call
|
||||||
|
* iso_node_ref() to get your own reference to the node.
|
||||||
|
* Note that you can pass NULL is the only thing you want to do is check
|
||||||
|
* if a node with such name already exists on dir.
|
||||||
|
* @return
|
||||||
|
* 1 node found, 0 child has no such node, < 0 error
|
||||||
|
* Possible errors:
|
||||||
|
* ISO_NULL_POINTER, if dir or name are NULL
|
||||||
|
*/
|
||||||
|
int iso_dir_get_node(IsoDir *dir, const char *name, IsoNode **node)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoNode **pos;
|
||||||
|
if (dir == NULL || name == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = iso_dir_exists(dir, name, &pos);
|
||||||
|
if (ret == 0) {
|
||||||
|
if (node) {
|
||||||
|
*node = NULL;
|
||||||
|
}
|
||||||
|
return 0; /* node not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
*node = *pos;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of children of a directory.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* >= 0 number of items, < 0 error
|
||||||
|
* Possible errors:
|
||||||
|
* ISO_NULL_POINTER, if dir is NULL
|
||||||
|
*/
|
||||||
|
int iso_dir_get_children_count(IsoDir *dir)
|
||||||
|
{
|
||||||
|
if (dir == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
return dir->nchildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter)
|
||||||
|
{
|
||||||
|
IsoDirIter *it;
|
||||||
|
|
||||||
|
if (dir == NULL || iter == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
it = malloc(sizeof(IsoDirIter));
|
||||||
|
if (it == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
it->dir = dir;
|
||||||
|
it->pos = dir->children;
|
||||||
|
|
||||||
|
*iter = it;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
|
||||||
|
{
|
||||||
|
IsoNode *n;
|
||||||
|
if (iter == NULL || node == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
n = iter->pos;
|
||||||
|
if (n == NULL) {
|
||||||
|
*node = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (n->parent != iter->dir) {
|
||||||
|
/* this can happen if the node has been moved to another dir */
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
*node = n;
|
||||||
|
iter->pos = n->next;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if there're more children.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 dir has more elements, 0 no, < 0 error
|
||||||
|
* Possible errors:
|
||||||
|
* ISO_NULL_POINTER, if iter is NULL
|
||||||
|
*/
|
||||||
|
int iso_dir_iter_has_next(IsoDirIter *iter)
|
||||||
|
{
|
||||||
|
if (iter == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
return iter->pos == NULL ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_dir_iter_free(IsoDirIter *iter)
|
||||||
|
{
|
||||||
|
free(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static IsoNode** iso_dir_find_node(IsoDir *dir, IsoNode *node)
|
||||||
|
{
|
||||||
|
IsoNode **pos;
|
||||||
|
pos = &(dir->children);
|
||||||
|
while (*pos != NULL && *pos != node) {
|
||||||
|
pos = &((*pos)->next);
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a child from a directory.
|
||||||
|
* The child is not freed, so you will become the owner of the node. Later
|
||||||
|
* you can add the node to another dir (calling iso_dir_add_node), or free
|
||||||
|
* it if you don't need it (with iso_node_unref).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_node_take(IsoNode *node)
|
||||||
|
{
|
||||||
|
IsoNode **pos;
|
||||||
|
IsoDir* dir;
|
||||||
|
|
||||||
|
if (node == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
dir = node->parent;
|
||||||
|
if (dir == NULL) {
|
||||||
|
return ISO_NODE_NOT_ADDED_TO_DIR;
|
||||||
|
}
|
||||||
|
pos = iso_dir_find_node(dir, node);
|
||||||
|
if (pos == NULL) {
|
||||||
|
/* should never occur */
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
*pos = node->next;
|
||||||
|
node->parent = NULL;
|
||||||
|
node->next = NULL;
|
||||||
|
dir->nchildren--;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a child from a directory and free (unref) it.
|
||||||
|
* If you want to keep the child alive, you need to iso_node_ref() it
|
||||||
|
* before this call, but in that case iso_node_take() is a better
|
||||||
|
* alternative.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_node_remove(IsoNode *node)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = iso_node_take(node);
|
||||||
|
if (ret == ISO_SUCCESS) {
|
||||||
|
iso_node_unref(node);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the parent of the given iso tree node. No extra ref is added to the
|
||||||
|
* returned directory, you must take your ref. with iso_node_ref() if you
|
||||||
|
* need it.
|
||||||
|
*
|
||||||
|
* If node is the root node, the same node will be returned as its parent.
|
||||||
|
*
|
||||||
|
* This returns NULL if the node doesn't pertain to any tree
|
||||||
|
* (it was removed/take).
|
||||||
|
*/
|
||||||
|
IsoDir *iso_node_get_parent(IsoNode *node)
|
||||||
|
{
|
||||||
|
return node->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO #00005 optimize iso_dir_iter_take */
|
||||||
|
int iso_dir_iter_take(IsoDirIter *iter)
|
||||||
|
{
|
||||||
|
IsoNode *pos;
|
||||||
|
if (iter == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = iter->dir->children;
|
||||||
|
if (iter->pos == pos) {
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
while (pos != NULL && pos->next == iter->pos) {
|
||||||
|
pos = pos->next;
|
||||||
|
}
|
||||||
|
if (pos == NULL) {
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
return iso_node_take(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_dir_iter_remove(IsoDirIter *iter)
|
||||||
|
{
|
||||||
|
IsoNode *pos;
|
||||||
|
if (iter == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
pos = iter->dir->children;
|
||||||
|
if (iter->pos == pos) {
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
while (pos != NULL && pos->next == iter->pos) {
|
||||||
|
pos = pos->next;
|
||||||
|
}
|
||||||
|
if (pos == NULL) {
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
return iso_node_remove(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the destination of a node.
|
||||||
|
* The returned string belongs to the node and should not be modified nor
|
||||||
|
* freed. Use strdup if you really need your own copy.
|
||||||
|
*/
|
||||||
|
const char *iso_symlink_get_dest(const IsoSymlink *link)
|
||||||
|
{
|
||||||
|
return link->dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the destination of a link.
|
||||||
|
*/
|
||||||
|
int iso_symlink_set_dest(IsoSymlink *link, const char *dest)
|
||||||
|
{
|
||||||
|
char *d;
|
||||||
|
if (!iso_node_is_valid_link_dest(dest)) {
|
||||||
|
/* guard against null or empty dest */
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
d = strdup(dest);
|
||||||
|
if (d == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
free(link->dest);
|
||||||
|
link->dest = d;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_node_set_sort_weight(IsoNode *node, int w)
|
||||||
|
{
|
||||||
|
if (node->type == LIBISO_DIR) {
|
||||||
|
IsoNode *child = ((IsoDir*)node)->children;
|
||||||
|
while (child) {
|
||||||
|
iso_node_set_sort_weight(child, w);
|
||||||
|
child = child->next;
|
||||||
|
}
|
||||||
|
} else if (node->type == LIBISO_FILE) {
|
||||||
|
((IsoFile*)node)->sort_weight = w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the sort weight of a file.
|
||||||
|
*/
|
||||||
|
int iso_file_get_sort_weight(IsoFile *file)
|
||||||
|
{
|
||||||
|
return file->sort_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size of the file, in bytes
|
||||||
|
*/
|
||||||
|
off_t iso_file_get_size(IsoFile *file)
|
||||||
|
{
|
||||||
|
return iso_stream_get_size(file->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given name is valid for an iso node.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 if yes, 0 if not
|
||||||
|
*/
|
||||||
|
int iso_node_is_valid_name(const char *name)
|
||||||
|
{
|
||||||
|
/* a name can't be NULL */
|
||||||
|
if (name == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* guard against the empty string or big names... */
|
||||||
|
if (name[0] == '\0' || strlen(name) > 255) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ...against "." and ".." names... */
|
||||||
|
if (!strcmp(name, ".") || !strcmp(name, "..")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ...and against names with '/' */
|
||||||
|
if (strchr(name, '/') != NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given path is valid for the destination of a link.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 if yes, 0 if not
|
||||||
|
*/
|
||||||
|
int iso_node_is_valid_link_dest(const char *dest)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *ptr, *brk_info, *component;
|
||||||
|
|
||||||
|
/* a dest can't be NULL */
|
||||||
|
if (dest == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* guard against the empty string or big dest... */
|
||||||
|
if (dest[0] == '\0' || strlen(dest) > PATH_MAX) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check that all components are valid */
|
||||||
|
if (!strcmp(dest, "/")) {
|
||||||
|
/* "/" is a valid component */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = strdup(dest);
|
||||||
|
if (ptr == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
component = strtok_r(ptr, "/", &brk_info);
|
||||||
|
while (component) {
|
||||||
|
if (strcmp(component, ".") && strcmp(component, "..")) {
|
||||||
|
ret = iso_node_is_valid_name(component);
|
||||||
|
if (ret == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
component = strtok_r(NULL, "/", &brk_info);
|
||||||
|
}
|
||||||
|
free(ptr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_dir_find(IsoDir *dir, const char *name, IsoNode ***pos)
|
||||||
|
{
|
||||||
|
*pos = &(dir->children);
|
||||||
|
while (**pos != NULL && strcmp((**pos)->name, name) < 0) {
|
||||||
|
*pos = &((**pos)->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos)
|
||||||
|
{
|
||||||
|
IsoNode **node;
|
||||||
|
|
||||||
|
iso_dir_find(dir, name, &node);
|
||||||
|
if (pos) {
|
||||||
|
*pos = node;
|
||||||
|
}
|
||||||
|
return (*node != NULL && !strcmp((*node)->name, name)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
|
||||||
|
enum iso_replace_mode replace)
|
||||||
|
{
|
||||||
|
if (*pos != NULL && !strcmp((*pos)->name, node->name)) {
|
||||||
|
/* a node with same name already exists */
|
||||||
|
switch(replace) {
|
||||||
|
case ISO_REPLACE_NEVER:
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
case ISO_REPLACE_IF_NEWER:
|
||||||
|
if ((*pos)->mtime >= node->mtime) {
|
||||||
|
/* old file is newer */
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ISO_REPLACE_IF_SAME_TYPE_AND_NEWER:
|
||||||
|
if ((*pos)->mtime >= node->mtime) {
|
||||||
|
/* old file is newer */
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
/* fall down */
|
||||||
|
case ISO_REPLACE_IF_SAME_TYPE:
|
||||||
|
if ((node->mode & S_IFMT) != ((*pos)->mode & S_IFMT)) {
|
||||||
|
/* different file types */
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ISO_REPLACE_ALWAYS:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* CAN'T HAPPEN */
|
||||||
|
return ISO_ASSERT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we are reach here we have to replace */
|
||||||
|
node->next = (*pos)->next;
|
||||||
|
(*pos)->parent = NULL;
|
||||||
|
(*pos)->next = NULL;
|
||||||
|
iso_node_unref(*pos);
|
||||||
|
*pos = node;
|
||||||
|
node->parent = dir;
|
||||||
|
return dir->nchildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->next = *pos;
|
||||||
|
*pos = node;
|
||||||
|
node->parent = dir;
|
||||||
|
|
||||||
|
return ++dir->nchildren;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_node_new_root(IsoDir **root)
|
||||||
|
{
|
||||||
|
IsoDir *dir;
|
||||||
|
|
||||||
|
dir = calloc(1, sizeof(IsoDir));
|
||||||
|
if (dir == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
dir->node.refcount = 1;
|
||||||
|
dir->node.type = LIBISO_DIR;
|
||||||
|
dir->node.atime = dir->node.ctime = dir->node.mtime = time(NULL);
|
||||||
|
dir->node.mode = S_IFDIR | 0555;
|
||||||
|
|
||||||
|
/* set parent to itself, to prevent root to be added to another dir */
|
||||||
|
dir->node.parent = dir;
|
||||||
|
*root = dir;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_node_new_dir(char *name, IsoDir **dir)
|
||||||
|
{
|
||||||
|
IsoDir *new;
|
||||||
|
|
||||||
|
if (dir == NULL || name == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if the name is valid */
|
||||||
|
if (!iso_node_is_valid_name(name)) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = calloc(1, sizeof(IsoDir));
|
||||||
|
if (new == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
new->node.refcount = 1;
|
||||||
|
new->node.type = LIBISO_DIR;
|
||||||
|
new->node.name = name;
|
||||||
|
new->node.mode = S_IFDIR;
|
||||||
|
*dir = new;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_node_new_file(char *name, IsoStream *stream, IsoFile **file)
|
||||||
|
{
|
||||||
|
IsoFile *new;
|
||||||
|
|
||||||
|
if (file == NULL || name == NULL || stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if the name is valid */
|
||||||
|
if (!iso_node_is_valid_name(name)) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = calloc(1, sizeof(IsoFile));
|
||||||
|
if (new == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
new->node.refcount = 1;
|
||||||
|
new->node.type = LIBISO_FILE;
|
||||||
|
new->node.name = name;
|
||||||
|
new->node.mode = S_IFREG;
|
||||||
|
new->stream = stream;
|
||||||
|
|
||||||
|
*file = new;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link)
|
||||||
|
{
|
||||||
|
IsoSymlink *new;
|
||||||
|
|
||||||
|
if (link == NULL || name == NULL || dest == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if the name is valid */
|
||||||
|
if (!iso_node_is_valid_name(name)) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if destination is valid */
|
||||||
|
if (!iso_node_is_valid_link_dest(dest)) {
|
||||||
|
/* guard against null or empty dest */
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = calloc(1, sizeof(IsoSymlink));
|
||||||
|
if (new == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
new->node.refcount = 1;
|
||||||
|
new->node.type = LIBISO_SYMLINK;
|
||||||
|
new->node.name = name;
|
||||||
|
new->dest = dest;
|
||||||
|
new->node.mode = S_IFLNK;
|
||||||
|
*link = new;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_node_new_special(char *name, mode_t mode, dev_t dev,
|
||||||
|
IsoSpecial **special)
|
||||||
|
{
|
||||||
|
IsoSpecial *new;
|
||||||
|
|
||||||
|
if (special == NULL || name == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (S_ISLNK(mode) || S_ISREG(mode) || S_ISDIR(mode)) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if the name is valid */
|
||||||
|
if (!iso_node_is_valid_name(name)) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = calloc(1, sizeof(IsoSpecial));
|
||||||
|
if (new == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
new->node.refcount = 1;
|
||||||
|
new->node.type = LIBISO_SPECIAL;
|
||||||
|
new->node.name = name;
|
||||||
|
|
||||||
|
new->node.mode = mode;
|
||||||
|
new->dev = dev;
|
||||||
|
|
||||||
|
*special = new;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBISO_NODE_H_
|
||||||
|
#define LIBISO_NODE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for the public iso tree
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* #define LIBISO_EXTENDED_INFORMATION */
|
||||||
|
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The extended information is a way to attach additional information to each
|
||||||
|
* IsoNode. External applications may want to use this extension system to
|
||||||
|
* store application speficic information related to each node. On the other
|
||||||
|
* side, libisofs may make use of this struct to attach information to nodes in
|
||||||
|
* some particular, uncommon, cases, without incrementing the size of the
|
||||||
|
* IsoNode struct.
|
||||||
|
*
|
||||||
|
* It is implemented like a chained list.
|
||||||
|
*/
|
||||||
|
typedef struct iso_extended_info IsoExtendedInfo;
|
||||||
|
|
||||||
|
struct iso_extended_info {
|
||||||
|
/**
|
||||||
|
* Next struct in the chain. NULL if it is the last item
|
||||||
|
*/
|
||||||
|
IsoExtendedInfo *next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to handle this particular extended information. The function
|
||||||
|
* pointer acts as an identifier for the type of the information. Structs
|
||||||
|
* with same information type must use the same function.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* Attached data
|
||||||
|
* @param flag
|
||||||
|
* What to do with the data. At this time the following values are
|
||||||
|
* defined:
|
||||||
|
* -> 1 the data must be freed
|
||||||
|
* @return
|
||||||
|
* 1
|
||||||
|
*/
|
||||||
|
int (*process)(void *data, int flag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer to information specific data.
|
||||||
|
*/
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct Iso_Node
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Initilized to 1, originally owned by user, until added to another node.
|
||||||
|
* Then it is owned by the parent node, so the user must take his own ref
|
||||||
|
* if needed. With the exception of the creation functions, none of the
|
||||||
|
* other libisofs functions that return an IsoNode increment its
|
||||||
|
* refcount. This is responsablity of the client, if (s)he needs it.
|
||||||
|
*/
|
||||||
|
int refcount;
|
||||||
|
|
||||||
|
/** Type of the IsoNode, do not confuse with mode */
|
||||||
|
enum IsoNodeType type;
|
||||||
|
|
||||||
|
char *name; /**< Real name, in default charset */
|
||||||
|
|
||||||
|
mode_t mode; /**< protection */
|
||||||
|
uid_t uid; /**< user ID of owner */
|
||||||
|
gid_t gid; /**< group ID of owner */
|
||||||
|
|
||||||
|
/* TODO #00001 : consider adding new timestamps */
|
||||||
|
time_t atime; /**< time of last access */
|
||||||
|
time_t mtime; /**< time of last modification */
|
||||||
|
time_t ctime; /**< time of last status change */
|
||||||
|
|
||||||
|
int hidden; /**< whether the node will be hidden, see IsoHideNodeFlag */
|
||||||
|
|
||||||
|
IsoDir *parent; /**< parent node, NULL for root */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pointer to the linked list of children in a dir.
|
||||||
|
*/
|
||||||
|
IsoNode *next;
|
||||||
|
|
||||||
|
#ifdef LIBISO_EXTENDED_INFORMATION
|
||||||
|
/**
|
||||||
|
* Extended information for the node.
|
||||||
|
*/
|
||||||
|
IsoExtendedInfo *xinfo;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Iso_Dir
|
||||||
|
{
|
||||||
|
IsoNode node;
|
||||||
|
|
||||||
|
size_t nchildren; /**< The number of children of this directory. */
|
||||||
|
IsoNode *children; /**< list of children. ptr to first child */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Iso_File
|
||||||
|
{
|
||||||
|
IsoNode node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Location of a file extent in a ms disc, 0 for newly added file
|
||||||
|
*/
|
||||||
|
uint32_t msblock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
int sort_weight;
|
||||||
|
IsoStream *stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Iso_Symlink
|
||||||
|
{
|
||||||
|
IsoNode node;
|
||||||
|
|
||||||
|
char *dest;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Iso_Special
|
||||||
|
{
|
||||||
|
IsoNode node;
|
||||||
|
dev_t dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An iterator for directory children.
|
||||||
|
*/
|
||||||
|
struct Iso_Dir_Iter
|
||||||
|
{
|
||||||
|
const IsoDir *dir;
|
||||||
|
IsoNode *pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
int iso_node_new_root(IsoDir **root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IsoDir. Attributes, uid/gid, timestamps, etc are set to
|
||||||
|
* default (0) values. You must set them.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* Name for the node. It is not strdup() so you shouldn't use this
|
||||||
|
* reference when this function returns successfully. NULL is not
|
||||||
|
* allowed.
|
||||||
|
* @param dir
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error.
|
||||||
|
*/
|
||||||
|
int iso_node_new_dir(char *name, IsoDir **dir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new file node. Attributes, uid/gid, timestamps, etc are set to
|
||||||
|
* default (0) values. You must set them.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* Name for the node. It is not strdup() so you shouldn't use this
|
||||||
|
* reference when this function returns successfully. NULL is not
|
||||||
|
* allowed.
|
||||||
|
* @param stream
|
||||||
|
* Source for file contents. The reference is taken by the node,
|
||||||
|
* you must call iso_stream_ref() if you need your own ref.
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error.
|
||||||
|
*/
|
||||||
|
int iso_node_new_file(char *name, IsoStream *stream, IsoFile **file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new IsoSymlink node. Attributes, uid/gid, timestamps, etc are set
|
||||||
|
* to default (0) values. You must set them.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* name for the new symlink. It is not strdup() so you shouldn't use this
|
||||||
|
* reference when this function returns successfully. NULL is not
|
||||||
|
* allowed.
|
||||||
|
* @param dest
|
||||||
|
* destination of the link. It is not strdup() so you shouldn't use this
|
||||||
|
* reference when this function returns successfully. NULL is not
|
||||||
|
* allowed.
|
||||||
|
* @param link
|
||||||
|
* place where to store a pointer to the newly created link.
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 otherwise
|
||||||
|
*/
|
||||||
|
int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new special file node. As far as libisofs concerns,
|
||||||
|
* an special file is a block device, a character device, a FIFO (named pipe)
|
||||||
|
* or a socket. You can choose the specific kind of file you want to add
|
||||||
|
* by setting mode propertly (see man 2 stat).
|
||||||
|
*
|
||||||
|
* Note that special files are only written to image when Rock Ridge
|
||||||
|
* extensions are enabled. Moreover, a special file is just a directory entry
|
||||||
|
* in the image tree, no data is written beyond that.
|
||||||
|
*
|
||||||
|
* Owner and hidden atts are taken from parent. You can modify any of them
|
||||||
|
* later.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* name for the new special file. It is not strdup() so you shouldn't use
|
||||||
|
* this reference when this function returns successfully. NULL is not
|
||||||
|
* allowed.
|
||||||
|
* @param mode
|
||||||
|
* file type and permissions for the new node. Note that you can't
|
||||||
|
* specify any kind of file here, only special types are allowed. i.e,
|
||||||
|
* S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK,
|
||||||
|
* S_IFREG and S_IFDIR aren't.
|
||||||
|
* @param dev
|
||||||
|
* device ID, equivalent to the st_rdev field in man 2 stat.
|
||||||
|
* @param special
|
||||||
|
* place where to store a pointer to the newly created special file.
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 otherwise
|
||||||
|
*/
|
||||||
|
int iso_node_new_special(char *name, mode_t mode, dev_t dev,
|
||||||
|
IsoSpecial **special);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given name is valid for an iso node.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 if yes, 0 if not
|
||||||
|
*/
|
||||||
|
int iso_node_is_valid_name(const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given path is valid for the destination of a link.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 if yes, 0 if not
|
||||||
|
*/
|
||||||
|
int iso_node_is_valid_link_dest(const char *dest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the position where to insert a node
|
||||||
|
*
|
||||||
|
* @param dir
|
||||||
|
* A valid dir. It can't be NULL
|
||||||
|
* @param name
|
||||||
|
* The node name to search for. It can't be NULL
|
||||||
|
* @param pos
|
||||||
|
* Will be filled with the position where to insert. It can't be NULL
|
||||||
|
*/
|
||||||
|
void iso_dir_find(IsoDir *dir, const char *name, IsoNode ***pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a node with the given name exists in a dir.
|
||||||
|
*
|
||||||
|
* @param dir
|
||||||
|
* A valid dir. It can't be NULL
|
||||||
|
* @param name
|
||||||
|
* The node name to search for. It can't be NULL
|
||||||
|
* @param pos
|
||||||
|
* If not NULL, will be filled with the position where to insert. If the
|
||||||
|
* node exists, (**pos) will refer to the given node.
|
||||||
|
* @return
|
||||||
|
* 1 if node exists, 0 if not
|
||||||
|
*/
|
||||||
|
int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a given node in a dir, at the specified position.
|
||||||
|
*
|
||||||
|
* @param dir
|
||||||
|
* Dir where to insert. It can't be NULL
|
||||||
|
* @param node
|
||||||
|
* The node to insert. It can't be NULL
|
||||||
|
* @param pos
|
||||||
|
* Position where the node will be inserted. It is a pointer previously
|
||||||
|
* obtained with a call to iso_dir_exists() or iso_dir_find().
|
||||||
|
* It can't be NULL.
|
||||||
|
* @param replace
|
||||||
|
* Whether to replace an old node with the same name with the new node.
|
||||||
|
* @return
|
||||||
|
* If success, number of children in dir. < 0 on error
|
||||||
|
*/
|
||||||
|
int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
|
||||||
|
enum iso_replace_mode replace);
|
||||||
|
|
||||||
|
#endif /*LIBISO_NODE_H_*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,267 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
* Copyright (c) 2007 Mario Danic
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This header defines the functions and structures needed to add RockRidge
|
||||||
|
* extensions to an ISO image.
|
||||||
|
*
|
||||||
|
* References:
|
||||||
|
*
|
||||||
|
* - SUSP (IEEE 1281).
|
||||||
|
* System Use Sharing Protocol, draft standard version 1.12.
|
||||||
|
*
|
||||||
|
* - RRIP (IEEE 1282)
|
||||||
|
* Rock Ridge Interchange Protocol, Draft Standard version 1.12.
|
||||||
|
*
|
||||||
|
* - ECMA-119 (ISO-9660)
|
||||||
|
* Volume and File Structure of CDROM for Information Interchange.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_ROCKRIDGE_H
|
||||||
|
#define LIBISO_ROCKRIDGE_H
|
||||||
|
|
||||||
|
#include "ecma119.h"
|
||||||
|
|
||||||
|
#define SUSP_SIG(entry, a, b) ((entry->sig[0] == a) && (entry->sig[1] == b))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This contains the information about the System Use Fields (SUSP, 4.1),
|
||||||
|
* that will be written in the System Use Areas, both in the ISO directory
|
||||||
|
* record System Use field (ECMA-119, 9.1.13) or in a Continuation Area as
|
||||||
|
* defined by SUSP.
|
||||||
|
*/
|
||||||
|
struct susp_info
|
||||||
|
{
|
||||||
|
/** Number of SUSP fields in the System Use field */
|
||||||
|
size_t n_susp_fields;
|
||||||
|
uint8_t **susp_fields;
|
||||||
|
|
||||||
|
/** Length of the part of the SUSP area that fits in the dirent. */
|
||||||
|
int suf_len;
|
||||||
|
|
||||||
|
/** Length of the part of the SUSP area that will go in a CE area. */
|
||||||
|
uint32_t ce_block;
|
||||||
|
uint32_t ce_len;
|
||||||
|
|
||||||
|
size_t n_ce_susp_fields;
|
||||||
|
uint8_t **ce_susp_fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SUSP 5.1 */
|
||||||
|
struct susp_CE {
|
||||||
|
uint8_t block[8];
|
||||||
|
uint8_t offset[8];
|
||||||
|
uint8_t len[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SUSP 5.3 */
|
||||||
|
struct susp_SP {
|
||||||
|
uint8_t be[1];
|
||||||
|
uint8_t ef[1];
|
||||||
|
uint8_t len_skp[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SUSP 5.5 */
|
||||||
|
struct susp_ER {
|
||||||
|
uint8_t len_id[1];
|
||||||
|
uint8_t len_des[1];
|
||||||
|
uint8_t len_src[1];
|
||||||
|
uint8_t ext_ver[1];
|
||||||
|
uint8_t ext_id[1]; /*< up to len_id bytes */
|
||||||
|
/* ext_des, ext_src */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** POSIX file attributes (RRIP, 4.1.1) */
|
||||||
|
struct rr_PX {
|
||||||
|
uint8_t mode[8];
|
||||||
|
uint8_t links[8];
|
||||||
|
uint8_t uid[8];
|
||||||
|
uint8_t gid[8];
|
||||||
|
uint8_t serial[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Time stamps for a file (RRIP, 4.1.6) */
|
||||||
|
struct rr_TF {
|
||||||
|
uint8_t flags[1];
|
||||||
|
uint8_t t_stamps[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Info for character and block device (RRIP, 4.1.2) */
|
||||||
|
struct rr_PN {
|
||||||
|
uint8_t high[8];
|
||||||
|
uint8_t low[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Alternate name (RRIP, 4.1.4) */
|
||||||
|
struct rr_NM {
|
||||||
|
uint8_t flags[1];
|
||||||
|
uint8_t name[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Link for a relocated directory (RRIP, 4.1.5.1) */
|
||||||
|
struct rr_CL {
|
||||||
|
uint8_t child_loc[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Sim link (RRIP, 4.1.3) */
|
||||||
|
struct rr_SL {
|
||||||
|
uint8_t flags[1];
|
||||||
|
uint8_t comps[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct for a SUSP System User Entry (SUSP, 4.1)
|
||||||
|
*/
|
||||||
|
struct susp_sys_user_entry
|
||||||
|
{
|
||||||
|
uint8_t sig[2];
|
||||||
|
uint8_t len_sue[1];
|
||||||
|
uint8_t version[1];
|
||||||
|
union {
|
||||||
|
struct susp_CE CE;
|
||||||
|
struct susp_SP SP;
|
||||||
|
struct susp_ER ER;
|
||||||
|
struct rr_PX PX;
|
||||||
|
struct rr_TF TF;
|
||||||
|
struct rr_PN PN;
|
||||||
|
struct rr_NM NM;
|
||||||
|
struct rr_CL CL;
|
||||||
|
struct rr_SL SL;
|
||||||
|
} data; /* 5 to 4+len_sue */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the length needed for write all RR and SUSP entries for a given
|
||||||
|
* node.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".."
|
||||||
|
* for that node (i.e., it will refer to the parent)
|
||||||
|
* @param space
|
||||||
|
* Available space in the System Use Area for the directory record.
|
||||||
|
* @param ce
|
||||||
|
* Will be filled with the space needed in a CE
|
||||||
|
* @return
|
||||||
|
* The size needed for the RR entries in the System Use Area
|
||||||
|
*/
|
||||||
|
size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t space,
|
||||||
|
size_t *ce);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill a struct susp_info with the RR/SUSP entries needed for a given
|
||||||
|
* node.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".."
|
||||||
|
* for that node (i.e., it will refer to the parent)
|
||||||
|
* @param space
|
||||||
|
* Available space in the System Use Area for the directory record.
|
||||||
|
* @param info
|
||||||
|
* Pointer to the struct susp_info where the entries will be stored.
|
||||||
|
* If some entries need to go to a Continuation Area, they will be added
|
||||||
|
* to the existing ce_susp_fields, and ce_len will be incremented
|
||||||
|
* propertly. Please ensure ce_block is initialized propertly.
|
||||||
|
* @return
|
||||||
|
* 1 success, < 0 error
|
||||||
|
*/
|
||||||
|
int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
|
||||||
|
size_t space, struct susp_info *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the given SUSP fields into buf. Note that Continuation Area
|
||||||
|
* fields are not written.
|
||||||
|
* If info does not contain any SUSP entry this function just return.
|
||||||
|
* After written, the info susp_fields array will be freed, and the counters
|
||||||
|
* updated propertly.
|
||||||
|
*/
|
||||||
|
void rrip_write_susp_fields(Ecma119Image *t, struct susp_info *info,
|
||||||
|
uint8_t *buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the Continuation Area entries for the given struct susp_info, using
|
||||||
|
* the iso_write() function.
|
||||||
|
* After written, the ce_susp_fields array will be freed.
|
||||||
|
*/
|
||||||
|
int rrip_write_ce_fields(Ecma119Image *t, struct susp_info *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SUSP iterator is used to iterate over the System User Entries
|
||||||
|
* of a ECMA-168 directory record.
|
||||||
|
* It takes care about Continuation Areas, handles the end of the different
|
||||||
|
* system user entries and skip padding areas. Thus, using an iteration
|
||||||
|
* we are accessing just to the meaning entries.
|
||||||
|
*/
|
||||||
|
typedef struct susp_iterator SuspIterator;
|
||||||
|
|
||||||
|
SuspIterator *
|
||||||
|
susp_iter_new(IsoDataSource *src, struct ecma119_dir_record *record,
|
||||||
|
uint8_t len_skp, int msgid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next SUSP System User Entry using given iterator.
|
||||||
|
*
|
||||||
|
* @param sue
|
||||||
|
* Pointer to the next susp entry. It refers to an internal buffer and
|
||||||
|
* it's not guaranteed to be allocated after calling susp_iter_next()
|
||||||
|
* again. Thus, if you need to keep some entry you have to do a copy.
|
||||||
|
* @return
|
||||||
|
* 1 on success, 0 if no more entries, < 0 error
|
||||||
|
*/
|
||||||
|
int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a given susp iterator.
|
||||||
|
*/
|
||||||
|
void susp_iter_free(SuspIterator *iter);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills a struct stat with the values of a Rock Ridge TF entry (RRIP, 4.1.6)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a RR NM entry (RRIP, 4.1.4), and appends the name stored there to
|
||||||
|
* the given name. You can pass a pointer to NULL as name.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_NM(struct susp_sys_user_entry *nm, char **name, int *cont);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a SL RR entry (RRIP, 4.1.3), checking if the destination continues.
|
||||||
|
*
|
||||||
|
* @param cont
|
||||||
|
* 0 not continue, 1 continue, 2 continue component
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills a struct stat with the values of a Rock Ridge PN entry (RRIP, 4.1.2).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st);
|
||||||
|
|
||||||
|
#endif /* LIBISO_ROCKRIDGE_H */
|
|
@ -0,0 +1,419 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file contains functions related to the reading of SUSP and
|
||||||
|
* Rock Ridge extensions on an ECMA-119 image.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "ecma119.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "rockridge.h"
|
||||||
|
#include "messages.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct susp_iterator
|
||||||
|
{
|
||||||
|
uint8_t* base;
|
||||||
|
int pos;
|
||||||
|
int size;
|
||||||
|
IsoDataSource *src;
|
||||||
|
int msgid;
|
||||||
|
|
||||||
|
/* block and offset for next continuation area */
|
||||||
|
uint32_t ce_block;
|
||||||
|
uint32_t ce_off;
|
||||||
|
|
||||||
|
/** Length of the next continuation area, 0 if no more CA are specified */
|
||||||
|
uint32_t ce_len;
|
||||||
|
|
||||||
|
uint8_t *buffer; /*< If there are continuation areas */
|
||||||
|
};
|
||||||
|
|
||||||
|
SuspIterator*
|
||||||
|
susp_iter_new(IsoDataSource *src, struct ecma119_dir_record *record,
|
||||||
|
uint8_t len_skp, int msgid)
|
||||||
|
{
|
||||||
|
int pad = (record->len_fi[0] + 1) % 2;
|
||||||
|
struct susp_iterator *iter = malloc(sizeof(struct susp_iterator));
|
||||||
|
if (iter == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->base = record->file_id + record->len_fi[0] + pad;
|
||||||
|
iter->pos = len_skp; /* 0 in most cases */
|
||||||
|
iter->size = record->len_dr[0] - record->len_fi[0] - 33 - pad;
|
||||||
|
iter->src = src;
|
||||||
|
iter->msgid = msgid;
|
||||||
|
|
||||||
|
iter->ce_len = 0;
|
||||||
|
iter->buffer = NULL;
|
||||||
|
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue)
|
||||||
|
{
|
||||||
|
struct susp_sys_user_entry *entry;
|
||||||
|
|
||||||
|
entry = (struct susp_sys_user_entry*)(iter->base + iter->pos);
|
||||||
|
|
||||||
|
if ( (iter->pos + 4 > iter->size) || (SUSP_SIG(entry, 'S', 'T'))) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* End of the System Use Area or Continuation Area.
|
||||||
|
* Note that ST is not needed when the space left is less than 4.
|
||||||
|
* (IEEE 1281, SUSP. section 4)
|
||||||
|
*/
|
||||||
|
if (iter->ce_len) {
|
||||||
|
uint32_t block;
|
||||||
|
int nblocks;
|
||||||
|
|
||||||
|
/* A CE has found, there is another continuation area */
|
||||||
|
nblocks = DIV_UP(iter->ce_off + iter->ce_len, BLOCK_SIZE);
|
||||||
|
iter->buffer = realloc(iter->buffer, nblocks * BLOCK_SIZE);
|
||||||
|
|
||||||
|
/* read all blocks needed to cache the full CE */
|
||||||
|
for (block = 0; block < nblocks; ++block) {
|
||||||
|
int ret;
|
||||||
|
ret = iter->src->read_block(iter->src, iter->ce_block + block,
|
||||||
|
iter->buffer + block * BLOCK_SIZE);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iter->base = iter->buffer + iter->ce_off;
|
||||||
|
iter->pos = 0;
|
||||||
|
iter->size = iter->ce_len;
|
||||||
|
iter->ce_len = 0;
|
||||||
|
entry = (struct susp_sys_user_entry*)iter->base;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->len_sue[0] == 0) {
|
||||||
|
/* a wrong image with this lead us to a infinity loop */
|
||||||
|
iso_msg_submit(iter->msgid, ISO_WRONG_RR, 0,
|
||||||
|
"Damaged RR/SUSP information.");
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter->pos += entry->len_sue[0];
|
||||||
|
|
||||||
|
if (SUSP_SIG(entry, 'C', 'E')) {
|
||||||
|
/* Continuation entry */
|
||||||
|
if (iter->ce_len) {
|
||||||
|
int ret;
|
||||||
|
ret = iso_msg_submit(iter->msgid, ISO_UNSUPPORTED_SUSP, 0,
|
||||||
|
"More than one CE System user entry has found in a single "
|
||||||
|
"System Use field or continuation area. This breaks SUSP "
|
||||||
|
"standard and it's not supported. Ignoring last CE. Maybe "
|
||||||
|
"the image is damaged.");
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iter->ce_block = iso_read_bb(entry->data.CE.block, 4, NULL);
|
||||||
|
iter->ce_off = iso_read_bb(entry->data.CE.offset, 4, NULL);
|
||||||
|
iter->ce_len = iso_read_bb(entry->data.CE.len, 4, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we don't want to return CE entry to the user */
|
||||||
|
return susp_iter_next(iter, sue);
|
||||||
|
} else if (SUSP_SIG(entry, 'P', 'D')) {
|
||||||
|
/* skip padding */
|
||||||
|
return susp_iter_next(iter, sue);
|
||||||
|
}
|
||||||
|
|
||||||
|
*sue = entry;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void susp_iter_free(SuspIterator *iter)
|
||||||
|
{
|
||||||
|
free(iter->buffer);
|
||||||
|
free(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st)
|
||||||
|
{
|
||||||
|
if (px == NULL || st == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (px->sig[0] != 'P' || px->sig[1] != 'X') {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (px->len_sue[0] != 44 && px->len_sue[0] != 36) {
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->st_mode = iso_read_bb(px->data.PX.mode, 4, NULL);
|
||||||
|
st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL);
|
||||||
|
st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL);
|
||||||
|
st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL);
|
||||||
|
if (px->len_sue[0] == 44) {
|
||||||
|
/* this corresponds to RRIP 1.12, so we have inode serial number */
|
||||||
|
st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills a struct stat with the values of a Rock Ridge TF entry (RRIP, 4.1.6)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st)
|
||||||
|
{
|
||||||
|
time_t time;
|
||||||
|
int s;
|
||||||
|
int nts = 0;
|
||||||
|
|
||||||
|
if (tf == NULL || st == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (tf->sig[0] != 'T' || tf->sig[1] != 'F') {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tf->data.TF.flags[0] & (1 << 7)) {
|
||||||
|
/* long form */
|
||||||
|
s = 17;
|
||||||
|
} else {
|
||||||
|
s = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1. Creation time */
|
||||||
|
if (tf->data.TF.flags[0] & (1 << 0)) {
|
||||||
|
|
||||||
|
/* the creation is the recording time. we ignore this */
|
||||||
|
/* TODO maybe it would be good to manage it in ms discs, where
|
||||||
|
* the recording time could be different than now!! */
|
||||||
|
++nts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2. modify time */
|
||||||
|
if (tf->data.TF.flags[0] & (1 << 1)) {
|
||||||
|
if (tf->len_sue[0] < 5 + (nts+1) * s) {
|
||||||
|
/* RR TF entry too short. */
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
if (s == 7) {
|
||||||
|
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
|
||||||
|
} else {
|
||||||
|
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
|
||||||
|
}
|
||||||
|
st->st_mtime = time;
|
||||||
|
++nts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. access time */
|
||||||
|
if (tf->data.TF.flags[0] & (1 << 2)) {
|
||||||
|
if (tf->len_sue[0] < 5 + (nts+1) * s) {
|
||||||
|
/* RR TF entry too short. */
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
if (s == 7) {
|
||||||
|
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
|
||||||
|
} else {
|
||||||
|
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
|
||||||
|
}
|
||||||
|
st->st_atime = time;
|
||||||
|
++nts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. attributes time */
|
||||||
|
if (tf->data.TF.flags[0] & (1 << 3)) {
|
||||||
|
if (tf->len_sue[0] < 5 + (nts+1) * s) {
|
||||||
|
/* RR TF entry too short. */
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
if (s == 7) {
|
||||||
|
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
|
||||||
|
} else {
|
||||||
|
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
|
||||||
|
}
|
||||||
|
st->st_ctime = time;
|
||||||
|
++nts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we ignore backup, expire and effect times */
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a RR NM entry (RRIP, 4.1.4), and appends the name stored there to
|
||||||
|
* the given name. You can pass a pointer to NULL as name.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_NM(struct susp_sys_user_entry *nm, char **name, int *cont)
|
||||||
|
{
|
||||||
|
if (nm == NULL || name == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (nm->sig[0] != 'N' || nm->sig[1] != 'M') {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nm->len_sue[0] == 5) {
|
||||||
|
if (nm->data.NM.flags[0] & 0x2) {
|
||||||
|
/* it is a "." entry */
|
||||||
|
if (*name == NULL) {
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
} else {
|
||||||
|
/* we can't have a previous not-NULL name */
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nm->len_sue[0] <= 5) {
|
||||||
|
/* ".." entry is an error, as we will never call it */
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* concatenate the results */
|
||||||
|
if (*cont) {
|
||||||
|
*name = realloc(*name, strlen(*name) + nm->len_sue[0] - 5 + 1);
|
||||||
|
strncat(*name, (char*)nm->data.NM.name, nm->len_sue[0] - 5);
|
||||||
|
} else {
|
||||||
|
*name = strcopy((char*)nm->data.NM.name, nm->len_sue[0] - 5);
|
||||||
|
}
|
||||||
|
if (*name == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* and set cond according to the value of CONTINUE flag */
|
||||||
|
*cont = nm->data.NM.flags[0] & 0x01;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a SL RR entry (RRIP, 4.1.3), checking if the destination continues.
|
||||||
|
*
|
||||||
|
* @param cont
|
||||||
|
* 0 not continue, 1 continue, 2 continue component
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
if (sl == NULL || dest == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (sl->sig[0] != 'S' || sl->sig[1] != 'L') {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pos = 0; pos + 5 < sl->len_sue[0];
|
||||||
|
pos += 2 + sl->data.SL.comps[pos + 1]) {
|
||||||
|
char *comp;
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t flags = sl->data.SL.comps[pos];
|
||||||
|
|
||||||
|
if (flags & 0x2) {
|
||||||
|
/* current directory */
|
||||||
|
len = 1;
|
||||||
|
comp = ".";
|
||||||
|
} else if (flags & 0x4) {
|
||||||
|
/* parent directory */
|
||||||
|
len = 2;
|
||||||
|
comp = "..";
|
||||||
|
} else if (flags & 0x8) {
|
||||||
|
/* root directory */
|
||||||
|
len = 1;
|
||||||
|
comp = "/";
|
||||||
|
} else if (flags & ~0x01) {
|
||||||
|
/* unsupported flag component */
|
||||||
|
return ISO_UNSUPPORTED_RR;
|
||||||
|
} else {
|
||||||
|
len = sl->data.SL.comps[pos + 1];
|
||||||
|
comp = (char*)&sl->data.SL.comps[pos + 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*cont == 1) {
|
||||||
|
/* new component */
|
||||||
|
size_t size = strlen(*dest);
|
||||||
|
*dest = realloc(*dest, strlen(*dest) + len + 2);
|
||||||
|
if (*dest == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
/* it is a new compoenent, add the '/' */
|
||||||
|
if ((*dest)[size-1] != '/') {
|
||||||
|
(*dest)[size] = '/';
|
||||||
|
(*dest)[size+1] = '\0';
|
||||||
|
}
|
||||||
|
strncat(*dest, comp, len);
|
||||||
|
} else if (*cont == 2) {
|
||||||
|
/* the component continues */
|
||||||
|
*dest = realloc(*dest, strlen(*dest) + len + 1);
|
||||||
|
if (*dest == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
/* we don't have to add the '/' */
|
||||||
|
strncat(*dest, comp, len);
|
||||||
|
} else {
|
||||||
|
*dest = strcopy(comp, len);
|
||||||
|
}
|
||||||
|
if (*dest == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
/* do the component continue or not? */
|
||||||
|
*cont = (flags & 0x01) ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*cont == 2) {
|
||||||
|
/* TODO check that SL flag is set to continute too ?*/
|
||||||
|
} else {
|
||||||
|
*cont = sl->data.SL.flags[0] & 0x1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills a struct stat with the values of a Rock Ridge PN entry (RRIP, 4.1.2).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
|
||||||
|
{
|
||||||
|
if (pn == NULL || pn == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (pn->sig[0] != 'P' || pn->sig[1] != 'N') {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pn->len_sue[0] != 20) {
|
||||||
|
return ISO_WRONG_RR;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->st_rdev = (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) << 32)
|
||||||
|
|| (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,434 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "stream.h"
|
||||||
|
#include "fsource.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
ino_t serial_id = (ino_t)1;
|
||||||
|
ino_t mem_serial_id = (ino_t)1;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
IsoFileSource *src;
|
||||||
|
|
||||||
|
/* key for file identification inside filesystem */
|
||||||
|
dev_t dev_id;
|
||||||
|
ino_t ino_id;
|
||||||
|
off_t size; /**< size of this file */
|
||||||
|
} FSrcStreamData;
|
||||||
|
|
||||||
|
static
|
||||||
|
int fsrc_open(IsoStream *stream)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct stat info;
|
||||||
|
off_t esize;
|
||||||
|
IsoFileSource *src;
|
||||||
|
if (stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
src = ((FSrcStreamData*)stream->data)->src;
|
||||||
|
ret = iso_file_source_stat(src, &info);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = iso_file_source_open(src);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
esize = ((FSrcStreamData*)stream->data)->size;
|
||||||
|
if (info.st_size == esize) {
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return (esize > info.st_size) ? 3 : 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int fsrc_close(IsoStream *stream)
|
||||||
|
{
|
||||||
|
IsoFileSource *src;
|
||||||
|
if (stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
src = ((FSrcStreamData*)stream->data)->src;
|
||||||
|
return iso_file_source_close(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
off_t fsrc_get_size(IsoStream *stream)
|
||||||
|
{
|
||||||
|
FSrcStreamData *data;
|
||||||
|
data = (FSrcStreamData*)stream->data;
|
||||||
|
|
||||||
|
return data->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int fsrc_read(IsoStream *stream, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
IsoFileSource *src;
|
||||||
|
if (stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
src = ((FSrcStreamData*)stream->data)->src;
|
||||||
|
return iso_file_source_read(src, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int fsrc_is_repeatable(IsoStream *stream)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct stat info;
|
||||||
|
FSrcStreamData *data;
|
||||||
|
if (stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = (FSrcStreamData*)stream->data;
|
||||||
|
|
||||||
|
/* mode is not cached, this function is only useful for filters */
|
||||||
|
ret = iso_file_source_stat(data->src, &info);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (S_ISREG(info.st_mode) || S_ISBLK(info.st_mode)) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void fsrc_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||||
|
ino_t *ino_id)
|
||||||
|
{
|
||||||
|
FSrcStreamData *data;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
|
||||||
|
data = (FSrcStreamData*)stream->data;
|
||||||
|
fs = iso_file_source_get_filesystem(data->src);
|
||||||
|
|
||||||
|
*fs_id = fs->get_id(fs);
|
||||||
|
*dev_id = data->dev_id;
|
||||||
|
*ino_id = data->ino_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
char *fsrc_get_name(IsoStream *stream)
|
||||||
|
{
|
||||||
|
FSrcStreamData *data;
|
||||||
|
data = (FSrcStreamData*)stream->data;
|
||||||
|
return iso_file_source_get_path(data->src);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void fsrc_free(IsoStream *stream)
|
||||||
|
{
|
||||||
|
FSrcStreamData *data;
|
||||||
|
data = (FSrcStreamData*)stream->data;
|
||||||
|
iso_file_source_unref(data->src);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
IsoStreamIface fsrc_stream_class = {
|
||||||
|
fsrc_open,
|
||||||
|
fsrc_close,
|
||||||
|
fsrc_get_size,
|
||||||
|
fsrc_read,
|
||||||
|
fsrc_is_repeatable,
|
||||||
|
fsrc_get_id,
|
||||||
|
fsrc_get_name,
|
||||||
|
fsrc_free
|
||||||
|
};
|
||||||
|
|
||||||
|
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct stat info;
|
||||||
|
IsoStream *str;
|
||||||
|
FSrcStreamData *data;
|
||||||
|
|
||||||
|
if (src == NULL || stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = iso_file_source_stat(src, &info);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (S_ISDIR(info.st_mode)) {
|
||||||
|
return ISO_FILE_IS_DIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for read access to contents */
|
||||||
|
r = iso_file_source_access(src);
|
||||||
|
if (r < 0) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = malloc(sizeof(IsoStream));
|
||||||
|
if (str == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
data = malloc(sizeof(FSrcStreamData));
|
||||||
|
if (str == NULL) {
|
||||||
|
free(str);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* take the ref to IsoFileSource */
|
||||||
|
data->src = src;
|
||||||
|
data->size = info.st_size;
|
||||||
|
|
||||||
|
/* get the id numbers */
|
||||||
|
{
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
unsigned int fs_id;
|
||||||
|
fs = iso_file_source_get_filesystem(data->src);
|
||||||
|
|
||||||
|
fs_id = fs->get_id(fs);
|
||||||
|
if (fs_id == 0) {
|
||||||
|
/*
|
||||||
|
* the filesystem implementation is unable to provide valid
|
||||||
|
* st_dev and st_ino fields. Use serial_id.
|
||||||
|
*/
|
||||||
|
data->dev_id = (dev_t) 0;
|
||||||
|
data->ino_id = serial_id++;
|
||||||
|
} else {
|
||||||
|
data->dev_id = info.st_dev;
|
||||||
|
data->ino_id = info.st_ino;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str->refcount = 1;
|
||||||
|
str->data = data;
|
||||||
|
str->class = &fsrc_stream_class;
|
||||||
|
|
||||||
|
*stream = str;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t *buf;
|
||||||
|
ssize_t offset; /* -1 if stream closed */
|
||||||
|
ino_t ino_id;
|
||||||
|
size_t size;
|
||||||
|
} MemStreamData;
|
||||||
|
|
||||||
|
static
|
||||||
|
int mem_open(IsoStream *stream)
|
||||||
|
{
|
||||||
|
MemStreamData *data;
|
||||||
|
if (stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = (MemStreamData*)stream->data;
|
||||||
|
if (data->offset != -1) {
|
||||||
|
return ISO_FILE_ALREADY_OPENNED;
|
||||||
|
}
|
||||||
|
data->offset = 0;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mem_close(IsoStream *stream)
|
||||||
|
{
|
||||||
|
MemStreamData *data;
|
||||||
|
if (stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = (MemStreamData*)stream->data;
|
||||||
|
if (data->offset == -1) {
|
||||||
|
return ISO_FILE_NOT_OPENNED;
|
||||||
|
}
|
||||||
|
data->offset = -1;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
off_t mem_get_size(IsoStream *stream)
|
||||||
|
{
|
||||||
|
MemStreamData *data;
|
||||||
|
data = (MemStreamData*)stream->data;
|
||||||
|
|
||||||
|
return (off_t)data->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mem_read(IsoStream *stream, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
MemStreamData *data;
|
||||||
|
if (stream == NULL || buf == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
data = stream->data;
|
||||||
|
|
||||||
|
if (data->offset == -1) {
|
||||||
|
return ISO_FILE_NOT_OPENNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->offset >= data->size) {
|
||||||
|
return 0; /* EOF */
|
||||||
|
}
|
||||||
|
|
||||||
|
len = MIN(count, data->size - data->offset);
|
||||||
|
memcpy(buf, data->buf + data->offset, len);
|
||||||
|
data->offset += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mem_is_repeatable(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void mem_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||||
|
ino_t *ino_id)
|
||||||
|
{
|
||||||
|
MemStreamData *data;
|
||||||
|
data = (MemStreamData*)stream->data;
|
||||||
|
*fs_id = ISO_MEM_FS_ID;
|
||||||
|
*dev_id = 0;
|
||||||
|
*ino_id = data->ino_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
char *mem_get_name(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return strdup("[MEMORY SOURCE]");
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void mem_free(IsoStream *stream)
|
||||||
|
{
|
||||||
|
MemStreamData *data;
|
||||||
|
data = (MemStreamData*)stream->data;
|
||||||
|
free(data->buf);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
IsoStreamIface mem_stream_class = {
|
||||||
|
mem_open,
|
||||||
|
mem_close,
|
||||||
|
mem_get_size,
|
||||||
|
mem_read,
|
||||||
|
mem_is_repeatable,
|
||||||
|
mem_get_id,
|
||||||
|
mem_get_name,
|
||||||
|
mem_free
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a stream for reading from a arbitrary memory buffer.
|
||||||
|
* When the Stream refcount reach 0, the buffer is free(3).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 sucess, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream)
|
||||||
|
{
|
||||||
|
IsoStream *str;
|
||||||
|
MemStreamData *data;
|
||||||
|
|
||||||
|
if (buf == NULL || stream == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = malloc(sizeof(IsoStream));
|
||||||
|
if (str == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
data = malloc(sizeof(MemStreamData));
|
||||||
|
if (str == NULL) {
|
||||||
|
free(str);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill data */
|
||||||
|
data->buf = buf;
|
||||||
|
data->size = size;
|
||||||
|
data->offset = -1;
|
||||||
|
data->ino_id = mem_serial_id++;
|
||||||
|
|
||||||
|
str->refcount = 1;
|
||||||
|
str->data = data;
|
||||||
|
str->class = &mem_stream_class;
|
||||||
|
|
||||||
|
*stream = str;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_stream_ref(IsoStream *stream)
|
||||||
|
{
|
||||||
|
++stream->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_stream_unref(IsoStream *stream)
|
||||||
|
{
|
||||||
|
if (--stream->refcount == 0) {
|
||||||
|
stream->class->free(stream);
|
||||||
|
free(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_stream_open(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return stream->class->open(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_stream_close(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return stream->class->close(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
off_t iso_stream_get_size(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return stream->class->get_size(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_stream_read(IsoStream *stream, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
return stream->class->read(stream, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
int iso_stream_is_repeatable(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return stream->class->is_repeatable(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||||
|
ino_t *ino_id)
|
||||||
|
{
|
||||||
|
stream->class->get_id(stream, fs_id, dev_id, ino_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
char *iso_stream_get_name(IsoStream *stream)
|
||||||
|
{
|
||||||
|
return stream->class->get_name(stream);
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBISO_STREAM_H_
|
||||||
|
#define LIBISO_STREAM_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions of streams.
|
||||||
|
*/
|
||||||
|
#include "fsource.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* serial number to be used when you can't get a valid id for a Stream by other
|
||||||
|
* means. If you use this, both fs_id and dev_id should be set to 0.
|
||||||
|
* This must be incremented each time you get a reference to it.
|
||||||
|
*/
|
||||||
|
extern ino_t serial_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some functions here will be moved to libisofs.h when we expose
|
||||||
|
* Streams.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct Iso_Stream IsoStream;
|
||||||
|
|
||||||
|
typedef struct IsoStream_Iface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Opens the stream.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, 2 file greater than expected, 3 file smaller than
|
||||||
|
* expected, < 0 on error
|
||||||
|
*/
|
||||||
|
int (*open)(IsoStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the Stream.
|
||||||
|
* @return 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int (*close)(IsoStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the size (in bytes) of the stream. This function should always
|
||||||
|
* return the same size, even if the underlying source size changes.
|
||||||
|
*/
|
||||||
|
off_t (*get_size)(IsoStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to read up to count bytes from the given stream into
|
||||||
|
* the buffer starting at buf.
|
||||||
|
*
|
||||||
|
* The stream must be open() before calling this, and close() when no
|
||||||
|
* more needed.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* number of bytes read, 0 if EOF, < 0 on error
|
||||||
|
*/
|
||||||
|
int (*read)(IsoStream *stream, void *buf, size_t count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this Stram can be read several times, with the same results.
|
||||||
|
* For example, a regular file is repeatable, you can read it as many
|
||||||
|
* times as you want. However, a pipe isn't.
|
||||||
|
*
|
||||||
|
* This function doesn't take into account if the file has been modified
|
||||||
|
* between the two reads.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 if stream is repeatable, 0 if not, < 0 on error
|
||||||
|
*/
|
||||||
|
int (*is_repeatable)(IsoStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an unique identifier for the IsoStream.
|
||||||
|
*/
|
||||||
|
void (*get_id)(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||||
|
ino_t *ino_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a name that identifies the Stream contents. It is used only for
|
||||||
|
* informational or debug purposes, so you can return anything you
|
||||||
|
* consider suitable for identification of the source, such as the path.
|
||||||
|
*/
|
||||||
|
char *(*get_name)(IsoStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free implementation specific data. Should never be called by user.
|
||||||
|
* Use iso_stream_unref() instead.
|
||||||
|
*/
|
||||||
|
void (*free)(IsoStream *stream);
|
||||||
|
} IsoStreamIface;
|
||||||
|
|
||||||
|
struct Iso_Stream
|
||||||
|
{
|
||||||
|
IsoStreamIface *class;
|
||||||
|
int refcount;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void iso_stream_ref(IsoStream *stream);
|
||||||
|
void iso_stream_unref(IsoStream *stream);
|
||||||
|
|
||||||
|
int iso_stream_open(IsoStream *stream);
|
||||||
|
|
||||||
|
int iso_stream_close(IsoStream *stream);
|
||||||
|
|
||||||
|
off_t iso_stream_get_size(IsoStream *stream);
|
||||||
|
|
||||||
|
int iso_stream_read(IsoStream *stream, void *buf, size_t count);
|
||||||
|
|
||||||
|
int iso_stream_is_repeatable(IsoStream *stream);
|
||||||
|
|
||||||
|
void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
|
||||||
|
ino_t *ino_id);
|
||||||
|
|
||||||
|
char *iso_stream_get_name(IsoStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a stream to read from a IsoFileSource.
|
||||||
|
* The stream will take the ref. to the IsoFileSource, so after a successfully
|
||||||
|
* exectution of this function, you musn't unref() the source, unless you
|
||||||
|
* take an extra ref.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 sucess, < 0 error
|
||||||
|
* Possible errors:
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a stream for reading from a arbitrary memory buffer.
|
||||||
|
* When the Stream refcount reach 0, the buffer is free(3).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 sucess, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream);
|
||||||
|
|
||||||
|
#endif /*STREAM_H_*/
|
|
@ -0,0 +1,751 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions that act on the iso tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "fsource.h"
|
||||||
|
#include "builder.h"
|
||||||
|
#include "messages.h"
|
||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new directory to the iso tree.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* the dir where the new directory will be created
|
||||||
|
* @param name
|
||||||
|
* name for the new dir. If a node with same name already exists on
|
||||||
|
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
|
||||||
|
* @param dir
|
||||||
|
* place where to store a pointer to the newly created dir. No extra
|
||||||
|
* ref is addded, so you will need to call iso_node_ref() if you really
|
||||||
|
* need it. You can pass NULL in this parameter if you don't need the
|
||||||
|
* pointer.
|
||||||
|
* @return
|
||||||
|
* number of nodes in dir if succes, < 0 otherwise
|
||||||
|
* Possible errors:
|
||||||
|
* ISO_NULL_POINTER, if parent or name are NULL
|
||||||
|
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
|
||||||
|
*/
|
||||||
|
int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *n;
|
||||||
|
IsoDir *node;
|
||||||
|
IsoNode **pos;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if (parent == NULL || name == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (dir) {
|
||||||
|
*dir = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find place where to insert and check if it exists */
|
||||||
|
if (iso_dir_exists(parent, name, &pos)) {
|
||||||
|
/* a node with same name already exists */
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = strdup(name);
|
||||||
|
ret = iso_node_new_dir(n, &node);
|
||||||
|
if (ret < 0) {
|
||||||
|
free(n);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* permissions from parent */
|
||||||
|
iso_node_set_permissions((IsoNode*)node, parent->node.mode);
|
||||||
|
iso_node_set_uid((IsoNode*)node, parent->node.uid);
|
||||||
|
iso_node_set_gid((IsoNode*)node, parent->node.gid);
|
||||||
|
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
|
||||||
|
|
||||||
|
/* current time */
|
||||||
|
now = time(NULL);
|
||||||
|
iso_node_set_atime((IsoNode*)node, now);
|
||||||
|
iso_node_set_ctime((IsoNode*)node, now);
|
||||||
|
iso_node_set_mtime((IsoNode*)node, now);
|
||||||
|
|
||||||
|
if (dir) {
|
||||||
|
*dir = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add to dir */
|
||||||
|
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new symlink to the directory tree. Permissions are set to 0777,
|
||||||
|
* owner and hidden atts are taken from parent. You can modify any of them
|
||||||
|
* later.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* the dir where the new symlink will be created
|
||||||
|
* @param name
|
||||||
|
* name for the new dir. If a node with same name already exists on
|
||||||
|
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
|
||||||
|
* @param dest
|
||||||
|
* destination of the link
|
||||||
|
* @param link
|
||||||
|
* place where to store a pointer to the newly created link. No extra
|
||||||
|
* ref is addded, so you will need to call iso_node_ref() if you really
|
||||||
|
* need it. You can pass NULL in this parameter if you don't need the
|
||||||
|
* pointer
|
||||||
|
* @return
|
||||||
|
* number of nodes in parent if success, < 0 otherwise
|
||||||
|
* Possible errors:
|
||||||
|
* ISO_NULL_POINTER, if parent, name or dest are NULL
|
||||||
|
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
|
||||||
|
* ISO_OUT_OF_MEM
|
||||||
|
*/
|
||||||
|
int iso_tree_add_new_symlink(IsoDir *parent, const char *name,
|
||||||
|
const char *dest, IsoSymlink **link)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *n, *d;
|
||||||
|
IsoSymlink *node;
|
||||||
|
IsoNode **pos;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if (parent == NULL || name == NULL || dest == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (link) {
|
||||||
|
*link = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find place where to insert */
|
||||||
|
if (iso_dir_exists(parent, name, &pos)) {
|
||||||
|
/* a node with same name already exists */
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = strdup(name);
|
||||||
|
d = strdup(dest);
|
||||||
|
ret = iso_node_new_symlink(n, d, &node);
|
||||||
|
if (ret < 0) {
|
||||||
|
free(n);
|
||||||
|
free(d);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* permissions from parent */
|
||||||
|
iso_node_set_permissions((IsoNode*)node, 0777);
|
||||||
|
iso_node_set_uid((IsoNode*)node, parent->node.uid);
|
||||||
|
iso_node_set_gid((IsoNode*)node, parent->node.gid);
|
||||||
|
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
|
||||||
|
|
||||||
|
/* current time */
|
||||||
|
now = time(NULL);
|
||||||
|
iso_node_set_atime((IsoNode*)node, now);
|
||||||
|
iso_node_set_ctime((IsoNode*)node, now);
|
||||||
|
iso_node_set_mtime((IsoNode*)node, now);
|
||||||
|
|
||||||
|
if (link) {
|
||||||
|
*link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add to dir */
|
||||||
|
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new special file to the directory tree. As far as libisofs concerns,
|
||||||
|
* an special file is a block device, a character device, a FIFO (named pipe)
|
||||||
|
* or a socket. You can choose the specific kind of file you want to add
|
||||||
|
* by setting mode propertly (see man 2 stat).
|
||||||
|
*
|
||||||
|
* Note that special files are only written to image when Rock Ridge
|
||||||
|
* extensions are enabled. Moreover, a special file is just a directory entry
|
||||||
|
* in the image tree, no data is written beyond that.
|
||||||
|
*
|
||||||
|
* Owner and hidden atts are taken from parent. You can modify any of them
|
||||||
|
* later.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* the dir where the new special file will be created
|
||||||
|
* @param name
|
||||||
|
* name for the new special file. If a node with same name already exists
|
||||||
|
* on parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
|
||||||
|
* @param mode
|
||||||
|
* file type and permissions for the new node. Note that you can't
|
||||||
|
* specify any kind of file here, only special types are allowed. i.e,
|
||||||
|
* S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK,
|
||||||
|
* S_IFREG and S_IFDIR aren't.
|
||||||
|
* @param dev
|
||||||
|
* device ID, equivalent to the st_rdev field in man 2 stat.
|
||||||
|
* @param special
|
||||||
|
* place where to store a pointer to the newly created special file. No
|
||||||
|
* extra ref is addded, so you will need to call iso_node_ref() if you
|
||||||
|
* really need it. You can pass NULL in this parameter if you don't need
|
||||||
|
* the pointer.
|
||||||
|
* @return
|
||||||
|
* number of nodes in parent if success, < 0 otherwise
|
||||||
|
* Possible errors:
|
||||||
|
* ISO_NULL_POINTER, if parent, name or dest are NULL
|
||||||
|
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
|
||||||
|
* ISO_OUT_OF_MEM
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
|
||||||
|
dev_t dev, IsoSpecial **special)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *n;
|
||||||
|
IsoSpecial *node;
|
||||||
|
IsoNode **pos;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if (parent == NULL || name == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (S_ISLNK(mode) || S_ISREG(mode) || S_ISDIR(mode)) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
if (special) {
|
||||||
|
*special = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find place where to insert */
|
||||||
|
if (iso_dir_exists(parent, name, &pos)) {
|
||||||
|
/* a node with same name already exists */
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = strdup(name);
|
||||||
|
ret = iso_node_new_special(n, mode, dev, &node);
|
||||||
|
if (ret < 0) {
|
||||||
|
free(n);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* atts from parent */
|
||||||
|
iso_node_set_uid((IsoNode*)node, parent->node.uid);
|
||||||
|
iso_node_set_gid((IsoNode*)node, parent->node.gid);
|
||||||
|
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
|
||||||
|
|
||||||
|
/* current time */
|
||||||
|
now = time(NULL);
|
||||||
|
iso_node_set_atime((IsoNode*)node, now);
|
||||||
|
iso_node_set_ctime((IsoNode*)node, now);
|
||||||
|
iso_node_set_mtime((IsoNode*)node, now);
|
||||||
|
|
||||||
|
if (special) {
|
||||||
|
*special = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add to dir */
|
||||||
|
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether to follow or not symbolic links when added a file from a source
|
||||||
|
* to IsoImage.
|
||||||
|
*/
|
||||||
|
void iso_tree_set_follow_symlinks(IsoImage *image, int follow)
|
||||||
|
{
|
||||||
|
image->follow_symlinks = follow ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current setting for follow_symlinks.
|
||||||
|
*
|
||||||
|
* @see iso_tree_set_follow_symlinks
|
||||||
|
*/
|
||||||
|
int iso_tree_get_follow_symlinks(IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->follow_symlinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether to skip or not hidden files when adding a directory recursibely.
|
||||||
|
* Default behavior is to not ignore them, i.e., to add hidden files to image.
|
||||||
|
*/
|
||||||
|
void iso_tree_set_ignore_hidden(IsoImage *image, int skip)
|
||||||
|
{
|
||||||
|
image->ignore_hidden = skip ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current setting for ignore_hidden.
|
||||||
|
*
|
||||||
|
* @see iso_tree_set_ignore_hidden
|
||||||
|
*/
|
||||||
|
int iso_tree_get_ignore_hidden(IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->ignore_hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iso_tree_set_replace_mode(IsoImage *image, enum iso_replace_mode mode)
|
||||||
|
{
|
||||||
|
image->replace = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum iso_replace_mode iso_tree_get_replace_mode(IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether to skip or not special files. Default behavior is to not skip
|
||||||
|
* them. Note that, despite of this setting, special files won't never be added
|
||||||
|
* to an image unless RR extensions were enabled.
|
||||||
|
*
|
||||||
|
* @param skip
|
||||||
|
* Bitmask to determine what kind of special files will be skipped:
|
||||||
|
* bit0: ignore FIFOs
|
||||||
|
* bit1: ignore Sockets
|
||||||
|
* bit2: ignore char devices
|
||||||
|
* bit3: ignore block devices
|
||||||
|
*/
|
||||||
|
void iso_tree_set_ignore_special(IsoImage *image, int skip)
|
||||||
|
{
|
||||||
|
image->ignore_special = skip & 0x0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current setting for ignore_special.
|
||||||
|
*
|
||||||
|
* @see iso_tree_set_ignore_special
|
||||||
|
*/
|
||||||
|
int iso_tree_get_ignore_special(IsoImage *image)
|
||||||
|
{
|
||||||
|
return image->ignore_special;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a callback function that libisofs will call for each file that is
|
||||||
|
* added to the given image by a recursive addition function. This includes
|
||||||
|
* image import.
|
||||||
|
*
|
||||||
|
* @param report
|
||||||
|
* pointer to a function that will be called just before a file will be
|
||||||
|
* added to the image. You can control whether the file will be in fact
|
||||||
|
* added or ignored.
|
||||||
|
* This function should return 1 to add the file, 0 to ignore it and
|
||||||
|
* continue, < 0 to abort the process
|
||||||
|
* NULL is allowed if you don't want any callback.
|
||||||
|
*/
|
||||||
|
void iso_tree_set_report_callback(IsoImage *image,
|
||||||
|
int (*report)(IsoImage*, IsoFileSource*))
|
||||||
|
{
|
||||||
|
image->report = report;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a excluded path. These are paths that won't never added to image,
|
||||||
|
* and will be excluded even when adding recursively its parent directory.
|
||||||
|
*
|
||||||
|
* For example, in
|
||||||
|
*
|
||||||
|
* iso_tree_add_exclude(image, "/home/user/data/private");
|
||||||
|
* iso_tree_add_dir_rec(image, root, "/home/user/data");
|
||||||
|
*
|
||||||
|
* the directory /home/user/data/private won't be added to image.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int iso_tree_add_exclude(IsoImage *image, const char *path)
|
||||||
|
{
|
||||||
|
if (image == NULL || path == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
image->excludes = realloc(image->excludes, ++image->nexcludes *
|
||||||
|
sizeof(void*));
|
||||||
|
if (image->excludes == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
image->excludes[image->nexcludes - 1] = strdup(path);
|
||||||
|
if (image->excludes[image->nexcludes - 1] == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a previously added exclude.
|
||||||
|
*
|
||||||
|
* @see iso_tree_add_exclude
|
||||||
|
* @return
|
||||||
|
* 1 on success, 0 exclude do not exists, < 0 on error
|
||||||
|
*/
|
||||||
|
int iso_tree_remove_exclude(IsoImage *image, const char *path)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
if (image == NULL || path == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < image->nexcludes; ++i) {
|
||||||
|
if (strcmp(image->excludes[i], path) == 0) {
|
||||||
|
/* exclude found */
|
||||||
|
free(image->excludes[i]);
|
||||||
|
--image->nexcludes;
|
||||||
|
for (j = i; j < image->nexcludes; ++j) {
|
||||||
|
image->excludes[j] = image->excludes[j+1];
|
||||||
|
}
|
||||||
|
image->excludes = realloc(image->excludes, image->nexcludes *
|
||||||
|
sizeof(void*));
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int iso_tree_add_node_builder(IsoImage *image, IsoDir *parent,
|
||||||
|
IsoFileSource *src, IsoNodeBuilder *builder,
|
||||||
|
IsoNode **node)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoNode *new;
|
||||||
|
IsoNode **pos;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
if (parent == NULL || src == NULL || builder == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
if (node) {
|
||||||
|
*node = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = iso_file_source_get_name(src);
|
||||||
|
|
||||||
|
/* find place where to insert */
|
||||||
|
result = iso_dir_exists(parent, name, &pos);
|
||||||
|
free(name);
|
||||||
|
if (result) {
|
||||||
|
/* a node with same name already exists */
|
||||||
|
return ISO_NODE_NAME_NOT_UNIQUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = builder->create_node(builder, image, src, &new);
|
||||||
|
if (result < 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
*node = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally, add node to parent */
|
||||||
|
return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
|
||||||
|
IsoNode **node)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
IsoFileSource *file;
|
||||||
|
|
||||||
|
if (image == NULL || parent == NULL || path == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = image->fs;
|
||||||
|
result = fs->get_by_path(fs, path, &file);
|
||||||
|
if (result < 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = iso_tree_add_node_builder(image, parent, file, image->builder,
|
||||||
|
node);
|
||||||
|
/* free the file */
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int check_excludes(IsoImage *image, const char *path)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < image->nexcludes; ++i) {
|
||||||
|
char *exclude = image->excludes[i];
|
||||||
|
if (exclude[0] == '/') {
|
||||||
|
/* absolute exclude, must completely match path */
|
||||||
|
if (!fnmatch(exclude, path, FNM_PERIOD|FNM_PATHNAME)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* relative exclude, it is enought if a part of the path matches */
|
||||||
|
char *pos = (char*)path;
|
||||||
|
while (pos != NULL) {
|
||||||
|
pos++;
|
||||||
|
if (!fnmatch(exclude, pos, FNM_PERIOD|FNM_PATHNAME)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
pos = strchr(pos, '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int check_hidden(IsoImage *image, const char *name)
|
||||||
|
{
|
||||||
|
return (image->ignore_hidden && name[0] == '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int check_special(IsoImage *image, mode_t mode)
|
||||||
|
{
|
||||||
|
if (image->ignore_special != 0) {
|
||||||
|
switch(mode & S_IFMT) {
|
||||||
|
case S_IFBLK:
|
||||||
|
return image->ignore_special & 0x08 ? 1 : 0;
|
||||||
|
case S_IFCHR:
|
||||||
|
return image->ignore_special & 0x04 ? 1 : 0;
|
||||||
|
case S_IFSOCK:
|
||||||
|
return image->ignore_special & 0x02 ? 1 : 0;
|
||||||
|
case S_IFIFO:
|
||||||
|
return image->ignore_special & 0x01 ? 1 : 0;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively add a given directory to the image tree.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 continue, < 0 error (ISO_CANCELED stop)
|
||||||
|
*/
|
||||||
|
int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoNodeBuilder *builder;
|
||||||
|
IsoFileSource *file;
|
||||||
|
IsoNode **pos;
|
||||||
|
struct stat info;
|
||||||
|
char *name, *path;
|
||||||
|
IsoNode *new;
|
||||||
|
enum iso_replace_mode replace;
|
||||||
|
|
||||||
|
ret = iso_file_source_open(dir);
|
||||||
|
if (ret < 0) {
|
||||||
|
char *path = iso_file_source_get_path(dir);
|
||||||
|
/* instead of the probable error, we throw a sorry event */
|
||||||
|
ret = iso_msg_submit(image->id, ISO_FILE_CANT_ADD, ret,
|
||||||
|
"Can't open dir %s", path);
|
||||||
|
free(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder = image->builder;
|
||||||
|
|
||||||
|
/* iterate over all directory children */
|
||||||
|
while (1) {
|
||||||
|
int skip = 0;
|
||||||
|
|
||||||
|
ret = iso_file_source_readdir(dir, &file);
|
||||||
|
if (ret <= 0) {
|
||||||
|
if (ret < 0) {
|
||||||
|
/* error reading dir */
|
||||||
|
ret = iso_msg_submit(image->id, ret, ret, "Error reading dir");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
path = iso_file_source_get_path(file);
|
||||||
|
name = strrchr(path, '/') + 1;
|
||||||
|
|
||||||
|
if (image->follow_symlinks) {
|
||||||
|
ret = iso_file_source_stat(file, &info);
|
||||||
|
} else {
|
||||||
|
ret = iso_file_source_lstat(file, &info);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
goto dir_rec_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check_excludes(image, path)) {
|
||||||
|
iso_msg_debug(image->id, "Skipping excluded file %s", path);
|
||||||
|
skip = 1;
|
||||||
|
} else if (check_hidden(image, name)) {
|
||||||
|
iso_msg_debug(image->id, "Skipping hidden file %s", path);
|
||||||
|
skip = 1;
|
||||||
|
} else if (check_special(image, info.st_mode)) {
|
||||||
|
iso_msg_debug(image->id, "Skipping special file %s", path);
|
||||||
|
skip = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip) {
|
||||||
|
goto dir_rec_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
replace = image->replace;
|
||||||
|
|
||||||
|
/* find place where to insert */
|
||||||
|
ret = iso_dir_exists(parent, name, &pos);
|
||||||
|
/* TODO
|
||||||
|
* if (ret && replace == ISO_REPLACE_ASK) {
|
||||||
|
* replace = /....
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* chek if we must insert or not */
|
||||||
|
/* TODO check for other replace behavior */
|
||||||
|
if (ret && (replace == ISO_REPLACE_NEVER)) {
|
||||||
|
/* skip file */
|
||||||
|
goto dir_rec_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we are here we must insert. Give user a chance for cancel */
|
||||||
|
if (image->report) {
|
||||||
|
int r = image->report(image, file);
|
||||||
|
if (r <= 0) {
|
||||||
|
ret = (r < 0 ? ISO_CANCELED : ISO_SUCCESS);
|
||||||
|
goto dir_rec_continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = builder->create_node(builder, image, file, &new);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = iso_msg_submit(image->id, ISO_FILE_CANT_ADD, ret,
|
||||||
|
"Error when adding file %s", path);
|
||||||
|
goto dir_rec_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok, node has correctly created, we need to add it */
|
||||||
|
ret = iso_dir_insert(parent, new, pos, replace);
|
||||||
|
if (ret < 0) {
|
||||||
|
iso_node_unref(new);
|
||||||
|
if (ret != ISO_NODE_NAME_NOT_UNIQUE) {
|
||||||
|
/* error */
|
||||||
|
goto dir_rec_continue;
|
||||||
|
} else {
|
||||||
|
/* file ignored because a file with same node already exists */
|
||||||
|
iso_msg_debug(image->id, "Skipping file %s. A node with same "
|
||||||
|
"file already exists", path);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iso_msg_debug(image->id, "Added file %s", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally, if the node is a directory we need to recurse */
|
||||||
|
if (new->type == LIBISO_DIR && S_ISDIR(info.st_mode)) {
|
||||||
|
ret = iso_add_dir_src_rec(image, (IsoDir*)new, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_rec_continue:;
|
||||||
|
free(path);
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
|
||||||
|
/* check for error severity to decide what to do */
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = iso_msg_submit(image->id, ret, 0, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* while */
|
||||||
|
|
||||||
|
iso_file_source_close(dir);
|
||||||
|
return ret < 0 ? ret : ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
struct stat info;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
IsoFileSource *file;
|
||||||
|
|
||||||
|
if (image == NULL || parent == NULL || dir == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = image->fs;
|
||||||
|
result = fs->get_by_path(fs, dir, &file);
|
||||||
|
if (result < 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we also allow dir path to be a symlink to a dir */
|
||||||
|
result = iso_file_source_stat(file, &info);
|
||||||
|
if (result < 0) {
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISDIR(info.st_mode)) {
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
return ISO_FILE_IS_NOT_DIR;
|
||||||
|
}
|
||||||
|
result = iso_add_dir_src_rec(image, parent, file);
|
||||||
|
iso_file_source_unref(file);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoNode *n;
|
||||||
|
IsoDir *dir;
|
||||||
|
char *ptr, *brk_info, *component;
|
||||||
|
|
||||||
|
if (image == NULL || path == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the first child at the root of the image that is "/" */
|
||||||
|
dir = image->root;
|
||||||
|
n = (IsoNode *)dir;
|
||||||
|
if (!strcmp(path, "/")) {
|
||||||
|
if (node) {
|
||||||
|
*node = n;
|
||||||
|
}
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = strdup(path);
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
/* get the first component of the path */
|
||||||
|
component = strtok_r(ptr, "/", &brk_info);
|
||||||
|
while (component) {
|
||||||
|
if (n->type != LIBISO_DIR) {
|
||||||
|
n = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dir = (IsoDir *)n;
|
||||||
|
|
||||||
|
result = iso_dir_get_node(dir, component, &n);
|
||||||
|
if (result != 1) {
|
||||||
|
n = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
component = strtok_r(NULL, "/", &brk_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(ptr);
|
||||||
|
if (node) {
|
||||||
|
*node = n;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBISO_IMAGE_TREE_H_
|
||||||
|
#define LIBISO_IMAGE_TREE_H_
|
||||||
|
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively add a given directory to the image tree.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 continue, 0 stop, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir);
|
||||||
|
|
||||||
|
#endif /*LIBISO_IMAGE_TREE_H_*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,438 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBISO_UTIL_H_
|
||||||
|
#define LIBISO_UTIL_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DIV_UP(n,div) ((n + div - 1) / div)
|
||||||
|
#define ROUND_UP(n,mul) (DIV_UP(n, mul) * mul)
|
||||||
|
|
||||||
|
int int_pow(int base, int power);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the charset encoding of a given string.
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
* Input string
|
||||||
|
* @param icharset
|
||||||
|
* Input charset. Must be supported by iconv
|
||||||
|
* @param ocharset
|
||||||
|
* Output charset. Must be supported by iconv
|
||||||
|
* @param output
|
||||||
|
* Location where the pointer to the ouput string will be stored
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int strconv(const char *input, const char *icharset, const char *ocharset,
|
||||||
|
char **output);
|
||||||
|
|
||||||
|
int strnconv(const char *str, const char *icharset, const char *ocharset,
|
||||||
|
size_t len, char **output);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a given string from any input charset to ASCII
|
||||||
|
*
|
||||||
|
* @param icharset
|
||||||
|
* Input charset. Must be supported by iconv
|
||||||
|
* @param input
|
||||||
|
* Input string
|
||||||
|
* @param output
|
||||||
|
* Location where the pointer to the ouput string will be stored
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int str2ascii(const char *icharset, const char *input, char **output);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a given string from any input charset to UCS-2BE charset,
|
||||||
|
* used for Joliet file identifiers.
|
||||||
|
*
|
||||||
|
* @param icharset
|
||||||
|
* Input charset. Must be supported by iconv
|
||||||
|
* @param input
|
||||||
|
* Input string
|
||||||
|
* @param output
|
||||||
|
* Location where the pointer to the ouput string will be stored
|
||||||
|
* @return
|
||||||
|
* 1 on success, < 0 on error
|
||||||
|
*/
|
||||||
|
int str2ucs(const char *icharset, const char *input, uint16_t **output);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a level 1 directory identifier.
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* The identifier, in ASCII encoding.
|
||||||
|
*/
|
||||||
|
char *iso_1_dirid(const char *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a level 2 directory identifier.
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* The identifier, in ASCII encoding.
|
||||||
|
*/
|
||||||
|
char *iso_2_dirid(const char *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a dir name suitable for an ISO image with relaxed constraints.
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* The identifier, in ASCII encoding.
|
||||||
|
* @param size
|
||||||
|
* Max len for the name
|
||||||
|
* @param relaxed
|
||||||
|
* 0 only allow d-characters, 1 allow also lowe case chars,
|
||||||
|
* 2 allow all characters
|
||||||
|
*/
|
||||||
|
char *iso_r_dirid(const char *src, int size, int relaxed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a level 1 file identifier that consists of a name, in 8.3
|
||||||
|
* format.
|
||||||
|
* Note that version number is not added to the file name
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* The identifier, in ASCII encoding.
|
||||||
|
*/
|
||||||
|
char *iso_1_fileid(const char *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a level 2 file identifier.
|
||||||
|
* Note that version number is not added to the file name
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* The identifier, in ASCII encoding.
|
||||||
|
*/
|
||||||
|
char *iso_2_fileid(const char *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a file name suitable for an ISO image with relaxed constraints.
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* The identifier, in ASCII encoding.
|
||||||
|
* @param len
|
||||||
|
* Max len for the name, without taken the "." into account.
|
||||||
|
* @param relaxed
|
||||||
|
* 0 only allow d-characters, 1 allow also lowe case chars,
|
||||||
|
* 2 allow all characters
|
||||||
|
* @param forcedot
|
||||||
|
* Whether to ensure that "." is added
|
||||||
|
*/
|
||||||
|
char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Joliet file identifier that consists of name and extension. The
|
||||||
|
* combined name and extension length will not exceed 128 bytes, and the
|
||||||
|
* name and extension will be separated (.). All characters consist of
|
||||||
|
* 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL.
|
||||||
|
*
|
||||||
|
* Note that version number and (;1) is not appended.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* NULL if the original name and extension both are of length 0.
|
||||||
|
*/
|
||||||
|
uint16_t *iso_j_file_id(const uint16_t *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Joliet directory identifier that consists of name and optionally
|
||||||
|
* extension. The combined name and extension length will not exceed 128 bytes,
|
||||||
|
* and the name and extension will be separated (.). All characters consist of
|
||||||
|
* 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* NULL if the original name and extension both are of length 0.
|
||||||
|
*/
|
||||||
|
uint16_t *iso_j_dir_id(const uint16_t *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like strlen, but for Joliet strings.
|
||||||
|
*/
|
||||||
|
size_t ucslen(const uint16_t *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like strrchr, but for Joliet strings.
|
||||||
|
*/
|
||||||
|
uint16_t *ucsrchr(const uint16_t *str, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like strdup, but for Joliet strings.
|
||||||
|
*/
|
||||||
|
uint16_t *ucsdup(const uint16_t *str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like strcmp, but for Joliet strings.
|
||||||
|
*/
|
||||||
|
int ucscmp(const uint16_t *s1, const uint16_t *s2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like strcpy, but for Joliet strings.
|
||||||
|
*/
|
||||||
|
uint16_t *ucscpy(uint16_t *dest, const uint16_t *src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like strncpy, but for Joliet strings.
|
||||||
|
* @param n
|
||||||
|
* Maximum number of characters to copy (2 bytes per char).
|
||||||
|
*/
|
||||||
|
uint16_t *ucsncpy(uint16_t *dest, const uint16_t *src, size_t n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a given input string to d-chars.
|
||||||
|
* @return
|
||||||
|
* 1 on succes, < 0 error, 0 if input was null (output is set to null)
|
||||||
|
*/
|
||||||
|
int str2d_char(const char *icharset, const char *input, char **output);
|
||||||
|
int str2a_char(const char *icharset, const char *input, char **output);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if error != NULL it will be set to 1 if LSB and MSB integers don't match.
|
||||||
|
*/
|
||||||
|
uint32_t iso_read_bb(const uint8_t *buf, int bytes, int *error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records the date/time into a 7 byte buffer (ECMA-119, 9.1.5)
|
||||||
|
*
|
||||||
|
* @param buf
|
||||||
|
* Buffer where the date will be written
|
||||||
|
* @param t
|
||||||
|
* The time to be written
|
||||||
|
* @param always_gmt
|
||||||
|
* Always write the date in GMT and not in local time.
|
||||||
|
*/
|
||||||
|
void iso_datetime_7(uint8_t *buf, time_t t, int always_gmt);
|
||||||
|
|
||||||
|
/** Records the date/time into a 17 byte buffer (ECMA-119, 8.4.26.1) */
|
||||||
|
void iso_datetime_17(uint8_t *buf, time_t t, int always_gmt);
|
||||||
|
|
||||||
|
time_t iso_datetime_read_7(const uint8_t *buf);
|
||||||
|
time_t iso_datetime_read_17(const uint8_t *buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the caller process has read access to the given local file.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on success (i.e, the process has read access), < 0 on error
|
||||||
|
* (including ISO_FILE_ACCESS_DENIED on access denied to the specified file
|
||||||
|
* or any directory on the path).
|
||||||
|
*/
|
||||||
|
int iso_eaccess(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy up to \p len chars from \p buf and return this newly allocated
|
||||||
|
* string. The new string is null-terminated.
|
||||||
|
*/
|
||||||
|
char *strcopy(const char *buf, size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy up to \p max characters from \p src to \p dest. If \p src has less than
|
||||||
|
* \p max characters, we pad dest with " " characters.
|
||||||
|
*/
|
||||||
|
void strncpy_pad(char *dest, const char *src, size_t max);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Joliet string with a length of \p len bytes to a new string
|
||||||
|
* in local charset.
|
||||||
|
*/
|
||||||
|
char *ucs2str(const char *buf, size_t len);
|
||||||
|
|
||||||
|
typedef struct iso_rbtree IsoRBTree;
|
||||||
|
typedef struct iso_htable IsoHTable;
|
||||||
|
|
||||||
|
typedef unsigned int (*hash_funtion_t)(const void *key);
|
||||||
|
typedef int (*compare_function_t)(const void *a, const void *b);
|
||||||
|
typedef void (*hfree_data_t)(void *key, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new binary tree. libisofs binary trees allow you to add any data
|
||||||
|
* passing it as a pointer. You must provide a function suitable for compare
|
||||||
|
* two elements.
|
||||||
|
*
|
||||||
|
* @param compare
|
||||||
|
* A function to compare two keys. It takes a pointer to both keys
|
||||||
|
* and return 0, -1 or 1 if the first key is equal, less or greater
|
||||||
|
* than the second one.
|
||||||
|
* @param tree
|
||||||
|
* Location where the tree structure will be stored.
|
||||||
|
*/
|
||||||
|
int iso_rbtree_new(int (*compare)(const void*, const void*), IsoRBTree **tree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a given tree.
|
||||||
|
*
|
||||||
|
* Note that only the structure itself is deleted. To delete the elements, you
|
||||||
|
* should provide a valid free_data function. It will be called for each
|
||||||
|
* element of the tree, so you can use it to free any related data.
|
||||||
|
*/
|
||||||
|
void iso_rbtree_destroy(IsoRBTree *tree, void (*free_data)(void *));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a given element in a Red-Black tree.
|
||||||
|
*
|
||||||
|
* @param tree
|
||||||
|
* the tree where to insert
|
||||||
|
* @param data
|
||||||
|
* element to be inserted on the tree. It can't be NULL
|
||||||
|
* @param item
|
||||||
|
* if not NULL, it will point to a location where the tree element ptr
|
||||||
|
* will be stored. If data was inserted, *item == data. If data was
|
||||||
|
* already on the tree, *item points to the previously inserted object
|
||||||
|
* that is equal to data.
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 element already inserted, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_rbtree_insert(IsoRBTree *tree, void *data, void **item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of elements in a given tree.
|
||||||
|
*/
|
||||||
|
size_t iso_rbtree_get_size(IsoRBTree *tree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array view of the elements of the tree.
|
||||||
|
*
|
||||||
|
* @param include_item
|
||||||
|
* Function to select which elements to include in the array. It that takes
|
||||||
|
* a pointer to an element and returns 1 if the element should be included,
|
||||||
|
* 0 if not. If you want to add all elements to the array, you can pass a
|
||||||
|
* NULL pointer.
|
||||||
|
* @param size
|
||||||
|
* If not null, will be filled with the number of elements in the array,
|
||||||
|
* without counting the final NULL item.
|
||||||
|
* @return
|
||||||
|
* A sorted array with the contents of the tree, or NULL if there is not
|
||||||
|
* enought memory to allocate the array. You should free(3) the array when
|
||||||
|
* no more needed. Note that the array is NULL-terminated, and thus it
|
||||||
|
* has size + 1 length.
|
||||||
|
*/
|
||||||
|
void **iso_rbtree_to_array(IsoRBTree *tree, int (*include_item)(void *),
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new hash table.
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* Number of slots in table.
|
||||||
|
* @param hash
|
||||||
|
* Function used to generate
|
||||||
|
*/
|
||||||
|
int iso_htable_create(size_t size, hash_funtion_t hash,
|
||||||
|
compare_function_t compare, IsoHTable **table);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put an element in a Hash Table. The element will be identified by
|
||||||
|
* the given key, that you should use to retrieve the element again.
|
||||||
|
*
|
||||||
|
* This function allow duplicates, i.e., two items with the same key. In those
|
||||||
|
* cases, the value returned by iso_htable_get() is undefined. If you don't
|
||||||
|
* want to allow duplicates, use iso_htable_put() instead;
|
||||||
|
*
|
||||||
|
* Both the key and data pointers will be stored internally, so you should
|
||||||
|
* free the objects they point to. Use iso_htable_remove() to delete an
|
||||||
|
* element from the table.
|
||||||
|
*/
|
||||||
|
int iso_htable_add(IsoHTable *table, void *key, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like iso_htable_add(), but this doesn't allow dulpicates.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 if an item with the same key already exists, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_htable_put(IsoHTable *table, void *key, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an element from the given table.
|
||||||
|
*
|
||||||
|
* @param table
|
||||||
|
* Hash table
|
||||||
|
* @param key
|
||||||
|
* Key of the element that will be removed
|
||||||
|
* @param data
|
||||||
|
* Will be filled with the element found. Remains untouched if no
|
||||||
|
* element with the given key is found.
|
||||||
|
* @return
|
||||||
|
* 1 if found, 0 if not, < 0 on error
|
||||||
|
*/
|
||||||
|
int iso_htable_get(IsoHTable *table, void *key, void **data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an item with the given key from the table. In tables that allow
|
||||||
|
* duplicates, it is undefined the element that will be deleted.
|
||||||
|
*
|
||||||
|
* @param table
|
||||||
|
* Hash table
|
||||||
|
* @param key
|
||||||
|
* Key of the element that will be removed
|
||||||
|
* @param free_data
|
||||||
|
* Function that will be called passing as parameters both the key and
|
||||||
|
* the element that will be deleted. The user can use it to free the
|
||||||
|
* element. You can pass NULL if you don't want to delete the item itself.
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 no element exists with the given key, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_htable_remove(IsoHTable *table, void *key, hfree_data_t free_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like remove, but instead of checking for key equality using the compare
|
||||||
|
* function, it just compare the key pointers. If the table allows duplicates,
|
||||||
|
* and you provide different keys (i.e. different pointers) to elements
|
||||||
|
* with same key (i.e. same content), this function ensure the exact element
|
||||||
|
* is removed.
|
||||||
|
*
|
||||||
|
* It has the problem that you must provide the same key pointer, and not just
|
||||||
|
* a key whose contents are equal. Moreover, if you use the same key (same
|
||||||
|
* pointer) to identify several objects, what of those are removed is
|
||||||
|
* undefined.
|
||||||
|
*
|
||||||
|
* @param table
|
||||||
|
* Hash table
|
||||||
|
* @param key
|
||||||
|
* Key of the element that will be removed
|
||||||
|
* @param free_data
|
||||||
|
* Function that will be called passing as parameters both the key and
|
||||||
|
* the element that will be deleted. The user can use it to free the
|
||||||
|
* element. You can pass NULL if you don't want to delete the item itself.
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 no element exists with the given key, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_htable_remove_ptr(IsoHTable *table, void *key, hfree_data_t free_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the given hash table.
|
||||||
|
*
|
||||||
|
* Note that you're responsible to actually destroy the elements by providing
|
||||||
|
* a valid free_data function. You can pass NULL if you only want to delete
|
||||||
|
* the hash structure.
|
||||||
|
*/
|
||||||
|
void iso_htable_destroy(IsoHTable *table, hfree_data_t free_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash function suitable for keys that are char strings.
|
||||||
|
*/
|
||||||
|
unsigned int iso_str_hash(const void *key);
|
||||||
|
|
||||||
|
#endif /*LIBISO_UTIL_H_*/
|
|
@ -0,0 +1,340 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "libisofs.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hash table implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct iso_hnode
|
||||||
|
{
|
||||||
|
void *key;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
/** next node for chaining */
|
||||||
|
struct iso_hnode *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iso_htable
|
||||||
|
{
|
||||||
|
struct iso_hnode **table;
|
||||||
|
|
||||||
|
size_t size; /**< number of items in table */
|
||||||
|
size_t cap; /**< number of slots in table */
|
||||||
|
|
||||||
|
hash_funtion_t hash;
|
||||||
|
compare_function_t compare;
|
||||||
|
};
|
||||||
|
|
||||||
|
static
|
||||||
|
struct iso_hnode *iso_hnode_new(void *key, void *data)
|
||||||
|
{
|
||||||
|
struct iso_hnode *node = malloc(sizeof(struct iso_hnode));
|
||||||
|
if (node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node->data = data;
|
||||||
|
node->key = key;
|
||||||
|
node->next = NULL;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put an element in a Hash Table. The element will be identified by
|
||||||
|
* the given key, that you should use to retrieve the element again.
|
||||||
|
*
|
||||||
|
* This function allow duplicates, i.e., two items with the same key. In those
|
||||||
|
* cases, the value returned by iso_htable_get() is undefined. If you don't
|
||||||
|
* want to allow duplicates, use iso_htable_put() instead;
|
||||||
|
*
|
||||||
|
* Both the key and data pointers will be stored internally, so you should
|
||||||
|
* free the objects they point to. Use iso_htable_remove() to delete an
|
||||||
|
* element from the table.
|
||||||
|
*/
|
||||||
|
int iso_htable_add(IsoHTable *table, void *key, void *data)
|
||||||
|
{
|
||||||
|
struct iso_hnode *node;
|
||||||
|
struct iso_hnode *new;
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
if (table == NULL || key == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = iso_hnode_new(key, data);
|
||||||
|
if (new == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = table->hash(key) % table->cap;
|
||||||
|
node = table->table[hash];
|
||||||
|
|
||||||
|
table->size++;
|
||||||
|
new->next = node;
|
||||||
|
table->table[hash] = new;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like iso_htable_add(), but this doesn't allow dulpicates.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 if an item with the same key already exists, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_htable_put(IsoHTable *table, void *key, void *data)
|
||||||
|
{
|
||||||
|
struct iso_hnode *node;
|
||||||
|
struct iso_hnode *new;
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
if (table == NULL || key == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = table->hash(key) % table->cap;
|
||||||
|
node = table->table[hash];
|
||||||
|
|
||||||
|
while (node) {
|
||||||
|
if (!table->compare(key, node->key)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
new = iso_hnode_new(key, data);
|
||||||
|
if (new == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->size++;
|
||||||
|
new->next = table->table[hash];
|
||||||
|
table->table[hash] = new;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an element from the given table.
|
||||||
|
*
|
||||||
|
* @param table
|
||||||
|
* Hash table
|
||||||
|
* @param key
|
||||||
|
* Key of the element that will be removed
|
||||||
|
* @param data
|
||||||
|
* Will be filled with the element found. Remains untouched if no
|
||||||
|
* element with the given key is found.
|
||||||
|
* @return
|
||||||
|
* 1 if found, 0 if not, < 0 on error
|
||||||
|
*/
|
||||||
|
int iso_htable_get(IsoHTable *table, void *key, void **data)
|
||||||
|
{
|
||||||
|
struct iso_hnode *node;
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
if (table == NULL || key == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = table->hash(key) % table->cap;
|
||||||
|
node = table->table[hash];
|
||||||
|
while (node) {
|
||||||
|
if (!table->compare(key, node->key)) {
|
||||||
|
if (data) {
|
||||||
|
*data = node->data;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an item with the given key from the table. In tables that allow
|
||||||
|
* duplicates, it is undefined the element that will be deleted.
|
||||||
|
*
|
||||||
|
* @param table
|
||||||
|
* Hash table
|
||||||
|
* @param key
|
||||||
|
* Key of the element that will be removed
|
||||||
|
* @param free_data
|
||||||
|
* Function that will be called passing as parameters both the key and
|
||||||
|
* the element that will be deleted. The user can use it to free the
|
||||||
|
* element. You can pass NULL if you don't want to delete the item itself.
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 no element exists with the given key, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_htable_remove(IsoHTable *table, void *key, hfree_data_t free_data)
|
||||||
|
{
|
||||||
|
struct iso_hnode *node, *prev;
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
if (table == NULL || key == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = table->hash(key) % table->cap;
|
||||||
|
node = table->table[hash];
|
||||||
|
prev = NULL;
|
||||||
|
while (node) {
|
||||||
|
if (!table->compare(key, node->key)) {
|
||||||
|
if (free_data)
|
||||||
|
free_data(node->key, node->data);
|
||||||
|
if (prev) {
|
||||||
|
prev->next = node->next;
|
||||||
|
} else {
|
||||||
|
table->table[hash] = node->next;
|
||||||
|
}
|
||||||
|
free(node);
|
||||||
|
table->size--;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
prev = node;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like remove, but instead of checking for key equality using the compare
|
||||||
|
* function, it just compare the key pointers. If the table allows duplicates,
|
||||||
|
* and you provide different keys (i.e. different pointers) to elements
|
||||||
|
* with same key (i.e. same content), this function ensure the exact element
|
||||||
|
* is removed.
|
||||||
|
*
|
||||||
|
* It has the problem that you must provide the same key pointer, and not just
|
||||||
|
* a key whose contents are equal. Moreover, if you use the same key (same
|
||||||
|
* pointer) to identify several objects, what of those are removed is
|
||||||
|
* undefined.
|
||||||
|
*
|
||||||
|
* @param table
|
||||||
|
* Hash table
|
||||||
|
* @param key
|
||||||
|
* Key of the element that will be removed
|
||||||
|
* @param free_data
|
||||||
|
* Function that will be called passing as parameters both the key and
|
||||||
|
* the element that will be deleted. The user can use it to free the
|
||||||
|
* element. You can pass NULL if you don't want to delete the item itself.
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 no element exists with the given key, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_htable_remove_ptr(IsoHTable *table, void *key, hfree_data_t free_data)
|
||||||
|
{
|
||||||
|
struct iso_hnode *node, *prev;
|
||||||
|
unsigned int hash;
|
||||||
|
|
||||||
|
if (table == NULL || key == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = table->hash(key) % table->cap;
|
||||||
|
node = table->table[hash];
|
||||||
|
prev = NULL;
|
||||||
|
while (node) {
|
||||||
|
if (key == node->key) {
|
||||||
|
if (free_data)
|
||||||
|
free_data(node->key, node->data);
|
||||||
|
if (prev) {
|
||||||
|
prev->next = node->next;
|
||||||
|
} else {
|
||||||
|
table->table[hash] = node->next;
|
||||||
|
}
|
||||||
|
free(node);
|
||||||
|
table->size--;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
prev = node;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash function suitable for keys that are char strings.
|
||||||
|
*/
|
||||||
|
unsigned int iso_str_hash(const void *key)
|
||||||
|
{
|
||||||
|
int i, len;
|
||||||
|
const char *p = key;
|
||||||
|
unsigned int h = 2166136261u;
|
||||||
|
|
||||||
|
len = strlen(p);
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
h = (h * 16777619 ) ^ p[i];
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the given hash table.
|
||||||
|
*
|
||||||
|
* Note that you're responsible to actually destroy the elements by providing
|
||||||
|
* a valid free_data function. You can pass NULL if you only want to delete
|
||||||
|
* the hash structure.
|
||||||
|
*/
|
||||||
|
void iso_htable_destroy(IsoHTable *table, hfree_data_t free_data)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
struct iso_hnode *node, *tmp;
|
||||||
|
|
||||||
|
if (table == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < table->cap; ++i) {
|
||||||
|
node = table->table[i];
|
||||||
|
while (node) {
|
||||||
|
tmp = node->next;
|
||||||
|
if (free_data)
|
||||||
|
free_data(node->key, node->data);
|
||||||
|
free(node);
|
||||||
|
node = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(table->table);
|
||||||
|
free(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new hash table.
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* Number of slots in table.
|
||||||
|
* @param hash
|
||||||
|
* Function used to generate
|
||||||
|
*/
|
||||||
|
int iso_htable_create(size_t size, hash_funtion_t hash,
|
||||||
|
compare_function_t compare, IsoHTable **table)
|
||||||
|
{
|
||||||
|
IsoHTable *t;
|
||||||
|
|
||||||
|
if (table == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = malloc(sizeof(IsoHTable));
|
||||||
|
if (t == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
t->table = calloc(size, sizeof(void*));
|
||||||
|
if (t->table == NULL) {
|
||||||
|
free(t);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
t->cap = size;
|
||||||
|
t->size = 0;
|
||||||
|
t->hash = hash;
|
||||||
|
t->compare = compare;
|
||||||
|
|
||||||
|
*table = t;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,296 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "libisofs.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This implementation of Red-Black tree is based on the public domain
|
||||||
|
* implementation of Julienne Walker.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct iso_rbnode
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
struct iso_rbnode *ch[2];
|
||||||
|
unsigned int red :1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iso_rbtree
|
||||||
|
{
|
||||||
|
struct iso_rbnode *root;
|
||||||
|
size_t size;
|
||||||
|
int (*compare)(const void *a, const void *b);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new binary tree. libisofs binary trees allow you to add any data
|
||||||
|
* passing it as a pointer. You must provide a function suitable for compare
|
||||||
|
* two elements.
|
||||||
|
*
|
||||||
|
* @param compare
|
||||||
|
* A function to compare two elements. It takes a pointer to both elements
|
||||||
|
* and return 0, -1 or 1 if the first element is equal, less or greater
|
||||||
|
* than the second one.
|
||||||
|
* @param tree
|
||||||
|
* Location where the tree structure will be stored.
|
||||||
|
*/
|
||||||
|
int iso_rbtree_new(int (*compare)(const void*, const void*), IsoRBTree **tree)
|
||||||
|
{
|
||||||
|
if (compare == NULL || tree == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
*tree = calloc(1, sizeof(IsoRBTree));
|
||||||
|
if (*tree == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
(*tree)->compare = compare;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void rbtree_destroy_aux(struct iso_rbnode *root, void (*free_data)(void *))
|
||||||
|
{
|
||||||
|
if (root == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (free_data != NULL) {
|
||||||
|
free_data(root->data);
|
||||||
|
}
|
||||||
|
rbtree_destroy_aux(root->ch[0], free_data);
|
||||||
|
rbtree_destroy_aux(root->ch[1], free_data);
|
||||||
|
free(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a given tree.
|
||||||
|
*
|
||||||
|
* Note that only the structure itself is deleted. To delete the elements, you
|
||||||
|
* should provide a valid free_data function. It will be called for each
|
||||||
|
* element of the tree, so you can use it to free any related data.
|
||||||
|
*/
|
||||||
|
void iso_rbtree_destroy(IsoRBTree *tree, void (*free_data)(void *))
|
||||||
|
{
|
||||||
|
if (tree == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rbtree_destroy_aux(tree->root, free_data);
|
||||||
|
free(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int is_red(struct iso_rbnode *root)
|
||||||
|
{
|
||||||
|
return root != NULL && root->red;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
struct iso_rbnode *iso_rbtree_single(struct iso_rbnode *root, int dir)
|
||||||
|
{
|
||||||
|
struct iso_rbnode *save = root->ch[!dir];
|
||||||
|
|
||||||
|
root->ch[!dir] = save->ch[dir];
|
||||||
|
save->ch[dir] = root;
|
||||||
|
|
||||||
|
root->red = 1;
|
||||||
|
save->red = 0;
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
struct iso_rbnode *iso_rbtree_double(struct iso_rbnode *root, int dir)
|
||||||
|
{
|
||||||
|
root->ch[!dir] = iso_rbtree_single(root->ch[!dir], !dir);
|
||||||
|
return iso_rbtree_single(root, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
struct iso_rbnode *iso_rbnode_new(void *data)
|
||||||
|
{
|
||||||
|
struct iso_rbnode *rn = malloc(sizeof(struct iso_rbnode));
|
||||||
|
|
||||||
|
if (rn != NULL) {
|
||||||
|
rn->data = data;
|
||||||
|
rn->red = 1;
|
||||||
|
rn->ch[0] = NULL;
|
||||||
|
rn->ch[1] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a given element in a Red-Black tree.
|
||||||
|
*
|
||||||
|
* @param tree
|
||||||
|
* the tree where to insert
|
||||||
|
* @param data
|
||||||
|
* element to be inserted on the tree. It can't be NULL
|
||||||
|
* @param item
|
||||||
|
* if not NULL, it will point to a location where the tree element ptr
|
||||||
|
* will be stored. If data was inserted, *item == data. If data was
|
||||||
|
* already on the tree, *item points to the previously inserted object
|
||||||
|
* that is equal to data.
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 element already inserted, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_rbtree_insert(IsoRBTree *tree, void *data, void **item)
|
||||||
|
{
|
||||||
|
struct iso_rbnode *new;
|
||||||
|
int added = 0; /* has a new node been added? */
|
||||||
|
|
||||||
|
if (tree == NULL || data == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree->root == NULL) {
|
||||||
|
/* Empty tree case */
|
||||||
|
tree->root = iso_rbnode_new(data);
|
||||||
|
if (tree->root == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
new = data;
|
||||||
|
added = 1;
|
||||||
|
} else {
|
||||||
|
struct iso_rbnode head = { 0 }; /* False tree root */
|
||||||
|
|
||||||
|
struct iso_rbnode *g, *t; /* Grandparent & parent */
|
||||||
|
struct iso_rbnode *p, *q; /* Iterator & parent */
|
||||||
|
int dir = 0, last = 0;
|
||||||
|
int comp;
|
||||||
|
|
||||||
|
/* Set up helpers */
|
||||||
|
t = &head;
|
||||||
|
g = p = NULL;
|
||||||
|
q = t->ch[1] = tree->root;
|
||||||
|
|
||||||
|
/* Search down the tree */
|
||||||
|
while (1) {
|
||||||
|
if (q == NULL) {
|
||||||
|
/* Insert new node at the bottom */
|
||||||
|
p->ch[dir] = q = iso_rbnode_new(data);
|
||||||
|
if (q == NULL) {
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
added = 1;
|
||||||
|
} else if (is_red(q->ch[0]) && is_red(q->ch[1])) {
|
||||||
|
/* Color flip */
|
||||||
|
q->red = 1;
|
||||||
|
q->ch[0]->red = 0;
|
||||||
|
q->ch[1]->red = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix red violation */
|
||||||
|
if (is_red(q) && is_red(p)) {
|
||||||
|
int dir2 = (t->ch[1] == g);
|
||||||
|
|
||||||
|
if (q == p->ch[last]) {
|
||||||
|
t->ch[dir2] = iso_rbtree_single(g, !last);
|
||||||
|
} else {
|
||||||
|
t->ch[dir2] = iso_rbtree_double(g, !last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comp = tree->compare(q->data, data);
|
||||||
|
|
||||||
|
/* Stop if found */
|
||||||
|
if (comp == 0) {
|
||||||
|
new = q->data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = dir;
|
||||||
|
dir = (comp < 0);
|
||||||
|
|
||||||
|
/* Update helpers */
|
||||||
|
if (g != NULL)
|
||||||
|
t = g;
|
||||||
|
g = p, p = q;
|
||||||
|
q = q->ch[dir];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update root */
|
||||||
|
tree->root = head.ch[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make root black */
|
||||||
|
tree->root->red = 0;
|
||||||
|
|
||||||
|
if (item != NULL) {
|
||||||
|
*item = new;
|
||||||
|
}
|
||||||
|
if (added) {
|
||||||
|
/* a new element has been added */
|
||||||
|
tree->size++;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of elements in a given tree.
|
||||||
|
*/
|
||||||
|
size_t iso_rbtree_get_size(IsoRBTree *tree)
|
||||||
|
{
|
||||||
|
return tree->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
size_t rbtree_to_array_aux(struct iso_rbnode *root, void **array, size_t pos,
|
||||||
|
int (*include_item)(void *))
|
||||||
|
{
|
||||||
|
if (root == NULL) {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
pos = rbtree_to_array_aux(root->ch[0], array, pos, include_item);
|
||||||
|
if (include_item == NULL || include_item(root->data)) {
|
||||||
|
array[pos++] = root->data;
|
||||||
|
}
|
||||||
|
pos = rbtree_to_array_aux(root->ch[1], array, pos, include_item);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array view of the elements of the tree.
|
||||||
|
*
|
||||||
|
* @param include_item
|
||||||
|
* Function to select which elements to include in the array. It that takes
|
||||||
|
* a pointer to an element and returns 1 if the element should be included,
|
||||||
|
* 0 if not. If you want to add all elements to the array, you can pass a
|
||||||
|
* NULL pointer.
|
||||||
|
* @return
|
||||||
|
* A sorted array with the contents of the tree, or NULL if there is not
|
||||||
|
* enought memory to allocate the array. You should free(3) the array when
|
||||||
|
* no more needed. Note that the array is NULL-terminated, and thus it
|
||||||
|
* has size + 1 length.
|
||||||
|
*/
|
||||||
|
void ** iso_rbtree_to_array(IsoRBTree *tree, int (*include_item)(void *),
|
||||||
|
size_t *size)
|
||||||
|
{
|
||||||
|
size_t pos;
|
||||||
|
void **array;
|
||||||
|
|
||||||
|
array = malloc((tree->size + 1) * sizeof(void*));
|
||||||
|
if (array == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill array */
|
||||||
|
pos = rbtree_to_array_aux(tree->root, array, 0, include_item);
|
||||||
|
array[pos] = NULL;
|
||||||
|
|
||||||
|
array = realloc(array, (pos + 1) * sizeof(void*));
|
||||||
|
if (size) {
|
||||||
|
*size = pos;
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBISO_IMAGE_WRITER_H_
|
||||||
|
#define LIBISO_IMAGE_WRITER_H_
|
||||||
|
|
||||||
|
#include "ecma119.h"
|
||||||
|
|
||||||
|
struct Iso_Image_Writer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int (*compute_data_blocks)(IsoImageWriter *writer);
|
||||||
|
|
||||||
|
int (*write_vol_desc)(IsoImageWriter *writer);
|
||||||
|
|
||||||
|
int (*write_data)(IsoImageWriter *writer);
|
||||||
|
|
||||||
|
int (*free_data)(IsoImageWriter *writer);
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
Ecma119Image *target;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the function all Writers shoudl call to write data to image.
|
||||||
|
* Currently, it is just a wrapper for write(2) Unix system call.
|
||||||
|
*
|
||||||
|
* It is implemented in ecma119.c
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 on sucess, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_write(Ecma119Image *target, void *buf, size_t count);
|
||||||
|
|
||||||
|
int ecma119_writer_create(Ecma119Image *target);
|
||||||
|
|
||||||
|
#endif /*LIBISO_IMAGE_WRITER_H_*/
|
|
@ -0,0 +1,378 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fsource.h"
|
||||||
|
#include "mocked_fsrc.h"
|
||||||
|
#include "libisofs.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
struct mock_file *path_to_node(IsoFilesystem *fs, const char *path);
|
||||||
|
|
||||||
|
static
|
||||||
|
char *get_path_aux(struct mock_file *file)
|
||||||
|
{
|
||||||
|
if (file->parent == NULL) {
|
||||||
|
return strdup("");
|
||||||
|
} else {
|
||||||
|
char *path = get_path_aux(file->parent);
|
||||||
|
int pathlen = strlen(path);
|
||||||
|
path = realloc(path, pathlen + strlen(file->name) + 2);
|
||||||
|
path[pathlen] = '/';
|
||||||
|
path[pathlen + 1] = '\0';
|
||||||
|
return strcat(path, file->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
char* mfs_get_path(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
struct mock_file *data;
|
||||||
|
data = src->data;
|
||||||
|
return get_path_aux(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
char* mfs_get_name(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
struct mock_file *data;
|
||||||
|
data = src->data;
|
||||||
|
return strdup(data->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mfs_lstat(IsoFileSource *src, struct stat *info)
|
||||||
|
{
|
||||||
|
struct mock_file *data;
|
||||||
|
|
||||||
|
if (src == NULL || info == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
data = src->data;
|
||||||
|
|
||||||
|
*info = data->atts;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mfs_stat(IsoFileSource *src, struct stat *info)
|
||||||
|
{
|
||||||
|
struct mock_file *node;
|
||||||
|
if (src == NULL || info == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
node = src->data;
|
||||||
|
|
||||||
|
while ( S_ISLNK(node->atts.st_mode) ) {
|
||||||
|
/* the destination is stated */
|
||||||
|
node = path_to_node(node->fs, (char *)node->content);
|
||||||
|
if (node == NULL) {
|
||||||
|
return ISO_FILE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*info = node->atts;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mfs_access(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
// TODO not implemented
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mfs_open(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
// TODO not implemented
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mfs_close(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
// TODO not implemented
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mfs_read(IsoFileSource *src, void *buf, size_t count)
|
||||||
|
{
|
||||||
|
// TODO not implemented
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mfs_readdir(IsoFileSource *src, IsoFileSource **child)
|
||||||
|
{
|
||||||
|
// TODO not implemented
|
||||||
|
return ISO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mfs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
|
||||||
|
{
|
||||||
|
struct mock_file *data;
|
||||||
|
|
||||||
|
if (src == NULL || buf == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufsiz <= 0) {
|
||||||
|
return ISO_WRONG_ARG_VALUE;
|
||||||
|
}
|
||||||
|
data = src->data;
|
||||||
|
|
||||||
|
if (!S_ISLNK(data->atts.st_mode)) {
|
||||||
|
return ISO_FILE_IS_NOT_SYMLINK;
|
||||||
|
}
|
||||||
|
strncpy(buf, data->content, bufsiz);
|
||||||
|
buf[bufsiz-1] = '\0';
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
IsoFilesystem* mfs_get_filesystem(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
struct mock_file *data;
|
||||||
|
data = src->data;
|
||||||
|
return data->fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void mfs_free(IsoFileSource *src)
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
IsoFileSourceIface mfs_class = {
|
||||||
|
0,
|
||||||
|
mfs_get_path,
|
||||||
|
mfs_get_name,
|
||||||
|
mfs_lstat,
|
||||||
|
mfs_stat,
|
||||||
|
mfs_access,
|
||||||
|
mfs_open,
|
||||||
|
mfs_close,
|
||||||
|
mfs_read,
|
||||||
|
mfs_readdir,
|
||||||
|
mfs_readlink,
|
||||||
|
mfs_get_filesystem,
|
||||||
|
mfs_free
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* 1 success, < 0 error
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
int mocked_file_source_new(struct mock_file *data, IsoFileSource **src)
|
||||||
|
{
|
||||||
|
IsoFileSource *mocked_src;
|
||||||
|
|
||||||
|
if (src == NULL || data == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate memory */
|
||||||
|
mocked_src = malloc(sizeof(IsoFileSource));
|
||||||
|
if (mocked_src == NULL) {
|
||||||
|
free(data);
|
||||||
|
return ISO_OUT_OF_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill struct */
|
||||||
|
mocked_src->refcount = 1;
|
||||||
|
mocked_src->data = data;
|
||||||
|
mocked_src->class = &mfs_class;
|
||||||
|
|
||||||
|
/* take a ref to filesystem */
|
||||||
|
//iso_filesystem_ref(fs);
|
||||||
|
|
||||||
|
/* return */
|
||||||
|
*src = mocked_src;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
struct mock_file *path_to_node(IsoFilesystem *fs, const char *path)
|
||||||
|
{
|
||||||
|
struct mock_file *node;
|
||||||
|
struct mock_file *dir;
|
||||||
|
char *ptr, *brk_info, *component;
|
||||||
|
|
||||||
|
/* get the first child at the root of the volume
|
||||||
|
* that is "/" */
|
||||||
|
dir = fs->data;
|
||||||
|
node = dir;
|
||||||
|
if (!strcmp(path, "/"))
|
||||||
|
return node;
|
||||||
|
|
||||||
|
ptr = strdup(path);
|
||||||
|
|
||||||
|
/* get the first component of the path */
|
||||||
|
component = strtok_r(ptr, "/", &brk_info);
|
||||||
|
while (component) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if ( !S_ISDIR(node->atts.st_mode) ) {
|
||||||
|
node=NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dir = node;
|
||||||
|
|
||||||
|
node=NULL;
|
||||||
|
if (!dir->content) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (((struct mock_file**)dir->content)[i]) {
|
||||||
|
if (!strcmp(component, ((struct mock_file**)dir->content)[i]->name)) {
|
||||||
|
node = ((struct mock_file**)dir->content)[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see if a node could be found */
|
||||||
|
if (node==NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
component = strtok_r(NULL, "/", &brk_info);
|
||||||
|
}
|
||||||
|
free(ptr);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void add_node(struct mock_file *parent, struct mock_file *node)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
if (parent->content) {
|
||||||
|
while (((struct mock_file**)parent->content)[i]) {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent->content = realloc(parent->content, (i+2) * sizeof(void*));
|
||||||
|
((struct mock_file**)parent->content)[i] = node;
|
||||||
|
((struct mock_file**)parent->content)[i+1] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mock_file *test_mocked_fs_get_root(IsoFilesystem *fs)
|
||||||
|
{
|
||||||
|
return fs->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_mocked_fs_add_dir(const char *name, struct mock_file *p,
|
||||||
|
struct stat atts, struct mock_file **node)
|
||||||
|
{
|
||||||
|
struct mock_file *dir = calloc(1, sizeof(struct mock_file));
|
||||||
|
dir->fs = p->fs;
|
||||||
|
dir->atts = atts;
|
||||||
|
dir->name = strdup(name);
|
||||||
|
dir->parent = p;
|
||||||
|
add_node(p, dir);
|
||||||
|
|
||||||
|
*node = dir;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_mocked_fs_add_symlink(const char *name, struct mock_file *p,
|
||||||
|
struct stat atts, const char *dest, struct mock_file **node)
|
||||||
|
{
|
||||||
|
struct mock_file *link = calloc(1, sizeof(struct mock_file));
|
||||||
|
link->fs = p->fs;
|
||||||
|
link->atts = atts;
|
||||||
|
link->name = strdup(name);
|
||||||
|
link->parent = p;
|
||||||
|
add_node(p, link);
|
||||||
|
link->content = strdup(dest);
|
||||||
|
*node = link;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mocked_get_root(IsoFilesystem *fs, IsoFileSource **root)
|
||||||
|
{
|
||||||
|
if (fs == NULL || root == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
return mocked_file_source_new(fs->data, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int mocked_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file)
|
||||||
|
{
|
||||||
|
struct mock_file *f;
|
||||||
|
if (fs == NULL || path == NULL || file == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
f = path_to_node(fs, path);
|
||||||
|
return mocked_file_source_new(f, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void free_mocked_file(struct mock_file *file)
|
||||||
|
{
|
||||||
|
if (S_ISDIR(file->atts.st_mode)) {
|
||||||
|
if (file->content) {
|
||||||
|
int i = 0;
|
||||||
|
while (((struct mock_file**)file->content)[i]) {
|
||||||
|
free_mocked_file(((struct mock_file**)file->content)[i]);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(file->content);
|
||||||
|
free(file->name);
|
||||||
|
free(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void mocked_fs_free(IsoFilesystem *fs)
|
||||||
|
{
|
||||||
|
free_mocked_file((struct mock_file *)fs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_mocked_filesystem_new(IsoFilesystem **fs)
|
||||||
|
{
|
||||||
|
struct mock_file *root;
|
||||||
|
IsoFilesystem *filesystem;
|
||||||
|
|
||||||
|
if (fs == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
root = calloc(1, sizeof(struct mock_file));
|
||||||
|
root->atts.st_atime = time(NULL);
|
||||||
|
root->atts.st_ctime = time(NULL);
|
||||||
|
root->atts.st_mtime = time(NULL);
|
||||||
|
root->atts.st_uid = 0;
|
||||||
|
root->atts.st_gid = 0;
|
||||||
|
root->atts.st_mode = S_IFDIR | 0777;
|
||||||
|
|
||||||
|
filesystem = malloc(sizeof(IsoFilesystem));
|
||||||
|
filesystem->refcount = 1;
|
||||||
|
root->fs = filesystem;
|
||||||
|
filesystem->data = root;
|
||||||
|
filesystem->get_root = mocked_get_root;
|
||||||
|
filesystem->get_by_path = mocked_get_by_path;
|
||||||
|
filesystem->free = mocked_fs_free;
|
||||||
|
*fs = filesystem;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Mocked objects to simulate an input filesystem.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MOCKED_FSRC_H_
|
||||||
|
#define MOCKED_FSRC_H_
|
||||||
|
|
||||||
|
struct mock_file {
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
struct mock_file *parent;
|
||||||
|
struct stat atts;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* for links, link dest. For dirs, children */
|
||||||
|
void *content;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mocked fs.
|
||||||
|
*/
|
||||||
|
int test_mocked_filesystem_new(IsoFilesystem **fs);
|
||||||
|
|
||||||
|
struct mock_file *test_mocked_fs_get_root(IsoFilesystem *fs);
|
||||||
|
|
||||||
|
int test_mocked_fs_add_dir(const char *name, struct mock_file *parent,
|
||||||
|
struct stat atts, struct mock_file **dir);
|
||||||
|
|
||||||
|
int test_mocked_fs_add_symlink(const char *name, struct mock_file *p,
|
||||||
|
struct stat atts, const char *dest, struct mock_file **node);
|
||||||
|
|
||||||
|
#endif /*MOCKED_FSRC_H_*/
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
static void create_test_suite()
|
||||||
|
{
|
||||||
|
add_node_suite();
|
||||||
|
add_image_suite();
|
||||||
|
add_tree_suite();
|
||||||
|
add_util_suite();
|
||||||
|
add_rockridge_suite();
|
||||||
|
add_stream_suite();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/* 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();
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef TEST_H_
|
||||||
|
#define TEST_H_
|
||||||
|
|
||||||
|
#include <CUnit/Basic.h>
|
||||||
|
#include "libisofs.h"
|
||||||
|
|
||||||
|
void add_node_suite();
|
||||||
|
void add_image_suite();
|
||||||
|
void add_tree_suite();
|
||||||
|
void add_util_suite();
|
||||||
|
void add_rockridge_suite();
|
||||||
|
void add_stream_suite();
|
||||||
|
|
||||||
|
#endif /*TEST_H_*/
|
|
@ -0,0 +1,354 @@
|
||||||
|
/*
|
||||||
|
* Unit test for image.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "test.h"
|
||||||
|
#include "image.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_image_new()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NOT_NULL(image);
|
||||||
|
CU_ASSERT_EQUAL(image->refcount, 1);
|
||||||
|
CU_ASSERT_PTR_NOT_NULL(image->root);
|
||||||
|
|
||||||
|
CU_ASSERT_STRING_EQUAL(image->volume_id, "volume_id");
|
||||||
|
CU_ASSERT_STRING_EQUAL(image->volset_id, "volume_id");
|
||||||
|
|
||||||
|
CU_ASSERT_PTR_NULL(image->publisher_id);
|
||||||
|
CU_ASSERT_PTR_NULL(image->data_preparer_id);
|
||||||
|
CU_ASSERT_PTR_NULL(image->system_id);
|
||||||
|
CU_ASSERT_PTR_NULL(image->application_id);
|
||||||
|
CU_ASSERT_PTR_NULL(image->copyright_file_id);
|
||||||
|
CU_ASSERT_PTR_NULL(image->abstract_file_id);
|
||||||
|
CU_ASSERT_PTR_NULL(image->biblio_file_id);
|
||||||
|
|
||||||
|
//CU_ASSERT_PTR_NULL(image->bootcat);
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_set_volume_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *volid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_STRING_EQUAL(image->volume_id, "volume_id");
|
||||||
|
|
||||||
|
volid = "new volume id";
|
||||||
|
iso_image_set_volume_id(image, volid);
|
||||||
|
CU_ASSERT_STRING_EQUAL(image->volume_id, "new volume id");
|
||||||
|
|
||||||
|
/* check string was strdup'ed */
|
||||||
|
CU_ASSERT_PTR_NOT_EQUAL(image->volume_id, volid);
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_get_volume_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *volid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_STRING_EQUAL(iso_image_get_volume_id(image), "volume_id");
|
||||||
|
|
||||||
|
volid = "new volume id";
|
||||||
|
iso_image_set_volume_id(image, volid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( iso_image_get_volume_id(image), "new volume id" );
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_set_publisher_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *pubid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->publisher_id);
|
||||||
|
|
||||||
|
pubid = "new publisher id";
|
||||||
|
iso_image_set_publisher_id(image, pubid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( image->publisher_id, "new publisher id" );
|
||||||
|
|
||||||
|
/* check string was strdup'ed */
|
||||||
|
CU_ASSERT_PTR_NOT_EQUAL( image->publisher_id, pubid );
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_get_publisher_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *pubid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->publisher_id);
|
||||||
|
|
||||||
|
pubid = "new publisher id";
|
||||||
|
iso_image_set_publisher_id(image, pubid);
|
||||||
|
CU_ASSERT_STRING_EQUAL(iso_image_get_publisher_id(image), "new publisher id");
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_set_data_preparer_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *dpid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->data_preparer_id);
|
||||||
|
|
||||||
|
dpid = "new data preparer id";
|
||||||
|
iso_image_set_data_preparer_id(image, dpid);
|
||||||
|
CU_ASSERT_STRING_EQUAL(image->data_preparer_id, "new data preparer id");
|
||||||
|
|
||||||
|
/* check string was strdup'ed */
|
||||||
|
CU_ASSERT_PTR_NOT_EQUAL(image->data_preparer_id, dpid);
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_get_data_preparer_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *dpid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->data_preparer_id);
|
||||||
|
|
||||||
|
dpid = "new data preparer id";
|
||||||
|
iso_image_set_data_preparer_id(image, dpid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( iso_image_get_data_preparer_id(image), "new data preparer id" );
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_set_system_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *sysid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->system_id);
|
||||||
|
|
||||||
|
sysid = "new system id";
|
||||||
|
iso_image_set_system_id(image, sysid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( image->system_id, "new system id" );
|
||||||
|
|
||||||
|
/* check string was strdup'ed */
|
||||||
|
CU_ASSERT_PTR_NOT_EQUAL( image->system_id, sysid );
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_get_system_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *sysid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(iso_image_get_system_id(image));
|
||||||
|
|
||||||
|
sysid = "new system id";
|
||||||
|
iso_image_set_system_id(image, sysid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( iso_image_get_system_id(image), "new system id" );
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_set_application_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *appid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->application_id);
|
||||||
|
|
||||||
|
appid = "new application id";
|
||||||
|
iso_image_set_application_id(image, appid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( image->application_id, "new application id" );
|
||||||
|
|
||||||
|
/* check string was strdup'ed */
|
||||||
|
CU_ASSERT_PTR_NOT_EQUAL( image->application_id, appid );
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_get_application_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *appid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(iso_image_get_application_id(image));
|
||||||
|
|
||||||
|
appid = "new application id";
|
||||||
|
iso_image_set_application_id(image, appid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( iso_image_get_application_id(image), "new application id" );
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_set_copyright_file_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *copid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->copyright_file_id);
|
||||||
|
|
||||||
|
copid = "new copyright id";
|
||||||
|
iso_image_set_copyright_file_id(image, copid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( image->copyright_file_id, "new copyright id" );
|
||||||
|
|
||||||
|
/* check string was strdup'ed */
|
||||||
|
CU_ASSERT_PTR_NOT_EQUAL( image->copyright_file_id, copid );
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_get_copyright_file_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *copid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(iso_image_get_copyright_file_id(image));
|
||||||
|
|
||||||
|
copid = "new copyright id";
|
||||||
|
iso_image_set_copyright_file_id(image, copid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( iso_image_get_copyright_file_id(image), "new copyright id" );
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_set_abstract_file_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *absid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->abstract_file_id);
|
||||||
|
|
||||||
|
absid = "new abstract id";
|
||||||
|
iso_image_set_abstract_file_id(image, absid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( image->abstract_file_id, "new abstract id" );
|
||||||
|
|
||||||
|
/* check string was strdup'ed */
|
||||||
|
CU_ASSERT_PTR_NOT_EQUAL( image->abstract_file_id, absid );
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_get_abstract_file_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *absid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(iso_image_get_abstract_file_id(image));
|
||||||
|
|
||||||
|
absid = "new abstract id";
|
||||||
|
iso_image_set_abstract_file_id(image, absid);
|
||||||
|
CU_ASSERT_STRING_EQUAL(iso_image_get_abstract_file_id(image), "new abstract id");
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_set_biblio_file_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *bibid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(image->biblio_file_id);
|
||||||
|
|
||||||
|
bibid = "new biblio id";
|
||||||
|
iso_image_set_biblio_file_id(image, bibid);
|
||||||
|
CU_ASSERT_STRING_EQUAL( image->biblio_file_id, "new biblio id" );
|
||||||
|
|
||||||
|
/* check string was strdup'ed */
|
||||||
|
CU_ASSERT_PTR_NOT_EQUAL( image->biblio_file_id, bibid );
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_iso_image_get_biblio_file_id()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoImage *image;
|
||||||
|
char *bibid;
|
||||||
|
|
||||||
|
ret = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
CU_ASSERT_PTR_NULL(iso_image_get_biblio_file_id(image));
|
||||||
|
|
||||||
|
bibid = "new biblio id";
|
||||||
|
iso_image_set_biblio_file_id(image, bibid);
|
||||||
|
CU_ASSERT_STRING_EQUAL(iso_image_get_biblio_file_id(image), "new biblio id");
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_image_suite()
|
||||||
|
{
|
||||||
|
CU_pSuite pSuite = CU_add_suite("imageSuite", NULL, NULL);
|
||||||
|
|
||||||
|
CU_add_test(pSuite, "iso_image_new()", test_iso_image_new);
|
||||||
|
CU_add_test(pSuite, "iso_image_set_volume_id()", test_iso_image_set_volume_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_get_volume_id()", test_iso_image_get_volume_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_set_publisher_id()", test_iso_image_set_publisher_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_get_publisher_id()", test_iso_image_get_publisher_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_set_data_preparer_id()", test_iso_image_set_data_preparer_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_get_data_preparer_id()", test_iso_image_get_data_preparer_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_set_system_id()", test_iso_image_set_system_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_get_system_id()", test_iso_image_get_system_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_set_application_id()", test_iso_image_set_application_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_get_application_id()", test_iso_image_get_application_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_set_copyright_file_id()", test_iso_image_set_copyright_file_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_get_copyright_file_id()", test_iso_image_get_copyright_file_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_set_abstract_file_id()", test_iso_image_set_abstract_file_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_get_abstract_file_id()", test_iso_image_get_abstract_file_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_set_biblio_file_id()", test_iso_image_set_biblio_file_id);
|
||||||
|
CU_add_test(pSuite, "iso_image_get_biblio_file_id()", test_iso_image_get_biblio_file_id);
|
||||||
|
}
|
|
@ -0,0 +1,690 @@
|
||||||
|
/*
|
||||||
|
* Unit test for node.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_new_root()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoDir *dir;
|
||||||
|
|
||||||
|
ret = iso_node_new_root(&dir);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_SUCCESS);
|
||||||
|
|
||||||
|
CU_ASSERT_EQUAL(dir->node.refcount, 1);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.mode, S_IFDIR | 0555);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.uid, 0);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.gid, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(dir->node.name);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.hidden, 0);
|
||||||
|
CU_ASSERT_PTR_EQUAL(dir->node.parent, dir);
|
||||||
|
CU_ASSERT_PTR_NULL(dir->node.next);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(dir->children);
|
||||||
|
|
||||||
|
iso_node_unref((IsoNode*)dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_new_dir()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoDir *dir;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
name = strdup("name1");
|
||||||
|
ret = iso_node_new_dir(name, &dir);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_SUCCESS);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.refcount, 1);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.mode, S_IFDIR);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.uid, 0);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.gid, 0);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.atime, 0);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.mtime, 0);
|
||||||
|
CU_ASSERT_EQUAL(dir->node.ctime, 0);
|
||||||
|
CU_ASSERT_STRING_EQUAL(dir->node.name, "name1");
|
||||||
|
CU_ASSERT_EQUAL(dir->node.hidden, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(dir->node.parent);
|
||||||
|
CU_ASSERT_PTR_NULL(dir->node.next);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(dir->children);
|
||||||
|
|
||||||
|
iso_node_unref((IsoNode*)dir);
|
||||||
|
|
||||||
|
/* try with invalid names */
|
||||||
|
ret = iso_node_new_dir("H/DHS/s", &dir);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_WRONG_ARG_VALUE);
|
||||||
|
ret = iso_node_new_dir(".", &dir);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_WRONG_ARG_VALUE);
|
||||||
|
ret = iso_node_new_dir("..", &dir);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_WRONG_ARG_VALUE);
|
||||||
|
ret = iso_node_new_dir(NULL, &dir);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_NULL_POINTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_new_symlink()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoSymlink *link;
|
||||||
|
char *name, *dest;
|
||||||
|
|
||||||
|
name = strdup("name1");
|
||||||
|
dest = strdup("/home");
|
||||||
|
ret = iso_node_new_symlink(name, dest, &link);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_SUCCESS);
|
||||||
|
CU_ASSERT_EQUAL(link->node.refcount, 1);
|
||||||
|
CU_ASSERT_EQUAL(link->node.type, LIBISO_SYMLINK);
|
||||||
|
CU_ASSERT_EQUAL(link->node.mode, S_IFLNK);
|
||||||
|
CU_ASSERT_EQUAL(link->node.uid, 0);
|
||||||
|
CU_ASSERT_EQUAL(link->node.gid, 0);
|
||||||
|
CU_ASSERT_EQUAL(link->node.atime, 0);
|
||||||
|
CU_ASSERT_EQUAL(link->node.mtime, 0);
|
||||||
|
CU_ASSERT_EQUAL(link->node.ctime, 0);
|
||||||
|
CU_ASSERT_STRING_EQUAL(link->node.name, "name1");
|
||||||
|
CU_ASSERT_EQUAL(link->node.hidden, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(link->node.parent);
|
||||||
|
CU_ASSERT_PTR_NULL(link->node.next);
|
||||||
|
CU_ASSERT_STRING_EQUAL(link->dest, "/home");
|
||||||
|
|
||||||
|
iso_node_unref((IsoNode*)link);
|
||||||
|
|
||||||
|
/* try with invalid names */
|
||||||
|
ret = iso_node_new_symlink("H/DHS/s", "/home", &link);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_WRONG_ARG_VALUE);
|
||||||
|
ret = iso_node_new_symlink(".", "/home", &link);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_WRONG_ARG_VALUE);
|
||||||
|
ret = iso_node_new_symlink("..", "/home", &link);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_WRONG_ARG_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_set_permissions()
|
||||||
|
{
|
||||||
|
IsoNode *node;
|
||||||
|
node = malloc(sizeof(IsoNode));
|
||||||
|
|
||||||
|
node->mode = S_IFDIR | 0777;
|
||||||
|
|
||||||
|
/* set permissions propertly */
|
||||||
|
iso_node_set_permissions(node, 0555);
|
||||||
|
CU_ASSERT_EQUAL(node->mode, S_IFDIR | 0555);
|
||||||
|
iso_node_set_permissions(node, 0640);
|
||||||
|
CU_ASSERT_EQUAL(node->mode, S_IFDIR | 0640);
|
||||||
|
|
||||||
|
/* try to change file type via this call */
|
||||||
|
iso_node_set_permissions(node, S_IFBLK | 0440);
|
||||||
|
CU_ASSERT_EQUAL(node->mode, S_IFDIR | 0440);
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_get_permissions()
|
||||||
|
{
|
||||||
|
IsoNode *node;
|
||||||
|
mode_t mode;
|
||||||
|
|
||||||
|
node = malloc(sizeof(IsoNode));
|
||||||
|
node->mode = S_IFDIR | 0777;
|
||||||
|
|
||||||
|
mode = iso_node_get_permissions(node);
|
||||||
|
CU_ASSERT_EQUAL(mode, 0777);
|
||||||
|
|
||||||
|
iso_node_set_permissions(node, 0640);
|
||||||
|
mode = iso_node_get_permissions(node);
|
||||||
|
CU_ASSERT_EQUAL(mode, 0640);
|
||||||
|
|
||||||
|
iso_node_set_permissions(node, S_IFBLK | 0440);
|
||||||
|
mode = iso_node_get_permissions(node);
|
||||||
|
CU_ASSERT_EQUAL(mode, 0440);
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_get_mode()
|
||||||
|
{
|
||||||
|
IsoNode *node;
|
||||||
|
mode_t mode;
|
||||||
|
|
||||||
|
node = malloc(sizeof(IsoNode));
|
||||||
|
node->mode = S_IFDIR | 0777;
|
||||||
|
|
||||||
|
mode = iso_node_get_mode(node);
|
||||||
|
CU_ASSERT_EQUAL(mode, S_IFDIR | 0777);
|
||||||
|
|
||||||
|
iso_node_set_permissions(node, 0640);
|
||||||
|
mode = iso_node_get_mode(node);
|
||||||
|
CU_ASSERT_EQUAL(mode, S_IFDIR | 0640);
|
||||||
|
|
||||||
|
iso_node_set_permissions(node, S_IFBLK | 0440);
|
||||||
|
mode = iso_node_get_mode(node);
|
||||||
|
CU_ASSERT_EQUAL(mode, S_IFDIR | 0440);
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_set_uid()
|
||||||
|
{
|
||||||
|
IsoNode *node;
|
||||||
|
node = malloc(sizeof(IsoNode));
|
||||||
|
|
||||||
|
node->uid = 0;
|
||||||
|
|
||||||
|
iso_node_set_uid(node, 23);
|
||||||
|
CU_ASSERT_EQUAL(node->uid, 23);
|
||||||
|
iso_node_set_uid(node, 0);
|
||||||
|
CU_ASSERT_EQUAL(node->uid, 0);
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_get_uid()
|
||||||
|
{
|
||||||
|
IsoNode *node;
|
||||||
|
uid_t uid;
|
||||||
|
|
||||||
|
node = malloc(sizeof(IsoNode));
|
||||||
|
node->uid = 0;
|
||||||
|
|
||||||
|
uid = iso_node_get_uid(node);
|
||||||
|
CU_ASSERT_EQUAL(uid, 0);
|
||||||
|
|
||||||
|
iso_node_set_uid(node, 25);
|
||||||
|
uid = iso_node_get_uid(node);
|
||||||
|
CU_ASSERT_EQUAL(uid, 25);
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_set_gid()
|
||||||
|
{
|
||||||
|
IsoNode *node;
|
||||||
|
node = malloc(sizeof(IsoNode));
|
||||||
|
|
||||||
|
node->gid = 0;
|
||||||
|
|
||||||
|
iso_node_set_gid(node, 23);
|
||||||
|
CU_ASSERT_EQUAL(node->gid, 23);
|
||||||
|
iso_node_set_gid(node, 0);
|
||||||
|
CU_ASSERT_EQUAL(node->gid, 0);
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_get_gid()
|
||||||
|
{
|
||||||
|
IsoNode *node;
|
||||||
|
gid_t gid;
|
||||||
|
|
||||||
|
node = malloc(sizeof(IsoNode));
|
||||||
|
node->gid = 0;
|
||||||
|
|
||||||
|
gid = iso_node_get_gid(node);
|
||||||
|
CU_ASSERT_EQUAL(gid, 0);
|
||||||
|
|
||||||
|
iso_node_set_gid(node, 25);
|
||||||
|
gid = iso_node_get_gid(node);
|
||||||
|
CU_ASSERT_EQUAL(gid, 25);
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_dir_add_node()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *dir;
|
||||||
|
IsoNode *node1, *node2, *node3, *node4, *node5;
|
||||||
|
|
||||||
|
/* init dir with default values, not all field need to be initialized */
|
||||||
|
dir = malloc(sizeof(IsoDir));
|
||||||
|
dir->children = NULL;
|
||||||
|
dir->nchildren = 0;
|
||||||
|
|
||||||
|
/* 1st node to be added */
|
||||||
|
node1 = calloc(1, sizeof(IsoNode));
|
||||||
|
node1->name = "Node1";
|
||||||
|
|
||||||
|
/* addition of node to an empty dir */
|
||||||
|
result = iso_dir_add_node(dir, node1, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(dir->children, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, dir);
|
||||||
|
|
||||||
|
/* addition of a node, to be inserted before */
|
||||||
|
node2 = calloc(1, sizeof(IsoNode));
|
||||||
|
node2->name = "A node to be added first";
|
||||||
|
|
||||||
|
result = iso_dir_add_node(dir, node2, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(dir->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->parent, dir);
|
||||||
|
|
||||||
|
/* addition of a node, to be inserted last */
|
||||||
|
node3 = calloc(1, sizeof(IsoNode));
|
||||||
|
node3->name = "This node will be inserted last";
|
||||||
|
|
||||||
|
result = iso_dir_add_node(dir, node3, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 3);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(dir->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->parent, dir);
|
||||||
|
|
||||||
|
/* force some failures */
|
||||||
|
result = iso_dir_add_node(NULL, node3, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
result = iso_dir_add_node(dir, NULL, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
|
||||||
|
result = iso_dir_add_node(dir, (IsoNode*)dir, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_WRONG_ARG_VALUE);
|
||||||
|
|
||||||
|
/* a node with same name */
|
||||||
|
node4 = calloc(1, sizeof(IsoNode));
|
||||||
|
node4->name = "This node will be inserted last";
|
||||||
|
result = iso_dir_add_node(dir, node4, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NODE_NAME_NOT_UNIQUE);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(dir->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->next);
|
||||||
|
CU_ASSERT_PTR_NULL(node4->parent);
|
||||||
|
|
||||||
|
/* a node already added to another dir should fail */
|
||||||
|
node5 = calloc(1, sizeof(IsoNode));
|
||||||
|
node5->name = "other node";
|
||||||
|
node5->parent = (IsoDir*)node4;
|
||||||
|
result = iso_dir_add_node(dir, node5, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NODE_ALREADY_ADDED);
|
||||||
|
|
||||||
|
free(node1);
|
||||||
|
free(node2);
|
||||||
|
free(node3);
|
||||||
|
free(node4);
|
||||||
|
free(node5);
|
||||||
|
free(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_dir_get_node()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *dir;
|
||||||
|
IsoNode *node1, *node2, *node3;
|
||||||
|
IsoNode *node;
|
||||||
|
|
||||||
|
/* init dir with default values, not all field need to be initialized */
|
||||||
|
dir = malloc(sizeof(IsoDir));
|
||||||
|
dir->children = NULL;
|
||||||
|
dir->nchildren = 0;
|
||||||
|
|
||||||
|
/* try to find a node in an empty dir */
|
||||||
|
result = iso_dir_get_node(dir, "a inexistent name", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
|
||||||
|
/* add a node */
|
||||||
|
node1 = calloc(1, sizeof(IsoNode));
|
||||||
|
node1->name = "Node1";
|
||||||
|
result = iso_dir_add_node(dir, node1, 0);
|
||||||
|
|
||||||
|
/* try to find a node not existent */
|
||||||
|
result = iso_dir_get_node(dir, "a inexistent name", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
|
||||||
|
/* and an existing one */
|
||||||
|
result = iso_dir_get_node(dir, "Node1", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||||
|
|
||||||
|
/* add another node */
|
||||||
|
node2 = calloc(1, sizeof(IsoNode));
|
||||||
|
node2->name = "A node to be added first";
|
||||||
|
result = iso_dir_add_node(dir, node2, 0);
|
||||||
|
|
||||||
|
/* try to find a node not existent */
|
||||||
|
result = iso_dir_get_node(dir, "a inexistent name", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
|
||||||
|
/* and the two existing */
|
||||||
|
result = iso_dir_get_node(dir, "Node1", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||||
|
result = iso_dir_get_node(dir, "A node to be added first", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||||
|
|
||||||
|
/* insert another node */
|
||||||
|
node3 = calloc(1, sizeof(IsoNode));
|
||||||
|
node3->name = "This node will be inserted last";
|
||||||
|
result = iso_dir_add_node(dir, node3, 0);
|
||||||
|
|
||||||
|
/* get again */
|
||||||
|
result = iso_dir_get_node(dir, "a inexistent name", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
result = iso_dir_get_node(dir, "This node will be inserted last", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node3);
|
||||||
|
|
||||||
|
/* force some failures */
|
||||||
|
result = iso_dir_get_node(NULL, "asas", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
result = iso_dir_get_node(dir, NULL, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
|
||||||
|
/* and try with null node */
|
||||||
|
result = iso_dir_get_node(dir, "asas", NULL);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
result = iso_dir_get_node(dir, "This node will be inserted last", NULL);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
free(node1);
|
||||||
|
free(node2);
|
||||||
|
free(node3);
|
||||||
|
free(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_iso_dir_get_children()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDirIter *iter;
|
||||||
|
IsoDir *dir;
|
||||||
|
IsoNode *node, *node1, *node2, *node3;
|
||||||
|
|
||||||
|
/* init dir with default values, not all field need to be initialized */
|
||||||
|
dir = malloc(sizeof(IsoDir));
|
||||||
|
dir->children = NULL;
|
||||||
|
dir->nchildren = 0;
|
||||||
|
|
||||||
|
result = iso_dir_get_children(dir, &iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* item should have no items */
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
iso_dir_iter_free(iter);
|
||||||
|
|
||||||
|
/* 1st node to be added */
|
||||||
|
node1 = calloc(1, sizeof(IsoNode));
|
||||||
|
node1->name = "Node1";
|
||||||
|
result = iso_dir_add_node(dir, node1, 0);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||||
|
|
||||||
|
/* test iteration again */
|
||||||
|
result = iso_dir_get_children(dir, &iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* iter should have a single item... */
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||||
|
|
||||||
|
/* ...and no more */
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
iso_dir_iter_free(iter);
|
||||||
|
|
||||||
|
/* add another node */
|
||||||
|
node2 = calloc(1, sizeof(IsoNode));
|
||||||
|
node2->name = "A node to be added first";
|
||||||
|
result = iso_dir_add_node(dir, node2, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
|
||||||
|
result = iso_dir_get_children(dir, &iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* iter should have two items... */
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||||
|
|
||||||
|
/* ...and no more */
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
iso_dir_iter_free(iter);
|
||||||
|
|
||||||
|
/* addition of a 3rd node, to be inserted last */
|
||||||
|
node3 = calloc(1, sizeof(IsoNode));
|
||||||
|
node3->name = "This node will be inserted last";
|
||||||
|
result = iso_dir_add_node(dir, node3, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 3);
|
||||||
|
|
||||||
|
result = iso_dir_get_children(dir, &iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* iter should have 3 items... */
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node3);
|
||||||
|
|
||||||
|
/* ...and no more */
|
||||||
|
result = iso_dir_iter_has_next(iter);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
result = iso_dir_iter_next(iter, &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
iso_dir_iter_free(iter);
|
||||||
|
|
||||||
|
free(node1);
|
||||||
|
free(node2);
|
||||||
|
free(node3);
|
||||||
|
free(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_iso_node_take()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *dir;
|
||||||
|
IsoNode *node1, *node2, *node3;
|
||||||
|
|
||||||
|
/* init dir with default values, not all field need to be initialized */
|
||||||
|
dir = malloc(sizeof(IsoDir));
|
||||||
|
dir->children = NULL;
|
||||||
|
dir->nchildren = 0;
|
||||||
|
|
||||||
|
/* 1st node to be added */
|
||||||
|
node1 = calloc(1, sizeof(IsoNode));
|
||||||
|
node1->name = "Node1";
|
||||||
|
|
||||||
|
/* addition of node to an empty dir */
|
||||||
|
result = iso_dir_add_node(dir, node1, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* and take it */
|
||||||
|
result = iso_node_take(node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(dir->children);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->parent);
|
||||||
|
|
||||||
|
/* insert it again */
|
||||||
|
result = iso_dir_add_node(dir, node1, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* addition of a 2nd node, to be inserted before */
|
||||||
|
node2 = calloc(1, sizeof(IsoNode));
|
||||||
|
node2->name = "A node to be added first";
|
||||||
|
result = iso_dir_add_node(dir, node2, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
|
||||||
|
/* take first child */
|
||||||
|
result = iso_node_take(node2);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(dir->children, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, dir);
|
||||||
|
CU_ASSERT_PTR_NULL(node2->next);
|
||||||
|
CU_ASSERT_PTR_NULL(node2->parent);
|
||||||
|
|
||||||
|
/* insert node 2 again */
|
||||||
|
result = iso_dir_add_node(dir, node2, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
|
||||||
|
/* now take last child */
|
||||||
|
result = iso_node_take(node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(dir->children, node2);
|
||||||
|
CU_ASSERT_PTR_NULL(node2->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->parent, dir);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->parent);
|
||||||
|
|
||||||
|
/* insert again node1... */
|
||||||
|
result = iso_dir_add_node(dir, node1, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
|
||||||
|
/* ...and a 3rd child, to be inserted last */
|
||||||
|
node3 = calloc(1, sizeof(IsoNode));
|
||||||
|
node3->name = "This node will be inserted last";
|
||||||
|
result = iso_dir_add_node(dir, node3, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 3);
|
||||||
|
|
||||||
|
/* and take the node in the middle */
|
||||||
|
result = iso_node_take(node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(dir->nchildren, 2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(dir->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->parent, dir);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->parent, dir);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->parent);
|
||||||
|
|
||||||
|
free(node1);
|
||||||
|
free(node2);
|
||||||
|
free(node3);
|
||||||
|
free(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_node_set_name()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *dir;
|
||||||
|
IsoNode *node1, *node2;
|
||||||
|
|
||||||
|
/* init dir with default values, not all field need to be initialized */
|
||||||
|
dir = malloc(sizeof(IsoDir));
|
||||||
|
dir->children = NULL;
|
||||||
|
dir->nchildren = 0;
|
||||||
|
|
||||||
|
/* cretae a node */
|
||||||
|
node1 = calloc(1, sizeof(IsoNode));
|
||||||
|
node1->name = strdup("Node1");
|
||||||
|
|
||||||
|
/* check name change */
|
||||||
|
result = iso_node_set_name(node1, "New name");
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node1->name, "New name");
|
||||||
|
|
||||||
|
/* add node dir */
|
||||||
|
result = iso_dir_add_node(dir, node1, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* check name change */
|
||||||
|
result = iso_node_set_name(node1, "Another name");
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node1->name, "Another name");
|
||||||
|
|
||||||
|
/* addition of a 2nd node */
|
||||||
|
node2 = calloc(1, sizeof(IsoNode));
|
||||||
|
node2->name = strdup("A node to be added first");
|
||||||
|
result = iso_dir_add_node(dir, node2, 0);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
|
||||||
|
result = iso_node_set_name(node2, "New name");
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->name, "New name");
|
||||||
|
|
||||||
|
/* and now try to give an existing name */
|
||||||
|
result = iso_node_set_name(node2, "Another name");
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NODE_NAME_NOT_UNIQUE);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->name, "New name");
|
||||||
|
|
||||||
|
free(node1->name);
|
||||||
|
free(node2->name);
|
||||||
|
free(node1);
|
||||||
|
free(node2);
|
||||||
|
free(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_node_suite()
|
||||||
|
{
|
||||||
|
CU_pSuite pSuite = CU_add_suite("Node Test Suite", NULL, NULL);
|
||||||
|
|
||||||
|
CU_add_test(pSuite, "iso_node_new_root()", test_iso_node_new_root);
|
||||||
|
CU_add_test(pSuite, "iso_node_new_dir()", test_iso_node_new_dir);
|
||||||
|
CU_add_test(pSuite, "iso_node_new_symlink()", test_iso_node_new_symlink);
|
||||||
|
CU_add_test(pSuite, "iso_node_set_permissions()", test_iso_node_set_permissions);
|
||||||
|
CU_add_test(pSuite, "iso_node_get_permissions()", test_iso_node_get_permissions);
|
||||||
|
CU_add_test(pSuite, "iso_node_get_mode()", test_iso_node_get_mode);
|
||||||
|
CU_add_test(pSuite, "iso_node_set_uid()", test_iso_node_set_uid);
|
||||||
|
CU_add_test(pSuite, "iso_node_get_uid()", test_iso_node_get_uid);
|
||||||
|
CU_add_test(pSuite, "iso_node_set_gid()", test_iso_node_set_gid);
|
||||||
|
CU_add_test(pSuite, "iso_node_get_gid()", test_iso_node_get_gid);
|
||||||
|
CU_add_test(pSuite, "iso_dir_add_node()", test_iso_dir_add_node);
|
||||||
|
CU_add_test(pSuite, "iso_dir_get_node()", test_iso_dir_get_node);
|
||||||
|
CU_add_test(pSuite, "iso_dir_get_children()", test_iso_dir_get_children);
|
||||||
|
CU_add_test(pSuite, "iso_node_take()", test_iso_node_take);
|
||||||
|
CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* Unit test for util.h
|
||||||
|
*
|
||||||
|
* This test utiliy functions
|
||||||
|
*/
|
||||||
|
#include "test.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_mem_new()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoStream *stream;
|
||||||
|
unsigned char *buf;
|
||||||
|
|
||||||
|
buf = malloc(3000);
|
||||||
|
ret = iso_memory_stream_new(buf, 3000, &stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
iso_stream_unref(stream);
|
||||||
|
|
||||||
|
ret = iso_memory_stream_new(NULL, 3000, &stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_NULL_POINTER);
|
||||||
|
|
||||||
|
ret = iso_memory_stream_new(buf, 3000, NULL);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_NULL_POINTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_mem_open()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoStream *stream;
|
||||||
|
unsigned char *buf;
|
||||||
|
|
||||||
|
buf = malloc(3000);
|
||||||
|
ret = iso_memory_stream_new(buf, 3000, &stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
ret = iso_stream_open(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
/* try to open an already opened stream */
|
||||||
|
ret = iso_stream_open(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_FILE_ALREADY_OPENNED);
|
||||||
|
|
||||||
|
ret = iso_stream_close(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
ret = iso_stream_close(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, ISO_FILE_NOT_OPENNED);
|
||||||
|
|
||||||
|
iso_stream_unref(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_mem_read()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
IsoStream *stream;
|
||||||
|
unsigned char *buf;
|
||||||
|
unsigned char rbuf[3000];
|
||||||
|
|
||||||
|
buf = malloc(3000);
|
||||||
|
memset(buf, 2, 200);
|
||||||
|
memset(buf + 200, 3, 300);
|
||||||
|
memset(buf + 500, 5, 500);
|
||||||
|
memset(buf + 1000, 10, 1000);
|
||||||
|
memset(buf + 2000, 56, 48);
|
||||||
|
memset(buf + 2048, 137, 22);
|
||||||
|
memset(buf + 2070, 13, 130);
|
||||||
|
memset(buf + 2200, 88, 800);
|
||||||
|
|
||||||
|
ret = iso_memory_stream_new(buf, 3000, &stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
/* test 1: read full buf */
|
||||||
|
ret = iso_stream_open(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
ret = iso_stream_read(stream, rbuf, 3000);
|
||||||
|
CU_ASSERT_EQUAL(ret, 3000);
|
||||||
|
CU_ASSERT_NSTRING_EQUAL(rbuf, buf, 3000);
|
||||||
|
|
||||||
|
/* read again is EOF */
|
||||||
|
ret = iso_stream_read(stream, rbuf, 20);
|
||||||
|
CU_ASSERT_EQUAL(ret, 0);
|
||||||
|
|
||||||
|
ret = iso_stream_close(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
/* test 2: read more than available bytes */
|
||||||
|
ret = iso_stream_open(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
ret = iso_stream_read(stream, rbuf, 3050);
|
||||||
|
CU_ASSERT_EQUAL(ret, 3000);
|
||||||
|
CU_ASSERT_NSTRING_EQUAL(rbuf, buf, 3000);
|
||||||
|
|
||||||
|
/* read again is EOF */
|
||||||
|
ret = iso_stream_read(stream, rbuf, 20);
|
||||||
|
CU_ASSERT_EQUAL(ret, 0);
|
||||||
|
|
||||||
|
ret = iso_stream_close(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
/* test 3: read in block size */
|
||||||
|
ret = iso_stream_open(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
ret = iso_stream_read(stream, rbuf, 2048);
|
||||||
|
CU_ASSERT_EQUAL(ret, 2048);
|
||||||
|
CU_ASSERT_NSTRING_EQUAL(rbuf, buf, 2048);
|
||||||
|
|
||||||
|
ret = iso_stream_read(stream, rbuf, 2048);
|
||||||
|
CU_ASSERT_EQUAL(ret, 3000 - 2048);
|
||||||
|
CU_ASSERT_NSTRING_EQUAL(rbuf, buf + 2048, 3000 - 2048);
|
||||||
|
|
||||||
|
ret = iso_stream_read(stream, rbuf, 20);
|
||||||
|
CU_ASSERT_EQUAL(ret, 0);
|
||||||
|
|
||||||
|
ret = iso_stream_close(stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
iso_stream_unref(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_mem_size()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
off_t size;
|
||||||
|
IsoStream *stream;
|
||||||
|
unsigned char *buf;
|
||||||
|
|
||||||
|
buf = malloc(3000);
|
||||||
|
ret = iso_memory_stream_new(buf, 3000, &stream);
|
||||||
|
CU_ASSERT_EQUAL(ret, 1);
|
||||||
|
|
||||||
|
size = iso_stream_get_size(stream);
|
||||||
|
CU_ASSERT_EQUAL(size, 3000);
|
||||||
|
|
||||||
|
iso_stream_unref(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_stream_suite()
|
||||||
|
{
|
||||||
|
CU_pSuite pSuite = CU_add_suite("IsoStreamSuite", NULL, NULL);
|
||||||
|
|
||||||
|
CU_add_test(pSuite, "iso_memory_stream_new()", test_mem_new);
|
||||||
|
CU_add_test(pSuite, "MemoryStream->open()", test_mem_open);
|
||||||
|
CU_add_test(pSuite, "MemoryStream->read()", test_mem_read);
|
||||||
|
CU_add_test(pSuite, "MemoryStream->get_size()", test_mem_size);
|
||||||
|
}
|
|
@ -0,0 +1,566 @@
|
||||||
|
/*
|
||||||
|
* Unit test for node.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libisofs.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
#include "mocked_fsrc.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_tree_add_new_dir()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *root;
|
||||||
|
IsoDir *node1, *node2, *node3, *node4;
|
||||||
|
IsoImage *image;
|
||||||
|
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
root = iso_image_get_root(image);
|
||||||
|
CU_ASSERT_PTR_NOT_NULL(root);
|
||||||
|
|
||||||
|
result = iso_tree_add_new_dir(root, "Dir1", &node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node1->node.type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node1->node.name, "Dir1");
|
||||||
|
|
||||||
|
/* creation of a second dir, to be inserted before */
|
||||||
|
result = iso_tree_add_new_dir(root, "A node to be added first", &node2);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node2->node.type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->node.name, "A node to be added first");
|
||||||
|
|
||||||
|
/* creation of a 3rd node, to be inserted last */
|
||||||
|
result = iso_tree_add_new_dir(root, "This node will be inserted last", &node3);
|
||||||
|
CU_ASSERT_EQUAL(result, 3);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node3->node.type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node3->node.name, "This node will be inserted last");
|
||||||
|
|
||||||
|
/* force some failures */
|
||||||
|
result = iso_tree_add_new_dir(NULL, "dsadas", &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
result = iso_tree_add_new_dir(root, NULL, &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
|
||||||
|
/* try to insert a new dir with same name */
|
||||||
|
result = iso_tree_add_new_dir(root, "This node will be inserted last", &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NODE_NAME_NOT_UNIQUE);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->node.next);
|
||||||
|
CU_ASSERT_PTR_NULL(node4);
|
||||||
|
|
||||||
|
/* but pointer to new dir can be null */
|
||||||
|
result = iso_tree_add_new_dir(root, "Another node", NULL);
|
||||||
|
CU_ASSERT_EQUAL(result, 4);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 4);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next->next, node1);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->node.next->name, "Another node");
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_tree_add_new_symlink()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *root;
|
||||||
|
IsoSymlink *node1, *node2, *node3, *node4;
|
||||||
|
IsoImage *image;
|
||||||
|
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
root = iso_image_get_root(image);
|
||||||
|
CU_ASSERT_PTR_NOT_NULL(root);
|
||||||
|
|
||||||
|
result = iso_tree_add_new_symlink(root, "Link1", "/path/to/dest", &node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node1->node.type, LIBISO_SYMLINK);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node1->node.name, "Link1");
|
||||||
|
CU_ASSERT_STRING_EQUAL(node1->dest, "/path/to/dest");
|
||||||
|
|
||||||
|
/* creation of a second link, to be inserted before */
|
||||||
|
result = iso_tree_add_new_symlink(root, "A node to be added first", "/home/me", &node2);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node2->node.type, LIBISO_SYMLINK);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->node.name, "A node to be added first");
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->dest, "/home/me");
|
||||||
|
|
||||||
|
/* creation of a 3rd node, to be inserted last */
|
||||||
|
result = iso_tree_add_new_symlink(root, "This node will be inserted last",
|
||||||
|
"/path/to/dest", &node3);
|
||||||
|
CU_ASSERT_EQUAL(result, 3);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node3->node.type, LIBISO_SYMLINK);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node3->node.name, "This node will be inserted last");
|
||||||
|
CU_ASSERT_STRING_EQUAL(node3->dest, "/path/to/dest");
|
||||||
|
|
||||||
|
/* force some failures */
|
||||||
|
result = iso_tree_add_new_symlink(NULL, "dsadas", "/path/to/dest", &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
result = iso_tree_add_new_symlink(root, NULL, "/path/to/dest", &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
result = iso_tree_add_new_symlink(root, "dsadas", NULL, &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
|
||||||
|
/* try to insert a new link with same name */
|
||||||
|
result = iso_tree_add_new_symlink(root, "This node will be inserted last", "/", &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NODE_NAME_NOT_UNIQUE);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->node.next);
|
||||||
|
CU_ASSERT_PTR_NULL(node4);
|
||||||
|
|
||||||
|
/* but pointer to new link can be null */
|
||||||
|
result = iso_tree_add_new_symlink(root, "Another node", ".", NULL);
|
||||||
|
CU_ASSERT_EQUAL(result, 4);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 4);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next->next, node1);
|
||||||
|
CU_ASSERT_EQUAL(node2->node.next->type, LIBISO_SYMLINK);
|
||||||
|
CU_ASSERT_STRING_EQUAL(((IsoSymlink*)(node2->node.next))->dest, ".");
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->node.next->name, "Another node");
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_tree_add_new_special()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *root;
|
||||||
|
IsoSpecial *node1, *node2, *node3, *node4;
|
||||||
|
IsoImage *image;
|
||||||
|
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
root = iso_image_get_root(image);
|
||||||
|
CU_ASSERT_PTR_NOT_NULL(root);
|
||||||
|
|
||||||
|
result = iso_tree_add_new_special(root, "Special1", S_IFSOCK | 0644, 0, &node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node1->node.type, LIBISO_SPECIAL);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node1->node.name, "Special1");
|
||||||
|
CU_ASSERT_EQUAL(node1->dev, 0);
|
||||||
|
CU_ASSERT_EQUAL(node1->node.mode, S_IFSOCK | 0644);
|
||||||
|
|
||||||
|
/* creation of a block dev, to be inserted before */
|
||||||
|
result = iso_tree_add_new_special(root, "A node to be added first", S_IFBLK | 0640, 34, &node2);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node2->node.type, LIBISO_SPECIAL);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->node.name, "A node to be added first");
|
||||||
|
CU_ASSERT_EQUAL(node2->dev, 34);
|
||||||
|
CU_ASSERT_EQUAL(node2->node.mode, S_IFBLK | 0640);
|
||||||
|
|
||||||
|
/* creation of a 3rd node, to be inserted last */
|
||||||
|
result = iso_tree_add_new_special(root, "This node will be inserted last",
|
||||||
|
S_IFCHR | 0440, 345, &node3);
|
||||||
|
CU_ASSERT_EQUAL(result, 3);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->node.next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->node.parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node3->node.type, LIBISO_SPECIAL);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node3->node.name, "This node will be inserted last");
|
||||||
|
CU_ASSERT_EQUAL(node3->dev, 345);
|
||||||
|
CU_ASSERT_EQUAL(node3->node.mode, S_IFCHR | 0440);
|
||||||
|
|
||||||
|
/* force some failures */
|
||||||
|
result = iso_tree_add_new_special(NULL, "dsadas", S_IFBLK | 0440, 345, &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
result = iso_tree_add_new_special(root, NULL, S_IFBLK | 0440, 345, &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NULL_POINTER);
|
||||||
|
result = iso_tree_add_new_special(root, "dsadas", S_IFDIR | 0666, 0, &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_WRONG_ARG_VALUE);
|
||||||
|
result = iso_tree_add_new_special(root, "dsadas", S_IFREG | 0666, 0, &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_WRONG_ARG_VALUE);
|
||||||
|
result = iso_tree_add_new_special(root, "dsadas", S_IFLNK | 0666, 0, &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_WRONG_ARG_VALUE);
|
||||||
|
|
||||||
|
/* try to insert a new special file with same name */
|
||||||
|
result = iso_tree_add_new_special(root, "This node will be inserted last", S_IFIFO | 0666, 0, &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, ISO_NODE_NAME_NOT_UNIQUE);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->node.next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->node.next);
|
||||||
|
CU_ASSERT_PTR_NULL(node4);
|
||||||
|
|
||||||
|
/* but pointer to new special can be null */
|
||||||
|
result = iso_tree_add_new_special(root, "Another node", S_IFIFO | 0666, 0, NULL);
|
||||||
|
CU_ASSERT_EQUAL(result, 4);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 4);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->node.next->next, node1);
|
||||||
|
CU_ASSERT_EQUAL(node2->node.next->type, LIBISO_SPECIAL);
|
||||||
|
CU_ASSERT_EQUAL(((IsoSpecial*)(node2->node.next))->dev, 0);
|
||||||
|
CU_ASSERT_EQUAL(node2->node.next->mode, S_IFIFO | 0666);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->node.next->name, "Another node");
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_tree_add_node_dir()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *root;
|
||||||
|
IsoNode *node1, *node2, *node3, *node4;
|
||||||
|
IsoImage *image;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
struct stat info;
|
||||||
|
struct mock_file *mroot, *dir1, *dir2;
|
||||||
|
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
root = iso_image_get_root(image);
|
||||||
|
CU_ASSERT_PTR_NOT_NULL(root);
|
||||||
|
|
||||||
|
/* replace image filesystem with out mockep one */
|
||||||
|
iso_filesystem_unref(image->fs);
|
||||||
|
result = test_mocked_filesystem_new(&fs);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
image->fs = fs;
|
||||||
|
mroot = test_mocked_fs_get_root(fs);
|
||||||
|
|
||||||
|
/* add some files to the filesystem */
|
||||||
|
info.st_mode = S_IFDIR | 0550;
|
||||||
|
info.st_uid = 20;
|
||||||
|
info.st_gid = 21;
|
||||||
|
info.st_atime = 234523;
|
||||||
|
info.st_ctime = 23432432;
|
||||||
|
info.st_mtime = 1111123;
|
||||||
|
result = test_mocked_fs_add_dir("dir", mroot, info, &dir1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
info.st_mode = S_IFDIR | 0555;
|
||||||
|
info.st_uid = 30;
|
||||||
|
info.st_gid = 31;
|
||||||
|
info.st_atime = 3234523;
|
||||||
|
info.st_ctime = 3234432;
|
||||||
|
info.st_mtime = 3111123;
|
||||||
|
result = test_mocked_fs_add_dir("a child node", dir1, info, &dir2);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
info.st_mode = S_IFDIR | 0750;
|
||||||
|
info.st_uid = 40;
|
||||||
|
info.st_gid = 41;
|
||||||
|
info.st_atime = 4234523;
|
||||||
|
info.st_ctime = 4234432;
|
||||||
|
info.st_mtime = 4111123;
|
||||||
|
result = test_mocked_fs_add_dir("another one", dir1, info, &dir2);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
info.st_mode = S_IFDIR | 0755;
|
||||||
|
info.st_uid = 50;
|
||||||
|
info.st_gid = 51;
|
||||||
|
info.st_atime = 5234523;
|
||||||
|
info.st_ctime = 5234432;
|
||||||
|
info.st_mtime = 5111123;
|
||||||
|
result = test_mocked_fs_add_dir("zzzz", mroot, info, &dir2);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* and now insert those files to the image */
|
||||||
|
result = iso_tree_add_node(image, root, "/dir", &node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node1->type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node1->name, "dir");
|
||||||
|
CU_ASSERT_EQUAL(node1->mode, S_IFDIR | 0550);
|
||||||
|
CU_ASSERT_EQUAL(node1->uid, 20);
|
||||||
|
CU_ASSERT_EQUAL(node1->gid, 21);
|
||||||
|
CU_ASSERT_EQUAL(node1->atime, 234523);
|
||||||
|
CU_ASSERT_EQUAL(node1->ctime, 23432432);
|
||||||
|
CU_ASSERT_EQUAL(node1->mtime, 1111123);
|
||||||
|
CU_ASSERT_PTR_NULL(((IsoDir*)node1)->children);
|
||||||
|
CU_ASSERT_EQUAL(((IsoDir*)node1)->nchildren, 0);
|
||||||
|
|
||||||
|
result = iso_tree_add_node(image, root, "/dir/a child node", &node2);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node2->type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->name, "a child node");
|
||||||
|
CU_ASSERT_EQUAL(node2->mode, S_IFDIR | 0555);
|
||||||
|
CU_ASSERT_EQUAL(node2->uid, 30);
|
||||||
|
CU_ASSERT_EQUAL(node2->gid, 31);
|
||||||
|
CU_ASSERT_EQUAL(node2->atime, 3234523);
|
||||||
|
CU_ASSERT_EQUAL(node2->ctime, 3234432);
|
||||||
|
CU_ASSERT_EQUAL(node2->mtime, 3111123);
|
||||||
|
CU_ASSERT_PTR_NULL(((IsoDir*)node2)->children);
|
||||||
|
CU_ASSERT_EQUAL(((IsoDir*)node2)->nchildren, 0);
|
||||||
|
|
||||||
|
result = iso_tree_add_node(image, root, "/dir/another one", &node3);
|
||||||
|
CU_ASSERT_EQUAL(result, 3);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->next, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node3->type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node3->name, "another one");
|
||||||
|
CU_ASSERT_EQUAL(node3->mode, S_IFDIR | 0750);
|
||||||
|
CU_ASSERT_EQUAL(node3->uid, 40);
|
||||||
|
CU_ASSERT_EQUAL(node3->gid, 41);
|
||||||
|
CU_ASSERT_EQUAL(node3->atime, 4234523);
|
||||||
|
CU_ASSERT_EQUAL(node3->ctime, 4234432);
|
||||||
|
CU_ASSERT_EQUAL(node3->mtime, 4111123);
|
||||||
|
CU_ASSERT_PTR_NULL(((IsoDir*)node3)->children);
|
||||||
|
CU_ASSERT_EQUAL(((IsoDir*)node3)->nchildren, 0);
|
||||||
|
|
||||||
|
result = iso_tree_add_node(image, root, "/zzzz", &node4);
|
||||||
|
CU_ASSERT_EQUAL(result, 4);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 4);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->next, node4);
|
||||||
|
CU_ASSERT_PTR_NULL(node4->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node4->parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node4->type, LIBISO_DIR);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node4->name, "zzzz");
|
||||||
|
CU_ASSERT_EQUAL(node4->mode, S_IFDIR | 0755);
|
||||||
|
CU_ASSERT_EQUAL(node4->uid, 50);
|
||||||
|
CU_ASSERT_EQUAL(node4->gid, 51);
|
||||||
|
CU_ASSERT_EQUAL(node4->atime, 5234523);
|
||||||
|
CU_ASSERT_EQUAL(node4->ctime, 5234432);
|
||||||
|
CU_ASSERT_EQUAL(node4->mtime, 5111123);
|
||||||
|
CU_ASSERT_PTR_NULL(((IsoDir*)node4)->children);
|
||||||
|
CU_ASSERT_EQUAL(((IsoDir*)node4)->nchildren, 0);
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_tree_add_node_link()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *root;
|
||||||
|
IsoNode *node1, *node2, *node3;
|
||||||
|
IsoImage *image;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
struct stat info;
|
||||||
|
struct mock_file *mroot, *link;
|
||||||
|
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
root = iso_image_get_root(image);
|
||||||
|
CU_ASSERT_PTR_NOT_NULL(root);
|
||||||
|
|
||||||
|
/* replace image filesystem with out mockep one */
|
||||||
|
iso_filesystem_unref(image->fs);
|
||||||
|
result = test_mocked_filesystem_new(&fs);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
image->fs = fs;
|
||||||
|
mroot = test_mocked_fs_get_root(fs);
|
||||||
|
|
||||||
|
/* add some files to the filesystem */
|
||||||
|
info.st_mode = S_IFLNK | 0777;
|
||||||
|
info.st_uid = 12;
|
||||||
|
info.st_gid = 13;
|
||||||
|
info.st_atime = 123444;
|
||||||
|
info.st_ctime = 123555;
|
||||||
|
info.st_mtime = 123666;
|
||||||
|
result = test_mocked_fs_add_symlink("link1", mroot, info, "/home/me", &link);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
info.st_mode = S_IFLNK | 0555;
|
||||||
|
info.st_uid = 22;
|
||||||
|
info.st_gid = 23;
|
||||||
|
info.st_atime = 223444;
|
||||||
|
info.st_ctime = 223555;
|
||||||
|
info.st_mtime = 223666;
|
||||||
|
result = test_mocked_fs_add_symlink("another link", mroot, info, "/", &link);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
info.st_mode = S_IFLNK | 0750;
|
||||||
|
info.st_uid = 32;
|
||||||
|
info.st_gid = 33;
|
||||||
|
info.st_atime = 323444;
|
||||||
|
info.st_ctime = 323555;
|
||||||
|
info.st_mtime = 323666;
|
||||||
|
result = test_mocked_fs_add_symlink("this will be the last", mroot, info, "/etc", &link);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* and now insert those files to the image */
|
||||||
|
result = iso_tree_add_node(image, root, "/link1", &node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node1->type, LIBISO_SYMLINK);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node1->name, "link1");
|
||||||
|
CU_ASSERT_EQUAL(node1->mode, S_IFLNK | 0777);
|
||||||
|
CU_ASSERT_EQUAL(node1->uid, 12);
|
||||||
|
CU_ASSERT_EQUAL(node1->gid, 13);
|
||||||
|
CU_ASSERT_EQUAL(node1->atime, 123444);
|
||||||
|
CU_ASSERT_EQUAL(node1->ctime, 123555);
|
||||||
|
CU_ASSERT_EQUAL(node1->mtime, 123666);
|
||||||
|
CU_ASSERT_STRING_EQUAL(((IsoSymlink*)node1)->dest, "/home/me");
|
||||||
|
|
||||||
|
result = iso_tree_add_node(image, root, "/another link", &node2);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node1);
|
||||||
|
CU_ASSERT_PTR_NULL(node1->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node2->type, LIBISO_SYMLINK);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node2->name, "another link");
|
||||||
|
CU_ASSERT_EQUAL(node2->mode, S_IFLNK | 0555);
|
||||||
|
CU_ASSERT_EQUAL(node2->uid, 22);
|
||||||
|
CU_ASSERT_EQUAL(node2->gid, 23);
|
||||||
|
CU_ASSERT_EQUAL(node2->atime, 223444);
|
||||||
|
CU_ASSERT_EQUAL(node2->ctime, 223555);
|
||||||
|
CU_ASSERT_EQUAL(node2->mtime, 223666);
|
||||||
|
CU_ASSERT_STRING_EQUAL(((IsoSymlink*)node2)->dest, "/");
|
||||||
|
|
||||||
|
result = iso_tree_add_node(image, root, "/this will be the last", &node3);
|
||||||
|
CU_ASSERT_EQUAL(result, 3);
|
||||||
|
CU_ASSERT_EQUAL(root->nchildren, 3);
|
||||||
|
CU_ASSERT_PTR_EQUAL(root->children, node2);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->next, node1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->next, node3);
|
||||||
|
CU_ASSERT_PTR_NULL(node3->next);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node1->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node2->parent, root);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node3->parent, root);
|
||||||
|
CU_ASSERT_EQUAL(node3->type, LIBISO_SYMLINK);
|
||||||
|
CU_ASSERT_STRING_EQUAL(node3->name, "this will be the last");
|
||||||
|
CU_ASSERT_EQUAL(node3->mode, S_IFLNK | 0750);
|
||||||
|
CU_ASSERT_EQUAL(node3->uid, 32);
|
||||||
|
CU_ASSERT_EQUAL(node3->gid, 33);
|
||||||
|
CU_ASSERT_EQUAL(node3->atime, 323444);
|
||||||
|
CU_ASSERT_EQUAL(node3->ctime, 323555);
|
||||||
|
CU_ASSERT_EQUAL(node3->mtime, 323666);
|
||||||
|
CU_ASSERT_STRING_EQUAL(((IsoSymlink*)node3)->dest, "/etc");
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void test_iso_tree_path_to_node()
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IsoDir *root;
|
||||||
|
IsoDir *node1, *node2, *node11;
|
||||||
|
IsoNode *node;
|
||||||
|
IsoImage *image;
|
||||||
|
IsoFilesystem *fs;
|
||||||
|
|
||||||
|
result = iso_image_new("volume_id", &image);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
root = iso_image_get_root(image);
|
||||||
|
CU_ASSERT_PTR_NOT_NULL(root);
|
||||||
|
|
||||||
|
/* replace image filesystem with out mockep one */
|
||||||
|
iso_filesystem_unref(image->fs);
|
||||||
|
result = test_mocked_filesystem_new(&fs);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
image->fs = fs;
|
||||||
|
|
||||||
|
/* add some files */
|
||||||
|
result = iso_tree_add_new_dir(root, "Dir1", &node1);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
result = iso_tree_add_new_dir(root, "Dir2", (IsoDir**)&node2);
|
||||||
|
CU_ASSERT_EQUAL(result, 2);
|
||||||
|
result = iso_tree_add_new_dir((IsoDir*)node1, "Dir11", (IsoDir**)&node11);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
|
||||||
|
/* retrive some items */
|
||||||
|
result = iso_tree_path_to_node(image, "/", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, root);
|
||||||
|
result = iso_tree_path_to_node(image, "/Dir1", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node1);
|
||||||
|
result = iso_tree_path_to_node(image, "/Dir2", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node2);
|
||||||
|
result = iso_tree_path_to_node(image, "/Dir1/Dir11", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(node, node11);
|
||||||
|
|
||||||
|
/* some failtures */
|
||||||
|
result = iso_tree_path_to_node(image, "/Dir2/Dir11", &node);
|
||||||
|
CU_ASSERT_EQUAL(result, 0);
|
||||||
|
CU_ASSERT_PTR_NULL(node);
|
||||||
|
|
||||||
|
iso_image_unref(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_tree_suite()
|
||||||
|
{
|
||||||
|
CU_pSuite pSuite = CU_add_suite("Iso Tree Suite", NULL, NULL);
|
||||||
|
|
||||||
|
CU_add_test(pSuite, "iso_tree_add_new_dir()", test_iso_tree_add_new_dir);
|
||||||
|
CU_add_test(pSuite, "iso_tree_add_new_symlink()", test_iso_tree_add_new_symlink);
|
||||||
|
CU_add_test(pSuite, "iso_tree_add_new_special()", test_iso_tree_add_new_special);
|
||||||
|
CU_add_test(pSuite, "iso_tree_add_node() [1. dir]", test_iso_tree_add_node_dir);
|
||||||
|
CU_add_test(pSuite, "iso_tree_add_node() [2. symlink]", test_iso_tree_add_node_link);
|
||||||
|
CU_add_test(pSuite, "iso_tree_path_to_node()", test_iso_tree_path_to_node);
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue