diff --git a/libisoburn/branches/XorrisoZeroOneTwo/AUTHORS b/libisoburn/branches/XorrisoZeroOneTwo/AUTHORS
new file mode 100644
index 00000000..0547ea18
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/AUTHORS
@@ -0,0 +1,3 @@
+Thomas Schmitt
+Vreixo Formoso Lopes
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/CONTRIBUTORS b/libisoburn/branches/XorrisoZeroOneTwo/CONTRIBUTORS
new file mode 100644
index 00000000..e69de29b
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/COPYING b/libisoburn/branches/XorrisoZeroOneTwo/COPYING
new file mode 100644
index 00000000..5a965fbc
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/COPYING
@@ -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
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/COPYRIGHT b/libisoburn/branches/XorrisoZeroOneTwo/COPYRIGHT
new file mode 100644
index 00000000..104853d2
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/COPYRIGHT
@@ -0,0 +1,23 @@
+Mario Danic ,
+Vreixo Formoso
+Thomas Schmitt
+libisoburn is Copyright (C) 2007-2008 Vreixo Formoso, Thomas Schmitt
+xorriso is Copyright (C) 2007-2008 Thomas Schmitt
+libisofs (if included) is Copyright (C) 2007-2008 Vreixo Formoso, Mario Danic
+libburn (if included) is Copyright (C) 2002-2006 Derek Foreman, Ben Jansens
+ and Copyright (C) 2006-2008 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
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/INSTALL b/libisoburn/branches/XorrisoZeroOneTwo/INSTALL
new file mode 100644
index 00000000..a6580e5a
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/INSTALL
@@ -0,0 +1,237 @@
+
+See file README for libisoburn and xorriso specific installation instructions.
+This file here is rather a manual for advanced usage of ./configure
+
+-------------------------------------------------------------------
+
+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.
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/Makefile.am b/libisoburn/branches/XorrisoZeroOneTwo/Makefile.am
new file mode 100644
index 00000000..e1b4711a
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/Makefile.am
@@ -0,0 +1,131 @@
+pkgconfigdir=$(libdir)/pkgconfig
+libincludedir=$(includedir)/libisoburn
+
+lib_LTLIBRARIES = libisoburn/libisoburn.la
+
+## ========================================================================= ##
+
+# Build libraries
+libisoburn_libisoburn_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+libisoburn_libisoburn_la_SOURCES = \
+ libisoburn/burn_wrap.c \
+ libisoburn/data_source.c \
+ libisoburn/isoburn.c \
+ libisoburn/isoburn.h \
+ libisoburn/isofs_wrap.c \
+ libisoburn/libisoburn.h \
+ version.h
+libisoburn_libisoburn_la_LIBADD = \
+ -lisofs \
+ -lburn
+libinclude_HEADERS = \
+ libisoburn/libisoburn.h
+
+## ========================================================================= ##
+
+
+# This is the reference application of libisoburn. See man xorriso/xorriso.1
+#
+bin_PROGRAMS = \
+ xorriso/xorriso
+
+xorriso_xorriso_CPPFLAGS = -Ilibisoburn
+xorriso_xorriso_CFLAGS = -DXorriso_with_maiN -DXorriso_with_regeX $(READLINE_DEF)
+xorriso_xorriso_LDADD = libisoburn/libisoburn.la -lisofs -lburn $(THREAD_LIBS)
+xorriso_xorriso_SOURCES = \
+ xorriso/xorriso.h \
+ xorriso/xorriso_private.h \
+ xorriso/xorriso.c \
+ xorriso/xorrisoburn.h \
+ xorriso/xorrisoburn.c \
+ xorriso/xorriso_timestamp.h
+
+
+## Build test applications
+noinst_PROGRAMS = \
+ test/compare_file
+
+# A program to compare two files in mirrored trees in mounted filesystems
+# To compare tree /media/dvd and /original/dir :
+# find /media/dvd -exec test/compare_file '{}' /media/dvd /original/dir ';'
+#
+test_compare_file_CPPFLAGS =
+test_compare_file_CFLAGS =
+test_compare_file_LDADD =
+test_compare_file_SOURCES = test/compare_file.c
+
+# ts A80110 - A80210 : we need as minimal demo something better than test.c
+# test/test
+
+# test_test_CPPFLAGS = -Ilibisofs -Ilibburn -Ilibisoburn
+# test_test_LDADD = $(libisoburn_libisoburn_la_OBJECTS) $(THREAD_LIBS) -lburn -lisofs
+# test_test_SOURCES = test/test.c
+
+
+## ========================================================================= ##
+
+## Build documentation (You need Doxygen for this to work)
+webhost = http://libburn-api.pykix.org
+webpath = /
+docdir = $(DESTDIR)$(prefix)/share/doc/$(PACKAGE)-$(VERSION)
+
+doc: doc/html
+
+doc/html: doc/doxygen.conf
+ if [ -f ./doc/doc.lock ]; then \
+ $(RM) -r doc/html; \
+ doxygen doc/doxygen.conf; \
+ fi
+
+doc-upload: doc/html
+ scp -r $* $(webhost):$(webpath)
+
+all: doc
+
+install-data-local:
+ if [ -f ./doc/doc.lock ]; then \
+ $(mkinstalldirs) $(docdir)/html; \
+ $(INSTALL_DATA) doc/html/* $(docdir)/html; \
+ fi
+
+uninstall-local:
+ rm -rf $(docdir)
+
+## ========================================================================= ##
+
+# Indent source files
+indent_files = \
+ $(libisoburn_libisoburn_la_SOURCES)
+
+
+indent: $(indent_files)
+ indent -bad -bap -nbbb -nbbo -nbc -bli0 -br -bls \
+ -cdw -ce -cli0 -ncs -nbfda -i8 -l79 -lc79 \
+ -lp -saf -sai -nprs -npsl -saw -sob -ss -ut \
+ -sbi0 -nsc -ts8 -npcs -ncdb -fca \
+ $^
+
+.PHONY: indent
+
+## ========================================================================= ##
+
+# Extra things
+nodist_pkgconfig_DATA = \
+ libisoburn-1.pc
+
+man_MANS = xorriso/xorriso.1
+
+EXTRA_DIST = \
+ libisoburn-1.pc.in \
+ version.h.in \
+ README \
+ AUTHORS \
+ CONTRIBUTORS \
+ COPYRIGHT \
+ COPYING \
+ INSTALL \
+ xorriso/changelog.txt \
+ xorriso/README \
+ $(man_MANS)
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/README b/libisoburn/branches/XorrisoZeroOneTwo/README
new file mode 100644
index 00000000..f08ffb65
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/README
@@ -0,0 +1,152 @@
+------------------------------------------------------------------------------
+ libburnia-project.org
+------------------------------------------------------------------------------
+libisoburn. By Vreixo Formoso
+ and Thomas Schmitt
+Integrated sub project of libburnia-project.org.
+Copyright (C) 2006-2008 Vreixo Formoso, Thomas Schmitt.
+Provided under GPL version 2.
+------------------------------------------------------------------------------
+
+libisoburn is a frontend for libraries libburn and libisofs which enables
+creation and expansion of ISO-9660 filesystems on all CD/DVD media supported
+by libburn. This includes media like DVD+RW, which do not support multi-session
+management on media level and even plain disk files or block devices.
+
+The price for that is thorough specialization on data files in ISO-9660
+filesystem images. So libisoburn is not suitable for audio (CD-DA) or any
+other CD layout which does not entirely consist of ISO-9660 sessions.
+
+Currently it is only supported on Linux with kernels >= 2.4.
+
+By using this software you agree to the disclaimer at the end of this text:
+"... without even the implied warranty ..."
+
+
+ Compilation, First Glimpse, Installation
+
+Dynamic library and compile time header requirements for libisoburn-0.1.1 :
+- libburn.so.4 , version libburn-0.4.2 or higher
+- libisofs.so.6 , version libisofs-0.6.2 or higher
+libisoburn and xorriso will not start with libraries which are older than their
+headers seen at compile time. So compile in the oldest possible installation
+setup unless you have reason to enforce a newer bug fix level.
+
+Obtain libisoburn-0.1.1.tar.gz, take it to a directory of your choice and do:
+
+ tar xzf libisoburn-0.1.1.tar.gz
+ cd libisoburn-0.1.1
+
+Within that directory execute:
+
+ ./configure --prefix=/usr
+ make
+
+Then become superuser and execute
+ make install
+which will make available libisoburn.so.1 .
+
+For the API concepts and calls see
+ ./libisoburn/libisoburn.h
+as well as
+ /usr/lib/libisofs/libisofs.h
+ /usr/lib/libburn/libburn.h
+
+
+ xorriso
+
+libisoburn includes a command line and dialog application named xorriso,
+which offers a substantial part of libisoburn features to shell scripts and
+users. Its file xorriso/README describes a standlone tarball as first
+preference for xorriso installation.
+The installation described here produces a dynamically linked xorriso binary
+as described in chapter "libisoburn" at the end of that text.
+
+After installation documentation is available via
+ man xorriso
+
+
+ Drives and Disk File Objects
+
+The user of libisoburn applications needs rw-permission for the CD/DVD burner
+devices which shall be used.
+A list of rw-accessible drives can be obtained by
+ xorriso -devices
+resp. by libburn API call
+ burn_drive_scan()
+
+
+A possible source of problems are hald or other automounters.
+If you can spot a process "hald-addon-storage" with the address of
+your desired drive, then consider to kill it.
+
+If you cannot get rid of the automounter that easily, try whether it helps
+to always load the drive tray manually before starting a write run of
+xorriso. Wait until the drive light is off.
+Better try to unmount an eventually mounted media before a write run.
+
+
+Besides true optical drives, libisoburn can also address disk files as input or
+output drives. The addresses of the disk files have to be preceded by "stdio:".
+Like:
+ "stdio:/tmp/pseudo_drive"
+
+
+ Testing
+
+We are quite sure that libisofs produces accurate representations of the disk
+files. This opinion is founded on a lot of test burns and checks by a little
+test program which compares files from the mounted image with the orignals
+on disk. It uses the normal POSIX filesystem calls, i.e. no libburnia stuff.
+
+This program is not installed systemwide but stays in the installation
+directory of the xorriso tarball as test/compare_file . Usually it is
+run as -exec payload of a find command. It demands at least three arguments:
+The path of the first file to compare, the prefix1 to be cut off from path
+and the prefix2 which gets prepended afterwards to obtain the path of the
+second file to compare.
+As further argument there can be -no_ctime which suppresses the comparison
+of ctime date stamps.
+The exit value is 0 if no difference was detected, non-0 else.
+
+Example: After
+ xorriso ... -pathspecs on -add /=/original/dir --
+ mount /media/dvd
+ cd test
+compare tree /media/dvd with tree /original/dir :
+ find /original/dir -exec ./compare_file '{}' /original/dir /media/dvd ';' \
+ | less
+and vice versa:
+ find /media/dvd -exec ./compare_file '{}' /media/dvd /original/dir ';' \
+ | less
+
+
+------------------------------------------------------------------------------
+
+ This program is free software; 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.
+
+ 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
+
+------------------------------------------------------------------------------
+Based on and sub project of:
+libburnia-project.org
+By Mario Danic ,
+ Vreixo Formoso
+ Thomas Schmitt
+Copyright (C) 2006-2008 Mario Danic, Vreixo Formoso, Thomas Schmitt.
+
+libburnia-project.org is inspired by and in other components still containing
+parts of old
+Libburn. By Derek Foreman and
+ Ben Jansens
+Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/TODO b/libisoburn/branches/XorrisoZeroOneTwo/TODO
new file mode 100644
index 00000000..23e3b643
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/TODO
@@ -0,0 +1,11 @@
+[Task] Figure out how to use "Requires" in pc.in (libisoburn and libisofs would benefit)
+[Task] Figure out the usage of Libs.private (used in libburn)
+[Task] Improve build system
+[Task] Investigate build system, so other libburnia components can benefit
+[Task] Write Doxygen files
+[Task] Explain to Thomas & Vreixo about NEWS importance (all libburnia components
+ will benefit
+[Task] Write a document about ABI & API
+[Task] Create following targets for make: Src, Indent, Docs, Test, All [Any other suggestions?)
+
+All those tasks are currently assigned to Mario.
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/acinclude.m4 b/libisoburn/branches/XorrisoZeroOneTwo/acinclude.m4
new file mode 100644
index 00000000..861847bb
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/acinclude.m4
@@ -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])
+])
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/bootstrap b/libisoburn/branches/XorrisoZeroOneTwo/bootstrap
new file mode 100755
index 00000000..3583d1c7
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/bootstrap
@@ -0,0 +1,7 @@
+#!/bin/sh -x
+
+aclocal
+libtoolize --copy --force
+autoconf
+automake --foreign --add-missing --copy --include-deps
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/configure.ac b/libisoburn/branches/XorrisoZeroOneTwo/configure.ac
new file mode 100644
index 00000000..9f4e0af8
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/configure.ac
@@ -0,0 +1,125 @@
+AC_INIT([libisoburn], [0.1.1], [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 The API version codes are now defined in libisoburn/libisoburn.h
+dnl #define isoburn_header_version_*
+dnl configure.ac only rules the libtool revision numbering about
+dnl LT_CURREN, LT_AGE, LT_REVISION where SONAME becomes LT_CURRENT - LT_AGE
+dnl
+dnl These three are only copies to provide libtool with unused LT_RELEASE
+ISOBURN_MAJOR_VERSION=0
+ISOBURN_MINOR_VERSION=1
+ISOBURN_MICRO_VERSION=1
+dnl ISOBURN_VERSION=$ISOBURN_MAJOR_VERSION.$ISOBURN_MINOR_VERSION.$ISOBURN_MICRO_VERSION
+
+AC_SUBST(ISOBURN_MAJOR_VERSION)
+AC_SUBST(ISOBURN_MINOR_VERSION)
+AC_SUBST(ISOBURN_MICRO_VERSION)
+dnl AC_SUBST(ISOBURN_VERSION)
+
+dnl Libtool versioning
+dnl Generate libisoburn.so.1.x.y
+dnl SONAME will become LT_CURRENT - LT_AGE
+dnl
+dnl ts A80215
+dnl This is the developmen t version after stable release libisoburn.so.1.1.0
+dnl LT_CURRENT++, LT_AGE++ has not happened yet.
+dnl
+dnl SONAME = 2 - 1 = 1 . Library name = libburn.so.1.1.1
+LT_RELEASE=$ISOBURN_MAJOR_VERSION.$ISOBURN_MINOR_VERSION
+LT_CURRENT=2
+LT_AGE=1
+LT_REVISION=1
+LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
+
+AC_SUBST(LT_RELEASE)
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+AC_SUBST(LT_AGE)
+AC_SUBST(LT_CURRENT_MINUS_AGE)
+
+AC_PREFIX_DEFAULT([/usr/local])
+test "$prefix" = "NONE" && prefix=$ac_default_prefix
+
+AM_MAINTAINER_MODE
+
+AM_PROG_CC_C_O
+AC_C_CONST
+AC_C_INLINE
+AC_C_BIGENDIAN
+
+dnl Large file support
+AC_SYS_LARGEFILE
+AC_FUNC_FSEEKO
+AC_CHECK_FUNC([fseeko])
+if test ! $ac_cv_func_fseeko; then
+ AC_ERROR([Libburn requires largefile support.])
+fi
+
+AC_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+LIBTOOL="$LIBTOOL --silent"
+
+AC_PROG_INSTALL
+
+AC_CHECK_HEADERS()
+
+THREAD_LIBS=-lpthread
+AC_SUBST(THREAD_LIBS)
+
+TARGET_SHIZZLE
+AC_SUBST(ARCH)
+AC_SUBST(LIBBURN_ARCH_LIBS)
+
+
+dnl Check whether there is readline-devel and readline-runtime.
+dnl If not, erase this macro which would enable use of readline(),add_history()
+READLINE_DEF="-DXorriso_with_readlinE"
+dnl The empty yes case obviously causes -lreadline to be linked
+AC_CHECK_HEADER(readline/readline.h, AC_CHECK_LIB(readline, readline, , READLINE_DEF= ), READLINE_DEF= )
+dnl The X= in the yes case prevents that -lreadline gets linked twice
+AC_CHECK_HEADER(readline/history.h, AC_CHECK_LIB(readline, add_history, X= , READLINE_DEF= ), READLINE_DEF= )
+AC_SUBST(READLINE_DEF)
+
+
+AC_CHECK_HEADER(libburn/libburn.h)
+AC_CHECK_HEADER(libisofs/libisofs.h)
+
+dnl Check for proper library versions
+LIBBURN_REQUIRED=0.4.2
+LIBISOFS_REQUIRED=0.6.2
+PKG_CHECK_MODULES(LIBBURN, libburn-1 >= $LIBBURN_REQUIRED)
+PKG_CHECK_MODULES(LIBISOFS, libisofs-1 >= $LIBISOFS_REQUIRED)
+
+dnl Add compiler-specific flags
+
+dnl See if the user wants aggressive optimizations of the code
+AC_ARG_ENABLE(debug,
+[ --enable-debug Disable aggressive optimizations [default=yes]],
+ , enable_debug=yes)
+if test x$enable_debug != xyes; then
+ if test x$GCC = xyes; then
+ CFLAGS="$CFLAGS -O3"
+ CFLAGS="$CFLAGS -fexpensive-optimizations"
+ fi
+ CFLAGS="$CFLAGS -DNDEBUG"
+else
+ if test x$GCC = xyes; then
+ CFLAGS="$CFLAGS -g -pedantic -Wall"
+ fi
+ CFLAGS="$CFLAGS -DDEBUG"
+fi
+
+AC_CONFIG_FILES([
+ Makefile
+ doc/doxygen.conf
+ version.h
+ libisoburn-1.pc
+ ])
+AC_OUTPUT
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/doc/doxygen.conf.in b/libisoburn/branches/XorrisoZeroOneTwo/doc/doxygen.conf.in
new file mode 100644
index 00000000..e36d6010
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/doc/doxygen.conf.in
@@ -0,0 +1,1300 @@
+# Doxyfile 1.5.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that
+# follow. The default is UTF-8 which is also the encoding used for all text before
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of
+# possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = @PACKAGE_NAME@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = @top_srcdir@
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = YES
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be extracted
+# and appear in the documentation as a namespace called 'anonymous_namespace{file}',
+# where file will be replaced with the base name of the file that contains the anonymous
+# namespace. By default anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command , where is the value of
+# the FILE_VERSION_FILTER tag, and is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text "
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = libburn \
+ doc \
+ test
+
+# This tag can be used to specify the character encoding of the source files that
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = libburn.h \
+ comments \
+ libburner.c
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the output.
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = test
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command , where
+# is the value of the INPUT_FILTER tag, and is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH
+# then you must also enable this option. If you don't then doxygen will produce
+# a warning and turn it on anyway
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX = OB \
+ OTK \
+ _
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = doc/html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 200
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = letter
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
+# be found in the default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = NO
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the number
+# of direct children of the root node in a graph is already larger than
+# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/libisoburn-1.pc.in b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn-1.pc.in
new file mode 100644
index 00000000..7fae3f90
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn-1.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libisoburn
+Description: Multi-session filesystem extension to libisofs, libburn.
+Version: @VERSION@
+Requires:
+Libs: -L${libdir} -lisoburn
+Cflags: -I${includedir}/libisoburn
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/burn_wrap.c b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/burn_wrap.c
new file mode 100644
index 00000000..de8c4a68
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/burn_wrap.c
@@ -0,0 +1,892 @@
+
+/*
+ cc -g -c \
+ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
+ burn_wrap.c
+*/
+/* libburn wrappers for libisoburn
+
+ Copyright 2007 Thomas Schmitt,
+*/
+
+/* <<< A70929 : hardcoded CD-RW with fabricated -msinfo
+#define Hardcoded_cd_rW 1
+#define Hardcoded_cd_rw_c1 12999
+#define Hardcoded_cd_rw_nwA 152660
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#ifndef Xorriso_standalonE
+
+#include
+
+#include
+
+#else /* ! Xorriso_standalonE */
+
+#include "../libisofs/libisofs.h"
+#include "../libburn/libburn.h"
+
+#endif /* Xorriso_standalonE */
+
+
+#include "libisoburn.h"
+#include "isoburn.h"
+
+
+/* The global list of isoburn objects. Usually there is only one. */
+extern struct isoburn *isoburn_list_start; /* in isoburn.c */
+
+
+int isoburn_initialize(char msg[1024], int flag)
+{
+ int major, minor, micro, bad_match= 0;
+
+
+/* First two ugly compile time checks for header version compatibility.
+ If everthing matches, then they produce no C code. In case of mismatch,
+ intentionally faulty C code will be inserted.
+*/
+
+#ifdef iso_lib_header_version_major
+/* The minimum requirement of libisoburn towards the libisofs header
+ at compile time is defined in libisoburn/libisoburn.h :
+ isoburn_libisofs_req_major
+ isoburn_libisofs_req_minor
+ isoburn_libisofs_req_micro
+ It gets compared against the version macros in libisofs/libisofs.h :
+ iso_lib_header_version_major
+ iso_lib_header_version_minor
+ iso_lib_header_version_micro
+ If the header is too old then the following code shall cause failure of
+ cdrskin compilation rather than to allow production of a program with
+ unpredictable bugs or memory corruption.
+ The compiler messages supposed to appear in this case are:
+ error: 'LIBISOFS_MISCONFIGURATION' undeclared (first use in this function)
+ error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h' undeclared (first use in this function)
+ error: 'LIBISOFS_MISCONFIGURATION_' undeclared (first use in this function)
+*/
+/* The indendation is an advise of man gcc to help old compilers ignoring */
+ #if isoburn_libisofs_req_major > iso_lib_header_version_major
+ #define Isoburn_libisofs_dot_h_too_olD 1
+ #endif
+ #if isoburn_libisofs_req_major == iso_lib_header_version_major && isoburn_libisofs_req_minor > iso_lib_header_version_minor
+ #define Isoburn_libisofs_dot_h_too_olD 1
+ #endif
+ #if isoburn_libisofs_req_minor == iso_lib_header_version_minor && isoburn_libisofs_req_micro > iso_lib_header_version_micro
+ #define Isoburn_libisofs_dot_h_too_olD 1
+ #endif
+
+#ifdef Isoburn_libisofs_dot_h_too_olD
+LIBISOFS_MISCONFIGURATION = 0;
+INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisofs_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0;
+LIBISOFS_MISCONFIGURATION_ = 0;
+#endif
+
+#endif /* iso_lib_header_version_major */
+
+/* The minimum requirement of libisoburn towards the libburn header
+ at compile time is defined in libisoburn/libisoburn.h :
+ isoburn_libburn_req_major
+ isoburn_libburn_req_minor
+ isoburn_libburn_req_micro
+ It gets compared against the version macros in libburn/libburn.h :
+ burn_header_version_major
+ burn_header_version_minor
+ burn_header_version_micro
+ If the header is too old then the following code shall cause failure of
+ cdrskin compilation rather than to allow production of a program with
+ unpredictable bugs or memory corruption.
+ The compiler messages supposed to appear in this case are:
+ error: 'LIBBURN_MISCONFIGURATION' undeclared (first use in this function)
+ error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h' undeclared (first use in this function)
+ error: 'LIBBURN_MISCONFIGURATION_' undeclared (first use in this function)
+*/
+
+/* The indendation is an advise of man gcc to help old compilers ignoring */
+ #if isoburn_libburn_req_major > burn_header_version_major
+ #define Isoburn_libburn_dot_h_too_olD 1
+ #endif
+ #if isoburn_libburn_req_major == burn_header_version_major && isoburn_libburn_req_minor > burn_header_version_minor
+ #define Isoburn_libburn_dot_h_too_olD 1
+ #endif
+ #if isoburn_libburn_req_minor == burn_header_version_minor && isoburn_libburn_req_micro > burn_header_version_micro
+ #define Isoburn_libburn_dot_h_too_olD 1
+ #endif
+
+#ifdef Isoburn_libburn_dot_h_too_olD
+LIBBURN_MISCONFIGURATION = 0;
+INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libburn_dot_h_TOO_OLD__SEE_libisoburn_dot_h_and_burn_wrap_dot_h = 0;
+LIBBURN_MISCONFIGURATION_ = 0;
+#endif
+
+/* End of ugly compile time tests (scroll up for explanation) */
+
+
+
+ msg[0]= 0;
+ if(iso_init()<0) {
+ sprintf(msg+strlen(msg), "Cannot initialize libisofs\n");
+ return(0);
+ }
+ iso_lib_version(&major, &minor, µ);
+ sprintf(msg+strlen(msg), "libisofs-%d.%d.%d ", major, minor, micro);
+#ifdef iso_lib_header_version_major
+ if(iso_lib_is_compatible(iso_lib_header_version_major,
+ iso_lib_header_version_minor,
+ iso_lib_header_version_micro)) {
+ sprintf(msg+strlen(msg), "ok, ");
+ } else {
+ sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
+ iso_lib_header_version_major, iso_lib_header_version_minor,
+ iso_lib_header_version_micro);
+ bad_match= 1;
+ }
+#else
+ if(iso_lib_is_compatible(isoburn_libisofs_req_major,
+ isoburn_libisofs_req_minor,
+ isoburn_libisofs_req_micro)) {
+ sprintf(msg+strlen(msg), "suspicious, ");
+ } else {
+ sprintf(msg+strlen(msg),"- TOO OLD -, need at least libisofs-%d.%d.%d ,\n",
+ isoburn_libisofs_req_major, isoburn_libisofs_req_minor,
+ isoburn_libisofs_req_micro);
+ bad_match= 1;
+ }
+#endif /* ! iso_lib_header_version_major */
+
+ if(!burn_initialize()) {
+ sprintf(msg+strlen(msg), "Cannot initialize libburn\n");
+ return(0);
+ }
+ burn_version(&major, &minor, µ);
+ sprintf(msg+strlen(msg), "libburn-%d.%d.%d ", major, minor, micro);
+ if(major > burn_header_version_major
+ || (major == burn_header_version_major
+ && (minor > burn_header_version_minor
+ || (minor == burn_header_version_minor
+ && micro >= burn_header_version_micro)))) {
+ sprintf(msg+strlen(msg), "ok, ");
+ } else {
+ sprintf(msg+strlen(msg), "- TOO OLD -, need at least libburn-%d.%d.%d ,\n",
+ burn_header_version_major, burn_header_version_minor,
+ burn_header_version_micro);
+ bad_match= 1;
+ }
+
+ isoburn_version(&major, &minor, µ);
+ sprintf(msg+strlen(msg), "for libisoburn-%d.%d.%d", major, minor, micro);
+ if(bad_match)
+ return(0);
+
+ isoburn_destroy_all(&isoburn_list_start, 0); /* isoburn_list_start= NULL */
+ return(1);
+}
+
+
+/* API @since 0.1.0 */
+int isoburn_libisofs_req(int *major, int *minor, int *micro)
+{
+ *major= iso_lib_header_version_major;
+ *minor= iso_lib_header_version_minor;
+ *micro= iso_lib_header_version_micro;
+ return(1);
+}
+
+
+/* API @since 0.1.0 */
+int isoburn_libburn_req(int *major, int *minor, int *micro)
+{
+ *major= burn_header_version_major;
+ *minor= burn_header_version_minor;
+ *micro= burn_header_version_micro;
+ return(1);
+}
+
+
+/** Examine the media and sets appropriate emulation if needed.
+ @param flag bit0= pretent blank on overwriteable media
+*/
+static int isoburn_welcome_media(struct isoburn **o, struct burn_drive *d,
+ int flag)
+{
+ int ret, lba, nwa;
+ struct burn_multi_caps *caps= NULL;
+
+ ret= burn_disc_get_multi_caps(d, BURN_WRITE_NONE, &caps, 0);
+ if(ret<0) /* == 0 is read-only media, but it is too early to reject it here */
+ goto ex;
+ ret= isoburn_new(o, 0);
+ if(ret<=0)
+ goto ex;
+ (*o)->drive= d;
+
+#ifdef Hardcoded_cd_rW
+ /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
+ caps->start_adr= 0;
+ (*o)->fabricated_disc_status= BURN_DISC_APPENDABLE;
+#endif
+
+ if(caps->start_adr) { /* set emulation to overwriteable */
+ (*o)->emulation_mode= 1;
+
+ if(flag&1) {
+ (*o)->nwa= 0;
+ (*o)->fabricated_disc_status= BURN_DISC_BLANK;
+ } else {
+ ret= isoburn_start_emulation(*o, 0);
+ if(ret<=0) {
+ (*o)->emulation_mode= -1;
+ goto ex;
+ }
+ }
+ } else {
+
+ /* >>> recognize unsuitable media (but allow read-only media) */;
+
+#ifdef Hardcoded_cd_rW
+ (*o)->nwa= Hardcoded_cd_rw_nwA;
+#else
+ ret= burn_disc_track_lba_nwa(d, NULL, 0, &lba, &nwa);
+ if(ret>0)
+ (*o)->nwa= nwa;
+#endif
+
+ }
+ ret= 1;
+ex:
+ if(caps!=NULL)
+ burn_disc_free_multi_caps(&caps);
+ return(ret);
+}
+
+
+/**
+ @param flag bit0= load
+ bit1= regard overwriteable media as blank
+ bit2= if the drive is a regular disk file: truncate it to
+ the write start address
+*/
+int isoburn_drive_aquire(struct burn_drive_info *drive_infos[],
+ char *adr, int flag)
+{
+ int ret, conv_ret, drive_grabbed= 0;
+ char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
+ struct isoburn *o= NULL;
+ char msg[BURN_MSGS_MESSAGE_LEN+4096];
+
+ conv_ret= burn_drive_convert_fs_adr(adr, libburn_drive_adr);
+ if(conv_ret<=0) {
+ sprintf(msg, "Unsuitable drive address: '%s'\n",adr);
+ msg[BURN_MSGS_MESSAGE_LEN-1]= 0;
+ burn_msgs_submit(0x00060000, msg, 0, "FAILURE", NULL);
+ ret= 0; goto ex;
+ }
+
+ ret= burn_drive_scan_and_grab(drive_infos, libburn_drive_adr, flag&1);
+ if(ret<=0)
+ goto ex;
+ drive_grabbed= 1;
+ ret= isoburn_welcome_media(&o, (*drive_infos)[0].drive, !!(flag&2));
+ if(ret<=0)
+ goto ex;
+
+ if(flag&4) {
+ ret= isoburn_find_emulator(&o, (*drive_infos)[0].drive, 0);
+ if(ret>0 && o!=NULL)
+ o->truncate= 1;
+ }
+
+ ret= 1;
+ex:
+ if(ret<=0) {
+ if(drive_grabbed)
+ burn_drive_release((*drive_infos)[0].drive, 0);
+ isoburn_destroy(&o, 0);
+ }
+ return(ret);
+}
+
+
+int isoburn_drive_scan_and_grab(struct burn_drive_info *drive_infos[],
+ char *adr, int load)
+{
+ int ret;
+
+ ret= isoburn_drive_aquire(drive_infos, adr, !!load);
+ return(ret);
+}
+
+
+int isoburn_drive_grab(struct burn_drive *drive, int load)
+{
+ int ret;
+ struct isoburn *o= NULL;
+
+ ret= burn_drive_grab(drive, load);
+ if(ret<=0)
+ goto ex;
+ ret= isoburn_welcome_media(&o, drive, 0);
+ if(ret<=0)
+ goto ex;
+
+ ret= 1;
+ex:
+ if(ret<=0)
+ isoburn_destroy(&o,0);
+ return(ret);
+}
+
+
+/** Retrieve media emulation and eventual isoburn emulator of drive.
+ @return -1 unsuitable media, 0 generic media, 1 emulated media.
+*/
+int isoburn_find_emulator(struct isoburn **pt,
+ struct burn_drive *drive, int flag)
+{
+ int ret;
+
+ ret= isoburn_find_by_drive(pt, drive, 0);
+ if(ret<=0)
+ return(0);
+ if((*pt)->emulation_mode==-1) {
+ burn_msgs_submit(0x00060000,
+ "Unsuitable drive and media state", 0, "FAILURE", NULL);
+ return(-1);
+ }
+ if((*pt)->emulation_mode==0)
+ return(0);
+ return(1);
+}
+
+
+enum burn_disc_status isoburn_disc_get_status(struct burn_drive *drive)
+{
+ int ret;
+ struct isoburn *o;
+
+ ret= isoburn_find_emulator(&o, drive, 0);
+ if(ret<0)
+ return(BURN_DISC_UNSUITABLE);
+ if(o!=NULL)
+ if(o->fabricated_disc_status!=BURN_DISC_UNREADY)
+ return(o->fabricated_disc_status);
+ if(ret==0)
+ return(burn_disc_get_status(drive));
+
+ /* emulated status */
+ if(o->emulation_mode==-1)
+ return(BURN_DISC_UNSUITABLE);
+ if(o->nwa>0)
+ return(BURN_DISC_APPENDABLE);
+ return(BURN_DISC_BLANK);
+}
+
+
+int isoburn_disc_erasable(struct burn_drive *d)
+{
+ int ret;
+ struct isoburn *o;
+
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret>0)
+ if(o->emulation_mode==1)
+ return(1);
+ return burn_disc_erasable(d);
+}
+
+
+void isoburn_disc_erase(struct burn_drive *drive, int fast)
+{
+ int ret;
+ struct isoburn *o;
+
+ ret= isoburn_find_emulator(&o, drive, 0);
+ if(ret>0) {
+ if(o->emulation_mode==-1) {
+ /* To cause a negative reply with burn_drive_wrote_well() */
+ burn_drive_cancel(drive);
+ return;
+ }
+ if(o->emulation_mode>0) {
+ ret= isoburn_invalidate_iso(o, 0);
+ if(ret<=0)
+ burn_drive_cancel(drive);
+ return;
+ }
+ }
+ burn_disc_erase(drive, fast);
+}
+
+
+off_t isoburn_disc_available_space(struct burn_drive *d,
+ struct burn_write_opts *opts)
+{
+ int ret;
+ struct isoburn *o;
+ off_t avail;
+
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret>0 && o!=NULL)
+ if(o->emulation_mode!=0)
+ burn_write_opts_set_start_byte(opts, ((off_t) o->nwa) * (off_t) 2048);
+ avail= burn_disc_available_space(d, opts);
+ return(avail);
+}
+
+
+int isoburn_disc_get_msc1(struct burn_drive *d, int *start_lba)
+{
+ int ret;
+ struct isoburn *o;
+
+#ifdef Hardcoded_cd_rW
+ /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
+ *start_lba= Hardcoded_cd_rw_c1;
+ return(1);
+#endif
+
+ if(isoburn_disc_get_status(d)!=BURN_DISC_APPENDABLE &&
+ isoburn_disc_get_status(d)!=BURN_DISC_FULL) {
+ burn_msgs_submit(0x00060000,
+ "Media contains no recognizable data", 0, "SORRY",NULL);
+ return(0);
+ }
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret<0)
+ return(0);
+ if(ret>0) if(o->emulation_mode>0) {
+ *start_lba= 0;
+ return(1);
+ }
+ return(burn_disc_get_msc1(d, start_lba));
+}
+
+
+int isoburn_disc_track_lba_nwa(struct burn_drive *d,
+ struct burn_write_opts *opts,
+ int trackno, int *lba, int *nwa)
+{
+ int ret;
+ struct isoburn *o;
+
+#ifdef Hardcoded_cd_rW
+ /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
+ *lba= Hardcoded_cd_rw_c1;
+ *nwa= Hardcoded_cd_rw_nwA;
+ return(1);
+#endif
+
+ *nwa= *lba= 0;
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret<0)
+ return(0);
+ if(ret>0) if(o->emulation_mode>0) {
+ *lba= 0;
+ *nwa= o->nwa;
+ return(1);
+ }
+ if(burn_drive_get_drive_role(d) != 1)
+ return(1);
+ return(burn_disc_track_lba_nwa(d, opts, trackno, lba, nwa));
+}
+
+
+void isoburn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
+{
+ int ret;
+ off_t nwa= 0;
+ struct isoburn *o;
+ struct burn_drive *drive;
+ char reasons[BURN_REASONS_LEN],msg[160+BURN_REASONS_LEN];
+ char adr[BURN_DRIVE_ADR_LEN];
+ enum burn_write_types write_type;
+ struct stat stbuf;
+
+ drive= burn_write_opts_get_drive(opts);
+ ret= isoburn_find_emulator(&o, drive, 0);
+ if(ret<0)
+ return;
+ if(o!=NULL) {
+ o->wrote_well= -1;
+ if(o->emulation_mode!=0) {
+ burn_write_opts_set_multi(opts, 0);
+ if(o->emulation_mode>0 && o->nwa >= 0) {
+ burn_write_opts_set_start_byte(opts, ((off_t) o->nwa) * (off_t) 2048);
+ nwa= o->nwa;
+ }
+ }
+ }
+
+ write_type= burn_write_opts_auto_write_type(opts, disc, reasons, 0);
+ if (write_type == BURN_WRITE_NONE) {
+ sprintf(msg, "Failed to find a suitable write mode:\n%s", reasons);
+ burn_msgs_submit(0x00060000, msg, 0, "FAILURE", NULL);
+ if(o!=NULL)
+ o->wrote_well= 0;
+ /* To cause a negative reply with burn_drive_wrote_well() */
+ burn_drive_cancel(drive);
+ return;
+ }
+
+/*
+ sprintf(reasons, "%d", (int) write_type);
+ fprintf(stderr, "isoburn_EXPERIMENTAL: write_type = %s\n",
+ (write_type == BURN_WRITE_SAO ? "SAO" :
+ (write_type == BURN_WRITE_TAO ? "TAO" : reasons)));
+*/
+
+#ifdef Hardcoded_cd_rW
+ /* <<< A70929 : hardcoded CD-RW with fabricated -msinfo */
+ fprintf(stderr, "Setting write address to LBA %d\n", Hardcoded_cd_rw_nwA);
+ burn_write_opts_set_start_byte(opts,
+ ((off_t) Hardcoded_cd_rw_nwA) * (off_t) 2048);
+#endif
+
+ if(o->truncate) {
+ ret= burn_drive_get_drive_role(drive);
+ if(ret==2) {
+ ret= burn_drive_d_get_adr(drive, adr);
+ if(ret>0) {
+ ret= lstat(adr, &stbuf);
+ if(ret!=-1)
+ if(S_ISREG(stbuf.st_mode))
+ truncate(adr, nwa * (off_t) 2048);
+ }
+ }
+ }
+
+ burn_disc_write(opts, disc);
+}
+
+
+void isoburn_drive_release(struct burn_drive *drive, int eject)
+{
+ int ret;
+ struct isoburn *o;
+
+ ret= isoburn_find_emulator(&o, drive, 0);
+ if(ret<0)
+ return;
+ if(o!=NULL) {
+ isoburn_destroy(&o, 0);
+ }
+ burn_drive_release(drive, eject);
+}
+
+
+void isoburn_finish(void)
+{
+ isoburn_destroy_all(&isoburn_list_start, 0);
+ burn_finish();
+ iso_finish();
+}
+
+
+int isoburn_needs_emulation(struct burn_drive *drive)
+{
+ int ret;
+ struct isoburn *o;
+ enum burn_disc_status s;
+
+ s= isoburn_disc_get_status(drive);
+ if(s!=BURN_DISC_BLANK && s!=BURN_DISC_APPENDABLE)
+ return(-1);
+ ret= isoburn_find_emulator(&o, drive, 0);
+ if(ret<0)
+ return(-1);
+ if(ret>0)
+ if(o->emulation_mode>0)
+ return(1);
+ return(0);
+}
+
+
+int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag)
+{
+ int ret;
+ struct burn_drive *drive = o->drive;
+ struct burn_multi_caps *caps= NULL;
+
+ ret= burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
+ if(ret<=0)
+ goto ex;
+ if(!caps->start_adr) {
+ burn_msgs_submit(0x00060000,
+ "Cannot set start byte address with this type of media",
+ 0, "FAILURE", NULL);
+ {ret= 0; goto ex;}
+ }
+ o->min_start_byte= value;
+ if(value % caps->start_alignment)
+ value+= caps->start_alignment - (value % caps->start_alignment);
+ o->nwa= value/2048;
+ /* If suitable for alignment, round up to full 16 sector addresses */
+ if((o->nwa%16) && ((16*2048) % caps->start_alignment)==0 )
+ o->nwa+= 16 - (o->nwa%16);
+ ret= 1;
+ex:
+ if(caps!=NULL)
+ burn_disc_free_multi_caps(&caps);
+ return(ret);
+}
+
+
+int isoburn_get_min_start_byte(struct burn_drive *d, off_t *start_byte,
+ int flag)
+{
+ int ret;
+ struct isoburn *o;
+
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret<0)
+ return(-1);
+ if(ret==0)
+ return(0);
+ *start_byte= o->min_start_byte;
+ if(o->min_start_byte<=0)
+ return(0);
+ return(1);
+}
+
+
+int isoburn_drive_wrote_well(struct burn_drive *d)
+{
+ int ret;
+ struct isoburn *o;
+
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret<0)
+ return(-1);
+ if(o!=NULL)
+ if(o->wrote_well>=0)
+ return(o->wrote_well);
+ ret= burn_drive_wrote_well(d);
+ return ret;
+}
+
+
+int isoburn_get_fifo_status(struct burn_drive *d, int *size, int *free_bytes,
+ char **status_text)
+{
+ int ret;
+ struct isoburn *o;
+#ifdef Libisoburn_no_fifO
+ size_t hsize= 0, hfree_bytes= 0;
+#endif
+
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret<0)
+ return(-1);
+
+#ifdef Libisoburn_no_fifO
+ if(o==NULL)
+ return(-1);
+ if(o->iso_source==NULL)
+ return(-1);
+ ret= iso_ring_buffer_get_status(o->iso_source, &hsize, &hfree_bytes);
+ if(hsize > 1024*1024*1024)
+ *size= 1024*1024*1024;
+ else
+ *size= hsize;
+ if(hfree_bytes > 1024*1024*1024)
+ *free_bytes= 1024*1024*1024;
+ else
+ *free_bytes= hfree_bytes;
+ *status_text= "";
+ if(ret==0)
+ *status_text= "standby";
+ else if(ret==1)
+ *status_text= "active";
+ else if(ret==2)
+ *status_text= "ending";
+ else if(ret==3)
+ *status_text= "failing";
+ else if(ret==4)
+ *status_text= "unused";
+ else if(ret==5)
+ *status_text= "abandoned";
+ else if(ret==6)
+ *status_text= "ended";
+ else if(ret==7)
+ *status_text= "aborted";
+#else
+ if(o==NULL)
+ return(0);
+ if(o->fifo==NULL)
+ return(0);
+ ret= burn_fifo_inquire_status(o->fifo, size, free_bytes, status_text);
+#endif /* ! Libisoburn_no_fifO */
+
+ return(ret);
+}
+
+
+#define Libisoburn_on_libisofs_after_0_6_2 yes
+
+/* >>> todo: throw out the copies of libdax_msgs entrails */
+
+/* <<< to be replaced by libburn-0.4.3 API call burn_sev_to_text().
+ This is a copy of libdax_msgs__sev_to_text() which is not exposed
+ by the API of of libburn-0.4.2 . As soon as xorriso gets based on
+ libburn-0.4.4 this redundancy is to be removed.
+ It is safe, nevertheless, because the severity codes are eternal.
+*/
+#define LIBDAX_MSGS_SEV_ALL 0x00000000
+#define LIBDAX_MSGS_SEV_ERRFILE 0x08000000
+#define LIBDAX_MSGS_SEV_DEBUG 0x10000000
+#define LIBDAX_MSGS_SEV_UPDATE 0x20000000
+#define LIBDAX_MSGS_SEV_NOTE 0x30000000
+#define LIBDAX_MSGS_SEV_HINT 0x40000000
+#define LIBDAX_MSGS_SEV_WARNING 0x50000000
+#define LIBDAX_MSGS_SEV_SORRY 0x60000000
+#define LIBDAX_MSGS_SEV_MISHAP 0x64000000
+#define LIBDAX_MSGS_SEV_FAILURE 0x68000000
+#define LIBDAX_MSGS_SEV_FATAL 0x70000000
+#define LIBDAX_MSGS_SEV_ABORT 0x71000000
+#define LIBDAX_MSGS_SEV_NEVER 0x7fffffff
+
+/* @param flag bit0= -reserved-
+ bit1= this is a libburn severity
+*/
+int isoburn__sev_to_text(int severity, char **severity_name,
+ int flag)
+{
+#ifdef Libisoburn_on_libisofs_after_0_6_2
+ int ret;
+#else
+#ifdef Libisoburn_on__libburn_after_0_4_2
+ int ret;
+#endif
+#endif
+
+#ifdef Libisoburn_on_libisofs_after_0_6_2
+ ret= iso_sev_to_text(severity, severity_name);
+ if(ret>0)
+ return(ret);
+#endif /* Libisoburn_on_libisofs_after_0_6_2 */
+#ifdef Libisoburn_on__libburn_after_0_4_2
+ ret= burn_sev_to_text(severity, severity_name, 0);
+ if(ret>0)
+ return(ret);
+#endif
+
+ if(flag&1) {
+ *severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL";
+ return(1);
+ }
+ *severity_name= "";
+ if(severity>=LIBDAX_MSGS_SEV_NEVER)
+ *severity_name= "NEVER";
+ else if(severity>=LIBDAX_MSGS_SEV_ABORT)
+ *severity_name= "ABORT";
+ else if(severity>=LIBDAX_MSGS_SEV_FATAL)
+ *severity_name= "FATAL";
+ else if(severity>=LIBDAX_MSGS_SEV_FAILURE)
+ *severity_name= "FAILURE";
+ else if(severity>=LIBDAX_MSGS_SEV_MISHAP)
+ *severity_name= "MISHAP";
+ else if(severity>=LIBDAX_MSGS_SEV_SORRY)
+ *severity_name= "SORRY";
+ else if(severity>=LIBDAX_MSGS_SEV_WARNING)
+ *severity_name= "WARNING";
+ else if(severity>=LIBDAX_MSGS_SEV_HINT)
+ *severity_name= "HINT";
+ else if(severity>=LIBDAX_MSGS_SEV_NOTE)
+ *severity_name= "NOTE";
+ else if(severity>=LIBDAX_MSGS_SEV_UPDATE)
+ *severity_name= "UPDATE";
+ else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
+ *severity_name= "DEBUG";
+ else if(severity>=LIBDAX_MSGS_SEV_ERRFILE)
+ *severity_name= "ERRFILE";
+ else if(severity>=LIBDAX_MSGS_SEV_ALL)
+ *severity_name= "ALL";
+ else {
+ *severity_name= "";
+ return(0);
+ }
+ return(1);
+}
+
+
+int isoburn__text_to_sev(char *severity_name, int *severity_number, int flag)
+{
+ int ret= 1;
+
+#ifdef Libisoburn_on_libisofs_after_0_6_2
+ ret= iso_text_to_sev(severity_name, severity_number);
+ if(ret>0)
+ return(ret);
+#endif /* Libisoburn_on_libisofs_after_0_6_2 */
+
+#ifndef Libisoburn_on__libburn_after_0_4_2
+ if(severity_name[0]==0)
+ *severity_number= 0;
+ else if(strcmp(severity_name, "MISHAP")==0)
+ *severity_number= LIBDAX_MSGS_SEV_MISHAP;
+ else if(strcmp(severity_name, "ERRFILE")==0)
+ *severity_number= LIBDAX_MSGS_SEV_ERRFILE;
+ else
+#endif /* ! Libisoburn_on__libburn_after_0_4_2 */
+
+ ret= burn_text_to_sev(severity_name, severity_number, 0);
+ return(ret);
+}
+
+
+int isoburn_report_iso_error(int iso_error_code, char msg_text[], int os_errno,
+ char min_severity[], int flag)
+{
+ int error_code, iso_sev, min_sev, ret;
+ char *sev_text_pt, *msg_text_pt= NULL;
+
+ error_code= iso_error_get_code(iso_error_code);
+ if(error_code < 0x00030000 || error_code >= 0x00040000)
+ error_code= (error_code & 0xffff) | 0x00050000;
+
+ if(iso_error_code<0)
+ msg_text_pt= (char *) iso_error_to_msg(iso_error_code);
+ if(msg_text_pt==NULL)
+ msg_text_pt= msg_text;
+ iso_sev= iso_error_get_severity(iso_error_code);
+ sev_text_pt= min_severity;
+
+#ifdef Libisoburn_on_libisofs_after_0_6_2
+
+ isoburn__text_to_sev(min_severity, &min_sev, 0);
+ if(min_sev < iso_sev)
+ isoburn__sev_to_text(iso_sev, &sev_text_pt, 0);
+ ret= iso_msgs_submit(error_code, msg_text_pt, os_errno, sev_text_pt, 0);
+
+#else
+
+ burn_text_to_sev(min_severity, &min_sev, 0);
+
+ /* <<< Tunnel MISHAP through libburn which knows no MISHAP
+ with libburn-0.4.4 this is not necessary */
+ if(iso_sev==LIBDAX_MSGS_SEV_MISHAP) {
+ iso_sev= LIBDAX_MSGS_SEV_SORRY;
+ error_code= 0x0005ff73;
+ } else if(iso_sev==LIBDAX_MSGS_SEV_ERRFILE) { /* same with ERRFILE */
+ iso_sev= LIBDAX_MSGS_SEV_DEBUG;
+ error_code= 0x00051001;
+ }
+ if(min_sev < iso_sev)
+ isoburn__sev_to_text(iso_sev, &sev_text_pt, 0);
+ ret= burn_msgs_submit(error_code, msg_text_pt, os_errno, sev_text_pt, NULL);
+
+#endif /* ! Libisoburn_on_libisofs_after_0_6_2 */
+
+ return(ret);
+}
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/data_source.c b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/data_source.c
new file mode 100644
index 00000000..01443086
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/data_source.c
@@ -0,0 +1,190 @@
+/*
+ data source for libisoburn.
+
+ Copyright 2007 Vreixo Formoso Lopes
+*/
+
+#include
+#include
+
+#include
+
+
+#ifndef Xorriso_standalonE
+
+#include
+
+#include
+
+#else /* ! Xorriso_standalonE */
+
+#include "../libisofs/libisofs.h"
+#include "../libburn/libburn.h"
+
+#endif /* Xorriso_standalonE */
+
+
+#include "isoburn.h"
+
+
+/* Cached reading of image tree data */
+/* Current implementation : single tile 128 kB */
+
+/* powers of 2 only ! */
+#define Libisoburn_cache_blockS 64
+
+struct isoburn_cached_drive {
+ struct burn_drive *drive;
+
+ char cache_data[Libisoburn_cache_blockS * 2048];
+ uint32_t cache_lba;
+ uint32_t last_error_lba;
+ uint32_t last_aligned_error_lba;
+ int cache_hits;
+};
+
+
+/* Debugging only: This reports cache loads on stderr.
+#define Libisoburn_read_cache_reporT 1
+*/
+#define Libisoburn_use_read_cachE
+
+#ifdef Libisoburn_use_read_cachE
+
+int
+ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
+{
+ int ret;
+ struct burn_drive *d;
+ off_t count;
+ uint32_t aligned_lba;
+ char msg[80];
+
+ struct isoburn_cached_drive *icd;
+
+ if(src == NULL || buffer == NULL)
+ return -1;
+
+ icd = (struct isoburn_cached_drive *) src->data;
+ d = (struct burn_drive*) icd->drive;
+
+ aligned_lba= lba & ~(Libisoburn_cache_blockS - 1);
+ if(aligned_lba == icd->cache_lba && icd->cache_lba != 0xffffffff) {
+ (icd->cache_hits)++;
+ memcpy(buffer, icd->cache_data + (lba - aligned_lba) * 2048, 2048);
+ count= 2048;
+ return 1;
+ }
+
+ icd->cache_lba= 0xffffffff; /* invalidate cache */
+ if(icd->last_aligned_error_lba == aligned_lba) {
+ ret = 0;
+ } else {
+ ret = burn_read_data(d, (off_t) aligned_lba * (off_t) 2048,
+ (char *) icd->cache_data,
+ Libisoburn_cache_blockS * 2048, &count, 0);
+ }
+ if (ret <= 0 ) {
+ icd->last_aligned_error_lba = aligned_lba;
+
+ /* Read-ahead failure ? Try to read 2048 directly. */
+ if(icd->last_error_lba == lba)
+ ret = 0;
+ else
+ ret = burn_read_data(d, (off_t) lba * (off_t) 2048, (char *) buffer,
+ 2048, &count, 0);
+ if (ret > 0)
+ return 1;
+ icd->last_error_lba = lba;
+ sprintf(msg, "ds_read_block(%lu) returns -1", (unsigned long) lba);
+ burn_msgs_submit(0x00060000, msg, 0, "DEBUG", NULL);
+ return -1;
+ }
+
+#ifdef Libisoburn_read_cache_reporT
+ fprintf(stderr, "After %3d hits, new load from %8x , count= %d\n",
+ icd->cache_hits, aligned_lba, (int) count);
+#endif
+
+ icd->cache_lba= aligned_lba;
+ icd->cache_hits= 1;
+ memcpy(buffer, icd->cache_data + (lba - aligned_lba) * 2048, 2048);
+ count= 2048;
+
+ return 1;
+}
+
+#else /* Libisoburn_use_read_cachE */
+
+static int
+ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
+{
+ int ret;
+ struct burn_drive *d;
+ off_t count;
+
+ if(src == NULL || buffer == NULL)
+ return -1;
+
+ d = (struct burn_drive*) ((struct isoburn_cached_drive *) src->data)->drive;
+
+ ret = burn_read_data(d, (off_t) lba * (off_t) 2048, (char *) buffer,
+ 2048, &count, 0);
+ if (ret <= 0 )
+ return -1;
+
+ return 1;
+}
+
+#endif /* ! Libisoburn_use_read_cachE */
+
+
+static int
+ds_open(IsoDataSource *src)
+{
+ /* nothing to do, device is always grabbed */
+ return 1;
+}
+
+static int
+ds_close(IsoDataSource *src)
+{
+ /* nothing to do, device is always grabbed */
+ return 1;
+}
+
+static void
+ds_free_data(IsoDataSource *src)
+{
+ /* nothing to do */;
+ if(src->data != NULL)
+ free(src->data);
+ src->data= NULL;
+}
+
+IsoDataSource *
+isoburn_data_source_new(struct burn_drive *d)
+{
+ IsoDataSource *ret;
+ struct isoburn_cached_drive *icd= NULL;
+
+ if (d==NULL)
+ return NULL;
+ ret = malloc(sizeof(IsoDataSource));
+ icd = calloc(1,sizeof(struct isoburn_cached_drive));
+ if (ret == NULL || icd == NULL)
+ return NULL;
+ ret->refcount = 1;
+ ret->read_block = ds_read_block;
+ ret->open = ds_open;
+ ret->close = ds_close;
+ ret->free_data = ds_free_data;
+ ret->data = icd;
+ icd->drive = d;
+ icd->cache_lba = 0xffffffff;
+ icd->cache_hits = 0;
+ icd->last_error_lba = 0xffffffff;
+ icd->last_aligned_error_lba = 0xffffffff;
+ return ret;
+}
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isoburn.c b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isoburn.c
new file mode 100644
index 00000000..61623e7c
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isoburn.c
@@ -0,0 +1,839 @@
+
+/*
+ cc -g -c isoburn.c
+*/
+
+/*
+ Class core of libisoburn.
+
+ Copyright 2007 Vreixo Formoso Lopes
+ and Thomas Schmitt
+*/
+
+/* ( derived from stub generated by CgeN on Sat, 01 Sep 2007 12:04:36 GMT ) */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef Xorriso_standalonE
+
+#include
+
+#include
+
+#else /* ! Xorriso_standalonE */
+
+#include "../libisofs/libisofs.h"
+#include "../libburn/libburn.h"
+
+#endif /* Xorriso_standalonE */
+
+
+#include "libisoburn.h"
+
+#include "isoburn.h"
+
+/* No more: version numbers out of configure.ac
+ major.minor.micro now comes from libisoburn.h
+#include "../version.h"
+*/
+
+/* -------------------------- isoburn ----------------------- */
+
+
+/* The global list of isoburn objects. Usually there is only one.
+ >>> we are not ready for multiple control threads yet. See >>> mutex .
+ Multiple burns under one control thread should work.
+*/
+struct isoburn *isoburn_list_start= NULL;
+
+
+int isoburn_new(struct isoburn **objpt, int flag)
+{
+ struct isoburn *o;
+ int i, ret;
+
+ *objpt= o= (struct isoburn *) malloc(sizeof(struct isoburn));
+ if(o==NULL) {
+ burn_msgs_submit(0x00060000,
+ "Cannot allocate memory for isoburn control object",
+ 0, "FATAL", NULL);
+ return(-1);
+ }
+
+ o->drive= NULL;
+ o->emulation_mode= 0;
+ o->min_start_byte= 0;
+ o->nwa= 0;
+ o->truncate= 0;
+
+#ifdef Libisoburn_no_fifO
+ o->iso_source= NULL;
+#else
+ o->fifo= NULL;
+#endif
+
+ o->wrote_well= -1;
+ o->fabricated_disc_status= BURN_DISC_UNREADY;
+ for(i=0;i<65536;i++)
+ o->target_iso_head[i]= 0;
+ o->image= NULL;
+ o->read_pacifier= NULL;
+ o->read_pacifier_handle= NULL;
+ o->prev= NULL;
+ o->next= NULL;
+ ret= iso_image_new("ISOIMAGE", &o->image);
+ if(ret<0) {
+ isoburn_report_iso_error(ret, "Cannot create image", 0, "FATAL", 0);
+ goto failed;
+ }
+ isoburn_link(o, isoburn_list_start, 1);
+ return(1);
+failed:;
+ isoburn_destroy(objpt, 0);
+ return(-1);
+}
+
+
+int isoburn_destroy(struct isoburn **objpt, int flag)
+{
+ struct isoburn *o;
+
+ o= *objpt;
+ if(o==NULL)
+ return(0);
+
+ /* >>> mutex */
+
+ if(o==isoburn_list_start)
+ isoburn_list_start= o->next;
+ if(o->prev!=NULL)
+ o->prev->next= o->next;
+ if(o->next!=NULL)
+ o->next->prev= o->prev;
+
+ /* >>> end mutex */
+
+ if(o->image!=NULL)
+ iso_image_unref(o->image);
+
+#ifdef Libisoburn_no_fifO
+ if(o->iso_source!=NULL)
+ burn_source_free(o->iso_source);
+#else
+ if(o->fifo!=NULL)
+ burn_source_free(o->fifo);
+#endif /* ! Libisoburn_no_fifO */
+
+
+ free((char *) o);
+ *objpt= NULL;
+ return(1);
+}
+
+
+int isoburn_destroy_all(struct isoburn **objpt, int flag)
+{
+ struct isoburn *o,*n;
+
+ o= *objpt;
+ if(o==NULL)
+ return(0);
+ for(;o->prev!=NULL;o= o->prev);
+ for(;o!=NULL;o= n) {
+ n= o->next;
+ isoburn_destroy(&o,0);
+ }
+ *objpt= NULL;
+ return(1);
+}
+
+
+int isoburn_get_target_image(struct isoburn *o, IsoImage **pt, int flag)
+{
+ *pt= o->image;
+ return(1);
+}
+
+
+int isoburn_get_prev(struct isoburn *o, struct isoburn **pt, int flag)
+{
+ *pt= o->prev;
+ return(1);
+}
+
+
+int isoburn_get_next(struct isoburn *o, struct isoburn **pt, int flag)
+{
+ *pt= o->next;
+ return(1);
+}
+
+
+int isoburn_link(struct isoburn *o, struct isoburn *link, int flag)
+/*
+ bit0= insert as link->prev rather than as link->next
+*/
+{
+
+ /* >>> mutex */
+
+ if(isoburn_list_start==NULL ||
+ (isoburn_list_start==link && (flag&1)))
+ isoburn_list_start= o;
+ if(o->prev!=NULL)
+ o->prev->next= o->next;
+ if(o->next!=NULL)
+ o->next->prev= o->prev;
+ o->prev= o->next= NULL;
+ if(link==NULL)
+ return(1);
+ if(flag&1) {
+ o->next= link;
+ o->prev= link->prev;
+ if(o->prev!=NULL)
+ o->prev->next= o;
+ link->prev= o;
+ } else {
+ o->prev= link;
+ o->next= link->next;
+ if(o->next!=NULL)
+ o->next->prev= o;
+ link->next= o;
+ }
+
+ /* >>> end mutex */
+
+ return(1);
+}
+
+
+int isoburn_count(struct isoburn *o, int flag)
+/* flag: bit1= count from start of list */
+{
+ int counter= 0;
+
+ if(flag&2)
+ for(;o->prev!=NULL;o= o->prev);
+ for(;o!=NULL;o= o->next)
+ counter++;
+ return(counter);
+}
+
+
+int isoburn_by_idx(struct isoburn *o, int idx, struct isoburn **pt, int flag)
+/* flag: bit0= fetch first (idx<0) or last (idx>0) item in list
+ bit1= address from start of list */
+{
+ int i,abs_idx;
+ struct isoburn *npt;
+
+ if(flag&2)
+ for(;o->prev!=NULL;o= o->prev);
+ abs_idx= (idx>0?idx:-idx);
+ *pt= o;
+ for(i= 0;(i0)
+ npt= o->next;
+ else
+ npt= o->prev;
+ if(npt==NULL && (flag&1))
+ break;
+ *pt= npt;
+ }
+ return(*pt!=NULL);
+}
+
+
+int isoburn_find_by_drive(struct isoburn **pt, struct burn_drive *d, int flag)
+{
+ struct isoburn *o;
+
+ *pt= NULL;
+ for(o= isoburn_list_start;o!=NULL;o= o->next)
+ if(o->drive==d) {
+ *pt= o;
+ return(1);
+ }
+ return(0);
+}
+
+static
+int isoburn_prepare_disc_aux(struct burn_drive *d, struct burn_disc **disc,
+ struct isoburn_imgen_opts *opts, int new_img)
+{
+ struct burn_source *wsrc;
+ struct burn_session *session;
+ struct burn_track *track;
+ struct isoburn *o;
+ IsoWriteOpts *wopts= NULL;
+ enum burn_disc_status state;
+ int ret, fifo_chunks;
+
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret<0 || o==NULL)
+ {ret= -1; goto ex;}
+ o->wrote_well= 0; /* early end will be registered as failure */
+
+ state = isoburn_disc_get_status(d);
+ if (state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE
+ && (state != BURN_DISC_FULL || ! new_img)) {
+ /* unsuitable status */
+ burn_msgs_submit(0x00060000, "Unsuitable media state", 0, "FAILURE", NULL);
+ {ret= -2; goto ex;}
+ }
+
+ fifo_chunks= 32;
+ if(opts->fifo_size >= 64*1024 && opts->fifo_size <= 1024.0 * 1024.0 * 1024.0){
+ fifo_chunks= opts->fifo_size/2048;
+ if(fifo_chunks*2048 < opts->fifo_size)
+ fifo_chunks++;
+ }
+
+ ret = iso_write_opts_new(&wopts, 0);
+ if (ret < 0) {
+ isoburn_report_iso_error(ret, "Cannot create iso_write_opts", 0, "FATAL",0);
+ goto ex;
+ }
+ iso_write_opts_set_iso_level(wopts, opts->level);
+ iso_write_opts_set_rockridge(wopts, opts->rockridge);
+ iso_write_opts_set_joliet(wopts, opts->joliet);
+ iso_write_opts_set_iso1999(wopts, opts->iso1999);
+ iso_write_opts_set_omit_version_numbers(wopts, opts->omit_version_numbers);
+ iso_write_opts_set_allow_deep_paths(wopts, opts->allow_deep_paths);
+ iso_write_opts_set_allow_longer_paths(wopts, opts->allow_longer_paths);
+ iso_write_opts_set_max_37_char_filenames(wopts, opts->max_37_char_filenames);
+ iso_write_opts_set_no_force_dots(wopts, opts->no_force_dots);
+ iso_write_opts_set_allow_lowercase(wopts, opts->allow_lowercase);
+ iso_write_opts_set_allow_full_ascii(wopts, opts->allow_full_ascii);
+ iso_write_opts_set_relaxed_vol_atts(wopts, 1);
+ iso_write_opts_set_joliet_longer_paths(wopts, opts->joliet_longer_paths);
+ iso_write_opts_set_sort_files(wopts, opts->sort_files);
+ iso_write_opts_set_replace_mode(wopts, opts->replace_dir_mode,
+ opts->replace_file_mode, opts->replace_uid, opts->replace_gid);
+ iso_write_opts_set_default_dir_mode(wopts, opts->dir_mode);
+ iso_write_opts_set_default_file_mode(wopts, opts->file_mode);
+ iso_write_opts_set_default_uid(wopts, opts->uid);
+ iso_write_opts_set_default_gid(wopts, opts->gid);
+ iso_write_opts_set_output_charset(wopts, opts->output_charset);
+#ifdef Libisoburn_no_fifO
+ iso_write_opts_set_fifo_size(wopts, fifo_chunks);
+#endif /* Libisoburn_no_fifO */
+
+ if (new_img) {
+ iso_write_opts_set_ms_block(wopts, 0);
+ iso_write_opts_set_appendable(wopts, 0);
+ iso_write_opts_set_overwrite_buf(wopts, NULL);
+ } else {
+ int lba, nwa;
+ ret = isoburn_disc_track_lba_nwa(d, NULL, 0, &lba, &nwa);
+ if (ret != 1) {
+ burn_msgs_submit(0x00060000, "Cannot determine next writeable address", 0,
+ "FAILURE", NULL);
+ {ret= -3; goto ex;}
+ }
+ if (nwa == 0 && state == BURN_DISC_APPENDABLE) {
+ /* invalid nwa */
+ burn_msgs_submit(0x00060000, "Encountered 0 as next writeable address", 0,
+ "FAILURE", NULL);
+ {ret= -4; goto ex;}
+ }
+ iso_write_opts_set_ms_block(wopts, nwa);
+ iso_write_opts_set_appendable(wopts, 1);
+ iso_write_opts_set_overwrite_buf(wopts, o->target_iso_head);
+ }
+
+ ret = iso_image_create_burn_source(o->image, wopts, &wsrc);
+ if (ret < 0) {
+ isoburn_report_iso_error(ret, "Cannot create burn source", 0, "FAILURE", 0);
+ {ret= -1; goto ex;}
+ }
+
+ /* TODO check return values for failure. propertly clean-up on error */
+
+#ifdef Libisoburn_no_fifO
+ o->iso_source= wsrc;
+#else
+ o->fifo = burn_fifo_source_new(wsrc, 2048, fifo_chunks, 0);
+ burn_source_free(wsrc);
+ if (o->fifo == NULL) {
+ burn_msgs_submit(0x00060000, "Cannot attach fifo", 0, "FATAL", NULL);
+ {ret= -1; goto ex;}
+ }
+#endif /* ! Libisoburn_no_fifO */
+
+ *disc = burn_disc_create();
+ session = burn_session_create();
+ burn_disc_add_session(*disc, session, BURN_POS_END);
+ track = burn_track_create();
+
+#ifdef Libisoburn_no_fifO
+ burn_track_set_source(track, o->iso_source);
+#else
+ burn_track_set_source(track, o->fifo);
+#endif /* ! Libisoburn_no_fifO */
+
+ burn_session_add_track(session, track, BURN_POS_END);
+
+ /* give up local references */
+ burn_track_free(track);
+ burn_session_free(session);
+
+ o->wrote_well= -1; /* neutral */
+ ret= 1;
+ex:
+ if(wopts!=NULL)
+ {iso_write_opts_free(wopts); wopts= NULL;}
+ return ret;
+}
+
+int isoburn_prepare_disc(struct burn_drive *d, struct burn_disc **disc,
+ struct isoburn_imgen_opts *opts)
+{
+ return isoburn_prepare_disc_aux(d, disc, opts, 0);
+}
+
+int isoburn_prepare_new_image(struct burn_drive *d, struct burn_disc **disc,
+ struct isoburn_imgen_opts *opts,
+ struct burn_drive *out_drive)
+{
+ int ret;
+ struct isoburn *in_o, *out_o;
+
+ ret= isoburn_prepare_disc_aux(d, disc, opts, 1);
+ if (ret<=0)
+ return ret;
+
+#ifdef Libisoburn_no_fifO
+ /* Hand over source reference for optional fifo status inquiry */
+ if(out_drive==NULL)
+ return 1;
+ ret= isoburn_find_emulator(&out_o, out_drive, 0);
+ if(ret<0 || out_o==NULL)
+ return 1;
+ ret= isoburn_find_emulator(&in_o, d, 0);
+ if(ret<0 || in_o==NULL)
+ return 1; /* then without fifo status inquiry */
+ if(out_o->iso_source!=NULL)
+ burn_source_free(out_o->iso_source);
+ out_o->iso_source= in_o->iso_source;
+ in_o->iso_source= NULL;
+#endif /* Libisoburn_no_fifO */
+
+ return 1;
+}
+
+
+/* API @since 0.1.0
+ @param flag bit0= this is a regular end, not an abort
+ give up source reference
+*/
+int isoburn_cancel_prepared_write(struct burn_drive *d,
+ struct burn_drive *output_drive, int flag)
+{
+ int ret;
+ struct isoburn *o= NULL;
+
+ if(output_drive!=NULL) {
+ ret= isoburn_find_emulator(&o, output_drive, 0);
+ if(ret<0 || o==NULL)
+ o= NULL;
+ else if(o->iso_source==NULL)
+ o= NULL;
+ }
+ if(o==NULL) {
+ ret= isoburn_find_emulator(&o, d, 0);
+ if(ret<0)
+ return(-1);
+ if(o==NULL)
+ return(0);
+ if(o->iso_source==NULL)
+ return(0);
+ }
+ if(o->iso_source->read!=NULL)
+ return(0);
+ if(o->iso_source->version<1)
+ return(0);
+ o->iso_source->cancel(o->iso_source);
+ burn_source_free(o->iso_source);
+ o->iso_source= NULL;
+ return(1);
+}
+
+
+/* API @since 0.1.0 */
+int isoburn_sync_after_write(struct burn_drive *d,
+ struct burn_drive *output_drive, int flag)
+{
+ return isoburn_cancel_prepared_write(d, output_drive, 1);
+}
+
+
+void isoburn_version(int *major, int *minor, int *micro)
+{
+ *major= isoburn_header_version_major;
+ *minor= isoburn_header_version_minor;
+ *micro= isoburn_header_version_micro;
+
+/* No more: values from version.h generated from version.h.in and
+ macro values defined in configure.ac
+
+ *major = ISOBURN_MAJOR_VERSION;
+ *minor = ISOBURN_MINOR_VERSION;
+ *micro = ISOBURN_MICRO_VERSION;
+*/
+}
+
+
+int isoburn_is_compatible(int major, int minor, int micro, int flag)
+{
+ int own_major, own_minor, own_micro;
+
+ isoburn_version(&own_major, &own_minor, &own_micro);
+ return(own_major > major ||
+ (own_major == major && (own_minor > minor ||
+ (own_minor == minor && own_micro >= micro))));
+}
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ Options for image reading.
+*/
+/* ----------------------------------------------------------------------- */
+
+
+int isoburn_ropt_new(struct isoburn_read_opts **new_o, int flag)
+{
+ struct isoburn_read_opts *o;
+
+ o= (*new_o)= calloc(1, sizeof(struct isoburn_read_opts));
+ if(o==NULL) {
+ burn_msgs_submit(0x00060000, "Cannot allocate memory for read options",
+ 0, "FATAL", NULL);
+ return(-1);
+ }
+ o->norock= 0;
+ o->nojoliet= 0;
+ o->noiso1999= 1;
+ o->preferjoliet= 0;
+ o->uid= geteuid();
+ o->gid= getegid();
+ o->mode= 0444;
+ o->dirmode= 0555;
+ o->input_charset= NULL;
+ o->hasRR= 0;
+ o->hasJoliet= 0;
+ o->hasIso1999= 0;
+ o->hasElTorito= 0;
+ o->size= 0;
+ o->pretend_blank= 1;
+ return(1);
+}
+
+
+int isoburn_ropt_destroy(struct isoburn_read_opts **o, int flag)
+{
+ if(*o==NULL)
+ return(0);
+ free(*o);
+ *o= NULL;
+ return(1);
+}
+
+
+int isoburn_ropt_set_extensions(struct isoburn_read_opts *o, int ext)
+{
+ o->norock= !!(ext&1);
+ o->nojoliet= !!(ext&2);
+ o->noiso1999= !!(ext&4);
+ o->preferjoliet= !!(ext&8);
+ o->pretend_blank= !!(ext&16);
+ return(1);
+}
+
+
+int isoburn_ropt_get_extensions(struct isoburn_read_opts *o, int *ext)
+{
+ *ext= (!!o->norock) | ((!!o->nojoliet)<<1) | ((!!o->noiso1999)<<2) |
+ ((!!o->preferjoliet)<<3) | ((!!o->pretend_blank)<<4);
+ return(1);
+}
+
+
+int isoburn_ropt_set_default_perms(struct isoburn_read_opts *o,
+ uid_t uid, gid_t gid, mode_t mode)
+{
+ mode_t dirmode;
+
+ o->uid= uid;
+ o->gid= gid;
+ o->mode= mode;
+ dirmode= mode;
+ if(dirmode & S_IRUSR)
+ dirmode|= S_IXUSR;
+ if(dirmode & S_IRGRP)
+ dirmode|= S_IXGRP;
+ if(dirmode & S_IROTH)
+ dirmode|= S_IXOTH;
+ o->dirmode= dirmode;
+ return(1);
+}
+
+
+int isoburn_ropt_get_default_perms(struct isoburn_read_opts *o,
+ uid_t *uid, gid_t *gid, mode_t *mode)
+{
+ *uid= o->uid;
+ *gid= o->gid;
+ *mode= o->mode;
+ return(1);
+}
+
+
+int isoburn_ropt_set_default_dirperms(struct isoburn_read_opts *o,
+ mode_t mode)
+{
+ o->dirmode= mode;
+ return(1);
+}
+
+
+int isoburn_ropt_get_default_dirperms(struct isoburn_read_opts *o,
+ mode_t *mode)
+{
+ *mode= o->dirmode;
+ return(1);
+}
+
+
+int isoburn_ropt_set_input_charset(struct isoburn_read_opts *o,
+ char *input_charset)
+{
+ o->input_charset= input_charset;
+ return(1);
+}
+
+
+int isoburn_igopt_get_in_charset(struct isoburn_read_opts *o,
+ char **input_charset)
+{
+ *input_charset= o->input_charset;
+ return(1);
+}
+
+
+int isoburn_ropt_get_size_what(struct isoburn_read_opts *o,
+ uint32_t *size, int *has_what)
+{
+ *size= o->size;
+ *has_what= (!!o->hasRR) | ((!!o->hasJoliet)<<1) |
+ ((!!o->hasIso1999)<<2) | ((!!o->hasElTorito)<<3);
+ return(1);
+}
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ Options for image generation by libisofs and image transport to libburn.
+*/
+/* ----------------------------------------------------------------------- */
+
+
+int isoburn_igopt_new(struct isoburn_imgen_opts **new_o, int flag)
+{
+ struct isoburn_imgen_opts *o;
+
+ o= (*new_o)= calloc(1, sizeof(struct isoburn_imgen_opts));
+ if(o==NULL) {
+ burn_msgs_submit(0x00060000,
+ "Cannot allocate memory for image generation options",
+ 0, "FATAL", NULL);
+ return(-1);
+ }
+ o->level= 2;
+ o->rockridge= 1;
+ o->joliet= 0;
+ o->iso1999= 0;
+ o->omit_version_numbers= 0;
+ o->allow_deep_paths= 1;
+ o->allow_longer_paths= 0;
+ o->max_37_char_filenames= 0;
+ o->no_force_dots= 0;
+ o->allow_lowercase= 0;
+ o->allow_full_ascii= 0;
+ o->joliet_longer_paths= 0;
+ o->sort_files= 0;
+ o->replace_dir_mode= 0;
+ o->replace_file_mode= 0;
+ o->replace_uid= 0;
+ o->replace_gid= 0;
+ o->dir_mode= 0555;
+ o->file_mode= 0444;
+ o->uid= 0;
+ o->gid= 0;
+ o->output_charset= 0;
+ o->fifo_size= 4*1024*1024;
+ return(1);
+}
+
+
+int isoburn_igopt_destroy(struct isoburn_imgen_opts **o, int flag)
+{
+ if(*o==NULL)
+ return(0);
+ free(*o);
+ *o= NULL;
+ return(1);
+}
+
+
+int isoburn_igopt_set_level(struct isoburn_imgen_opts *o, int level)
+{
+ o->level= level;
+ return(1);
+}
+
+
+int isoburn_igopt_get_level(struct isoburn_imgen_opts *o, int *level)
+{
+ *level= o->level;
+ return(1);
+}
+
+
+int isoburn_igopt_set_extensions(struct isoburn_imgen_opts *o, int ext)
+{
+ o->rockridge= !!(ext&1);
+ o->joliet= !!(ext&2);
+ o->iso1999= !!(ext&4);
+ return(1);
+}
+
+
+int isoburn_igopt_get_extensions(struct isoburn_imgen_opts *o, int *ext)
+{
+ *ext= (!!o->rockridge) | ((!!o->joliet)<<1) | ((!!o->iso1999)<<2);
+ return(1);
+}
+
+
+int isoburn_igopt_set_relaxed(struct isoburn_imgen_opts *o, int relax)
+{
+ o->omit_version_numbers= !!(relax&1);
+ o->allow_deep_paths= !!(relax&2);
+ o->allow_longer_paths= !!(relax&4);
+ o->max_37_char_filenames= !!(relax&8);
+ o->no_force_dots= !!(relax&16);
+ o->allow_lowercase= !!(relax&32);
+ o->allow_full_ascii= !!(relax&64);
+ o->joliet_longer_paths= !!(relax&128);
+ return(1);
+}
+
+
+int isoburn_igopt_get_relaxed(struct isoburn_imgen_opts *o, int *relax)
+{
+ *relax= (!!o->omit_version_numbers) | ((!!o->allow_deep_paths)<<1) |
+ ((!!o->allow_longer_paths)<<2) | ((!!o->max_37_char_filenames)<<3) |
+ ((!!o->no_force_dots)<<4) | ((!!o->allow_lowercase)<<5) |
+ ((!!o->allow_full_ascii)<<6) | ((!!o->joliet_longer_paths)<<7);
+ return(1);
+}
+
+
+int isoburn_igopt_set_sort_files(struct isoburn_imgen_opts *o, int value)
+{
+ o->sort_files= !!(value&1);
+ return(1);
+}
+
+
+int isoburn_igopt_get_sort_files(struct isoburn_imgen_opts *o, int *value)
+{
+ *value= !!o->sort_files;
+ return(1);
+}
+
+
+int isoburn_igopt_set_over_mode(struct isoburn_imgen_opts *o,
+ int replace_dir_mode, int replace_file_mode,
+ mode_t dir_mode, mode_t file_mode)
+{
+ o->replace_dir_mode= replace_dir_mode%3;
+ o->replace_file_mode= replace_file_mode%3;
+ o->dir_mode= dir_mode;
+ o->file_mode= file_mode;
+ return(1);
+}
+
+
+int isoburn_igopt_get_over_mode(struct isoburn_imgen_opts *o,
+ int *replace_dir_mode, int *replace_file_mode,
+ mode_t *dir_mode, mode_t *file_mode)
+{
+ *replace_dir_mode= o->replace_dir_mode%3;
+ *replace_file_mode= o->replace_file_mode%3;
+ *dir_mode= o->dir_mode;
+ *file_mode= o->file_mode;
+ return(1);
+}
+
+
+int isoburn_igopt_set_over_ugid(struct isoburn_imgen_opts *o,
+ int replace_uid, int replace_gid,
+ uid_t uid, gid_t gid)
+{
+ o->replace_uid= replace_uid%3;
+ o->replace_gid= replace_gid%3;
+ o->uid= uid;
+ o->gid= gid;
+ return(1);
+}
+
+int isoburn_igopt_get_over_ugid(struct isoburn_imgen_opts *o,
+ int *replace_uid, int *replace_gid,
+ uid_t *uid, gid_t *gid)
+{
+ *replace_uid= o->replace_uid%3;
+ *replace_gid= o->replace_gid%3;
+ *uid= o->uid;
+ *gid= o->gid;
+ return(1);
+}
+
+
+int isoburn_igopt_set_out_charset(struct isoburn_imgen_opts *o,
+ char *output_charset)
+{
+ o->output_charset= output_charset;
+ return(1);
+}
+
+
+int isoburn_igopt_get_out_charset(struct isoburn_imgen_opts *o,
+ char **output_charset)
+{
+ *output_charset= o->output_charset;
+ return(1);
+}
+
+
+int isoburn_igopt_set_fifo_size(struct isoburn_imgen_opts *o, int fifo_size)
+{
+ o->fifo_size= fifo_size;
+ return(1);
+}
+
+
+int isoburn_igopt_get_fifo_size(struct isoburn_imgen_opts *o, int *fifo_size)
+{
+ *fifo_size= o->fifo_size;
+ return(1);
+}
+
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isoburn.h b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isoburn.h
new file mode 100644
index 00000000..d613f68b
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isoburn.h
@@ -0,0 +1,325 @@
+
+/*
+ Class struct of libisoburn.
+
+ Copyright 2007 Vreixo Formoso Lopes
+ and Thomas Schmitt
+*/
+
+#ifndef Isoburn_includeD
+#define Isoburn_includeD
+
+
+/* <<< transition macro */
+#define Libisoburn_no_fifO 1
+
+
+/* for uint8_t */
+#include
+
+
+struct isoburn {
+
+
+ /* The libburn drive to which this isoburn object is related
+ Most isoburn calls will use a burn_drive as object handle */
+ struct burn_drive *drive;
+
+ /* -1= inappropriate media state detected
+ 0= libburn multi-session media, resp. undecided yet
+ 1= random access media */
+ int emulation_mode;
+
+ /* Although rarely used, libburn can operate on several
+ drives simultaneously. */
+ struct isoburn *prev;
+ struct isoburn *next;
+
+
+ /* Start address as given by image examination (bytes, not blocks) */
+ off_t min_start_byte;
+
+ /* Aligned start address to be used for processing (counted in blocks) */
+ int nwa;
+
+ /* Truncate to .nwa an eventual regular file serving as output drive */
+ int truncate;
+
+ /* Eventual freely fabricated isoburn_disc_get_status().
+ BURN_DISC_UNREADY means that this variable is disabled
+ and normally emulated status is in effect.
+ */
+ enum burn_disc_status fabricated_disc_status;
+
+#ifndef Libisoburn_no_fifO
+ /* The fifo which is installed between track and libisofs burn_source
+ */
+ struct burn_source *fifo;
+#endif /* ! Libisoburn_no_fifO */
+
+ /* Indicator wether the most recent burn run worked :
+ -1 = undetermined, ask libburn , 0 = failure , 1 = success
+ To be inquired by isoburn_drive_wrote_well()
+ */
+ int wrote_well;
+
+
+ /* Buffered ISO head from media (should that become part of
+ ecma119_read_opts ?) */
+ uint8_t target_iso_head[65536];
+
+ /* Libisofs image context */
+ IsoImage *image;
+
+#ifdef Libisoburn_no_fifO
+ /* The burn source which transfers data from libisofs to libburn.
+ It has its own fifo.
+ */
+ struct burn_source *iso_source;
+#endif /* Libisoburn_no_fifO */
+
+ /* For iso_tree_set_report_callback() */
+ int (*read_pacifier)(IsoImage*, IsoFileSource*);
+
+ /* For iso_image_attach_data() */
+ void *read_pacifier_handle;
+
+};
+
+
+/* Creation and disposal function */
+int isoburn_new(struct isoburn **objpt, int flag);
+int isoburn_destroy(struct isoburn **objpt, int flag);
+
+/* Eventual readers for public attributes */
+/* ( put into separate .h file then ) */
+int isoburn_get_emulation_mode(struct isoburn *o, int *pt, int flag);
+int isoburn_get_target_volset(struct isoburn *o, IsoImage **pt, int flag);
+
+/* List management */
+int isoburn_get_prev(struct isoburn *o, struct isoburn **pt, int flag);
+int isoburn_get_next(struct isoburn *o, struct isoburn **pt, int flag);
+int isoburn_destroy_all(struct isoburn **objpt, int flag);
+int isoburn_link(struct isoburn *o, struct isoburn *link, int flag);
+int isoburn_count(struct isoburn *o, int flag);
+int isoburn_by_idx(struct isoburn *o, int idx, struct isoburn **pt, int flag);
+int isoburn_find_by_drive(struct isoburn **pt, struct burn_drive *d, int flag);
+
+
+/* Non API inner interfaces */
+
+/* Submit a libisofs error to the libburn messenger. An application message
+ reader shall recognize the error code range and attribute it to the
+ libisofs message channel to which one cannot submit via API.
+ @param iso_error_code return value <= 0 from a libisofs API call.
+ @param default_msg_text is to be put out if iso_error_code leads to no
+ error message
+ @param os_errno operating system errno, submit 0 if none is known
+ @param min_severity minimum severity, might be be increased if libisofs
+ error severity surpasses min_severity.
+ @param flag Bitfield, submit 0 for now
+*/
+int isoburn_report_iso_error(int iso_error_code, char default_msg_text[],
+ int os_errno, char min_severity[], int flag);
+
+/* Calls from burn_wrap.c into isofs_wrap.c */
+
+int isoburn_start_emulation(struct isoburn *o, int flag);
+int isoburn_invalidate_iso(struct isoburn *o, int flag);
+
+
+/* Calls from isofs_wrap.c into burn_wrap.c */
+
+/** Get an eventual isoburn object which is wrapped around the drive.
+ @param pt Eventually returns a pointer to the found object.
+ It is allowed to become NULL if return value is -1 or 0.
+ In this case, the drive is a genuine libburn drive
+ with no emulation activated by isoburn.
+ @param drive The drive to be searched for
+ @param flag unused yet
+ @return -1 unsuitable media, 0 generic media, 1 emulated media.
+*/
+int isoburn_find_emulator(struct isoburn **pt,
+ struct burn_drive *drive, int flag);
+
+
+/** Set the start address for an emulated add-on session. The value will
+ be rounded up to the alignment necessary for the media. The aligned
+ value will be divided by 2048 and then put into o->nwa .
+ @param o The isoburn object to be programmed.
+ @param value The start address in bytes
+ @param flag unused yet
+ @return <=0 is failure , >0 success
+*/
+int isoburn_set_start_byte(struct isoburn *o, off_t value, int flag);
+
+/** Get a data source suitable for read from a drive using burn_read_data()
+ function.
+ @param d drive to read from. Must be grabbed.
+ @return the data source, NULL on error. Must be freed with libisofs
+ iso_data_source_unref() function. Note: this doesn't release
+ the drive.
+*/
+IsoDataSource *
+isoburn_data_source_new(struct burn_drive *d);
+
+
+/**
+ * Options for image reading.
+ (Comments here may be outdated. API getter/setter function descriptions
+ may override the descriptions here. Any difference is supposed to be a
+ minor correction only.)
+ */
+struct isoburn_read_opts {
+ unsigned int norock:1; /*< Do not read Rock Ridge extensions */
+ unsigned int nojoliet:1; /*< Do not read Joliet extensions */
+ unsigned int noiso1999:1; /*< Do not read ISO 9660:1999 enhanced tree */
+ unsigned int preferjoliet:1;
+ /*< When both Joliet and RR extensions are present, the RR
+ * tree is used. If you prefer using Joliet, set this to 1. */
+ uid_t uid; /**< Default uid when no RR */
+ gid_t gid; /**< Default uid when no RR */
+ mode_t mode; /**< Default mode when no RR (only permissions) */
+ mode_t dirmode; /**< Default mode for directories
+ when no RR (only permissions) */
+
+ /**
+ * Input charset for RR file names. NULL to use default locale charset.
+ */
+ char *input_charset;
+
+ /* modified by the function isoburn_read_image */
+ unsigned int hasRR:1; /*< It will be set to 1 if RR extensions are present,
+ to 0 if not. */
+ unsigned int hasJoliet:1; /*< It will be set to 1 if Joliet extensions are
+ present, to 0 if not. */
+
+ /**
+ * It will be set to 1 if the image is an ISO 9660:1999, i.e. it has
+ * a version 2 Enhanced Volume Descriptor.
+ */
+ unsigned int hasIso1999:1;
+
+ /** It will be set to 1 if El-Torito boot record is present, to 0 if not.*/
+ unsigned int hasElTorito:1;
+
+ uint32_t size; /**< Will be filled with the size (in 2048 byte block) of
+ * the image, as reported in the PVM. */
+ unsigned int pretend_blank:1; /* always create empty image */
+};
+
+
+/**
+ * Options for image generation by libisofs and image transport to libburn.
+ (Comments here may be outdated. API getter/setter function descriptions
+ may override the descriptions here. Any difference is supposed to be a
+ minor correction only.)
+ */
+struct isoburn_imgen_opts {
+
+ /* Options for image generation */
+
+ int level; /**< ISO level to write at. */
+
+ /** Which extensions to support. */
+ unsigned int rockridge :1;
+ unsigned int joliet :1;
+ unsigned int iso1999 :1;
+
+ /* relaxed constraints */
+
+ /*
+ * 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 paths in the Joliet tree to have more than 240 characters.
+ */
+ unsigned int joliet_longer_paths :1;
+
+ unsigned int sort_files:1;
+ /**< If files should be sorted based on their weight. */
+
+ /**
+ * 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 set 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. */
+
+ char *output_charset; /**< NULL to use default charset */
+
+
+ /* Options for image transport */
+
+ /** The number of bytes to be used for the fifo which decouples libisofs
+ and libburn for better throughput and for reducing the risk of
+ interrupting signals hitting the libburn thread which operates the
+ MMC drive.
+ The size will be rounded up to the next full 2048.
+ Minimum is 64kiB, maximum is 1 GiB (but that is too much anyway).
+ */
+ int fifo_size;
+
+};
+
+#endif /* Isoburn_includeD */
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isofs_wrap.c b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isofs_wrap.c
new file mode 100644
index 00000000..4ee8c765
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/isofs_wrap.c
@@ -0,0 +1,398 @@
+
+/*
+ cc -g -c isofs_wrap.c
+*/
+
+/*
+ libisofs related functions of libisoburn.
+
+ Copyright 2007 Vreixo Formoso Lopes
+ Thomas Schmitt
+*/
+
+#include
+#include
+
+#ifndef Xorriso_standalonE
+
+#include
+
+#include
+
+#else /* ! Xorriso_standalonE */
+
+#include "../libisofs/libisofs.h"
+#include "../libburn/libburn.h"
+
+#endif /* Xorriso_standalonE */
+
+
+#include "isoburn.h"
+#include "libisoburn.h"
+
+#define BP(a,b) [(b) - (a) + 1]
+
+struct ecma119_pri_vol_desc
+{
+ uint8_t vol_desc_type BP(1, 1);
+ uint8_t std_identifier BP(2, 6);
+ uint8_t vol_desc_version BP(7, 7);
+ uint8_t unused1 BP(8, 8);
+ uint8_t system_id BP(9, 40);
+ uint8_t volume_id BP(41, 72);
+ uint8_t unused2 BP(73, 80);
+ uint8_t vol_space_size BP(81, 88);
+ uint8_t unused3 BP(89, 120);
+ uint8_t vol_set_size BP(121, 124);
+ uint8_t vol_seq_number BP(125, 128);
+ uint8_t block_size BP(129, 132);
+ uint8_t path_table_size BP(133, 140);
+ uint8_t l_path_table_pos BP(141, 144);
+ uint8_t opt_l_path_table_pos BP(145, 148);
+ uint8_t m_path_table_pos BP(149, 152);
+ uint8_t opt_m_path_table_pos BP(153, 156);
+ uint8_t root_dir_record BP(157, 190);
+ uint8_t vol_set_id BP(191, 318);
+ uint8_t publisher_id BP(319, 446);
+ uint8_t data_prep_id BP(447, 574);
+ uint8_t application_id BP(575, 702);
+ uint8_t copyright_file_id BP(703, 739);
+ uint8_t abstract_file_id BP(740, 776);
+ uint8_t bibliographic_file_id BP(777, 813);
+ uint8_t vol_creation_time BP(814, 830);
+ uint8_t vol_modification_time BP(831, 847);
+ uint8_t vol_expiration_time BP(848, 864);
+ uint8_t vol_effective_time BP(865, 881);
+ uint8_t file_structure_version BP(882, 882);
+ uint8_t reserved1 BP(883, 883);
+ uint8_t app_use BP(884, 1395);
+ uint8_t reserved2 BP(1396, 2048);
+};
+
+static
+uint32_t iso_read_lsb(const uint8_t *buf, int bytes)
+{
+ int i;
+ uint32_t ret = 0;
+
+ for (i=0; iimage);
+ return o->image;
+}
+
+
+static void isoburn_idle_free_function(void *ignored)
+{
+ return;
+}
+
+
+/* API function. See libisoburn.h
+*/
+int isoburn_read_image(struct burn_drive *d,
+ struct isoburn_read_opts *read_opts,
+ IsoImage **image)
+{
+ int ret, int_num;
+ IsoReadOpts *ropts= NULL;
+ IsoReadImageFeatures *features= NULL;
+ uint32_t ms_block;
+
+ enum burn_disc_status status= BURN_DISC_BLANK;
+ IsoDataSource *ds= NULL;
+ struct isoburn *o= NULL;
+
+ if(read_opts==NULL) {
+ burn_msgs_submit(0x00060000,
+ "Program error: isoburn_read_image: read_opts==NULL",
+ 0, "FATAL", NULL);
+ return(-1);
+ }
+ if(d != NULL) {
+ ret = isoburn_find_emulator(&o, d, 0);
+ if (ret < 0 || o == NULL)
+ return 0;
+ status = isoburn_disc_get_status(d);
+ }
+ if (d == NULL || status == BURN_DISC_BLANK || read_opts->pretend_blank) {
+
+ /*
+ * Blank disc, we create a new image without files.
+ */
+
+ if (d == NULL) {
+ /* New empty image without relation to a drive */
+ if (image==NULL) {
+ burn_msgs_submit(0x00060000,
+ "Program error: isoburn_read_image: image==NULL",
+ 0, "FATAL", NULL);
+ return -1;
+ }
+ /* create a new image */
+ ret = iso_image_new("ISOIMAGE", image);
+ if (ret < 0) {
+ isoburn_report_iso_error(ret, "Cannot create image", 0, "FATAL", 0);
+ return ret;
+ }
+ } else {
+ /* Blank new image for the drive */
+ iso_image_unref(o->image);
+ ret = iso_image_new("ISOIMAGE", &o->image);
+ if (ret < 0) {
+ isoburn_report_iso_error(ret, "Cannot create image", 0, "FATAL", 0);
+ return ret;
+ }
+ if (image) {
+ *image = o->image;
+ iso_image_ref(*image); /*protects object from premature free*/
+ }
+ }
+ return 1;
+ }
+
+ if (status != BURN_DISC_APPENDABLE && status != BURN_DISC_FULL) {
+ burn_msgs_submit(0x00060000,
+ "Program error: isoburn_read_image: incorrect disc status",
+ 0, "FATAL", NULL);
+ return -4;
+ }
+
+ memset((char *) &ropts, 0, sizeof(ropts));
+
+ ret = isoburn_disc_get_msc1(d, &int_num);
+ if (ret <= 0)
+ return -2;
+ ms_block= int_num;
+
+ /* create the data source */
+ ret = iso_read_opts_new(&ropts, 0);
+ if (ret < 0) {
+ isoburn_report_iso_error(ret, "Cannot create write opts", 0, "FATAL", 0);
+ return ret;
+ }
+ /* Important: do not return until iso_read_opts_free() */
+ iso_read_opts_set_start_block(ropts, ms_block);
+ iso_read_opts_set_no_rockridge(ropts, read_opts->norock);
+ iso_read_opts_set_no_joliet(ropts, read_opts->nojoliet);
+ iso_read_opts_set_no_iso1999(ropts, read_opts->noiso1999);
+ iso_read_opts_set_preferjoliet(ropts, read_opts->preferjoliet);
+ iso_read_opts_set_default_permissions(ropts,
+ read_opts->mode, read_opts->dirmode);
+ iso_read_opts_set_default_uid(ropts, read_opts->uid);
+ iso_read_opts_set_default_gid(ropts, read_opts->gid);
+ iso_read_opts_set_input_charset(ropts, read_opts->input_charset);
+ ds = isoburn_data_source_new(d);
+ iso_image_attach_data(o->image, o->read_pacifier_handle,
+ isoburn_idle_free_function);
+ if(o->read_pacifier_handle==NULL)
+ iso_tree_set_report_callback(o->image, NULL);
+ else
+ iso_tree_set_report_callback(o->image, o->read_pacifier);
+ ret = iso_image_import(o->image, ds, ropts, &features);
+ iso_tree_set_report_callback(o->image, NULL);
+ iso_read_opts_free(ropts);
+ iso_data_source_unref(ds);
+ if (ret < 0) {
+ isoburn_report_iso_error(ret, "Cannot import image", 0, "FAILURE", 0);
+ return ret;
+ }
+ /* Important: do not return until free(features) */
+ if (image!=NULL) {
+ *image = o->image;
+ iso_image_ref(*image); /*protects object from premature free*/
+ }
+ read_opts->hasRR = iso_read_image_features_has_rockridge(features);
+ read_opts->hasJoliet = iso_read_image_features_has_joliet(features);
+ read_opts->hasIso1999 = iso_read_image_features_has_iso1999(features);
+ read_opts->hasElTorito = iso_read_image_features_has_eltorito(features);
+ read_opts->size = iso_read_image_features_get_size(features);
+
+#ifdef NIX
+ read_opts->hasRR = features->hasRR;
+ read_opts->hasJoliet = features->hasJoliet;
+ read_opts->hasIso1999 = features->hasIso1999;
+ read_opts->hasElTorito = features->hasElTorito;
+ read_opts->size = features->size;
+#endif
+
+ iso_read_image_features_destroy(features);
+ return 1;
+}
+
+
+/* API function. See libisoburn.h
+*/
+int isoburn_attach_image(struct burn_drive *d, IsoImage *image)
+{
+ int ret;
+ struct isoburn *o;
+
+ if (image == NULL) {
+ burn_msgs_submit(0x00060000,
+ "Program error: isoburn_attach_image: image==NULL",
+ 0, "FATAL", NULL);
+ return -1;
+ }
+ ret = isoburn_find_emulator(&o, d, 0);
+ if (ret < 0 || o == NULL)
+ return 0;
+ if(o->image != NULL)
+ iso_image_unref(o->image);
+ o->image = image;
+ return(1);
+}
+
+
+/* API function. See libisoburn.h
+*/
+int isoburn_activate_session(struct burn_drive *drive)
+{
+ int ret;
+ struct isoburn *o;
+
+ ret = isoburn_find_emulator(&o, drive, 0);
+ if (ret < 0)
+ return -1;
+
+ if (o->emulation_mode != 1)
+ return 1; /* don't need to activate session */
+
+ if (o->fabricated_disc_status != BURN_DISC_APPENDABLE)
+ return 1;
+
+ ret = burn_random_access_write(drive, 0, (char*)o->target_iso_head,
+ 32*2048, 1);
+
+ return ret;
+}
+
+
+/** Initialize the emulation of multi-session on random access media.
+ The need for emulation is confirmed already.
+ @param o A freshly created isoburn object. isoburn_create_data_source() was
+ already called, nevertheless.
+ @return <=0 error , 1 = success
+*/
+int isoburn_start_emulation(struct isoburn *o, int flag)
+{
+ int ret, i;
+ off_t data_count;
+ struct burn_drive *drive;
+ struct ecma119_pri_vol_desc *pvm;
+
+ if(o==NULL) {
+ burn_msgs_submit(0x00060000,
+ "Program error: isoburn_start_emulation: o==NULL",
+ 0, "FATAL", NULL);
+ return -1;
+ }
+
+ drive= o->drive;
+
+ /* we can assume 0 as start block for image */
+ /* TODO what about ms? where we validate valid iso image in ms disc? */
+ ret = burn_read_data(drive, (off_t) 0, (char*)o->target_iso_head,
+ sizeof(o->target_iso_head), &data_count, 2);
+
+ /* an error means an empty disc */
+ if (ret <= 0) {
+ o->fabricated_disc_status= BURN_DISC_BLANK;
+ return 1;
+ }
+
+ /* check first 64K. If 0's, the disc is treated as a blank disc, and thus
+ overwritten without extra check. */
+ i = sizeof(o->target_iso_head);
+ while (i && !o->target_iso_head[i-1])
+ --i;
+
+ if (!i) {
+ o->fabricated_disc_status= BURN_DISC_BLANK;
+ return 1;
+ }
+
+ pvm = (struct ecma119_pri_vol_desc *)(o->target_iso_head + 16 * 2048);
+
+ if (!strncmp((char*)pvm->std_identifier, "CD001", 5)) {
+ off_t size;
+
+ /* sanity check */
+ if (pvm->vol_desc_type[0] != 1 || pvm->vol_desc_version[0] != 1
+ || pvm->file_structure_version[0] != 1 ) {
+ /* TODO for now I treat this as a full disc */
+ o->fabricated_disc_status= BURN_DISC_FULL;
+ return 1;
+ }
+
+ /* ok, PVM found, set size */
+ size = (off_t) iso_read_lsb(pvm->vol_space_size, 4);
+ size *= (off_t) 2048; /* block size in bytes */
+ isoburn_set_start_byte(o, size, 0);
+ o->fabricated_disc_status= BURN_DISC_APPENDABLE;
+ } else if (!strncmp((char*)pvm->std_identifier, "CDXX1", 5)) {
+
+ /* empty image */
+ isoburn_set_start_byte(o, (off_t) 0, 0);
+ o->fabricated_disc_status= BURN_DISC_BLANK;
+ } else {
+ /* treat any disc in an unknown format as full */
+ o->fabricated_disc_status= BURN_DISC_FULL;
+ }
+ return 1;
+}
+
+
+/** Alters and writes the first 64 kB of a "media" to invalidate
+ an ISO image. (It shall stay restorable by skilled humans, though).
+ The result shall especially keep libisoburn from accepting the media
+ image as ISO filesystem.
+ @param o A fully activated isoburn object. isoburn_start_emulation()
+ was already called.
+ @return <=0 error , 1 = success
+*/
+int isoburn_invalidate_iso(struct isoburn *o, int flag)
+{
+ /*
+ * replace CD001 with CDXX1 in PVM.
+ * I think this is enought for invalidating an iso image
+ */
+ strncpy((char*)o->target_iso_head + 16 * 2048 + 1, "CDXX1", 5);
+ return isoburn_activate_session(o->drive);
+}
+
+
+/* API @since 0.1.0 */
+int isoburn_set_read_pacifier(struct burn_drive *drive,
+ int (*read_pacifier)(IsoImage*, IsoFileSource*),
+ void *read_handle)
+{
+ int ret;
+ struct isoburn *o;
+
+ ret = isoburn_find_emulator(&o, drive, 0);
+ if(ret < 0 || o == NULL)
+ return -1;
+ o->read_pacifier_handle= read_handle;
+ o->read_pacifier= read_pacifier;
+ return(1);
+}
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/libisoburn.h b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/libisoburn.h
new file mode 100644
index 00000000..c9efa65e
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/libisoburn/libisoburn.h
@@ -0,0 +1,1054 @@
+
+/*
+ API definition of libisoburn.
+
+ Copyright 2007-2008 Vreixo Formoso Lopes
+ and Thomas Schmitt
+*/
+
+/** Overview
+
+libisoburn is a frontend for libraries libburn and libisofs which enables
+creation and expansion of ISO-9660 filesystems on all CD/DVD media supported
+by libburn. This includes media like DVD+RW, which do not support multi-session
+management on media level and even plain disk files or block devices.
+
+The price for that is thorough specialization on data files in ISO-9660
+filesystem images. So libisoburn is not suitable for audio (CD-DA) or any
+other CD layout which does not entirely consist of ISO-9660 sessions.
+
+
+ Connector functions
+
+libisofs and libburn do not depend on each other but share some interfaces
+by which they can cooperate.
+libisoburn establishes the connection between both modules by creating the
+necessary interface objects and attaching them to the right places.
+
+
+ Wrapper functions
+
+The priciple of this frontend is that you may use any call of libisofs or
+libburn unless it has a isoburn_*() wrapper listed in the following function
+documentation.
+
+E.g. call isoburn_initialize() rather than iso_init(); burn_initialize();
+and call isoburn_drive_scan_and_grab() rather than burn_drive_scan_and_grab().
+But you may call burn_disc_get_profile() directly if you want to display
+the media type.
+
+The wrappers will transparently provide the necessary emulations which
+are appropriate for particular target drives and media states.
+To learn about them you have to read both API descriptions: the one of
+the wrapper and the one of the underlying libburn or libisofs call.
+
+Macros BURN_* and functions burn_*() are documented in
+Macros ISO_* and functions iso_*() are documented in
+
+
+ Usage model
+
+There may be an input drive and an output drive. Either of them may be missing
+with the consequence that no reading resp. writing is possible.
+Both drive roles can be fulfilled by the same drive.
+
+Input can be a random access readable libburn drive:
+ optical media, regular files, block devices.
+Output can be any writeable libburn drive:
+ writeable optical media in burner, writeable file objects (no directories).
+
+libburn demands rw-permissions to drive device file resp. file object.
+
+If the input drive provides a suitable ISO RockRidge image, then its tree
+may be loaded into memory and can then be manipulated by libisofs API calls.
+The loading is done by isoburn_read_image() under control of
+struct isoburn_read_opts which the application obtains from libisoburn
+and manipulates by the family of isoburn_ropt_set_*() functions.
+
+Writing of result images is controlled by libisofs related parameters
+in a struct isoburn_imgen_opts which the application obtains from libisoburn
+and manipulates by the family of isoburn_igopt_set_*() functions.
+
+All multi-session aspects are handled by libisoburn according to these
+settings. The application does not have to analyze media state and write
+job parameters. It rather states its desires which libisoburn tries to
+fulfill, or else will refuse to start the write run.
+
+
+ Setup for Growing or Modifying
+
+The connector function family offers two alternative API calls for performing
+the setup for two alternative image generation strategies.
+
+Growing:
+If input and output drive is the same, then isoburn_prepare_disc() is to
+be used. It will lead to an add-on session on appendable or overwriteable
+media with existing ISO image. With blank media it will produce a first
+session.
+
+Modifying:
+If the output drive is not the input drive, then it has to bear blank media
+or overwriteable without a valid ISO image. To prepare for such an image
+generation run, use isoburn_prepare_new_image(). The run will copy file data
+from an eventual input drive with valid image, add any newly introduced data
+from the local filesystem, and produce a first session on output media.
+
+After either of these setups, some peripheral libburn drive parameter settings
+like burn_write_opts_set_simulate(), burn_write_opts_set_multi(),
+ burn_drive_set_speed(), burn_write_opts_set_underrun_proof() should be made.
+Do not set the write mode. It will be chosen by libisoburn so it matches job
+and media state.
+
+ Writing the image
+
+Then one may start image generation and write threads by isoburn_disc_write().
+Progress may be watched at the output drive by burn_drive_get_status() and
+isoburn_get_fifo_status().
+
+At some time, the output drive will be BURN_DRIVE_IDLE indicating that
+writing has ended.
+One should inquire isoburn_drive_wrote_well() to learn about overall success.
+
+Finally one must call isoburn_activate_session() which will complete any
+eventual multi-session emulation.
+
+*/
+
+
+ /* API functions */
+
+
+/** Initialize libisoburn, libisofs and libburn.
+ Wrapper for : iso_init() and burn_initialize()
+ @since 0.1.0
+ @param msg A character array for eventual messages (e.g. with errors)
+ @param flag Bitfield for control purposes (unused yet, submit 0)
+ @return 1 indicates success, 0 is failure
+*/
+int isoburn_initialize(char msg[1024], int flag);
+
+
+/** Check whether all features of header file libisoburn.h from the given
+ major.minor.micro revision triple can be delivered by the library version
+ which is performing this call.
+ An application of libisoburn can easily memorize the version of the
+ libisofs.h header in its own code. Immediately after isoburn_initialize()
+ it should simply do this check:
+ if (! isoburn_is_compatible(isoburn_header_version_major,
+ isoburn_header_version_minor,
+ isoburn_header_version_micro, 0))
+ ...refuse to start the program with this dynamic library version...
+ @since 0.1.0
+ @param major obtained at build time
+ @param minor obtained at build time
+ @param micro obtained at build time
+ @param flag Bitfield for control purposes. Unused yet. Submit 0.
+ @return 1= library can work for caller
+ 0= library is not usable in some aspects. Caller must restrict
+ itself to an earlier API version or must not use this libray
+ at all.
+*/
+int isoburn_is_compatible(int major, int minor, int micro, int flag);
+
+
+/** Obtain the three release version numbers of the library. These are the
+ numbers encountered by the application when linking with libisoburn,
+ i.e. possibly not before run time.
+ Better do not base the fundamental compatibility decision of an application
+ on these numbers. For a reliable check use isoburn_is_compatible().
+ @since 0.1.0
+ @param major The maturity version (0 for now, as we are still learning)
+ @param minor The development goal version.
+ @param micro The development step version. This has an additional meaning:
+
+ Pare numbers indicate a version with frozen API. I.e. you can
+ rely on the same set of features to be present in all
+ published releases with that major.minor.micro combination.
+ Features of a pare release will stay available and ABI
+ compatible as long as the SONAME of libisoburn stays "1".
+ Currently there are no plans to ever change the SONAME.
+
+ Odd numbers indicate that API upgrades are in progress.
+ I.e. new features might be already present or they might
+ be still missing. Newly introduced features may be changed
+ incompatibly or even be revoked before release of a pare
+ version.
+ So micro revisions {1,3,5,7,9} should never be used for
+ dynamic linking unless the proper library match can be
+ guaranteed by external circumstances.
+
+ @return 1 success, <=0 might in future become an error indication
+*/
+void isoburn_version(int *major, int *minor, int *micro);
+
+
+/** The minimum version of libisofs to be used with this version of libisoburn
+ at compile time.
+ @since 0.1.0
+*/
+#define isoburn_libisofs_req_major 0
+#define isoburn_libisofs_req_minor 6
+#define isoburn_libisofs_req_micro 3
+
+/** The minimum version of libburn to be used with this version of libisoburn
+ at compile time.
+ @since 0.1.0
+*/
+#define isoburn_libburn_req_major 0
+#define isoburn_libburn_req_minor 4
+#define isoburn_libburn_req_micro 2
+
+
+/** The minimum version of libisofs to be used with this version of libisoburn
+ at runtime. This is checked already in isoburn_initialize() which will
+ refuse on outdated version. So this call is for information purposes after
+ successful startup only.
+ @since 0.1.0
+ @param major isoburn_libisofs_req_major as seen at build time
+ @param minor as seen at build time
+ @param micro as seen at build time
+ @return 1 success, <=0 might in future become an error indication
+*/
+int isoburn_libisofs_req(int *major, int *minor, int *micro);
+
+
+/** The minimum version of libburn to be used with this version of libisoburn
+ at runtime. This is checked already in isoburn_initialize() which will
+ refuse on outdated version. So this call is for information purposes after
+ successful startup only.
+ @since 0.1.0
+ @param major isoburn_libburn_req_major as seen at build time
+ @param minor as seen at build time
+ @param micro as seen at build time
+ @return 1 success, <=0 might in future become an error indication
+*/
+int isoburn_libburn_req(int *major, int *minor, int *micro);
+
+
+/** These three release version numbers tell the revision of this header file
+ and of the API it describes. They are memorized by applications at build
+ time.
+ @since 0.1.0
+*/
+#define isoburn_header_version_major 0
+#define isoburn_header_version_minor 1
+#define isoburn_header_version_micro 1
+/** Note:
+ Above version numbers are also recorded in configure.ac because libtool
+ wants them as parameters at build time.
+ For the library compatibility check, ISOBURN_*_VERSION in configure.ac
+ are not decisive. Only the three numbers here do matter.
+*/
+/** Usage discussion:
+
+Some developers of the libburnia project have differing
+opinions how to ensure the compatibility of libaries
+and applications.
+
+It is about whether to use at compile time and at runtime
+the version numbers isoburn_header_version_* provided here.
+Thomas Schmitt advises to use them.
+Vreixo Formoso advises to use other means.
+
+At compile time:
+
+Vreixo Formoso advises to leave proper version matching
+to properly programmed checks in the the application's
+build system, which will eventually refuse compilation.
+
+Thomas Schmitt advises to use the macros defined here
+for comparison with the application's requirements of
+library revisions and to eventually break compilation.
+
+Both advises are combinable. I.e. be master of your
+build system and have #if checks in the source code
+of your application, nevertheless.
+
+At runtime (via *_is_compatible()):
+
+Vreixo Formoso advises to compare the application's
+requirements of library revisions with the runtime
+library. This is to allow runtime libraries which are
+young enough for the application but too old for
+the lib*.h files seen at compile time.
+
+Thomas Schmitt advises to compare the header
+revisions defined here with the runtime library.
+This is to enforce a strictly monotonous chain
+of revisions from app to header to library,
+at the cost of excluding some older libraries.
+
+These two advises are mutually exclusive.
+
+-----------------------------------------------------
+
+For an implementation of the Thomas Schmitt approach,
+see libisoburn/burn_wrap.c : isoburn_initialize()
+This connects libisoburn as "application" with libisofs
+as "library".
+
+The compatible part of Vreixo Formoso's approach is implemented
+in configure.ac LIBBURN_REQUIRED, LIBISOFS_REQUIRED.
+In isoburn_initialize() it would rather test by
+ iso_lib_is_compatible(isoburn_libisofs_req_major,...
+than by
+ iso_lib_is_compatible(iso_lib_header_version_major,...
+and would leave out the ugly compile time traps.
+
+*/
+
+
+/** Aquire a target drive by its filesystem path resp. libburn persistent
+ address.
+ Wrapper for: burn_drive_scan_and_grab()
+ @since 0.1.0
+ @param drive_infos On success returns a one element array with the drive
+ (cdrom/burner). Thus use with driveno 0 only. On failure
+ the array has no valid elements at all.
+ The returned array should be freed via burn_drive_info_free()
+ when the drive is no longer needed.
+ @param adr The persistent address of the desired drive.
+ @param load 1 attempt to load the disc tray. 0 no attempt,rather failure.
+ @return 1 = success , 0 = drive not found , <0 = other error
+*/
+int isoburn_drive_scan_and_grab(struct burn_drive_info *drive_infos[],
+ char* adr, int load);
+
+
+/** Aquire a target drive by its filesystem path resp. libburn persistent
+ address. This is a modern successor of isoburn_drive_scan_and_grab().
+ Wrapper for: burn_drive_scan_and_grab()
+ @since 0.1.2
+ @param drive_infos On success returns a one element array with the drive
+ (cdrom/burner). Thus use with driveno 0 only. On failure
+ the array has no valid elements at all.
+ The returned array should be freed via burn_drive_info_free()
+ when the drive is no longer needed.
+ @param adr The persistent address of the desired drive.
+ @param flag bit0= attempt to load the disc tray.
+ Else: failure if not loaded.
+ bit1= regard overwriteable media as blank
+ bit2= if the drive is a regular disk file: truncate it to
+ the write start address
+ @return 1 = success , 0 = drive not found , <0 = other error
+*/
+int isoburn_drive_aquire(struct burn_drive_info *drive_infos[],
+ char* adr, int flag);
+
+
+/** Aquire a drive from the burn_drive_info[] array which was obtained by
+ a previous call of burn_drive_scan().
+ Wrapper for: burn_drive_grab()
+ @since 0.1.0
+ @param drive The drive to grab. E.g. drive_infos[1].drive .
+ @param load 1 attempt to load the disc tray. 0 no attempt, rather failure.
+ @return 1 success, <=0 failure
+*/
+int isoburn_drive_grab(struct burn_drive *drive, int load);
+
+
+/** Inquire the media status. Expect the whole spectrum of libburn BURN_DISC_*
+ with multi-session media. Emulated states with random access media are
+ BURN_DISC_BLANK and BURN_DISC_APPENDABLE.
+ Wrapper for: burn_disc_get_status()
+ @since 0.1.0
+ @param drive The drive to inquire.
+ @return The status of the drive, or what kind of disc is in it.
+ Note: BURN_DISC_UNGRABBED indicates wrong API usage
+*/
+enum burn_disc_status isoburn_disc_get_status(struct burn_drive *drive);
+
+
+/** Tells whether the media can be treated by isoburn_disc_erase().
+ Wrapper for: burn_disc_erasable()
+ @since 0.1.0
+ @param drive The drive to inquire.
+ @return 0=not erasable , else erasable
+*/
+int isoburn_disc_erasable(struct burn_drive *d);
+
+
+/** Mark the media as blank. With multi-session media this will call
+ burn_disc_erase(). With random access media, an eventual ISO-9660
+ filesystem will get invalidated by altering its start blocks on media.
+ In case of success, the media is in status BURN_DISC_BLANK afterwards.
+ Wrapper for: burn_disc_erase()
+ @since 0.1.0
+ @param drive The drive with the media to erase.
+ @param fast 1=fast erase, 0=thorough erase
+ With DVD-RW, fast erase yields media incapable of multi-session.
+*/
+void isoburn_disc_erase(struct burn_drive *drive, int fast);
+
+
+/* ----------------------------------------------------------------------- */
+/*
+
+ Options for image reading.
+
+ An application shall create an option set object by isoburn_ropt_new(),
+ program it by isoburn_ropt_set_*(), use it with isoburn_read_image(),
+ and finally delete it by isoburn_ropt_destroy().
+
+*/
+/* ----------------------------------------------------------------------- */
+
+struct isoburn_read_opts;
+
+/** Produces a set of image read options, initialized with default values.
+ @since 0.1.0
+ @param o the newly created option set object
+ @param flag Bitfield for control purposes. Submit 0 for now.
+ @return 1=ok , <0 = failure
+*/
+int isoburn_ropt_new(struct isoburn_read_opts **o, int flag);
+
+
+/** Deletes an option set which was created by isoburn_ropt_new().
+ @since 0.1.0
+ @param o The option set to work on
+ @param flag Bitfield for control purposes. Submit 0 for now.
+ @return 1= **o destroyed , 0= *o was already NULL (harmless)
+*/
+int isoburn_ropt_destroy(struct isoburn_read_opts **o, int flag);
+
+
+/** Which existing ISO 9660 extensions in the image to read or not to read.
+ Whether to read the content of an existing image at all.
+ The bits can be combined by | resp. inquired by &.
+ @since 0.1.0
+ @param ext Bitfield:
+ bit0= norock
+ Do not read Rock Ridge extensions
+ bit1= nojoliet
+ Do not read Joliet extensions
+ bit2= noiso1999
+ Do not read ISO 9660:1999 enhanced tree
+ bit3= preferjoliet
+ When both Joliet and RR extensions are present, the RR
+ tree is used. If you prefer using Joliet, set this to 1.
+ bit4= pretend_blank
+ Always create empty image.Ignore any image on input drive.
+ @return 1 success, <=0 failure
+*/
+#define isoburn_ropt_norock 1
+#define isoburn_ropt_nojoliet 2
+#define isoburn_ropt_noiso1999 4
+#define isoburn_ropt_preferjoliet 8
+#define isoburn_ropt_pretend_blank 16
+int isoburn_ropt_set_extensions(struct isoburn_read_opts *o, int ext);
+int isoburn_ropt_get_extensions(struct isoburn_read_opts *o, int *ext);
+
+
+/** Default attributes to use if no RockRidge extension gets loaded.
+ @since 0.1.0
+ @param o The option set to work on
+ @param uid user id number (see /etc/passwd)
+ @param gid group id number (see /etc/group)
+ @param mode permissions (not file type) as of man 2 stat.
+ With directories, r-permissions will automatically imply
+ x-permissions. See isoburn_ropt_set_default_dirperms() below.
+ @return 1 success, <=0 failure
+*/
+int isoburn_ropt_set_default_perms(struct isoburn_read_opts *o,
+ uid_t uid, gid_t gid, mode_t mode);
+int isoburn_ropt_get_default_perms(struct isoburn_read_opts *o,
+ uid_t *uid, gid_t *gid, mode_t *mode);
+
+/** Default attributes to use on directories if no RockRidge extension
+ gets loaded.
+ Above call isoburn_ropt_set_default_perms() automatically adds
+ x-permissions to r-permissions for directories. This call here may
+ be done afterwards to set independend permissions for directories,
+ especially to override the automatically added x-permissions.
+ @since 0.1.0
+ @param o The option set to work on
+ @param mode permissions (not file type) as of man 2 stat.
+ @return 1 success, <=0 failure
+*/
+int isoburn_ropt_set_default_dirperms(struct isoburn_read_opts *o,
+ mode_t mode);
+int isoburn_ropt_get_default_dirperms(struct isoburn_read_opts *o,
+ mode_t *mode);
+
+
+
+/** Set the character set for reading RR file names from ISO images.
+ @since 0.1.0
+ @param o The option set to work on
+ @param input_charset Set this to NULL to use the default locale charset.
+ For selecting a particular character set, submit its
+ name, e.g. as listed by program iconv -l.
+ Example: "UTF-8".
+ @return 1 success, <=0 failure
+*/
+int isoburn_ropt_set_input_charset(struct isoburn_read_opts *o,
+ char *input_charset);
+int isoburn_ropt_get_input_charset(struct isoburn_read_opts *o,
+ char **input_charset);
+
+
+/** After calling function isoburn_read_image() there are informations
+ available in the option set.
+ This info can be obtained as bits in parameter has_what. Like:
+ joliet_available = (has_what & isoburn_ropt_has_joliet);
+ @since 0.1.0
+ @param o The option set to work on
+ @param size Number of image data blocks, 2048 bytes each.
+ @param has_what Bitfield:
+ bit0= has_rockridge
+ RockRidge extension info is available (POSIX filesystem)
+ bit1= has_joliet
+ Joliet extension info is available (suitable for MS-Windows)
+ bit2= has_iso1999
+ ISO version 2 Enhanced Volume Descriptor is available.
+ This is rather exotic.
+ bit3= has_el_torito
+ El-Torito boot record is present
+ @return 1 success, <=0 failure
+*/
+#define isoburn_ropt_has_rockridge 1
+#define isoburn_ropt_has_joliet 2
+#define isoburn_ropt_has_iso1999 4
+#define isoburn_ropt_has_el_torito 8
+int isoburn_ropt_get_size_what(struct isoburn_read_opts *o,
+ uint32_t *size, int *has_what);
+
+
+/* ----------------------------------------------------------------------- */
+/* End of Options for image reading */
+/* ----------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+/*
+
+ Options for image generation by libisofs and image transport to libburn.
+
+ An application shall create an option set by isoburn_igopt_new(),
+ program it by isoburn_igopt_set_*(), use it with either
+ isoburn_prepare_new_image() or isoburn_prepare_disc(), and finally delete
+ it by isoburn_igopt_destroy().
+
+*/
+/* ----------------------------------------------------------------------- */
+
+struct isoburn_imgen_opts;
+
+/** Produces a set of generation and transfer options, initialized with default
+ values.
+ @since 0.1.0
+ @param o the newly created option set object
+ @param flag Bitfield for control purposes. Submit 0 for now.
+ @return 1=ok , <0 = failure
+*/
+int isoburn_igopt_new(struct isoburn_imgen_opts **o, int flag);
+
+
+/** Deletes an option set which was created by isoburn_igopt_new().
+ @since 0.1.0
+ @param o The option set to give up
+ @param flag Bitfield for control purposes. Submit 0 for now.
+ @return 1= **o destroyed , 0= *o was already NULL (harmless)
+*/
+int isoburn_igopt_destroy(struct isoburn_imgen_opts **o, int flag);
+
+
+/** ISO level to write at.
+ @since 0.1.0
+ @param o The option set to work on
+ @param level is a term of the ISO 9660 standard. It should be one of:
+ 1= filenames restricted to form 8.3
+ 2= filenames allowed up to 31 characters
+ @return 1 success, <=0 failure
+*/
+int isoburn_igopt_set_level(struct isoburn_imgen_opts *o, int level);
+int isoburn_igopt_get_level(struct isoburn_imgen_opts *o, int *level);
+
+
+/** Which extensions to support.
+ @since 0.1.0
+ @param o The option set to work on
+ @param ext Bitfield:
+ bit0= rockridge
+ Rock Ridge extensions add POSIX file attributes like
+ owner, group, access permissions, long filenames. Very
+ advisable if the designed audience has Unix style systems.
+ bit1= joliet
+ Longer filenames for Windows systems.
+ Weaker than RockRidge, but also readable with Linux.
+ bit2= iso1999
+ This is rather exotic. Better do not surprise the readers.
+ @return 1 success, <=0 failure
+*/
+#define isoburn_igopt_rockridge 1
+#define isoburn_igopt_joliet 2
+#define isoburn_igopt_iso1999 4
+int isoburn_igopt_set_extensions(struct isoburn_imgen_opts *o, int ext);
+int isoburn_igopt_get_extensions(struct isoburn_imgen_opts *o, int *ext);
+
+/** Relaxed constraints. Setting any of the bits to 1 break the specifications,
+ but it is supposed to work on most moderns systems. Use with caution.
+ @since 0.1.0
+ @param o The option set to work on
+ @param relax Bitfield:
+ bit0= omit_version_numbers
+ Omit the version number (";1") at the end of the
+ ISO-9660 identifiers. Version numbers are usually
+ not used.
+ bit1= allow_deep_paths
+ Allow ISO-9660 directory hierarchy to be deeper
+ than 8 levels.
+ bit2= allow_longer_paths
+ Allow path in the ISO-9660 tree to have more than
+ 255 characters.
+ bit3= max_37_char_filenames
+ 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.
+ bit4= no_force_dots
+ ISO-9660 forces filenames to have a ".", that separates
+ file name from extension. libisofs adds it if original
+ filename has none. Set this to 1 to prevent this
+ behavior.
+ bit5= allow_lowercase
+ Allow lowercase characters in ISO-9660 filenames.
+ By default, only uppercase characters, numbers and
+ a few other characters are allowed.
+ bit6= allow_full_ascii
+ Allow all ASCII characters to be appear on an ISO-9660
+ filename. Note * that "/" and "\0" characters are never
+ allowed, even in RR names.
+ bit7= joliet_longer_paths
+ Allow paths in the Joliet tree to have more than
+ 240 characters.
+ @return 1 success, <=0 failure
+*/
+#define isoburn_igopt_omit_version_numbers 1
+#define isoburn_igopt_allow_deep_paths 2
+#define isoburn_igopt_allow_longer_paths 4
+#define isoburn_igopt_max_37_char_filenames 8
+#define isoburn_igopt_no_force_dots 16
+#define isoburn_igopt_allow_lowercase 32
+#define isoburn_igopt_allow_full_ascii 64
+#define isoburn_igopt_joliet_longer_paths 128
+int isoburn_igopt_set_relaxed(struct isoburn_imgen_opts *o, int relax);
+int isoburn_igopt_get_relaxed(struct isoburn_imgen_opts *o, int *relax);
+
+
+/** Whether and how files should be sorted.
+ @since 0.1.0
+ @param o The option set to work on
+ @param value Bitfield: bit0= sort_files_by_weight
+ files should be sorted based on their weight.
+ Weight is attributed to files in the image
+ by libisofs call iso_node_set_sort_weight().
+ @return 1 success, <=0 failure
+*/
+#define isoburn_igopt_sort_files_by_weight 1
+int isoburn_igopt_set_sort_files(struct isoburn_imgen_opts *o, int value);
+int isoburn_igopt_get_sort_files(struct isoburn_imgen_opts *o, int *value);
+
+
+/** Set the override values for files and directory permissions.
+ The parameters replace_* these take one of three values: 0, 1 or 2.
+ If 0, the corresponding attribute will be kept as set in the IsoNode
+ at the time of image generation.
+ If set to 1, the corresponding attrib. will be changed by a default
+ suitable value.
+ With value 2, the attrib. will be changed with the value specified
+ in the corresponding *_mode options. Note that only the permissions
+ are set, the file type remains unchanged.
+ @since 0.1.0
+ @param o The option set to work on
+ @param replace_dir_mode whether and how to override directories
+ @param replace_file_mode whether and how to override files of other type
+ @param dir_mode Mode to use on dirs with replace_dir_mode == 2.
+ @param file_mode; Mode to use on files with replace_file_mode == 2.
+ @return 1 success, <=0 failure
+*/
+int isoburn_igopt_set_over_mode(struct isoburn_imgen_opts *o,
+ int replace_dir_mode, int replace_file_mode,
+ mode_t dir_mode, mode_t file_mode);
+int isoburn_igopt_get_over_mode(struct isoburn_imgen_opts *o,
+ int *replace_dir_mode, int *replace_file_mode,
+ mode_t *dir_mode, mode_t *file_mode);
+
+/** Set the override values values for group id and user id.
+ The rules are like with above overriding of mode values. replace_* controls
+ whether and how. The other two parameters provide values for eventual use.
+ @since 0.1.0
+ @param o The option set to work on
+ @param replace_uid whether and how to override user ids
+ @param replace_gid whether and how to override group ids
+ @param uid User id to use with replace_uid == 2.
+ @param gid Group id to use on files with replace_gid == 2.
+ @return 1 success, <=0 failure
+*/
+int isoburn_igopt_set_over_ugid(struct isoburn_imgen_opts *o,
+ int replace_uid, int replace_gid,
+ uid_t uid, gid_t gid);
+int isoburn_igopt_get_over_ugid(struct isoburn_imgen_opts *o,
+ int *replace_uid, int *replace_gid,
+ uid_t *uid, gid_t *gid);
+
+/** Set the charcter set to use for representing filenames in the image.
+ @since 0.1.0
+ @param o The option set to work on
+ @param output_charset Set this to NULL to use the default output charset.
+ For selecting a particular character set, submit its
+ name, e.g. as listed by program iconv -l.
+ Example: "UTF-8".
+ @return 1 success, <=0 failure
+*/
+int isoburn_igopt_set_out_charset(struct isoburn_imgen_opts *o,
+ char *output_charset);
+int isoburn_igopt_get_out_charset(struct isoburn_imgen_opts *o,
+ char **output_charset);
+
+
+/** The number of bytes to be used for the fifo which decouples libisofs
+ and libburn for better throughput and for reducing the risk of
+ interrupting signals hitting the libburn thread which operates the
+ MMC drive.
+ The size will be rounded up to the next full 2048.
+ Minimum is 64kiB, maximum is 1 GiB (but that is too much anyway).
+ @since 0.1.0
+ @param o The option set to work on
+ @param fifo_size Number of bytes to use
+ @return 1 success, <=0 failure
+*/
+int isoburn_igopt_set_fifo_size(struct isoburn_imgen_opts *o, int fifo_size);
+int isoburn_igopt_get_fifo_size(struct isoburn_imgen_opts *o, int *fifo_size);
+
+
+/* ----------------------------------------------------------------------- */
+/* End of Options for image generation */
+/* ----------------------------------------------------------------------- */
+
+
+/** Get the image attached to a drive, if any.
+ @since 0.1.0
+ @param d The drive to inquire
+ @return A reference to attached image, or NULL if the drive has no image
+ attached. This reference needs to be released via iso_image_unref()
+ when it is not longer needed.
+*/
+IsoImage *isoburn_get_attached_image(struct burn_drive *d);
+
+
+/** Load the ISO filesystem directory tree from the media in the given drive.
+ This will give libisoburn the base on which it can let libisofs perform
+ image growing or image modification. The loaded volset gets attached
+ to the drive object and handed out to the application.
+ Not a wrapper, but peculiar to libisoburn.
+ @since 0.1.0
+ @param d The drive which holds an existing ISO filesystem or blank media.
+ d is allowed to be NULL which produces an empty ISO image. In
+ this case one has to call before writing isoburn_attach_volset()
+ with the volset from this call and with the intended output
+ drive.
+ @param read_opts The read options which can be chosen by the application
+ @param image the image read, if the disc is blank it will have no files.
+ This reference needs to be released via iso_image_unref() when
+ it is not longer needed. The drive, if not NULL, will hold an
+ own reference which it will release when it gets a new volset
+ or when it gets released via isoburn_drive_release().
+ You can pass NULL if you already have a reference or you plan to
+ obtain it later with isoburn_get_attached_image(). Of course, if
+ you haven't specified a valid drive (i.e., if d == NULL), this
+ parameter can't be NULL.
+ @return <=0 error , 1 = success
+*/
+int isoburn_read_image(struct burn_drive *d,
+ struct isoburn_read_opts *read_opts,
+ IsoImage **image);
+
+/** Set a callback function for producing pacifier messages during the lengthy
+ process of image reading. The callback function and the application handle
+ are stored until they are needed for the underlying call to libisofs.
+ Other than with libisofs the handle is managed entirely by the application.
+ An idle .free() function is exposed to libisofs. The handle has to stay
+ valid until isoburn_read_image() is done. It has to be detached by
+ isoburn_set_read_pacifier(drive, NULL, NULL);
+ before it may be removed from memory.
+ @since 0.1.0
+ @param drive The drive which will be used with isoburn_read_image()
+ It has to be aquired by an isoburn_* wrapper call.
+ @param read_pacifier The callback function
+ @param app_handle The app handle which the callback function can obtain
+ via iso_image_get_attached_data() from its IsoImage*
+ @return 1 success, <=0 failure
+*/
+int isoburn_set_read_pacifier(struct burn_drive *drive,
+ int (*read_pacifier)(IsoImage*, IsoFileSource*),
+ void *app_handle);
+
+
+/** Set the IsoImage to be used with a drive. This eventually releases
+ the reference to the old IsoImage attached to the drive.
+ Caution: Use with care. It hardly makes sense to replace an image that
+ reflects a valid ISO image on media.
+ This call is rather intended for writing a newly created and populated
+ image to blank media. The use case in xorriso is to let an image survive
+ the change or demise of the outdev target drive.
+ @since 0.1.0
+ @param d The drive which shall be write target of the volset.
+ @param image The image that represents the image to be written.
+ This image pointer MUST already be a valid reference suitable
+ for iso_image_unref().
+ It may have been obtained by appropriate libisofs calls or by
+ isoburn_read_image() with d==NULL.
+ @return <=0 error , 1 = success
+*/
+int isoburn_attach_image(struct burn_drive *d, IsoImage *image);
+
+
+/** Return the best possible estimation of the currently available capacity of
+ the media. This might depend on particular write option settings and on
+ drive state.
+ An eventual start address for emulated multi-session will be subtracted
+ from the capacity estimation given by burn_disc_available_space().
+ Negative results get defaulted to 0.
+ Wrapper for: burn_disc_available_space()
+ @since 0.1.0
+ @param d The drive to query.
+ @param o If not NULL: write parameters to be set on drive before query
+ @return number of most probably available free bytes
+*/
+off_t isoburn_disc_available_space(struct burn_drive *d,
+ struct burn_write_opts *o);
+
+
+/** Obtain the start block number of the most recent session on media. In
+ case of random access media this will always be 0. Succesfull return is
+ not a guarantee that there is a ISO-9660 image at all. The call will fail,
+ nevertheless,if isoburn_disc_get_status() returns not BURN_DISC_APPENDABLE.
+ Wrapper for: burn_disc_get_msc1()
+ @since 0.1.0
+ @param d The drive to inquire
+ @param start_lba Contains on success the start address in 2048 byte blocks
+ @return <=0 error , 1 = success
+*/
+int isoburn_disc_get_msc1(struct burn_drive *d, int *start_lba);
+
+
+/** Use this with trackno==0 to obtain the predicted start block number of the
+ new session. The interesting number is returned in parameter nwa.
+ Wrapper for: burn_disc_track_lba_nwa()
+ @since 0.1.0
+ @param d The drive to inquire
+ @param o If not NULL: write parameters to be set on drive before query
+ @param trackno Submit 0.
+ @param lba return value: start lba
+ @param nwa return value: Next Writeable Address
+ @return 1=nwa is valid , 0=nwa is not valid , -1=error
+*/
+int isoburn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
+ int trackno, int *lba, int *nwa);
+
+
+/** Obtain the size which was attributed to an emulated appendable on actually
+ overwriteable media. This value is supposed to be <= 2048 * nwa as of
+ isoburn_disc_track_lba_nwa().
+ @since 0.1.0
+ @param drive The drive holding the media.
+ @param start_byte The reply value counted in bytes, not in sectors.
+ @param flag Unused yet. Submit 0.
+ @return 1=stat_byte is valid, 0=not an emulated appendable, -1=error
+*/
+int isoburn_get_min_start_byte(struct burn_drive *d, off_t *start_byte,
+ int flag);
+
+
+/** Create a disc object for writing the new session from the created or loaded
+ iso_volset which has been manipulated via libisofs, to the same media from
+ where the image was eventually loaded. This struct burn_disc is ready for
+ use by a subsequent call to isoburn_disc_write().
+ After this asynchronous writing has ended and the drive is BURN_DRIVE_IDLE
+ again, the burn_disc object has to be disposed by burn_disc_free().
+ @since 0.1.0
+ @param drive The combined source and target drive, grabbed with
+ isoburn_drive_scan_and_grab(). .
+ @param disc Returns the newly created burn_disc object.
+ @param opts Image generation options, see isoburn_igopt_*()
+ @return <=0 error , 1 = success
+*/
+int isoburn_prepare_disc(struct burn_drive *drive, struct burn_disc **disc,
+ struct isoburn_imgen_opts *opts);
+
+
+/** Create a disc object for producing a new image from a previous image
+ plus the changes made by user. The generated burn_disc is suitable
+ to be written to any grabbed libburn drive with blank writeable media.
+ But you must not use the same drive for input and output, because data
+ will be read from the source drive while at the same time the target
+ drive is already writing.
+ The resulting burn_disc object has to be disposed when all its writing
+ is done and the drive is BURN_DRIVE_IDLE again after asynchronous
+ burn_disc_write().
+ @since 0.1.0
+ @param in_drive The input drive,grabbed with isoburn_drive_scan_and_grab().
+ @param disc Returns the newly created burn_disc object.
+ @param opts Options for image generation and data transport to media.
+ @param out_drive The libburn drive which shall be write target.
+ If the drive was grabbed via libisoburn then it can later
+ access the libisofs source fifo via
+ isoburn_get_fifo_status().
+ Mere libburn drives cannot obtain this info.
+ In that case out_drive may be NULL, as well.
+ @return <=0 error , 1 = success
+*/
+int isoburn_prepare_new_image(struct burn_drive *in_drive,
+ struct burn_disc **disc,
+ struct isoburn_imgen_opts *opts,
+ struct burn_drive *out_drive);
+
+/** @since 0.1.0
+ Revoke isoburn_prepare_new_image() or isoburn_prepare_disc() instead of
+ running isoburn_disc_write().
+ libisofs reserves resources and maybe already starts generating the
+ image stream when one of above two calls is performed. It is mandatory to
+ either run isoburn_disc_write() or to revoke the preparations by the
+ call described here.
+ @since 0.1.0
+ @param input_drive The drive resp. in_drive which was used with the
+ preparation call.
+ @param output_drive The out_drive used with isoburn_prepare_new_image(),
+ NULL if none.
+ @param flag Bitfield, submit 0 for now.
+ bit0= -reserved for internal use-
+ @return <0 error, 0= no pending preparations detectable, 1 = canceled
+*/
+int isoburn_cancel_prepared_write(struct burn_drive *input_drive,
+ struct burn_drive *output_drive, int flag);
+
+
+/** Start writing of the new session.
+ This call is asynchrounous. I.e. it returns quite soon and the progress has
+ to be watched by a loop with call burn_drive_get_status() until
+ BURN_DRIVE_IDLE is returned.
+ Wrapper for: burn_disc_write()
+ @since 0.1.0
+ @param o Options which control the burn process. See burnwrite_opts_*()
+ in libburn.h.
+ @param disc Disc object created either by isoburn_prepare_disc() or by
+ isoburn_prepare_new_image().
+*/
+void isoburn_disc_write(struct burn_write_opts *o, struct burn_disc *disc);
+
+
+/** Inquire state and fill parameters of the fifo which is attached to
+ the emerging track. This should be done in the pacifier loop while
+ isoburn_disc_write() or burn_disc_write() are active.
+ This works only with drives obtained by isoburn_drive_scan_and_grab()
+ or isoburn_drive_grab(). If isoburn_prepare_new_image() was used, then
+ parameter out_drive must have announced the track output drive.
+ Hint: If only burn_write_opts and not burn_drive is known, then the drive
+ can be obtained by burn_write_opts_get_drive().
+ @since 0.1.0
+ @parm d The drive to which the track with the fifo gets burned.
+ @param size The total size of the fifo
+ @param free_bytes The current free capacity of the fifo
+ @param status_text Returns a pointer to a constant text, see below
+ @return <0 reply invalid, >=0 fifo status code:
+ bit0+1=input status, bit2=consumption status, i.e:
+ 0="standby" : data processing not started yet
+ 1="active" : input and consumption are active
+ 2="ending" : input has ended without error
+ 3="failing" : input had error and ended,
+ 4="unused" : ( consumption has ended before processing start )
+ 5="abandoned" : consumption has ended prematurely
+ 6="ended" : consumption has ended without input error
+ 7="aborted" : consumption has ended after input error
+*/
+int isoburn_get_fifo_status(struct burn_drive *d, int *size, int *free_bytes,
+ char **status_text);
+
+
+/** Inquire whether the most recent write run was successful.
+ Wrapper for: burn_drive_wrote_well()
+ @since 0.1.0
+ @param d The drive to inquire
+ @return 1=burn seems to have went well, 0=burn failed
+*/
+int isoburn_drive_wrote_well(struct burn_drive *d);
+
+
+/** Call this after isoburn_disc_write has finished and burn_drive_wrote_well()
+ indicates success. It will eventually complete the emulation of
+ multi-session functionality, if needed at all. Let libisoburn decide.
+ Not a wrapper, but peculiar to libisoburn.
+ @since 0.1.0
+ @param d The output drive to which the session was written
+ @return 1 success , <=0 failure
+*/
+int isoburn_activate_session(struct burn_drive *drive);
+
+
+/** @since 0.1.0
+ Wait after normal end of operations until libisofs ended all write
+ threads and freed resource reservations.
+ This call is not mandatory. But without it, messages from the ending
+ threads might appear after the application ended its write procedure.
+ @since 0.1.0
+ @param input_drive The drive resp. in_drive which was used with the
+ preparation call.
+ @param output_drive The out_drive used with isoburn_prepare_new_image(),
+ NULL if none.
+ @param flag Bitfield, submit 0 for now.
+ @return <=0 error , 1 = success
+*/
+int isoburn_sync_after_write(struct burn_drive *input_drive,
+ struct burn_drive *output_drive, int flag);
+
+
+#if 0
+/* >>> NOT YET IMPLEMENTED <<< */
+/** Write a new session to a disc.
+ This is a synchronous call equivalent to isoburn_prepare_disc +
+ isoburn_disc_write + isoburn_activate_session
+ @param pacifier_func If not NULL: a function to produce appeasing messages.
+ See burn_abort_pacifier() in libburn.h for an example.
+*/
+/* TODO implement this */
+int isoburn_perform_write(struct burn_write_opts *o,
+ int (*pacifier_func)(void *handle, int patience,
+ int elapsed));
+#endif /* 0 */
+
+
+/** Release an aquired drive.
+ Wrapper for: burn_drive_release()
+ @since 0.1.0
+ @param drive The drive to be released
+ @param eject 1= eject media from drive , 0= do not eject
+*/
+void isoburn_drive_release(struct burn_drive *drive, int eject);
+
+
+/** Shutdown all three libraries.
+ Wrapper for : iso_finish() and burn_finish().
+ @since 0.1.0
+*/
+void isoburn_finish(void);
+
+
+/*
+ The following calls are for expert applications only.
+ An application should have a special reason to use them.
+*/
+
+
+/** Inquire wether the media needs emulation or would be suitable for
+ generic multi-session via libburn.
+ @since 0.1.0
+ @param d The drive to inquire
+ @return 0 is generic multi-session
+ 1 is emulated multi-session
+ -1 is not suitable for isoburn
+*/
+int isoburn_needs_emulation(struct burn_drive *drive);
+
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/test/compare_file.c b/libisoburn/branches/XorrisoZeroOneTwo/test/compare_file.c
new file mode 100644
index 00000000..2d460f54
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/test/compare_file.c
@@ -0,0 +1,275 @@
+/*
+ Compare two copies of a file object in as many aspects as i can imagine
+ to make sense. (E.g.: comparing atime makes no sense.)
+
+ To compare tree /media/dvd and /original/dir :
+ find /media/dvd -exec compare_file '{}' /media/dvd /original/dir ';'
+
+ Copyright 2008 Thomas Schmitt,
+
+ Provided under GPL version 2.
+
+
+ cc -g -o compare_file compare_file.c
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/* @param flag bit0= single letters */
+char *Ftypetxt(mode_t st_mode, int flag)
+{
+ if(flag&1)
+ goto single_letters;
+ if(S_ISDIR(st_mode))
+ return("directory");
+ else if(S_ISREG(st_mode))
+ return("regular_file");
+ else if(S_ISLNK(st_mode))
+ return("symbolic_link");
+ else if(S_ISBLK(st_mode))
+ return("block_device");
+ else if(S_ISCHR(st_mode))
+ return("char_device");
+ else if(S_ISFIFO(st_mode))
+ return("name_pipe");
+ else if(S_ISSOCK(st_mode))
+ return("unix_socket");
+ return("unknown");
+single_letters:;
+ if(S_ISDIR(st_mode))
+ return("d");
+ else if(S_ISREG(st_mode))
+ return("-");
+ else if(S_ISLNK(st_mode))
+ return("l");
+ else if(S_ISBLK(st_mode))
+ return("b");
+ else if(S_ISCHR(st_mode))
+ return("c");
+ else if(S_ISFIFO(st_mode))
+ return("p");
+ else if(S_ISSOCK(st_mode))
+ return("s");
+ return("?");
+}
+
+
+char *Ftimetxt(time_t t, char timetext[40], int flag)
+{
+ char *rpt;
+ struct tm tms, *tmpt;
+ static char months[12][4]= { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ tmpt= localtime_r(&t, &tms);
+ rpt= timetext;
+ rpt[0]= 0;
+ if(tmpt==0)
+ sprintf(rpt+strlen(rpt), "%12.f", (double) t);
+ else if(time(NULL)-t < 180*86400 && time(NULL)-t >= 0)
+ sprintf(rpt+strlen(rpt), "%3s %2d %2.2d:%2.2d",
+ months[tms.tm_mon], tms.tm_mday, tms.tm_hour, tms.tm_min);
+ else
+ sprintf(rpt+strlen(rpt), "%3s %2d %4.4d",
+ months[tms.tm_mon], tms.tm_mday, 1900+tms.tm_year);
+ return(timetext);
+}
+
+
+/* @param flag bit0= compare atime
+ bit1= compare ctime
+*/
+int Compare_2_files(char *adr1, char *adr2, char *adrc, int flag)
+{
+ struct stat s1, s2;
+ int ret, differs= 0, r1, r2, fd1= -1, fd2= -1, i, done;
+ char buf1[4096], buf2[4096], a[4096], ttx1[40], ttx2[40];
+ off_t r1count= 0, r2count= 0, diffcount= 0, first_diff= -1;
+
+ ret= lstat(adr1, &s1);
+ if(ret==-1) {
+ printf("? %s : cannot lstat() : %s\n", adr1, strerror(errno));
+ return(0);
+ }
+ strcpy(a, Ftypetxt(s1.st_mode, 1));
+ strcat(a, " ");
+ if(adrc[0])
+ strcat(a, adrc);
+ else
+ strcat(a, ".");
+
+ ret= lstat(adr2, &s2);
+ if(ret==-1) {
+ printf("? %s : cannot lstat() : %s\n", adr2, strerror(errno));
+ return(0);
+ }
+
+ /* Attributes */
+ if(s1.st_mode != s2.st_mode) {
+ if((s1.st_mode&~S_IFMT)!=(s2.st_mode&~S_IFMT))
+ printf("%s : st_mode : %7.7o <> %7.7o\n", a, s1.st_mode, s2.st_mode);
+ if((s1.st_mode&S_IFMT)!=(s2.st_mode&S_IFMT))
+ printf("%s : type : %s <> %s\n",
+ a, Ftypetxt(s1.st_mode, 0), Ftypetxt(s2.st_mode, 0));
+ differs= 1;
+ }
+ if(s1.st_uid != s2.st_uid) {
+ printf("%s : st_uid : %d <> %d\n", a, s1.st_uid, s2.st_uid);
+ differs= 1;
+ }
+ if(s1.st_gid != s2.st_gid) {
+ printf("%s : st_gid : %d <> %d\n", a, s1.st_gid, s2.st_gid);
+ differs= 1;
+ }
+ if((S_ISCHR(s1.st_mode) && S_ISCHR(s2.st_mode)) ||
+ (S_ISBLK(s1.st_mode) && S_ISBLK(s2.st_mode))) {
+ if(s1.st_rdev != s2.st_rdev) {
+ printf("%s : %s st_rdev : %lu <> %lu\n", a,
+ (S_ISCHR(s1.st_mode) ? "S_IFCHR" : "S_IFBLK"),
+ (unsigned long) s1.st_rdev, (unsigned long) s1.st_rdev);
+ differs= 1;
+ }
+ }
+ if(S_ISREG(s2.st_mode) && s1.st_size != s2.st_size) {
+ printf("%s : st_size : %.f <> %.f diff= %.f\n",
+ a, (double) s1.st_size, (double) s2.st_size,
+ ((double) s1.st_size) - (double) s2.st_size);
+ differs= 1;
+ }
+ if(s1.st_mtime != s2.st_mtime) {
+ printf("%s : st_mtime : %s <> %s diff= %.f s\n",
+ a, Ftimetxt(s1.st_mtime, ttx1, 0),
+ Ftimetxt(s2.st_mtime, ttx2, 0),
+ ((double) s1.st_mtime) - (double) s2.st_mtime);
+ differs= 1;
+ }
+ if(flag&1) {
+ if(s1.st_atime != s2.st_atime) {
+ printf("%s : st_atime : %s <> %s diff= %.f s\n",
+ a, Ftimetxt(s1.st_atime, ttx1, 0),
+ Ftimetxt(s2.st_atime, ttx2, 0),
+ ((double) s1.st_atime) - (double) s2.st_atime);
+ differs= 1;
+ }
+ }
+ if(flag&2) {
+ if(s1.st_ctime != s2.st_ctime) {
+ printf("%s : st_ctime : %s <> %s diff= %.f s\n",
+ a, Ftimetxt(s1.st_ctime, ttx1, 0),
+ Ftimetxt(s2.st_ctime, ttx2, 0),
+ ((double) s1.st_ctime) - (double) s2.st_ctime);
+ differs= 1;
+ }
+ }
+ if(S_ISREG(s1.st_mode) && S_ISREG(s2.st_mode)) {
+ fd1= open(adr1, O_RDONLY);
+ if(fd1==-1) {
+ printf("- %s : cannot open() : %s\n", adr1, strerror(errno));
+ return(0);
+ }
+ fd2= open(adr2, O_RDONLY);
+ if(fd2==-1) {
+ printf("- %s : cannot open() : %s\n", adr2, strerror(errno));
+ close(fd1);
+ return(0);
+ }
+
+ /* Content */
+ done= 0;
+ while(!done) {
+ r1= read(fd1, buf1, sizeof(buf1));
+ r2= read(fd2, buf2, sizeof(buf2));
+ if((r1==EOF && r2==EOF) || (r1==0 && r2==0))
+ break;
+ if(r1==EOF || r1==0) {
+ if(r1==EOF)
+ r1= 0;
+ if(s1.st_size > r1count + r1)
+ printf("- %s : early EOF after %.f bytes\n", adr1, (double) r1count);
+ differs= 1;
+ }
+ r1count+= r1;
+ if(r2==EOF || r2 r2count + r2)
+ printf("- %s : early EOF after %.f bytes\n", adr2, (double) r2count);
+ differs= 1;
+ done= 1;
+ }
+ if(r2>r1) {
+ if(s1.st_size > r1count + r1)
+ printf("- %s : early EOF after %.f bytes\n", adr1, (double) r1count);
+ differs= 1;
+ done= 1;
+ }
+ r2count+= r2;
+ if(r1>r2)
+ r1= r2;
+ for(i= 0; i0 || r1count!=r2count) {
+ if(first_diff<0)
+ first_diff= (r1count>r2count ? r2count : r1count);
+ printf("%s : %s : differs by at least %.f bytes. First at %.f\n", a,
+ (s1.st_mtime==s2.st_mtime ? "CONTENT":"content"),
+ (double) (diffcount + abs(r1count-r2count)), (double) first_diff);
+ differs= 1;
+ }
+ }
+ if(fd1!=-1)
+ close(fd1);
+ if(fd2!=-1)
+ close(fd2);
+ return(!differs);
+}
+
+
+int main(int argc, char **argv)
+{
+ int ret, i, with_ctime= 1;
+ char adr1[4096], adr2[4096], adrc[4096];
+
+ if(argc<4) {
+ fprintf(stderr, "usage: %s path prefix1 prefix2\n", argv[0]);
+ exit(2);
+ }
+ for(i= 4; i
+ and Thomas Schmitt
+*/
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#include
+#include
+#include "../src/libisoburn.h"
+
+const char * const optstring = "JRh";
+extern char *optarg;
+extern int optind;
+
+
+/** Activates the usage of function graft_point() rather than
+ plain iso_tree_radd_dir() from libisofs
+*/
+#define With_graft_poinT 1
+
+
+static int graft_point(struct iso_volume *volume, const char *disk_path,
+ const char *img_path, struct iso_tree_radd_dir_behavior *behav)
+{
+ char path[4096], *apt, *npt;
+ struct iso_tree_node_dir *dir;
+ struct iso_tree_node *node;
+ int done= 0, is_dir= 0;
+ struct stat stbuf;
+
+ strncpy(path, img_path, sizeof(path)-1);
+ path[sizeof(path)-1]= 0;
+ apt= npt= path;
+
+ if(lstat(disk_path, &stbuf) == -1) {
+ fprintf(stderr, "Cannot determine attributes of '%s' : %s (%d)\n",
+ disk_path, (errno > 0 ? strerror(errno) : "unknown error"), errno);
+ return(0);
+ }
+ if(S_ISDIR(stbuf.st_mode))
+ is_dir= 1;
+ else if(!(S_ISREG(stbuf.st_mode) || S_ISLNK(stbuf.st_mode))) {
+ fprintf(stderr, "File object '%s' is of non-supported file type\n",
+ disk_path);
+ return(0);
+ }
+
+ dir= iso_volume_get_root(volume);
+ if(dir==NULL) {
+ fprintf(stderr, "While grafting '%s' : no root node available\n", img_path);
+ return(0);
+ }
+ for(npt= apt; !done; apt= npt+1) {
+ npt= strchr(apt, '/');
+ if(npt==NULL) {
+ npt= apt+strlen(apt);
+ done= 1;
+ } else
+ *npt= 0;
+ if(*apt==0) {
+ *apt= '/';
+ apt++;
+ continue;
+ }
+ node= iso_tree_volume_path_to_node(volume,path);
+ if(node!=NULL) {
+ if(iso_tree_node_get_type(node)!=LIBISO_NODE_DIR) {
+ fprintf(stderr, "While grafting '%s' : '%s' is not a directory\n",
+ img_path, path);
+ return(0);
+ }
+ dir= (struct iso_tree_node_dir *) node;
+ } else {
+ dir= iso_tree_add_dir(dir, apt);
+ if(dir==NULL) {
+ fprintf(stderr, "While grafting '%s' : could not insert '%s'\n",
+ img_path, path);
+ return(0);
+ }
+ }
+ if(done) {
+ if(is_dir) {
+ iso_tree_radd_dir(dir, disk_path, behav);
+ } else {
+ node= iso_tree_add_node(dir, disk_path);
+ if(node == NULL) {
+ fprintf(stderr, "While grafting '%s'='%s' : libisofs_errno = %d\n",
+ img_path, disk_path, libisofs_errno);
+ }
+ }
+ } else
+ *npt= '/';
+ }
+ fprintf(stderr, "NOTE: added %s '%s'='%s'\n", (is_dir ? "directory" : "node"),
+ img_path, disk_path);
+ return(1);
+}
+
+
+static
+void usage()
+{
+ printf("test [OPTIONS] DRIVE DIRECTORY\n");
+}
+
+static
+void help()
+{
+ printf(
+"Options:\n"
+" -J Add Joliet support\n"
+" -R Add Rock Ridge support\n"
+" -h Print this message\n"
+);
+}
+
+int main(int argc, char **argv)
+{
+ struct burn_drive_info *drives;
+ struct iso_volset *volset;
+ struct burn_drive *drive;
+ struct burn_disc *disc;
+ enum burn_disc_status state;
+ struct isoburn_read_opts ropts;
+ struct isoburn_source_opts sopts;
+ int c;
+ struct iso_tree_radd_dir_behavior behav = {0,0,0};
+ int flags=0;
+ int ret=0, i;
+ int size, free_bytes;
+ char *status_text;
+
+ while ((c = getopt(argc, argv, optstring)) != -1) {
+ switch(c) {
+ case 'h':
+ usage();
+ help();
+ exit(0);
+ break;
+ case 'J':
+ flags |= ECMA119_JOLIET;
+ break;
+ case 'R':
+ flags |= ECMA119_ROCKRIDGE;
+ break;
+ case '?':
+ usage();
+ exit(1);
+ break;
+ }
+ }
+
+ if (argc < optind + 1) {
+ fprintf(stderr, "Please supply device name\n");
+ usage();
+ exit(1);
+ }
+ if (argc < optind + 2) {
+ fprintf(stderr, "Please supply directory to add to disc\n");
+ usage();
+ exit(1);
+ }
+
+
+ if (!isoburn_initialize()) {
+ fprintf(stderr, "Can't init libisoburn\n");
+ exit(1);
+ }
+
+ /* TODO change this. maybe we can add wrapp in libisoburn */
+ iso_msgs_set_severities("NEVER", "DEBUG", "libisofs : ");
+ burn_msgs_set_severities("NEVER", "DEBUG", "libburn : ");
+ burn_set_signal_handling("libisoburn/test/test : ", NULL, 0);
+
+ printf("Growing drive %s\n", argv[optind]);
+
+ if (isoburn_drive_scan_and_grab(&drives, argv[optind], 1) <= 0) {
+ fprintf(stderr,
+ "Can't open device. Are you sure it is a valid drive?\n");
+ exit(1);
+ }
+ drive = drives[0].drive;
+
+ /* check for invalid state */
+ state = isoburn_disc_get_status(drive);
+ if (state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE) {
+ fprintf(stderr, "Unsuitable disc status\n");
+ goto exit_cleanup;
+ }
+
+ /* fill read opts */
+ memset(&ropts, sizeof(ropts), 0);
+ ropts.norock = 0;
+ ropts.nojoliet = 0;
+ ropts.preferjoliet = 0;
+ ropts.uid = 0;
+ ropts.gid = 0;
+ ropts.mode = 0555;
+ ropts.pretend_blank= 0;
+
+ if (isoburn_read_volset(drive, &ropts, &volset) <= 0) {
+ fprintf(stderr, "Can't read volset\n");
+ goto exit_cleanup;
+ }
+
+
+#ifdef With_graft_poinT
+ for (i = optind + 1; i < argc; i++) {
+ if (graft_point(iso_volset_get_volume(volset, 0),
+ argv[i], argv[i], &behav) <= 0) {
+ fprintf(stderr, "Canot graft '%s'\n", argv[optind+1]);
+ goto exit_cleanup;
+ }
+ }
+
+#else
+ struct iso_tree_node_dir *root;
+ root = iso_volume_get_root(iso_volset_get_volume(volset, 0));
+ /* add a new dir */
+ iso_tree_radd_dir(root, argv[optind+1], &behav);
+#endif /* ! With_graft_poinT */
+
+
+ sopts.level = 2;
+ sopts.flags = flags;
+ sopts.relaxed_constraints = 0;
+ sopts.copy_eltorito = 1;
+ sopts.no_cache_inodes = 0;
+ sopts.sort_files = 1;
+ sopts.default_mode = 0;
+ sopts.replace_dir_mode = 0;
+ sopts.replace_file_mode = 0;
+ sopts.replace_uid = 0;
+ sopts.replace_gid = 0;
+ sopts.dir_mode = 0555;
+ sopts.file_mode = 0444;
+ sopts.gid = 0;
+ sopts.uid = 0;
+ sopts.input_charset = NULL;
+ sopts.ouput_charset = NULL;
+
+ if (isoburn_prepare_disc(drive, &disc, &sopts) <= 0) {
+ fprintf(stderr, "Can't prepare disc\n");
+ goto volset_cleanup;
+ }
+
+ /* a. write the new image */
+ printf("Adding new data...\n");
+ {
+ struct burn_write_opts *burn_options;
+ struct burn_progress progress;
+
+ burn_options = burn_write_opts_new(drive);
+ burn_drive_set_speed(drive, 0, 0);
+ burn_write_opts_set_underrun_proof(burn_options, 1);
+
+ /* ok, write the new track */
+ isoburn_disc_write(burn_options, disc);
+ burn_write_opts_free(burn_options);
+
+ while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
+ usleep(100002);
+
+ while (burn_drive_get_status(drive, &progress)
+ != BURN_DRIVE_IDLE) {
+
+ printf("Writing: sector %d of %d",
+ progress.sector, progress.sectors);
+ ret = isoburn_get_fifo_status(drive, &size,
+ &free_bytes, &status_text);
+ if (ret > 0 )
+ printf(" [fifo %s, %2d%% fill]", status_text,
+ (int) (100.0 - 100.0 *
+ ((double) free_bytes) /
+ (double) size));
+ printf("\n");
+ sleep(1);
+ }
+ }
+
+ /* b. write the new vol desc */
+ printf("Writing the new vol desc...\n");
+ if (isoburn_activate_session(drive) <= 0) {
+ fprintf(stderr, "Ups, new vol desc write failed\n");
+ }
+
+ ret= 0;
+volset_cleanup:;
+/*
+ iso_volset_free(volset);
+*/
+
+exit_cleanup:;
+ isoburn_drive_release(drive, 0);
+ isoburn_finish();
+
+ exit(ret);
+}
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/version.h.in b/libisoburn/branches/XorrisoZeroOneTwo/version.h.in
new file mode 100644
index 00000000..cf529233
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/version.h.in
@@ -0,0 +1,6 @@
+
+/* <<< this file is on its way out
+#define ISOBURN_MAJOR_VERSION @ISOBURN_MAJOR_VERSION@
+#define ISOBURN_MINOR_VERSION @ISOBURN_MINOR_VERSION@
+#define ISOBURN_MICRO_VERSION @ISOBURN_MICRO_VERSION@
+*/
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/README b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/README
new file mode 100644
index 00000000..fd4636ee
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/README
@@ -0,0 +1,201 @@
+------------------------------------------------------------------------------
+ libburnia-project.org scdbackup.sourceforge.net/xorriso_eng.html
+------------------------------------------------------------------------------
+xorriso. By Thomas Schmitt
+Integrated sub project of libburnia-project.org but also published via:
+http://scdbackup.sourceforge.net/xorriso_eng.html
+http://scdbackup.sourceforge.net/xorriso-0.1.1.tar.gz
+Copyright (C) 2006-2008 Thomas Schmitt, provided under GPL version 2.
+------------------------------------------------------------------------------
+
+
+xorriso is a program which maps file objects from POSIX compliant
+filesystems into Rock Ridge enhanced ISO 9660 filesystems and allows
+session-wise manipulation of such filesystems. It can load the management
+information of existing ISO images and it writes the session results to
+optical media or to filesystem objects.
+
+Currently it is only supported on Linux with kernels >= 2.4.
+
+A special property of xorriso is that it needs neither an external ISO 9660
+formatter program nor an external burn program for CD or DVD but rather
+incorporates the libraries of libburnia-project.org .
+
+By using this software you agree to the disclaimer at the end of this text:
+"... without even the implied warranty ..."
+
+
+ Compilation, First Glimpse, Installation
+
+The most simple way to get xorriso from source code is the xorriso standalone
+tarball.
+
+Prerequisites:
+The tarball contains anything that is needed except libc and libpthread.
+libreadline and the readline-dev headers will make dialog mode more convenient,
+but are not mandatory.
+
+Obtain xorriso-0.1.1.tar.gz, take it to a directory of your choice and do:
+
+ tar xzf xorriso-0.1.1.tar.gz
+ cd xorriso-0.1.1
+
+Within that directory execute:
+
+ ./configure --prefix=/usr
+ make
+
+This will produce a binary named
+ ./xorriso/xorriso
+
+which you may strip to reduce it in size
+ strip ./xorriso/xorriso
+
+You may copy or move it to a directory where it can be found by the shell,
+you may execute xorriso at the place where it was built, or you may execute
+as superuser:
+ make install
+
+For general concepts, options and usage examples see
+ man 1 xorriso
+
+This man page is part of the tarball as
+ xorriso/xorriso.1
+You may get a first glimpse by
+ man ./xorriso/xorriso.1
+
+It gets installed with "make install" but may also be placed manually in the
+./man1 directory below one of the directories mentioned in environment
+variable $MANPATH.
+
+
+ Drives and Disk File Objects
+
+The user of xorriso needs rw-permission for the CD burner device.
+A list of rw-accessible drives can be obtained by
+
+ xorriso -devices
+
+CD devices which offer no rw-permission are invisible to normal users.
+The superuser should be able to see any usable drive and then set the
+permissions as needed.
+
+The output of xorriso -devices might look like
+
+0 -dev '/dev/sr0' rwrw-- : 'TSSTcorp' 'CDDVDW SH-S203B'
+1 -dev '/dev/hda' rwrw-- : 'HL-DT-ST' 'DVD-ROM GDR8162B'
+
+Full and insecure enabling of both for everybody would look like
+ chmod a+rw /dev/sr0 /dev/hda
+This is equivalent to the traditional setup chmod a+x,u+s cdrecord.
+
+I strongly discourage to run xorriso with setuid root or via sudo !
+It is not checked for the necessary degree of hacker safety.
+
+Consider to put all authorized users into group "floppy", to chgrp the
+device file to that group and to disallow w-access to others.
+
+
+A possible source of problems are hald or other automounters.
+If you can spot a process "hald-addon-storage" with the address of
+your desired drive, then consider to kill it.
+
+If you cannot get rid of the automounter that easily, try whether it helps
+to always load the drive tray manually before starting a write run of
+xorriso. Wait until the drive light is off.
+Better try to unmount an eventually mounted media before a write run.
+
+
+Besides true optical drives, xorriso can also address disk files as input or
+output drives. The addresses of the disk files have to be preceded by "stdio:".
+Like:
+ xorriso -dev stdio:/tmp/pseudo_drive ...more arguments...
+
+
+ Testing
+
+We are quite sure that libisofs produces accurate representations of the disk
+files. This opinion is founded on a lot of test burns and checks by a little
+test program which compares files from the mounted image with the orignals
+on disk. It uses the normal POSIX filesystem calls, i.e. no libburnia stuff.
+
+This program is not installed systemwide but stays in the installation
+directory of the xorriso tarball as test/compare_file . Usually it is
+run as -exec payload of a find command. It demands at least three arguments:
+The path of the first file to compare, the prefix1 to be cut off from path
+and the prefix2 which gets prepended afterwards to obtain the path of the
+second file to compare.
+As further argument there can be -no_ctime which suppresses the comparison
+of ctime date stamps.
+The exit value is 0 if no difference was detected, non-0 else.
+
+Example: After
+ xorriso ... -pathspecs on -add /=/original/dir --
+ mount /media/dvd
+ cd test
+compare tree /media/dvd with tree /original/dir :
+ find /original/dir -exec ./compare_file '{}' /original/dir /media/dvd ';' \
+ | less
+and vice versa:
+ find /media/dvd -exec ./compare_file '{}' /media/dvd /original/dir ';' \
+ | less
+
+
+ libisoburn
+
+xorriso is based on libisofs which does ISO 9600 filesystem aspects and on
+libburn which does the input and output aspects. Parts of this foundation
+are accessed via libisoburn, which is closely related to xorriso.
+
+libisoburn provides two services:
+- Encapsulation of coordination between libisofs and libburn.
+- Emulation of ISO 9660 multi-session on overwriteable media
+ or random access files.
+
+The sourcecode of all three libraries is included in the xorriso standalone
+tarball. It is compiled with xorriso and linked statically.
+But you may as well get and install releases of libburn and libisofs, in order
+to be able to install a release of libisoburn which produces libisoburn.so.1
+and a matching dynamically linked xorriso binary.
+This binary is leaner but depends on properly installed libraries of suitable
+revision.
+
+Dynamic library and compile time header requirements for libisoburn-0.1.1 :
+- libburn.so.4 , version libburn-0.4.2 or higher
+- libisofs.so.6 , version libisofs-0.6.2 or higher
+libisoburn and xorriso will not start with libraries which are older than their
+headers seen at compile time. So compile in the oldest possible installation
+setup unless you have reason to enforce a newer bug fix level.
+
+Standalone xorriso has less runtime dependencies and can be moved more freely.
+
+
+------------------------------------------------------------------------------
+
+ This program is free software; 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.
+
+ 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
+
+------------------------------------------------------------------------------
+Based on and sub project of:
+libburnia-project.org
+By Mario Danic ,
+ Vreixo Formoso
+ Thomas Schmitt
+Copyright (C) 2006-2008 Mario Danic, Vreixo Formoso, Thomas Schmitt.
+
+libburnia-project.org is inspired by and in other components still containing
+parts of old
+Libburn. By Derek Foreman and
+ Ben Jansens
+Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/changelog.txt b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/changelog.txt
new file mode 100644
index 00000000..e064ef27
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/changelog.txt
@@ -0,0 +1,1906 @@
+------------------------------------------------------------------------------
+ libburnia-project.org libisoburn , xorriso
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+ Changelog
+------------------------------------------------------------------------------
+
+
+1 Sep 2007 [983]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+libisoburn/isofs_wrap.c
+Initial content of libisoburn
+
+1 Sep 2007 [985]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/isofs_wrap.c
+Should have used copy+paste when writing Vreixos name
+
+5 Sep 2007 [990]
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+Implemented use of stdio-pseudo-drives
+
+5 Sep 2007 [993]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+Changes in plans as discussed up to Sep 5 2007
+
+5 Sep 2007 [994]
+libisoburn/libisoburn.h
+Updated explanations about the usage principles of libisoburn
+
+6 Sep 2007 [998]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+Updated to state of discussion
+
+9 Sep 2007 [1025]
+libisoburn/burn_wrap.c
+New wrapper isoburn_disc_erasable() declares ISO DVD-RAM, DVD+RW erasable
+
+10 Sep 2007 [1027]
+libisoburn/libisoburn.h
+New wrapper isoburn_disc_erasable() declares ISO DVD-RAM, DVD+RW erasable
+
+11 Sep 2007 [1029]
+libisoburn/burn_wrap.c
+libisoburn/isoburn.h
+New inner function isoburn_set_start_byte()
+
+12 Sep 2007 [1031]
+libisoburn/libisoburn.h
+libisoburn/burn_wrap.c
+Removed isoburn_write_opts_set_start_byte()
+
+13 Sep 2007 [1043]
+libisoburn/burn_wrap.c
+Took into respect fabricated_disc_status
+
+21 Sep 2007 [1092]
+Makefile.am
+Removed libburn file addresses
+
+22 Sep 2007 [1093]
++ doc/doxygen.conf.in
+Added file demanded by build system
+
+22 Sep 2007 [1094]
+src/burn_wrap.c
+Prevented SIGSEGV in isoburn_drive_scan_and_grab()
+
+22 Sep 2007 [1095]
+src/burn_wrap.c
+Enabled treatment==2 in isoburn_drive_scan_and_grab()
+
+22 Sep 2007 [1099]
+src/burn_wrap.c
+Made use of burn_msgs_submit() for error messages
+
+23 Sep 2007 [1102]
+src/burn_wrap.c
+Removed all references to isoburn.treatment from burn_wrap.c
+
+23 Sep 2007 [1105]
+src/burn_wrap.c
+Called isoburn_create_data_source() and isoburn_free_data_source()
+
+28 Sep 2007 [1129] libisofs
+libisofs/libiso_msgs.h
+Removed apostrophes which my compiler does not like
+
+29 Sep 2007 [1133]
+src/burn_wrap.c
+Added optional code for a pseudo CD-RW to test the code for MMC multi-session
+
+29 Sep 2007 [1134]
+src/burn_wrap.c
+Released drive in case welcome_media fails
+
+1 Oct 2007 [1141]
+src/burn_wrap.c
+Allowed isoburn_disc_get_msc1() for closed media
+
+2 Oct 2007 [1149]
+test/test.c
+Function graft_point(),some general polishing, call of iso_volset_free disabled
+
+8 Oct 2007 [1169]
+src/libisoburn.h
+src/isoburn.h
+src/isoburn.c
+src/burn_wrap.c
+Introduced fifo reference into isoburn object
+
+8 Oct 2007 [1170]
+test/test.c
+Several directories and files in one session, added display of fifo
+
+12 Oct 2007 [1171]
++ test/xorriso.h
++ test/xorriso.c
++ test/xorriso.txt
+The stub of new application xorriso
+
+12 Oct 2007 [1172]
++ test/compile_xorriso.sh
++ test/make_timestamp.sh
++ test/xorriso_timestamp.h
+A build facility to circumvent autotools during development
+
+12 Oct 2007 [1173]
+test/xorriso.c
+Introduced version and build timestamps, library headers
+
+13 Oct 2007 [1174]
+test/xorriso.c
++ test/changelog.txt
+Made -dialog and -options_from_file work
+
+2007.10.13.141503 [1175]
+test/xorriso.c
+Implemented -speed and enlarged -status list
+
+2007.10.13.152252 [1176]
+test/xorriso.c
+test/xorriso.txt
+Implemented xorriso setter level of -fs, -gid, -uid
+
+2007.10.14.110003 [1177]
+test/xorriso.c
+Implemented setter level of -abort_on, fixed bugs about -f,-no_rc,startup files
+
+2007.10.14.122456 [1178]
+test/xorriso.c
++ test/xorriso_private.h
++ test/xorrisoburn.h
++ test/xorrisoburn.c
+Began to implement interface to our libraries
+
+2007.10.15.152705 [1183]
+test/xorriso.h
+test/xorriso.c
+test/xorriso_private.h
+test/xorrisoburn.h
+test/xorrisoburn.c
+Implemented -dev, -add, -commit
+
+2007.10.15.160303 [1184]
+test/xorriso.c
+Made -end give up drives
+
+2007.10.15.203554 [1185]
+test/xorriso.c
+Some safety precautions against malicious input, enabled -cdx, -cdi for -add
+
+2007.10.15.203714 [1186]
+test/xorrisoburn.c
+Corrected image path bug with -add of regular files, and -add /=/some/dir
+
+2007.10.15.224005 [1187]
+test/xorriso.c
+test/xorrisoburn.c
+Implemented -rollback
+
+2007.10.16.210911 [1188]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Worked on failure severities, message system, program abort decision
+
+2007.10.17.130041 [1190] [1191
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Worked on failure severities, message system, program abort decision
+
+2007.10.17.130311 [1192]
+src/isofs_wrap.c
+Told burn_read_data() to stay silent on non-existent drive or read error
+
+2007.10.17.150142 [1193]
+test/xorriso.c
+test/xorrisoburn.c
+Reinstated the distinction of message sources, respected '#' in dialog
+
+2007.10.17.165352 [1194]
+test/xorriso.c
+Prepended a "-" to any input line if missing
+
+2007.10.17.183024 [1195]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Implemented core of option -toc
+
+2007.10.17.200241 [1196]
+test/xorrisoburn.c
+Continued work with -toc
+
+2007.10.17.213852 [1197]
+test/compile_xorriso.sh
+Forgot to make off_t 64 bit
+
+2007.10.17.214228 [1198]
+src/libisoburn.h
+src/burn_wrap.c
+test/xorrisoburn.c
+Rounding up fabricated nwa to full 32k addresses, API call for exact image size
+
+2007.10.17.215809 [1199]
+test/xorriso.c
+Activated -ban_stdio_write
+
+2007.10.17.224924 [1200]
+test/xorrisoburn.c
+Fixed obvious bug with -J. (Still wondering wether it works)
+
+2007.10.17.225039 [1201]
+test/xorriso.c
+Fixed bug with -speed.
+
+2007.10.17.225837 [1202]
+test/xorriso.c
+Fixed bug with -prompt. Fixed bug with # comments. (of rev 1194)
+
+18 Oct 2007 [1203]
+test/changelog.txt
+Updated changelog and todo list
+
+2007.10.18.144841 [1205]
+src/isofs_wrap.c
+test/xorrisoburn.c
+isoburn_read_volset() now hands out an official volset reference
+
+2007.10.18.171415 [1206]
+test/xorriso.c
+test/xorriso.txt
+test/xorrisoburn.h
+test/xorrisoburn.c
+Implemented option -devices
+
+2007.10.18.183200 [1207]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Implemented option -tell_media_space
+
+2007.10.18.185731 [1208]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.c
+Fixed a SIGSEGV with xorriso -version run
+
+2007.10.18.221756 [1211]
+test/xorrisoburn.c
+src/libisoburn.h
+Took care of disposal of burn_disc ovbject
+
+18 Oct 2007 [1212]
+test/test.c
+Silenced compile warning
+
+2007.10.18.225654 [1213]
+src/isofs_wrap.c
+test/xorriso.c
+test/xorrisoburn.c
+Fixed a SIGSEGV with empty drive
+
+2007.10.19.140031 [1218]
+test/xorrisoburn.c
+Made reports with -add normal infos (formerly NOTE events)
+
+2007.10.19.151339 [1219]
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.txt
+Implemented -print-size
+
+2007.10.19.164957 [1220]
+test/xorriso_private.h
+test/xorriso.c
+test/xorriso.h
+test/xorrisoburn.c
+test/xorriso.txt
+Implemented verbosity control by option -report_about
+
+2007.10.19.173547 [1221]
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.txt
+Implemented option -eject
+
+2007.10.19.204155 [1222]
+test/xorriso_private.h
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Implemented option -blank
+
+2007.10.20.170731 [1223]
+src/burn_wrap.c
+Directed write mode failure message to libburn queue, repaired wrote_well
+
+2007.10.20.171046 [1224]
+test/xorrisoburn.c
+test/xorriso_private.h
+test/xorriso.c
+Implemented options -format and -blank deformat, -close and closed media
+
+20 Oct 2007 [1225]
+test/xorriso.txt
++ test/xorriso.1
+test/changelog.txt
+Splitted think text from emerging man page, formatted man page
+
+2007.10.20.194918 [1226]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Completed -tell_media_space, checked space before burn, failed -end exits >0
+
+20 Oct 2007 [1227]
+test/xorriso.1
+Polished man page
+
+2007.10.21.094818 [1228]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Implemented -rm and -rm_r
+
+2007.10.21.105228 [1229]
+src/data_source.c
+Silenced compiler warning about C++ style comment
+
+2007.10.21.124315 [1230]
+test/xorriso.c
+test/xorrisoburn.c
+test/xorrisoburn.h
+Began to implement -ls and -ls_l, enhanced -cdi, not done yet
+
+2007.10.21.151124 [1231]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorrisoburn.h
+Hopefully completed -cd alias -cdi
+
+2007.10.21.185248 [1232]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Hopefully completed -cdx
+
+2007.10.21.213303 [1233]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.1
+Implemented sorting of -ls by node name, implemented leaf name search patterns
+
+2007.10.22.211928 [1237]
+test/xorrisoburn.c
+test/xorriso.1
+Implemented file size and mtime for -ls_l
+
+2007.10.23.122349 [1238]
+src/libisoburn.h
+src/isoburn.c
+Added fifo_size to struct isoburn_source_opts
+
+2007.10.23.122753 [1239]
+test/xorrisoburn.c
+test/xorriso.c
+test/xorriso.1
+Made use of isoburn_source_opts.fifo_size
+
+2007.10.24.100156 [1244]
+test/xorriso.c
+test/xorrisoburn.c
+Normalized paths to target and source before adding or removing from image
+
+2007.10.24.105424 [1245]
+test/xorriso.c
+test/xorriso.h
+Implemented option -path-list
+
+2007.10.24.175337 [1247]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Made -cd useable with no image loaded
+
+2007.10.27.224148 [1257]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Implemented option -mv
+
+2007.10.27.230512 [1258]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Bug fixes with option -mv
+
+2007.10.28.125501 [1260]
+test/xorriso.c
+test/xorrisoburn.c
+Prevented some interesting pitfalls with -mv
+
+2007.10.28.165516 [1261]
+test/xorriso.c
+test/xorriso.1
+test/xorrisoburn.h
+test/xorrisoburn.c
+Implemented option -mkdir
+
+2007.10.28.174550 [1262]
+test/xorriso.c
+Warning of wildcards in paths
+
+28 Oct 2007 [1263]
+test/xorriso.1
+Updated man page about -path-list
+
+2007.10.29.213920 [1273]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Structured patterns for options -ls and -ls_l
+
+2007.10.30.214242 [1274]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+test/compile_xorriso.sh
+Multiple structured patterns, changed option -ls from single to multi args
+
+2007.10.31.103338 [1275]
+test/xorriso_private.h
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.1
+Implemented new option -temp_mem_limit
+
+2007.10.31.165413 [1276]
+test/xorriso.c
+test/xorrisoburn.c
+test/xorrisoburn.h
+Gave simple -ls an implemention with minimal memory consumption
+
+31 Oct 2007 [1277]
+test/xorriso.1
+Overhauled info paragraphs of man page
+
+2007.10.31.175916 [1278]
+test/xorriso_private.h
+Overhauled comments in struct XorrisO
+
+31 Oct 2007 [1279]
+test/changelog.txt
+Updating changelog
+
+2007.11.01.111351 [1280]
+test/xorrisoburn.c
+Got rid of bad pacifier text at end of CD writing
+
+2007.11.01.191106 [1281]
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorrisoburn.h
+test/xorriso.1
+Implemented option -du
+
+2007.11.02.143549 [1282]
+test/xorrisoburn.h
+test/xorrisoburn.c
+Clearer status messages after reading new volume and after burning
+
+2007.11.02.143658 [1283]
+test/xorriso.c
+Made -abort_on and -report_about complain with bad severity names
+
+2007.11.02.184705 [1284]
+test/xorrisoburn.c
+test/xorriso.1
+Polished write success message and man page
+
+2007.11.06.163305 [1285]
+test/xorriso_private.h
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.1
+Implemented -overwrite control
+
+2007.11.06.163929 [1286]
+src/libisoburn.h
+Corrected a typo in a comment
+
+2007.11.06.164029 [1287]
+src/isoburn.c
+Closed memory leak by freeing session and track in isoburn_prepare_disc_aux()
+
+2007.11.07.123744 [1288]
+test/xorriso_private.h
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Implemented option -reassure
+
+2007.11.07.150157 [1289]
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.1
+Implemented option -rmdir
+
+2007.11.07.191915 [1290]
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Implemented option -chmod (does not get written into image, though)
+
+2007.11.07.225624 [1291]
+test/xorriso.c
+test/xorrisoburn.c
+test/xorrisoburn.h
+Implemented options -chown and -chgrp (not written into image, though)
+
+2007.11.08.144451 [1292]
+test/xorriso.c
+test/xorrisoburn.c
+test/xorrisoburn.h
+test/xorriso.1
+Implemented option -alter_date, corrected write problem with mode and ownership
+
+2007.11.08.145016 [1293]
+test/xorriso_private.h
+Forgotten source file for rev 1292
+
+8 Nov 2007 [1294]
+test/xorriso.1
+Enhanced man page text for options -chmod, -chown, -chgrp
+
+2007.11.08.160302 [1295]
+test/xorriso.c
+Fixed bug with -chmod go=r
+
+2007.11.08.161215 [1296]
+test/xorriso.c
+test/xorrisoburn.c
+Enlarged string size limit of Text_shellsafe()
+
+2007.11.09.193142 [1297]
+test/xorriso_private.h
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+New option -iso_rr_pattern, influencing several options with multiple args
+
+2007.11.11.112321 [1298]
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.c
+Gave problem handling finer granularity within loops
+
+11 Nov 2007 [1299]
+test/xorriso.1
+Clarified man page
+
+2007.11.11.154453 [1300]
+test/xorriso.c
+Added missing commit to normal end of program
+
+11 Nov 2007 [1301]
+test/xorriso.1
+Added some examples to man page
+
+2007.11.14.142904 [1302]
+src/libisoburn.h
+src/isofs_wrap.c
+src/isoburn.c
+test/test.c
+New API call isoburn_attach_volset(), changes with isoburn_read_volset()
+
+2007.11.14.143119 [1303]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Implemented options -outdev and -indev
+
+2007.11.14.175446 [1304]
+test/xorriso.c
+Corrected premature abort bug with misspelled command words
+
+14 Nov 2007 [1305]
+test/xorriso.1
+Polished xorriso man page
+
+14 Nov 2007 [1306]
+test/changelog.txt
+Updated xorriso changelog
+
+2007.11.26.192113 [1311]
+test/xorriso.c
+test/xorrisoburn.c
+Reacted on warnings on a 64 bit system
+
+2007.12.04.074340 [1314]
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.1
+Implemented -disk_pattern, -lsx, ls_lx, -dux, -du_lx
+
+2007.12.04.205919 [1315]
+test/xorrisoburn.c
+test/xorriso_private.h
+test/xorriso.c
+Removed some redundancy of disk_pattern and iso_rr_pattern matching
+
+4 Dec 2007 [1316]
+test/xorriso.1
+Polished man page
+
+2007.12.05.090438 [1317]
+test/xorriso.h
+test/xorriso.c
+test/xorriso.1
+Option -f-off as counterpart of option -f
+
+2007.12.05.143632 [1318]
+test/xorriso.c
+Made dashes at options optional
+
+5 Dec 2007 [1319]
+test/xorriso.1
+Overhauled description of media types, states and expansion methods
+
+2007.12.06.150102 [1320]
+test/xorriso.h
+test/xorriso.c
+test/xorriso.1
+Changed -f, -f-off to -follow, -graft-points, -graf-points-off to -pathspecs
+
+6 Dec 2007 [1321]
+test/xorriso.1
+Removed references to option -graft-points
+
+2007.12.06.192437 [1322]
+test/xorriso.c
+Corrected warning function about wildcards
+
+8 Dec 2007 [1326]
+test/xorriso.1
+Explained result pager
+
+2007.12.08.175117 [1327]
+test/xorriso.c
+test/xorriso_private.h
+test/xorrisoburn.c
+Removed more code redundancies and fd leak with Xorriso_obtain_pattern_files_x()
+
+2007.12.15.162039 [1328]
+test/compile_xorriso.sh
+Added -O0 to -g to get better gdb behavior on my new system
+
+2007.12.15.183022 [1329]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Implemented option -follow
+
+2007.12.16.103456 [1330]
+test/xorriso.c
+test/xorriso.1
+Added link hop limit to option -follow
+
+2007.12.16.122626 [1331]
+test/xorrisoburn.c
+Added copying of attributes from symbolic link into image
+
+2007.12.16.144615 [1332]
+test/xorrisoburn.c
+Removed waste of time in Xorriso_show_du_subs()
+
+2007.12.18.175924 [1333]
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Changed options -ls* to -lsd*, introduced new family of -ls* without d
+
+2007.12.20.111338 [1334]
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.1
+Changed -du_s* into -dus*
+
+2007.12.21.131538 [1335]
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Implemented option -find alias -findi
+
+2007.12.21.132017 [1336]
+test/xorriso.c
+test/xorriso.1
+Corrected documentation about -find
+
+2007.12.22.143803 [1337]
+test/xorriso.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.1
+Implemented option -findx
+
+2007.12.24.161107 [1339]
+test/xorriso.c
+Repaired options -dus and -dusx
+
+24 Dec 2007 [1340]
+test/changelog.txt
+Updated changelog
+
+2007.12.25.160100 [1341]
+test/xorriso.h
+test/xorriso.c
+test/xorriso.1
+Implemented option -cpr
+
+2007.12.26.160040 [1342]
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Changed option -J to -joliet "on"|"off", implemented option -volid
+
+2007.12.28.132741 [1343]
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.c
+Made leaner the local memory of recursive functions (because of ulimit -s)
+
+2007.12.30.190138 [1344]
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.c
+test/xorriso.1
+Implemented -find option -exec echo, chown, chgrp, chmod, alter_date, lsdl
+
+2007.12.30.203336 [1345]
+test/xorriso.c
+Corrected superuser behavior of Sfile_lookup_permissions()
+
+2007.12.31.095229 [1346]
+test/xorriso.c
+test/xorrisoburn.c
+Repaired some bugs in -find and -findx
+
+2007.12.31.135237 [1347]
+test/xorriso.h
+test/xorriso.c
+test/xorriso.1
+Implemented options -chown_r, -chgrp_r, -chmod_r, -alter_date_r
+
+2007.12.31.135330 [1348]
+test/xorrisoburn.c
+Repaired a bug in -find
+
+2008.01.01.123118 [1349]
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+test/xorriso.1
+Implemented -find actions chown_r, chgrp_r, chmod_r, alter_date_r, find
+
+2008.01.02.175011 [1350]
+test/xorriso.c
+test/xorriso.1
+Implemented -find test -type
+
+2008.01.09.175418 [1351]
+test/xorrisoburn.c
+Corrections made during porting to nglibisofs
+
+2008.01.10.114451 [1352]
++ test/ng_xorrisoburn.h
++ test/ng_xorrisoburn.c
+test/compile_xorriso.sh
+Begin of porting to next generation libisofs
+
+2008.01.10.151924 [1353]
+Makefile.am
++ ng_src
++ ng_src/libisoburn.h
++ ng_src/isoburn.h
++ ng_src/isoburn.c
++ ng_src/isofs_wrap.c
++ ng_src/data_source.c
++ ng_src/burn_wrap.c
+Begin of porting to next generation libisofs
+
+2008.01.10.152353 [1354]
+test/ng_xorrisoburn.c
+test/compile_xorriso.sh
+Made compile_xorriso.sh -nglibisofs work on ./ng_src
+
+2008.01.10.154948 [1355]
+test/ng_xorrisoburn.c
+test/compile_xorriso.sh
+Made compile_xorriso.sh -oglibisofs work on ./og_src
+
+2008.01.11.133319 [1356]
+test/compile_xorriso.sh
+Adapted to existence of nglibisofs eltorito.o
+
+2008.01.11.133631 [1357]
+test/xorriso.c
+test/ng_xorrisoburn.c
+test/xorrisoburn.c
+Removed old and new bugs
+
+2008.01.11.174733 [1358]
+test/xorriso.c
+test/ng_xorrisoburn.c
+test/xorrisoburn.c
+Tracing the different behavior of isoburn_read_image()
+
+2008.01.11.175423 [1359]
+test/ng_xorrisoburn.c
+ng_src/isoburn.c
+ng_src/libisoburn.h
+Changed isoburn_source_opts.ouput_charset to output_charset
+
+2008.01.11.212545 [1361]
+ng_src/isofs_wrap.c
+Made initialization of iso_read_opts safer
+
+13 Jan 2008 [1364]
++ og_src
+- src src/burn_wrap.c
+- src/isoburn.c
+- src/isoburn.h
+- src/data_source.c
+- src/isofs_wrap.c
+- src/libisoburn.h
++ og_src/burn_wrap.c
++ og_src/isoburn.c
++ og_src/isoburn.h
++ og_src/data_source.c
++ og_src/isofs_wrap.c
++ og_src/libisoburn.h
+Moved src to og_src and installed symbolic link instead
+
+13 Jan 2008 [1365]
+ng_src/isofs_wrap.c
+Changes about blanking loaded image
+
+2008.01.13.224929 [1366]
+test/ng_xorrisoburn.c
+Allowed all filetypes as input, silenced debug during image read
+
+14 Jan 2008 [1367]
+test/compile_xorriso.sh
+Added forgotten source module
+
+14 Jan 2006 [1368]
+ng_src/libisoburn.h
+ng_src/isoburn.c
+New members in isoburn_source_opts
+
+2008.01.14.163814 [1369]
+test/ng_xorrisoburn.c
+Closed memory leak, adapted to new members in isoburn_source_opts
+
+2008.01.14.164628 [1370]
+test/ng_xorrisoburn.c
+Repaired memory hog and a freshly introduced bug
+
+2008.01.14.190220 [1371]
+test/xorriso.c
+test/ng_xorrisoburn.c
+test/xorriso.1
+Removed some bugs and made adaptions to nglibisofs
+
+2008.01.14.224645 [1372]
+test/xorriso_private.h
+test/xorriso.c
+test/ng_xorrisoburn.h
+test/ng_xorrisoburn.c
+test/xorriso.1
+Made improvements around volume id
+
+2008.01.15.174409 [1373]
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/ng_xorrisoburn.h
+test/ng_xorrisoburn.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Made improvements about pattern matching .., closed small memory leaks
+
+2008.01.15.204057 [1374]
+test/xorriso.c
+test/ng_xorrisoburn.h
+test/ng_xorrisoburn.c
+test/xorrisoburn.h
+test/xorrisoburn.c
+Closed a small memory leak
+
+2008.01.15.211511 [1375]
+test/ng_xorrisoburn.c
+Added a forgotten iso_dir_iter_free()
+
+2008.01.16.132909 [1376]
+ng_src/isofs_wrap.c
+Repaired bug about MMC multi-session image loading
+
+2008.01.16.141631 [1378]
+ng_src/isoburn.c
+Changed default name of initial image to ISOIMAGE
+
+16 Jan 2008 [1378]
+libisoburn.pc.in
+Set correct name of library
+
+2008.01.16.200942 [1379]
+test/xorriso.c
+test/ng_xorrisoburn.c
+Adaption to Xorriso_standalonE, some consequences from compiler warnings
+
+16 Jan 2008 [1380]
++ test/make_xorriso_standalone.sh
++ test/xorriso_makefile_am.txt
++ test/configure_ac.txt
++ test/xorriso_pc_in.txt
+A sketch of a xorriso source standalone release generator
+
+16 Jan 2008 [1381]
+test/configure_ac.txt
+test/xorriso_makefile_am.txt
+Added a test for readline.h and eventually enabled use of libreadline
+
+2008.01.17.145135 [1382]
+test/ng_xorrisoburn.c
+Silenced -pedantic compiler warnings about type punning
+
+17 Jan 2008 [1385]
+test/make_xorriso_standalone.sh
+Silenced most compiler warnings of libisofs in xorriso-standalone
+
+17 Jan 2008 [1386]
++ test/README
+Began a README file for xorriso
+
+18 Jan 2008 [1387]
+test/make_xorriso_standalone.sh
+test/README
++ test/xorriso_eng.html
+Worked on documentation
+
+2008.01.18.101933 [1388]
+test/xorriso.c
+Changed -report_about default to "UPDATE"
+
+18 Jan 2008 [1389]
+test/xorriso.1
+test/make_xorriso_standalone.sh
++ test/convert_man_to_html.sh
+Made a generator for HTML man page
+
+2008.01.19.090417 [1390]
+ng_src/libisoburn.h
+ng_src/isoburn.c
+ng_src/isofs_wrap.c
+test/ng_xorrisoburn.c
+test/compile_xorriso.sh
+test/xorriso_makefile_am.txt
+Adaptions to revision 241 of nglibisofs
+
+2008.01.19.090546 [1391]
+test/xorriso.c
+Added startup message. Removed helptext sentence about unimplemented options
+
+19 Jan 2008 [1392]
+test/xorriso_eng.html
+test/make_xorriso_standalone.sh
+Producing a bootstrapped xorriso standalone tarball
+
+19 Jan 2008 [1393]
+test/README
+test/xorriso.1
+test/xorriso_eng.html
+Some polishing of xorriso documentation
+
+2008.01.19.162244 [1394]
+test/xorriso.c
+test/ng_xorrisoburn.c
+Small corrections with version number and write counter report
+
+19 Jan 2008 [1395]
+test/changelog.txt
+Updated SVN copy of changelog
+
+2008.01.20.102946 [1397]
+ng_src/burn_wrap.c
+ng_src/data_source.c
+ng_src/isoburn.c
+ng_src/isofs_wrap.c
+Made forgotten adaption to Xorriso_standalonE
+
+2008.01.20.131050 [1398]
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/ng_xorrisoburn.c
+test/xorriso.1
+Made -outdev stdio:/dev/fd/1 safe for single session runs
+
+2008.01.20.200254 [1399]
+test/xorriso.h
+test/xorriso_private.h
+test/xorriso.c
+test/xorriso.1
+New option -add_plainly
+
+2008.01.21.221939 [1400]
+test/xorriso.c
+test/xorriso.1
+Rejected unsuitable addresses "stdio:" , "stdio:/", "stdio:-", "stdio:."
+
+22 Jan 2008 [1401]
++ test/compare_file.c
+Program which compares two files in different trees. Attributes and content.
+
+22 Jan 2008 [1402]
+test/configure_ac.txt
+Copied test for tm.tm_gmtim from libisofs configure.ac
+
+22 Jan 2008 [1403]
+test/compare_file.c
+Prepended type indication letter to report lines
+
+2008.01.22.224321 [1404]
+test/ng_xorrisoburn.c
+Better attributes with directories
+
+2008.01.23.195855 []
+ng_src/burn_wrap.c
+test/ng_xorrisoburn.c
+Adapted to libisofs revision 261
+
+24 Jan 2008 [1410]
+test/make_xorriso_standalone.sh
+Removed remover of C++ comment lines
+
+2008.01.24.202206 [1411]
+ng_src/isoburn.c
+ng_src/burn_wrap.c
+ng_src/isoburn.h
+Gave up use of libburn fifo. Attached -fs and pacifier to libisofs fifo.
+
+2008.01.25.150902 [1413]
+test/xorriso.h
+test/xorriso.c
+test/xorriso.1
+New option -rollback_end
+
+25 Jan 2008 [1414]
+test/compare_file.c
+Fixed bug about file content comparison.
+
+25 Jan 2008 [1415]
+test/compare_file.c
+Better handling of various content difference situations
+
+2008.01.25.175353 [1416]
+test/xorriso.h
+test/xorriso.c
+test/xorriso.1
+test/ng_xorrisoburn.c
+New option -commit_eject
+
+2008.01.26.002011 [1417]
+- og_src/libisoburn.h
+- og_src/isoburn.h
+- og_src/isoburn.c
+- og_src/isofs_wrap.c
+- og_src/burn_wrap.c
+- og_src/data_source.c
+- og_src/
++ libisoburn/
+- ng_src/libisoburn.h
+- ng_src/isoburn.h
+- ng_src/isoburn.c
+- ng_src/isofs_wrap.c
+- ng_src/burn_wrap.c
+- ng_src/data_source.c
++ libisoburn/libisoburn.h
++ libisoburn/isoburn.h
+*+ libisoburn/isoburn.c
+*+ libisoburn/isofs_wrap.c
+*+ libisoburn/burn_wrap.c
+*+ libisoburn/data_source.c
++ xorriso/
+- test/README
+- test/changelog.txt
+- test/compare_file.c
+- test/compile_xorriso.sh
+- test/configure_ac.txt
+- test/convert_man_to_html.sh
+- test/make_timestamp.sh
+- test/make_xorriso_standalone.sh
+- test/ng_xorrisoburn.c
+- test/ng_xorrisoburn.h
+- test/xorriso.1
+- test/xorriso.c
+- test/xorriso.h
+- test/xorriso_eng.html
+- test/xorriso_makefile_am.txt
+- test/xorriso_pc_in.txt
+- test/xorriso_private.h
+- test/xorriso_timestamp.h
+- test/xorrisoburn.c
+- test/xorrisoburn.h
++ xorriso/README
++ xorriso/changelog.txt
++ xorriso/compare_file.c
+*+ xorriso/compile_xorriso.sh
++ xorriso/configure_ac.txt
+*+ xorriso/convert_man_to_html.sh
+*+ xorriso/make_timestamp.sh
+*+ xorriso/make_xorriso_standalone.sh
++ xorriso/xorriso.1
+*+ xorriso/xorriso.c
++ xorriso/xorriso.h
++ xorriso/xorriso_eng.html
++ xorriso/xorriso_makefile_am.txt
++ xorriso/xorriso_pc_in.txt
++ xorriso/xorriso_private.h
++ xorriso/xorriso_timestamp.h
+*+ xorriso/xorrisoburn.c
++ xorriso/xorrisoburn.h
+Makefile.am
+Gave up adapter to old libisofs. Renaming libisoburn and xorriso dirs.
+
+2008.01.26.113604 [1418]
+libisoburn/libisoburn.h
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+INCOMPATIBLE API CHANGE: isoburn_initialize(char msg[1024], int flag)
+
+2008.01.26.120534 [1419]
+libisoburn/libisoburn.h
+configure.ac
+version.h.in
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+Introduced versioning (still pre-release) and new API function isoburn_version()
+
+2008.01.26.140005 [1423]
+xorriso/make_xorriso_standalone.sh
+xorriso/configure_ac.txt
+xorriso/xorriso_eng.html
+Adapted standalone tarball to version functions
+
+2008.01.26.142130 [1424]
+xorriso/xorriso.c
+Set program revision to 0.0.1 (previous 0.1.0 was too early)
+
+2008.01.26.171156 [1425]
+libisoburn/libisoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+INCOMPATIBLE API CHANGE: isoburn_prepare_new_image() now gets output drive
+
+2008.01.27.174454 [1434]
+xorriso/xorriso.c
+xorriso/xorriso.1
+Changed meaning of -add relative/path
+
+2008.01.28.105404 [1435]
+xorriso/xorriso.c
+xorriso/xorrisoburn.h
+xorriso/xorrisoburn.c
+Made use of iso_set_abort_severity() with option -abort_on
+
+2008.01.28.140149 [1436]
+libisoburn/libisoburn.h
+Updated API introduction and marked API instabilities for mending (soon)
+
+2008.01.28.171915 [1437]
+libisoburn/isoburn.c
+libisoburn/isofs_wrap.c
+xorriso/xorrisoburn.c
+xorriso/compile_xorriso.sh
+xorriso/make_xorriso_standalone.sh
+Adapted to libisofs revison 294
+
+2008.01.28.235717 [1438]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+xorriso/xorrisoburn.c
+Changed struct isoburn_source_opts to opaque handle struct isoburn_imgen_opts
+
+2008.01.29.125956 [1439]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+xorriso/xorrisoburn.c
+Changed struct isoburn_read_opts to opaque handle
+
+2008.01.29.184356 [1440]
+configure.ac
+version.h.in
+libisoburn/libisoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+xorriso/configure_ac.txt
+New API call isoburn_is_compatible()
+
+29 Jan 2008 [1441]
+libisoburn/libisoburn.h
+Some API documentation enhancements
+
+2008.01.29.211543 [1443]
+libisoburn/burn_wrap.c
+Made use of newest libburn version features
+
+2008.01.31.152131 [1449]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/isofs_wrap.c
+xorriso/make_xorriso_standalone.sh
+Adapted to libisofs revision 313
+
+2008.01.31.214647 [1450]
+xorriso/xorrisoburn.h
+libisoburn/libisoburn.h
+libisoburn/burn_wrap.c
+xorriso/make_xorriso_standalone.sh
+Compile time and runtime checks for library compatibility
+
+2008.02.01.195817 [1455]
+configure.ac
+Makefile.am
+- libisoburn.pc.in
++ libisoburn-1.pc.in
+xorriso/README
+Enabled build of dynamically linked xorriso, joined -1.pc club
+
+2008.02.01.200153 [1456]
+xorriso/xorriso_makefile_am.txt
+Corrected some false paths in xorriso-standalone Makefile.am
+
+2008.02.02.131049 [1457]
+configure.ac
+Added version checks for libburn and libisofs (by Vreixo)
+
+2008.02.02.131903 [1458]
+xorriso/xorriso.h
+xorriso/xorriso.c
+Added argument to option -commit_eject
+
+2 Feb 2008 [1459]
+xorriso/xorriso_eng.html
+Updated to current state of development
+
+2008.02.02.181200 [1460]
+xorriso/xorrisoburn.c
+Compile time check of libisoburn. Enforced minimum track size of 300 sectors.
+
+2008.02.03.131525 [1466]
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+libisoburn/isofs_wrap.c
+xorriso/xorrisoburn.c
+Made use of ISO_ERR_SEV() and ISO_ERR_PRIO()
+
+2008.02.03.155704 [1467]
+libisoburn/isofs_wrap.c
+Adapted to libisofs revisio 328
+
+2008.02.03.164038 [1468]
+libisoburn/libisoburn.h
+libisoburn/isoburn.c
+xorriso/xorrisoburn.c
+New API call isoburn_cancel_prepared_write()
+
+2008.02.03.164916 [1469]
+xorriso/xorrisoburn.c
+Reacted on compiler warning
+
+2008.02.03.181259 [1470]
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+Made -abort_on and -report_about preemptive if given as dashed start arguments
+
+2008.02.04.093106 [1471]
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+Adapted to libisofs revision 332
+
+2008.02.04.154405 [1472]
+libisoburn/libisoburn.h
+libisoburn/isoburn.c
+xorriso/xorrisoburn.c
+New API call isoburn_sync_after_write()
+
+2008.02.04.184038 [1475]
+libisoburn/libisoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+libisoburn/isofs_wrap.c
+xorriso/xorrisoburn.c
+Inserted problem messages where libisoburn API produces own failures
+
+2008.02.04.214133 [1476]
+libisoburn/libisoburn.h
+libisoburn/isoburn.c
+xorriso/xorrisoburn.c
+Added parameter to new API calls isoburn_cancel_prepared_write, isoburn_sync_after_write
+
+2008.02.05.162621 [1477]
+xorriso/xorriso.h
+xorriso/xorriso_private.h
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+New option -padding
+
+2008.02.05.175733 [1478]
+xorriso/xorriso.h
+xorriso/xorriso.c
+xorriso/xorriso.1
+Implemented reassure for -rollback, -rollback_end, -end, -commit, -commit_eject
+
+2008.02.05.191456 [1479]
+xorriso/xorriso.h
+xorriso/xorriso.c
+xorriso/xorriso.1
+Implemented reassure for -blank, -format, -dev, -indev, -devices
+
+2008.02.06.131028 [1480]
+xorriso/xorriso.c
+xorriso/xorriso_private.h
+xorriso/xorrisoburn.h
+xorriso/xorrisoburn.c
+libisoburn/libisoburn.h
+libisoburn/burn_wrap.c
+Now loading libraries before -version, pacifier for -add
+
+2008.02.06.153709 [1481]
+libisoburn/burn_wrap.c
+xorriso/xorriso.c
+xorriso/xorriso.1
+xorriso/xorrisoburn.c
+Rectified SORRY,FAILURE,FATAL classification
+
+2008.02.06.183423 [1484]
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+Adapted to libisofs revision 337
+
+2008.02.06.183557 [1485]
+xorriso/xorriso.c
+Removed some unused code
+
+2009.02.06.184008 [1486]
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+Added a missing 0 digit
+
+2008.02.06.214426 [1487]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/isofs_wrap.c
+xorriso/xorrisoburn.c
+Pacifier for isoburn_read_image()
+
+2008.02.07.074248 [1489]
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso_private.h
+Added final message to image read pacifier
+
+2008.02.07.154947 [1490]
+libisoburn/data_source.c
+Implemented a primitive single tile cache for image reading
+
+2008.02.07.211424 [1491]
+libisoburn/data_source.c
+Stuffed memory leak with read cache. Economized on error retries.
+
+8 Feb 2008 [1494]
+- xorriso/compare_file.
++ test/compare_file.c
+- ng_src
+Cleaning up remainings of move to ng_src
+
+8 Feb 2008 [1495]
+test/compare_file.c
+Fixed an endless cycle with early EOF
+
+2008.02.08.102122 [1496]
+xorriso/xorriso_makefile_am.txt
+xorriso/make_xorriso_standalone.sh
+xorriso/configure_ac.txt
+xorriso/README
+Added test/compare_file.c to xorriso-standalone tarball
+
+2008.02.08.173928 [1497]
+2008.02.08.174126 [1498]
+libisoburn/data_source.c
+Renamed macro which controls read caching
+
+2008.02.08.175152 [1499]
+xorriso/xorriso_private.h
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+Protecting volume ids from getting overwritten by predecessor
+
+2008.02.08.195627 [1500]
+xorriso/xorriso.c
+Warning of -volid which are not ECMA 119 compliant
+
+2008.02.08.215113 [1501]
+xorriso/xorriso.h
+xorriso/xorriso.c
+Silenced misleading toc messages with -commit_eject "in"
+
+2008.02.09.092805 [1502]
+libisoburn/libisoburn.h
+libisoburn/isoburn.c
+Adapted to libisofs revision 346
+
+2008.02.09.100750 [1503]
+libisoburn/libisoburn.h
+libisoburn/burn_wrap.c
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+New API function isoburn_disc_available_space() fixes bug with DVD+RW capacity
+
+10 Feb 2008 [1504]
+xorriso/README
+Some adjustments in description of compare_file and libisoburn
+
+2008.02.10.122020 [1505]
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+Fixed bugs about -mv /im/age . -cdx / -cpr di/sk im/age -- -cpr di/sk . --
+
+2008.02.10.130852 [1506]
+Makefile.am
+Added build of test/compare_file as noinst binary
+
+2008.02.10.135822 [1507]
+xorriso/xorriso.c
+xorriso/xorrisoburn.h
+xorriso/xorrisoburn.c
+Better handling of not-yet-existing -cd
+
+2008.02.11.094742 [1509]
+xorriso/xorriso_private.h
+xorriso/xorriso.h
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+Discarding, keeping or patching boot images from existing ISO images
+
+2008.02.11.112917 [1510]
+xorriso/xorrisoburn.c
+Corrected message about isolinux patch option
+
+2008.02.11.113235 [1511]
+xorriso/xorriso.h
+xorriso/xorriso.c
+Final UPDATE message after grafting in files from disk
+
+2008.02.11.135418 [1512]
+xorriso/xorriso_private.h
+xorriso/xorriso.h
+xorriso/xorriso.c
+xorriso/xorriso.1
+New option -return_with
+
+2008.02.11.150123 [1513]
+xorriso/xorrisoburn.c
+isoburn_igopt_allow_full_ascii for -bootimage any keep
+
+2008.02.11.150700 [1514]
+xorriso/xorriso.c
+xorriso/xorriso.1
+Clarifications about -volid rules
+
+11 Feb 2008 [1515]
+xorriso/README
+Adjustments about libisoburn and xorriso dynamic dependencies, compare_file
+
+2008.02.11.162406 [1516]
+xorriso/xorrisoburn.c
+xorriso/xorriso.c
+Changed failure to find a file for removal from FAILURE to SORRY
+
+2008.02.11.174517 [1517]
+xorriso/xorriso.c
+Corrected a bug about -status -return_with
+
+2008.02.11.194807 [1519]
+libisoburn/burn_wrap.c
+xorriso/xorriso_private.h
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+New severity MISHAP
+
+2008.02.11.213918 [1520]
+xorriso/xorrisoburn.c
+Mapping in burn runs -abort_on MISHAP to SORRY
+
+2008.02.12.215327 [1521]
+libisoburn/burn_wrap.c
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+Improved MISHAP - SORRY mapping and tunneling
+
+2008.02.14.084342 [1525]
++ README
++ COPYING
++ COPYRIGHT
++ INSTALL
+libisoburn/libisoburn.h
+Completing documentation
+
+2008.02.14.101916 [1526]
+Makefile.am
+Adjusted EXTRA_DIST list of files
+
+2008.02.14.120557 [1527]
+xorriso/xorrisoburn.c
+Made a final abort check before burning begins
+
+2008.02.14.175623 [1528]
+xorriso/xorriso_private.h
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+Imprinting version of xorriso and libraries into ISO preparer_id
+
+2008.02.14.182351 [1529]
+xorriso/xorrisoburn.c
+Made preparer_id more safe against oversize
+
+14 Feb 2008 [1530]
+xorriso/xorriso.1
+Polished man page
+
+14 Feb 2008 [1531]
+xorriso/changelog.txt
+Updated changelog
+
+2008.02.15.100001 [branch 1533]
+configure.ac
+README
+libisoburn/libisoburn.h
+xorriso/README
+xorriso/xorriso_timestamp.h
+xorriso/xorriso_private.h
+xorriso/xorrisoburn.h
+xorriso/xorriso_eng.html
+xorriso/compile_xorriso.sh
+xorriso/make_xorriso_standalone.sh
+xorriso/configure_ac.txt
+Made version number leap to 0.1.0
+
+15 Feb 2008 [branch 1534]
+xorriso/changelog.txt
+Documented initial release and timestamp
+
+15 Feb 2008 [1536]
+configure.ac
+Increased libisofs requirement to 0.6.2
+
+----------------------------- release - xorriso-0.1.0.pl00 - 2008.02.15.100001
+* Operates on an existing ISO image or creates a new one.
+* Copies files from filesystem into the ISO image.
+* Renames or deletes file objects in the ISO image.
+* Changes file properties in the ISO image.
+* Can write result as completely new image to optical media
+ or filesystem objects.
+* Can write result as add-on session to appendable
+ multi-session media, to overwriteable media,
+ to regular files, and to block devices.
+* Scans for optical drives, blanks re-useable optical media.
+* Reads its instructions from command line arguments, dialog, and batch files.
+* Provides navigation commands for interactive ISO image manipulation.
+* Adjustable thresholds for abort, exit value, and problem reporting.
+
+
+2008.02.15.211836 [1537]
+configure.ac
+README
+libisoburn/libisoburn.h
+xorriso/README
+xorriso/xorriso_timestamp.h
+xorriso/xorriso_private.h
+xorriso/xorrisoburn.h
+xorriso/xorriso_eng.html
+xorriso/compile_xorriso.sh
+xorriso/make_xorriso_standalone.sh
+xorriso/configure_ac.txt
+Version leap to 0.1.1
+
+15 Feb 2008 [1538]
+COPYRIGHT
+Corrected according to content of libisofs/COPYRIGHT
+
+2008.02.15.212030 [1539]
+xorriso/xorriso.c
+Changed pacifier text for 0 nodes read from blank image
+
+------------------------------------ cycle - xorriso-0.1.1 - 2008.02.15.212030
+
+15 Feb 2008 [1540]
+xorriso/changelog.txt
+Updated changelog
+
+16 Feb 2008 [1543]
+xorriso/xorriso.1
+Adjusted CREDITS text
+
+2008.02.16.202533 [1544]
+xorriso/xorriso_private.h
+xorriso/xorrisoburn.c
+Transfering properties from disk to implicit directories in image path
+
+2008.02.16.211549 [1545]
+xorriso/xorriso_eng.html
+xorriso/changelog.txt
+Mentioned better directory attribute copying
+
+------------------------------------ cycle - xorriso-0.1.1 - 2008.02.16.211549
+* Improved attribute transfer from disk for implicit target directories
+
+2008.02.18.210343 [1546]
+xorriso/xorriso.c
+Bug fix: -report_about higher than NOTE did not report at all
+
+19 Feb 2008 [1547]
+test/compare_file.c
+Improved report format
+
+2008.02.19.184432 [1548]
+xorriso/xorriso.c
+xorriso/xorrisoburn.h
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+New option -as cdrecord emulates a narrow set of cdrecord gestures
+
+2008.02.19.212322 [1549]
+xorriso/xorriso.c
+xorriso/xorriso_private.h
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+Improved -as cdrecord
+
+20 Feb 2008 [1550]
+test/compare_file.c
+Revoked inflation of file type characters to words
+
+2008.02.20.234726 [1551]
+libisoburn/libisoburn.h
+libisoburn/burn_wrap.c
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+New option -as mkisofs emulates a narrow set of mkisofs gestures
+
+------------------------------------ cycle - xorriso-0.1.1 - 2008.02.21.090014
+* Bug fix: -report_about HINT or higher did not report at all
+* Bug fix: speed=number without unit or media type letter was always CD speed
+* Bug fix: it was possible to write to appendable media which was not -indev
+* New option -as "cdrecord" emulates a narrow set of cdrecord gestures
+* New option -as "mkisofs" emulates a narrow set of mkisofs gestures
+
+2008.02.21.090014 [1552]
+xorriso/xorriso.h
+xorriso/xorriso_private.h
+xorriso/xorriso.c
+xorriso/xorrisoburn.h
+xorriso/xorrisoburn.c
+New option -publisher
+
+2008.02.21.185203 [1553]
+libisoburn/libisoburn.h
+libisoburn/isoburn.h
+libisoburn/isoburn.c
+libisoburn/burn_wrap.c
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+xorriso/xorriso.1
+Implemented a more reasonable solution for drive truncation with regular files
+
+2008.02.21.204613 [1558]
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+Introduced new severity ERRFILE
+
+2008.02.21.211101 [1559]
+xorriso/xorriso.c
+Updated -help text
+
+2008.02.22.114917 [1561]
+libisoburn/burn_wrap.c
+xorriso/xorriso.c
+xorriso/xorrisoburn.c
+Producing ERRFILE messages where appropriate
+
+2008.02.23.101619 [1568]
+libisoburn/libisoburn.h
+Changed libisofs requirements to 0.6.3
+
+2008.02.23.101619 [1569]
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+Testwise implementation of libisofs.0.6.3 features
+
+2008.02.23.101619 [1570]
+xorriso/xorriso_private.h
+xorriso/xorriso.c
+xorriso/xorriso.1
+New option -errfile_log
+
+2008.02.23.102903 [1571]
+xorriso/configure_ac.txt
+Made libisofs version leap in xorriso-standalone
+
+2008.02.23.113902 [1572]
+xorriso/xorriso.h
+xorriso/xorriso.c
+Directed -as mkisofs -print-size to real stdout
+
+2008.02.23.125537 [1573]
+xorriso/xorrisoburn.c
+Various bugs and deviations around -as mkisofs -print-size
+
+2008.02.23.131825 [1574]
+xorriso/xorrisoburn.c
+Wrong description text
+
+2008.02.25.090001 [ZeroOneZero-pl01 1576 1577]
+libisoburn/burn_wrap.c
+xorriso/xorriso_timestamp.h
+Safety cap for ABI usage bug towards libisofs >= 0.6.2
+
+2008.02.25.174229 [1579]
+libisoburn/burn_wrap.c
+xorriso/xorrisoburn.c
+Adapted to libisofs 362 from Vreixo bzr
+
+2008.02.25.204402 [1580]
+xorriso/xorriso.c
+Adaptions of -as mkisofs and -as cdrecord to enable full use by scdbackup
+
+
+------------------------------------ cycle - xorriso-0.1.1 -
+* New option -publisher
+* New option -errfile_log
+
+
+===============================================================================
+ TODO
+===============================================================================
+
+------------------------------------------------- bugs
+
+
+
+------------------------------------------------- important
+
+< xorriso configurable in scdbackup
+
+------------------------------------------------- development
+
+- mkisofs,cdrecord multi session
+
+- -restore
+- -compare_file
+- -update , -update_r
+> Vreixo wrote:
+> public API to access old images, and extract file
+> contents (look at demo/isoread and demo/isocat for
+> usage examples).
+- iso_file_source_open() iso_file_source_read() iso_file_source_close()
+
+
+> Relative addressing and pattern matching :
+ iso_rr_pattern on
+ cd /u/FERTIG
+ lsd nonexist/..
+
+- regularly do valgrind check for memory leaks
+
+- ??? http://scan.coverity.com/faq.html
+
+- ??? curb depth of tree traversal recursion
+
+- make xorrisoburn.c leaner
+
+- eject a not yet aquired device (e.g. after modifying commit)
+
+- -cd[ix] and pattern
+
+- memory curb for image model
+
+??? semicolon as alias of -- ?
+
+> Make transactional the tree deletions meant for replacing
+
+- Introduce an interrupt key for dialog
+
+-------------------------------------------- jump to libburn 0.4.4
+
+- make use of burn_sev_to_text() in libisoburn and xorriso
+
+- If iso_msgs_submit() : use it in isoburn_report_iso_error()
+
+
+===============================================================================
+ This is the dirty end of the todo list.
+ The recent changelog entries are above the headline "TODO".
+===============================================================================
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/compile_xorriso.sh b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/compile_xorriso.sh
new file mode 100755
index 00000000..85732da9
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/compile_xorriso.sh
@@ -0,0 +1,155 @@
+#!/bin/sh
+
+# compile_xorriso.sh
+# Copyright 2005 - 2008 Thomas Schmitt, scdbackup@gmx.net, GPL
+#
+# Not intended for general use in production installations !
+# Rather use: ./bootstrap ; ./configure ; make
+#
+# This is a development tool which expects a special setup of directories.
+# It is to be executed in a common parent of the directories given with
+# $isofs $isoburn $burn $xorr
+
+isofs=./nglibisofs-develop/libisofs
+burn=./libburn-develop/libburn
+isoburn=./libisoburn-develop/libisoburn
+xorr=./libisoburn-develop/xorriso
+
+debug_opts="-O2"
+def_opts=
+largefile_opts="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1"
+do_strip=0
+static_opts=
+warn_opts="-Wall"
+nglibisofs=1
+
+for i in "$@"
+do
+ if test "$i" = "-do_diet"
+ then
+ def_opts="$def_opts -DXorriso_no_helP"
+ warn_opts=
+ elif test "$i" = "-do_strip"
+ then
+ do_strip=1
+ elif test "$i" = "-g"
+ then
+ debug_opts="-g -O0"
+ elif test "$i" = "-help" -o "$i" = "--help" -o "$i" = "-h"
+ then
+ echo \
+ "$xorr/compile_xorriso.sh : to be executed above top level directories"
+ echo "Options:"
+ echo " -do_diet produce capability reduced lean version."
+ echo " -do_strip apply program strip to compiled programs."
+ echo " -g produce debuggable programm."
+ echo " -static compile with cc option -static."
+ exit 0
+ elif test "$i" = "-static"
+ then
+ static_opts="-static"
+ fi
+done
+
+libisofs=
+libisofs="$libisofs $isofs"/buffer.o
+libisofs="$libisofs $isofs"/builder.o
+libisofs="$libisofs $isofs"/data_source.o
+libisofs="$libisofs $isofs"/ecma119.o
+libisofs="$libisofs $isofs"/ecma119_tree.o
+libisofs="$libisofs $isofs"/eltorito.o
+libisofs="$libisofs $isofs"/filesrc.o
+libisofs="$libisofs $isofs"/fs_image.o
+libisofs="$libisofs $isofs"/fs_local.o
+libisofs="$libisofs $isofs"/fsource.o
+libisofs="$libisofs $isofs"/image.o
+libisofs="$libisofs $isofs"/iso1999.o
+libisofs="$libisofs $isofs"/joliet.o
+libisofs="$libisofs $isofs"/libiso_msgs.o
+libisofs="$libisofs $isofs"/messages.o
+libisofs="$libisofs $isofs"/node.o
+libisofs="$libisofs $isofs"/rockridge.o
+libisofs="$libisofs $isofs"/rockridge_read.o
+libisofs="$libisofs $isofs"/stream.o
+libisofs="$libisofs $isofs"/tree.o
+libisofs="$libisofs $isofs"/util.o
+libisofs="$libisofs $isofs"/util_htable.o
+libisofs="$libisofs $isofs"/util_rbtree.o
+
+timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
+echo "Version timestamp : $(sed -e 's/#define Xorriso_timestamP "//' -e 's/"$//' "$xorr"/xorriso_timestamp.h)"
+echo "Build timestamp : $timestamp"
+
+echo "compiling program $xorr/xorriso.c $static_opts $debug_opts $def_opts"
+cc -I. -DXorriso_with_maiN -DXorriso_with_regeX -DXorriso_with_readlinE \
+ $warn_opts \
+ $static_opts \
+ $debug_opts \
+ $def_opts \
+ $largefile_opts \
+ \
+ -DXorriso_build_timestamP='"'"$timestamp"'"' \
+ \
+ -o "$xorr"/xorriso \
+ \
+ "$xorr"/xorriso.c \
+ \
+ "$xorr"/xorrisoburn.c \
+ \
+ "$burn"/async.o \
+ "$burn"/debug.o \
+ "$burn"/drive.o \
+ "$burn"/file.o \
+ "$burn"/init.o \
+ "$burn"/options.o \
+ "$burn"/source.o \
+ "$burn"/structure.o \
+ \
+ "$burn"/sg.o \
+ "$burn"/write.o \
+ "$burn"/read.o \
+ "$burn"/libdax_audioxtr.o \
+ "$burn"/libdax_msgs.o \
+ "$burn"/cleanup.o \
+ \
+ "$burn"/mmc.o \
+ "$burn"/sbc.o \
+ "$burn"/spc.o \
+ "$burn"/util.o \
+ \
+ "$burn"/sector.o \
+ "$burn"/toc.o \
+ \
+ "$burn"/crc.o \
+ "$burn"/lec.o \
+ \
+ "$isoburn"/isoburn.o \
+ "$isoburn"/burn_wrap.o \
+ "$isoburn"/data_source.o \
+ "$isoburn"/isofs_wrap.o \
+ \
+ $libisofs \
+ \
+ -lreadline \
+ \
+ -lpthread
+
+ ret=$?
+ if test "$ret" = 0
+ then
+ dummy=dummy
+ else
+ echo >&2
+ echo "+++ FATAL : Compilation of xorriso failed" >&2
+ echo >&2
+ exit 1
+ fi
+
+
+if test "$do_strip" = 1
+then
+ echo "stripping result $xorr/xorriso"
+ strip "$xorr"/xorriso
+fi
+
+echo 'done.'
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/configure_ac.txt b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/configure_ac.txt
new file mode 100644
index 00000000..dad879ff
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/configure_ac.txt
@@ -0,0 +1,114 @@
+AC_INIT([xorriso], [0.1.1], [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])
+
+BURN_MAJOR_VERSION=0
+BURN_MINOR_VERSION=4
+BURN_MICRO_VERSION=3
+AC_SUBST(BURN_MAJOR_VERSION)
+AC_SUBST(BURN_MINOR_VERSION)
+AC_SUBST(BURN_MICRO_VERSION)
+
+LIBISOFS_MAJOR_VERSION=0
+LIBISOFS_MINOR_VERSION=6
+LIBISOFS_MICRO_VERSION=3
+AC_SUBST(LIBISOFS_MAJOR_VERSION)
+AC_SUBST(LIBISOFS_MINOR_VERSION)
+AC_SUBST(LIBISOFS_MICRO_VERSION)
+
+dnl The API version codes are defined in libisoburn/libisoburn.h
+dnl #define isoburn_header_version_*
+
+
+AC_PREFIX_DEFAULT([/usr/local])
+test "$prefix" = "NONE" && prefix=$ac_default_prefix
+
+AM_MAINTAINER_MODE
+
+AM_PROG_CC_C_O
+AC_C_CONST
+AC_C_INLINE
+AC_C_BIGENDIAN
+
+dnl Large file support
+AC_SYS_LARGEFILE
+AC_FUNC_FSEEKO
+AC_CHECK_FUNC([fseeko])
+if test ! $ac_cv_func_fseeko; then
+ AC_ERROR([Libburn requires largefile support.])
+fi
+
+AC_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+LIBTOOL="$LIBTOOL --silent"
+
+AC_PROG_INSTALL
+
+AC_CHECK_HEADERS()
+
+AC_CHECK_MEMBER([struct tm.tm_gmtoff],
+ [AC_DEFINE(HAVE_TM_GMTOFF, 1,
+ [Define this if tm structure includes a tm_gmtoff entry.])],
+ ,
+ [#include ])
+
+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 ])
+
+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 ])
+
+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 Check whether there is readline-devel and readline-runtime.
+dnl If not, erase this macro which would enable use of readline(),add_history()
+READLINE_DEF="-DXorriso_with_readlinE"
+dnl The empty yes case obviously causes -lreadline to be linked
+AC_CHECK_HEADER(readline/readline.h, AC_CHECK_LIB(readline, readline, , READLINE_DEF= ), READLINE_DEF= )
+dnl The X= in the yes case prevents that -lreadline gets linked twice
+AC_CHECK_HEADER(readline/history.h, AC_CHECK_LIB(readline, add_history, X= , READLINE_DEF= ), READLINE_DEF= )
+AC_SUBST(READLINE_DEF)
+
+
+AC_CONFIG_FILES([
+ Makefile
+ version.h
+ xorriso.pc
+ ])
+AC_OUTPUT
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/convert_man_to_html.sh b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/convert_man_to_html.sh
new file mode 100755
index 00000000..f73f24aa
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/convert_man_to_html.sh
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+#
+# convert_man_to_html.sh - ts A80118
+#
+# Generates a HTML version of man page xorriso.1
+#
+# To be executed in the libisoburn toplevel directory (eg. ./libisoburn-0.1.0)
+#
+
+# set -x
+
+man_dir=$(pwd)"/xorriso"
+export MANPATH="$man_dir"
+manpage="xorriso"
+raw_html=$(pwd)/"xorriso/raw_man_1_xorriso.html"
+htmlpage=$(pwd)/"xorriso/man_1_xorriso.html"
+
+if test -r "$man_dir"/"$manpage".1
+then
+ dummy=dummy
+else
+ echo "Cannot find readable man page source $1" >&2
+ exit 1
+fi
+
+if test -e "$man_dir"/man1
+then
+ dummy=dummy
+else
+ ln -s . "$man_dir"/man1
+fi
+
+if test "$1" = "-work_as_filter"
+then
+
+# set -x
+
+ sed \
+ -e 's/ / /' \
+ -e 's/ / /' \
+ -e 's/XORRISO<\/title>/man 1 xorriso<\/title>/' \
+ -e 's/
+
Hardware requirements:
+A CD/DVD recorder suitable for
+http://libburnia-project.org
+(SCSI , ATA , USB , or SATA writers compliant to standard MMC-3 for CD
+and to MMC-5 for DVD).
+
+
+
+
+
Software requirements :
+
+Linux with kernel 2.4 or higher (and libc, of course) :
+With kernel 2.4 an ATA drive has to be under ide-scsi emulation.
+With kernel 2.6 the drive should not be under ide-scsi.
+libpthread
+is supposed to be a standard system component.
+libreadline and libreadline-dev
+are optional and eventually make dialog more convenient.
+
+
+
+
+
+GPL software included:
+
+
+libburn-0.4.3
+reads and writes data from and to CD and DVD.
+(founded by Derek Foreman and Ben Jansens,
+furthered by team of libburnia-project.org)
+libisofs-0.6.2
+operates ISO 9660 images.
+(By Vreixo Formoso and Mario Danic from team of libburnia-project.org)
+libisoburn-0.1.0
+coordinates libburn and libisofs, emulates multi-session where needed.
+(By Vreixo Formoso and Thomas Schmitt
+from team of libburnia-project.org)
+
+The source code of this software is independent of
+cdrecord and mkisofs.
+
+
+
+
+This program system has been tested on Intel/AMD Linux systems only.
+For ports to other usable systems contact us .
+
+
+
+
+
+
Special features:
+
+
+ISO 9660 formatter and burner for CD or DVD are fixely integrated.
+
+
+Operates on an existing ISO image or creates a new one.
+
+
+Copies files from filesystem into the ISO image.
+
+
+Renames or deletes file objects in the ISO image.
+
+Changes file properties in the ISO image.
+
+
+Can write result as completely new image to optical media or
+filesystem objects.
+
+
+Can write result as add-on session to appendable multi-session media,
+to overwriteable media, to regular files, and to block devices.
+
+
+Scans for optical drives, blanks re-useable optical media.
+
+
+Suitable for: CD-R, CD-RW, DVD-R, DVD-RW, DVD+R, DVD+R/DL, DVD+RW, DVD-RAM.
+
+
+Reads its instructions from command line arguments, dialog, and batch files.
+
+
+Provides navigation commands for interactive ISO image manipulation.
+
+
+Adjustable thresholds for abort, exit value, and problem reporting.
+
+
+
+
+
+
+
Command Examples:
+
+Get an overview of drives and their addresses
+# xorriso -devices
+Being superuser avoids permission problems with /dev/srN resp. /dev/hdX .
+
+Ordinary users should then get granted rw access to the /dev files
+as listed by option -devices.
+
+
+Options are either performed as program arguments or as dialog input.
+Some options have a parameter list of variable length. This list has to
+be terminated by word '--' or by the end of the input line. Option -add
+may accept pathspecs of form target=source as known from program mkisofs.
+
+
+
+Get info about a particular drive and loaded media:
+$ xorriso -indev /dev/sr0 -du / -- -toc 2>&1 | less
+
+Make re-usable media writable again, delete any ISO 9660 image:
+$ xorriso -outdev /dev/sr0 -blank fast -eject all
+
+
+
+
+
+Write some directories into a new or existing ISO 9660 image:
+$ xorriso -dev /dev/sr0 -add /home/me/sounds /home/me/pictures
+
+
+Check the result:
+$ xorriso -indev /dev/sr0 -du / -- -toc 2>&1 | less
+
+
+
+
+
+Create new ISO-9660 filesystem image, compose content,
+adjust permissions to make it publicly read-only,
+write it to media and immediately eject media without
+previously reloading the written image.
+
+$ xorriso -outdev /dev/sr0 -blank fast -pathspecs on \
+ -add /sounds=/home/me/sounds \
+
+/pictures=/home/me/pictures -- \
+ -rm_r /sounds/indecent '/pictures/*private*' -- \
+ -add /pictures/private/horses=/home/me/pictures/private/horses -- \
+ -chmod_r a+r,a-w / -- \
+ -find / -type d -exec chmod a+x -- \
+ -volid SOUNDS_PICS_2008_01_16 \
+ -commit_eject all
+
+
+
+
+
+Load the previous session from media,
+remove (i.e. hide) directory /sounds,
+rename /pictures/private/horses,
+add new directory trees /sounds and /movies,
+disallow any access for group and others.
+Finally write as additional session to media and eject:
+$ xorriso -dev /dev/sr0 -pathspecs on \
+ -rm_r /sounds -- \
+ -mv /pictures/private/horses /horse_show -- \
+ -add /sounds=/home/me/prepared_for_dvd/sounds_dummy \
+ /movies=/home/me/prepared_for_dvd/movies -- \
+ -chmod_r go-rwx / -- \
+ -volid SOUNDS_PICS_2008_01_17 \
+ -commit_eject all
+
+
+
+
+
+Merge the various sessions from old readable media into a single session
+on new writeable media,
+cleaning out all invalidated files and session overhead.
+Touch / in order to mark the image as worth to be written.
+
+Important: -indev and -outdev have to be different drives.
+
+$ xorriso -indev /dev/dvd \
+ -alter_date a +0 / -- \
+ -outdev /dev/sr0 -blank fast \
+ -commit_eject all
+
+
+
+
+
+Dialog mode accepts one or more options per line. An option and all its
+arguments have to be given in one single line. Command -end stops the program
+run. It will write eventually pending changes to media, if that has not
+already been done by a previous -commit.
+$ xorriso -dialog on
+enter option and arguments :
+-dev /dev/sr0 -pathspecs on
+enter option and arguments :
+-add /sounds=/home/me/prepared_for_dvd/sounds_dummy /movies=/home/me/prepared_for_dvd/movies
+Available navigation commands: -cd, -ls, -du, -find
+enter option and arguments :
+-commit
+... perform further commands and finally do:
+enter option and arguments :
+-end
+
+
+
+
+
+In batch mode it is possible to operate xorriso in a pipeline
+with an external consumer of the generated ISO image. Any message
+output will be redirected to stderr in this case.
+$ xorriso -outdev - ...other.options... | consumer
+
+
+
+
+
+
+Get overview of the options:
+$ xorriso -help
+
+Read the detailed manual page:
+$ man xorriso
+
+
+
+Testers wanted who are willing to risk some double layer DVD media.
+
+
+
+
+
+
+
+Download as source code (see README):
+xorriso-0.1.0.pl00.tar.gz
+(900 KB).
+
+
+
+
+
+
+
+Documentation:
+README about installation and drive setup
+xorriso -help gives an overview of options
+man xorriso is the manual page
+
+
+Contact:
+Thomas Schmitt, scdbackup@gmx.net
+libburn development mailing list,
+libburn-hackers@pykix.org
+
+License:
+GPL version 2 ,
+an Open Source approved license
+
+
+
+
+
+
+
+
+
+Development snapshot, version 0.1.1 :
+Bug fixes towards xorriso-0.1.0.pl00:
+
+-report_about HINT or higher did not report at all
+speed=number without unit or media type letter was always CD speed
+it was possible to write to appendable media which was not -indev
+-follow param did not work for adding non-directory symbolic links
+
+
+
+Enhancements towards stable version 0.1.0.pl00:
+
+Improved attribute transfer from disk for implicit target directories
+New option -as "cdrecord" emulates a narrow set of cdrecord gestures
+New option -as "mkisofs" emulates a narrow set of mkisofs gestures
+New option -publisher
+New option -errfile_log
+Support for DVD+R/DL media
+
+
+
+
+
+README 0.1.1
+xorriso_0.1.1 -help
+man xorriso (as of 0.1.1)
+
+The following download is intended for adventurous end users or
+admins with full system souvereignty.
+Source (./bootstrap is already applied, build tested,
+installation see README)
+
+
+xorriso-0.1.1.tar.gz
+(900 KB).
+
+Maintainers of dynamically linked xorriso please use SVN of
+ libburnia-project.org .
+xorriso is part of libisoburn/trunk and will get built by its "make".
+Download: svn co http://svn.libburnia-project.org/libburn/trunk libburn
+
+Install: cd libburn ; ./bootstrap ; ./configure --prefix /usr ; make ; make install
+
+Download: bzr branch lp:libisofs
+Install: cd libisofs ; ./bootstrap ; ./configure --prefix /usr ; make ; make install
+
+Download: svn co http://svn.libburnia-project.org/libisoburn/trunk libisoburn
+
+Install: cd libisoburn ; ./bootstrap ; ./configure --prefix /usr ; make ; make install
+
+Build of SVN versions needs
+autotools of at least version 1.7 installed.
+But after the run of ./bootstrap , only
+vanilla tools like make and gcc are needed.
+
+
+
+
+
+
+
+
+
+
+
+Many thanks to Derek Foreman and Ben Jansens for starting libburn.
+
+Very special thanks to Andy Polyakov whose
+dvd+rw-tools
+provide the libburnia project with invaluable examples on how to deal
+with DVD media and how to emulate multi-session on overwriteable media.
+
+
+
+
+
+
+
+
+Enjoying free Open Source hosting by www.webframe.org
+
+
+and by sourceforge.net
+
+
+
+
+
+
+Links to my other published software projects :
+
+cdrskin, a cdrecord emulator
+
+scdbackup, multi volume CD backup
+
+(a second source of above)
+Some Tools for Image Collectors
+
+pppoem, a DSL throughput monitor (mainly for Linux kernel 2.4)
+
+
+Legal statement: This website does not serve any commercial purpose.
+
+
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_makefile_am.txt b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_makefile_am.txt
new file mode 100644
index 00000000..6cdb689b
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_makefile_am.txt
@@ -0,0 +1,189 @@
+pkgconfigdir=$(libdir)/pkgconfig
+libincludedir=
+
+lib_LTLIBRARIES =
+
+## ========================================================================= ##
+
+libinclude_HEADERS =
+
+## ========================================================================= ##
+
+bin_PROGRAMS = \
+ xorriso/xorriso
+
+xorriso_xorriso_CPPFLAGS = -I./libburn -I./libisofs -I./libisoburn -I./xorriso
+
+# No readline in the vanilla version because the necessary headers
+# are in a separate readline-development package.
+xorriso_xorriso_CFLAGS = -DXorriso_standalonE -DXorriso_with_maiN -DXorriso_with_regeX $(READLINE_DEF)
+
+xorriso_xorriso_LDADD = $(THREAD_LIBS)
+
+xorriso_xorriso_SOURCES = \
+ \
+ xorriso/xorriso.h \
+ xorriso/xorriso_private.h \
+ xorriso/xorriso.c \
+ xorriso/xorrisoburn.h \
+ xorriso/xorrisoburn.c \
+ xorriso/xorriso_timestamp.h \
+ \
+ libisoburn/libisoburn.h \
+ libisoburn/isoburn.h \
+ libisoburn/isoburn.c \
+ libisoburn/isofs_wrap.c \
+ libisoburn/burn_wrap.c \
+ libisoburn/data_source.c \
+ \
+ libisofs/builder.h \
+ libisofs/builder.c \
+ libisofs/error.h \
+ libisofs/node.h \
+ libisofs/node.c \
+ libisofs/tree.h \
+ libisofs/tree.c \
+ libisofs/image.h \
+ libisofs/image.c \
+ libisofs/iso1999.h \
+ libisofs/iso1999.c \
+ libisofs/fsource.h \
+ libisofs/fsource.c \
+ libisofs/fs_local.c \
+ libisofs/fs_image.h \
+ 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.c \
+ libisofs/rockridge.h \
+ libisofs/rockridge.c \
+ libisofs/rockridge_read.c \
+ libisofs/joliet.h \
+ libisofs/joliet.c \
+ libisofs/eltorito.h \
+ libisofs/eltorito.c \
+ libisofs/data_source.c \
+ libisofs/find.c \
+ libisofs/filter.h \
+ libisofs/filter.c \
+ libisofs/filters/xor_encrypt.c \
+ \
+ libburn/async.c \
+ libburn/async.h \
+ libburn/back_hacks.h \
+ libburn/cleanup.c \
+ libburn/cleanup.h \
+ libburn/crc.c \
+ libburn/crc.h \
+ libburn/debug.c \
+ libburn/debug.h \
+ libburn/drive.c \
+ libburn/drive.h \
+ libburn/error.h \
+ libburn/file.c \
+ libburn/file.h \
+ libburn/init.c \
+ libburn/init.h \
+ libburn/lec.c \
+ libburn/lec.h \
+ libburn/libburn.h \
+ libburn/libdax_audioxtr.h \
+ libburn/libdax_audioxtr.c \
+ libburn/libdax_msgs.h \
+ libburn/libdax_msgs.c \
+ libburn/mmc.c \
+ libburn/mmc.h \
+ libburn/null.c \
+ libburn/null.h \
+ libburn/options.c \
+ libburn/options.h \
+ libburn/os.h \
+ libburn/read.c \
+ libburn/read.h \
+ libburn/sbc.c \
+ libburn/sbc.h \
+ libburn/sector.c \
+ libburn/sector.h \
+ libburn/sg.c \
+ libburn/sg.h \
+ libburn/source.h \
+ libburn/source.c \
+ libburn/spc.c \
+ libburn/spc.h \
+ libburn/structure.c \
+ libburn/structure.h \
+ libburn/toc.c \
+ libburn/toc.h \
+ libburn/transport.h \
+ libburn/util.c \
+ libburn/util.h \
+ libburn/write.c \
+ libburn/write.h \
+ \
+ version.h
+
+
+noinst_PROGRAMS = \
+ test/compare_file
+
+# A program to compare two trees of files in mounted filesystems
+# To compare tree /media/dvd and /original/dir :
+# find /media/dvd -exec test/compare_file '{}' /media/dvd /original/dir ';'
+#
+test_compare_file_CPPFLAGS =
+test_compare_file_CFLAGS =
+test_compare_file_LDADD =
+test_compare_file_SOURCES = test/compare_file.c
+
+
+## ========================================================================= ##
+
+# Indent source files
+indent_files =
+
+
+indent: $(indent_files)
+ indent -bad -bap -nbbb -nbbo -nbc -bli0 -br -bls \
+ -cdw -ce -cli0 -ncs -nbfda -i8 -l79 -lc79 \
+ -lp -saf -sai -nprs -npsl -saw -sob -ss -ut \
+ -sbi0 -nsc -ts8 -npcs -ncdb -fca \
+ $^
+
+.PHONY: indent
+
+## ========================================================================= ##
+
+# Extra things
+nodist_pkgconfig_DATA = \
+ xorriso.pc
+
+man_MANS = xorriso/xorriso.1
+
+EXTRA_DIST = \
+ xorriso.pc.in \
+ version.h.in \
+ README \
+ AUTHORS \
+ CONTRIBUTORS \
+ COPYRIGHT \
+ COPYING \
+ INSTALL \
+ xorriso/changelog.txt \
+ $(man_MANS)
+
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_pc_in.txt b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_pc_in.txt
new file mode 100644
index 00000000..5e35e873
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_pc_in.txt
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: xorriso
+Description: ISO 9660 filesystem image manipulator
+Version: @VERSION@
+Requires:
+Libs: -L${libdir} -lpthread
+Cflags:
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_private.h b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_private.h
new file mode 100644
index 00000000..039a7dbc
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_private.h
@@ -0,0 +1,427 @@
+
+/* Command line oriented batch and dialog tool which creates, loads,
+ manipulates and burns ISO 9660 filesystem images.
+
+ Copyright 2007-2008 Thomas Schmitt,
+
+ Provided under GPL version 2.
+
+ This file contains inner declarations of xorriso.
+ The public interface is in xorriso.h
+*/
+
+
+/* For now, #ifdef Xorriso_is_xorriso_selF has no meaning.
+ But it is already now to be set only by the xorriso.c module.
+*/
+
+#ifndef Xorriso_private_includeD
+#define Xorriso_private_includeD yes
+
+#define Xorriso_program_versioN "0.1.1"
+
+/** The source code release timestamp */
+#include "xorriso_timestamp.h"
+#ifndef Xorriso_timestamP
+#define Xorriso_timestamP "-none-given-"
+#endif
+
+/** The binary build timestamp is to be set externally by the compiler */
+#ifndef Xorriso_build_timestamP
+#define Xorriso_build_timestamP "-none-given-"
+#endif
+
+
+/* Because regex_t is mentioned in struct XorrisO */
+#ifdef Xorriso_with_regeX
+#include
+#endif /* Xorriso_with_regeX */
+
+
+#define Smem_malloC malloc
+#define Smem_freE free
+#define SfileadrL 4096
+
+/* <<< ??? */
+typedef int (*Cleanup_app_handler_T)();
+
+struct LinkiteM;
+
+/* maximum number of history lines to be reported with -status:long_history */
+#define Xorriso_status_history_maX 100
+
+/* <<< ??? */
+/* try to catch signals and ignore them during abort handling */
+#define Xorriso_abort_handler_defaulT (1|(2<<4))
+
+
+/** The list of startup file names */
+#define Xorriso_rc_nuM 4
+
+
+struct XorrisO { /* the global context of xorriso */
+
+ int libs_are_started;
+
+ /* source */
+ char progname[SfileadrL];
+ char initial_wdx[SfileadrL];
+ int no_rc;
+
+ /** List of startupfiles */
+ char rc_filenames[Xorriso_rc_nuM][SfileadrL];
+ int rc_filename_count;
+
+ char wdi[SfileadrL];
+ char wdx[SfileadrL];
+ int did_something_useful;
+
+ int add_plainly;
+
+ /* >>> put libisofs aspects here <<< */
+
+ int do_joliet;
+ int do_follow_pattern;
+ int do_follow_param;
+ int do_follow_links;
+ int follow_link_limit;
+ int do_follow_mount;
+ int do_global_uid;
+ uid_t global_uid;
+ int do_global_gid;
+ gid_t global_gid;
+ int do_global_mode;
+ mode_t global_dir_mode;
+ mode_t global_file_mode;
+
+ int do_overwrite; /* 0=off, 1=on, 2=nondir */
+ int do_reassure; /* 0=off, 1=on, 2=tree */
+
+ char volid[33];
+ int volid_default;
+ char loaded_volid[33];
+
+ char publisher[129];
+
+ /* >>> put libburn/isoburn aspects here */
+
+ char indev[SfileadrL];
+ void *in_drive_handle; /* interpreted only by xorrisoburn.c */
+ void *in_volset_handle; /* interpreted only by xorrisoburn.c */
+
+ int volset_change_pending; /* whether -commit would make sense */
+
+ char outdev[SfileadrL];
+ void *out_drive_handle; /* interpreted only by xorrisoburn.c */
+ int dev_fd_1; /* The fd which substitutes for /dev/fd/1 and is
+ connected to externaly perveived stdout.
+ */
+
+ int ban_stdio_write;
+ int do_dummy;
+ int do_close;
+ int speed; /* in libburn units : 1000 bytes/second , 0 = Max, -1 = Min */
+ int fs; /* fifo size in 2048 byte chunks : at most 1 GB */
+ int padding; /* number of bytes to add after ISO 9660 image */
+
+ int keep_boot_image;
+ int patch_isolinux_image;
+
+
+ /* XORRISO options */
+ int allow_graft_points;
+
+ int dialog;
+
+
+ /* Pattern matching facility. It still carries legacy from scdbackup/askme.c
+ but is fully functional for xorriso.
+ */
+ int search_mode;
+ /* 0= start text
+ 1= fgrep ,
+ 2= regular expression
+ 3= (eventually structured) shell parser expression
+ 4= shell parser expression for leaf name
+ */
+
+ int structured_search;
+ /* 0= flat text search
+ 1= '/' is a significant separator that cannot be matched by wildcards
+ ( 2= like 1 : but report only occurence in tree, no payload, no location )
+ ( 3= like 2 : but report first content level of matching directories )
+ 4= actually not structured but unique find mode (with search_mode 4)
+ */
+
+ int do_iso_rr_pattern; /* 0=off, 1=on, 2=ls */
+ int do_disk_pattern; /* 0=off, 1=on, 2=ls */
+
+ int temp_mem_limit;
+
+ int use_stdin; /* use raw stdin even if readline support is compiled */
+ int result_page_length;
+ int result_page_width;
+ char mark_text[SfileadrL]; /* ( stdout+stderr, M: ) */
+ int packet_output;
+ char logfile[4][SfileadrL];
+ int status_history_max; /* for -status long_history */
+
+ char report_about_text[20];
+ int report_about_severity;
+ int library_msg_direct_print;
+ char abort_on_text[20];
+ int abort_on_severity; /* A severity rank number as threshold */
+ int problem_status; /* Severity rank number. 0= no abort condition present */
+ char problem_status_text[20];
+
+ char errfile_log[SfileadrL]; /* for -errfile_log */
+ int errfile_mode; /* bit0= marked */
+ FILE *errfile_fp;
+
+ char return_with_text[20];
+ int return_with_severity;
+ int return_with_value;
+ int eternal_problem_status;
+ char eternal_problem_status_text[20];
+
+ /* temporary search facilities */
+#ifdef Xorriso_with_regeX
+ regex_t *re;
+ regmatch_t match[1];
+#endif /* Xorriso_with_regeX */
+ char **re_constants;
+ int re_count;
+ int re_fill;
+ char reg_expr[2*SfileadrL];
+
+ /* run state */
+ int run_state; /* 0=preparing , 1=writing image */
+ int is_dialog;
+ int bar_is_fresh;
+ char pending_option[SfileadrL]; /* eventual option entered at page prompt */
+ int request_to_abort; /* abort a single operation like -ls, not the program */
+ int request_not_to_ask; /* suppress reassure and pager */
+ double idle_time;
+ int re_failed_at; /* mismatch position with structured_search */
+ int prepended_wd;
+ double insert_count;
+ double insert_bytes;
+ double error_count; /* double will not roll over */
+
+ /* pacifiers */
+ double pacifier_interval;
+ double start_time;
+ double last_update_time;
+ /* optional global counters for brain reduced callback functions */
+ off_t pacifier_count;
+ off_t pacifier_total;
+
+ void *pacifier_fifo;
+
+ int find_compare_result; /* 1=everything matches , 0=mismatch , -1=error */
+
+ /* result (stdout, R: ) */
+ char result_line[5*SfileadrL];
+ int result_line_counter;
+ int result_page_counter;
+ int result_open_line_len;
+
+
+ /* info (stderr, I:) */
+ char info_text[10*SfileadrL];
+
+};
+
+
+int Xorriso_prepare_regex(struct XorrisO *xorriso, char *adr, int flag);
+
+int Xorriso_result(struct XorrisO *xorriso, int flag);
+
+int Xorriso_info(struct XorrisO *xorriso, int flag);
+
+int Xorriso_request_confirmation(struct XorrisO *xorriso, int flag);
+
+int Xorriso_prescan_args(struct XorrisO *xorriso, int argc, char **argv,
+ int flag);
+
+int Xorriso_execute_option(struct XorrisO *xorriso, char *line, int flag);
+
+/* @return 0=match , else no match
+*/
+int Xorriso_regexec(struct XorrisO *xorriso, char *to_match, int *failed_at,
+ int flag);
+
+int Xorriso_prepare_expansion_pattern(struct XorrisO *xorriso, char *pattern,
+ int flag);
+
+int Xorriso__mode_to_perms(mode_t st_mode, char perms[10], int flag);
+
+int Xorriso_much_too_long(struct XorrisO *xorriso, int len, int flag);
+
+int Xorriso_check_temp_mem_limit(struct XorrisO *xorriso, off_t mem, int flag);
+
+int Xorriso_eval_nonmatch(struct XorrisO *xorriso, char *pattern,
+ int *nonconst_mismatches, off_t *mem, int flag);
+
+/* @param flag bit0= a match count !=1 is a SORRY event
+*/
+int Xorriso_check_matchcount(struct XorrisO *xorriso,
+ int count, int nonconst_mismatches, int num_patterns,
+ char **patterns, int flag);
+
+int Xorriso_no_pattern_memory(struct XorrisO *xorriso, off_t mem, int flag);
+
+int Xorriso_alloc_pattern_mem(struct XorrisO *xorriso, off_t mem,
+ int count, char ***filev, int flag);
+
+/* @param flag bit0= count results rather than storing them
+ @return <=0 error , 1 is root (end processing) ,
+ 2 is not root (go on processing)
+*/
+int Xorriso_check_for_root_pattern(struct XorrisO *xorriso,
+ int *filec, char **filev, int count_limit, off_t *mem, int flag);
+
+/* @param flag bit0= prepend wd only if name does not begin by '/'
+ bit2= prepend wd (automatically done if wd[0]!=0)
+*/
+int Xorriso_make_abs_adr(struct XorrisO *xorriso, char *wd, char *name,
+ char adr[], int flag);
+
+/* @param flag bit0= count result rather than storing it
+ bit1= unexpected change of number is a FATAL event
+*/
+int Xorriso_register_matched_adr(struct XorrisO *xorriso,
+ char *adr, int count_limit,
+ int *filec, char **filev, off_t *mem, int flag);
+
+int Xorriso_format_ls_l(struct XorrisO *xorriso, struct stat *stbuf, int flag);
+
+/* @param flag bit0= simple readlink(): no normalization, no multi-hop
+*/
+int Xorriso_resolve_link(struct XorrisO *xorriso,
+ char *link_path, char result_path[SfileadrL], int flag);
+
+/* @param flag bit0= for Xorriso_msgs_submit: use pager
+*/
+int Xorriso_hop_link(struct XorrisO *xorriso, char *link_path,
+ struct LinkiteM **link_stack, struct stat *stbuf, int flag);
+
+/* reg_expr should be twice as large as bourne_expr ( + 2 to be exact) */
+/* return: 2= bourne_expr is surely a constant */
+int Xorriso__bourne_to_reg(char bourne_expr[], char reg_expr[], int flag);
+
+int Xorriso_no_malloc_memory(struct XorrisO *xorriso, char **to_free,
+ int flag);
+
+int Xorriso_pacifier_reset(struct XorrisO *xorriso, int flag);
+
+/* This call is to be issued by long running workers in short intervals.
+ It will check whether enough time has elapsed since the last pacifier
+ message and eventually issue an update message.
+ @param what_done A sparse description of the action, preferrably in past
+ tense. E.g. "done" , "files added".
+ @param count The number of objects processed so far.
+ Is ignored if <=0.
+ @param todo The number of objects to be done in total.
+ Is ignored if <=0.
+ @param current_object A string telling the object currently processed.
+ Ignored if "".
+ @param flag bit0= report unconditionally, no time check
+*/
+int Xorriso_pacifier_callback(struct XorrisO *xorriso, char *what_done,
+ off_t count, off_t todo, char *current_object,
+ int flag);
+
+/* @param boss_iter Opaque handle to be forwarded to actions in ISO image
+ Set to NULL if calling this function from outside ISO world
+ @param flag bit0= update rather than compare
+*/
+int Xorriso_find_compare(struct XorrisO *xorriso, void *boss_iter,
+ char *iso_path, char *iso_prefix, char *disk_prefix,
+ int flag);
+
+/* @param boss_iter Opaque handle to be forwarded to actions in ISO image
+ Set to NULL if calling this function from outside ISO world
+*/
+int Xorriso_update_interpreter(struct XorrisO *xorriso, void *boss_iter,
+ int compare_result, char *disk_path,
+ char *iso_rr_path, int flag);
+
+int Sfile_str(char target[SfileadrL], char *source, int flag);
+
+double Sfile_microtime(int flag);
+
+int Sfile_add_to_path(char path[SfileadrL], char *addon, int flag);
+
+int Sfile_scale(double value, char *result, int siz, double thresh, int flag);
+
+int Sfile_destroy_argv(int *argc, char ***argv, int flag);
+
+/*
+ bit0= do not ignore trailing slash
+ bit1= do not ignore empty components (other than the empty root name)
+*/
+int Sfile_count_components(char *path, int flag);
+
+
+char *Text_shellsafe(char *in_text, char *out_text, int flag);
+
+int Sort_argv(int argc, char **argv, int flag);
+
+struct DirseQ;
+
+int Dirseq_new(struct DirseQ **o, char *adr, int flag);
+
+int Dirseq_destroy(struct DirseQ **o, int flag);
+
+int Dirseq_next_adr(struct DirseQ *o, char reply[SfileadrL], int flag);
+
+
+int Linkitem_reset_stack(struct LinkiteM **o, struct LinkiteM *to, int flag);
+
+
+struct FindjoB;
+
+/* @return 0=no match , 1=match , <0 = error
+*/
+int Findjob_test(struct FindjoB *job, char *name,
+ struct stat *boss_stbuf, struct stat *stbuf,
+ int depth, int flag);
+
+/* @return <0 error, >=0 see xorriso.c struct FindjoB.action
+*/
+int Findjob_get_action(struct FindjoB *o, int flag);
+
+/* @return <0 error, >=0 see xorriso.c struct FindjoB.action
+*/
+int Findjob_get_action_parms(struct FindjoB *o, char **target,
+ uid_t *user, gid_t *group,
+ mode_t *mode_and, mode_t *mode_or,
+ int *type, time_t *date, struct FindjoB **subjob,
+ int flag);
+
+/* @param flag bit0= recursive
+*/
+int Findjob_set_action_target(struct FindjoB *o, int action, char *target,
+ int flag);
+
+/* @param flag bit0= recursive
+*/
+int Findjob_set_action_chgrp(struct FindjoB *o, gid_t group, int flag);
+
+/* @param flag bit0= recursive
+*/
+int Findjob_set_action_chmod(struct FindjoB *o,
+ mode_t mode_and, mode_t mode_or, int flag);
+
+/* @param flag bit0= recursive
+*/
+int Findjob_set_action_ad(struct FindjoB *o, int type, time_t date, int flag);
+
+int Findjob_set_start_path(struct FindjoB *o, char *start_path, int flag);
+
+int Findjob_get_start_path(struct FindjoB *o, char **start_path, int flag);
+
+
+#endif /* Xorriso_private_includeD */
+
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_timestamp.h b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_timestamp.h
new file mode 100644
index 00000000..e53edaad
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorriso_timestamp.h
@@ -0,0 +1 @@
+#define Xorriso_timestamP "2008.03.08.104231"
diff --git a/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorrisoburn.c b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorrisoburn.c
new file mode 100644
index 00000000..545b11a7
--- /dev/null
+++ b/libisoburn/branches/XorrisoZeroOneTwo/xorriso/xorrisoburn.c
@@ -0,0 +1,4745 @@
+
+
+/* Adapter to libisoburn, libisofs and libburn for xorriso,
+ a command line oriented batch and dialog tool which creates, loads,
+ manipulates and burns ISO 9660 filesystem images.
+
+ Copyright 2007-2008 Thomas Schmitt,
+
+ Provided under GPL version 2.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#define Xorriso_on_libisofs_after_0_6_2 yes
+
+
+/* ------------------------------------------------------------------------ */
+
+#ifndef Xorriso_standalonE
+
+/* The library which does the ISO 9660 / RockRidge manipulations */
+#include
+
+/* The library which does MMC optical drive operations */
+#include
+
+/* The library which enhances overwriteable media with ISO 9660 multi-session
+ capabilities via the method invented by Andy Polyakov for growisofs */
+#include
+
+/* The official xorriso options API. "No shortcuts" */
+#include "xorriso.h"
+
+/* The inner description of XorrisO */
+#include "xorriso_private.h"
+
+/* The inner isofs- and burn-library interface */
+#include "xorrisoburn.h"
+
+#else /* ! Xorriso_standalonE */
+
+#include "../libisofs/libisofs.h"
+#include "../libburn/libburn.h"
+#include "../libisoburn/libisoburn.h"
+#include "xorriso.h"
+#include "xorriso_private.h"
+#include "xorrisoburn.h"
+
+#endif /* Xorriso_standalonE */
+
+
+int Xorriso_pacifier_loop(struct XorrisO *xorriso, struct burn_drive *drive,
+ int flag);
+
+int Xorriso__read_pacifier(IsoImage *image, IsoFileSource *filesource);
+
+
+#define LIBISO_ISDIR(node) (iso_node_get_type(node) == LIBISO_DIR)
+#define LIBISO_ISREG(node) (iso_node_get_type(node) == LIBISO_FILE)
+#define LIBISO_ISLNK(node) (iso_node_get_type(node) == LIBISO_SYMLINK)
+#define LIBISO_ISCHR(node) (iso_node_get_type(node) == LIBISO_SPECIAL && \
+ S_ISCHR(iso_node_get_mode(node)))
+#define LIBISO_ISBLK(node) (iso_node_get_type(node) == LIBISO_SPECIAL && \
+ S_ISBLK(iso_node_get_mode(node)))
+#define LIBISO_ISFIFO(node) (iso_node_get_type(node) == LIBISO_SPECIAL && \
+ S_ISFIFO(iso_node_get_mode(node)))
+#define LIBISO_ISSOCK(node) (iso_node_get_type(node) == LIBISO_SPECIAL && \
+ S_ISSOCK(iso_node_get_mode(node)))
+
+/* CD specs say one shall not write tracks < 600 kiB */
+#define Xorriso_cd_min_track_sizE 300
+
+
+/* ------------------------------------------------------------------------ */
+
+
+int Xorriso_startup_libraries(struct XorrisO *xorriso, int flag)
+{
+ int ret, major, minor, micro;
+ char *handler_prefix= NULL;
+ char *queue_sev, *print_sev, reason[1024];
+
+
+/* First an ugly compile time check for header version compatibility.
+ If everthing matches, then no C code is produced. In case of mismatch,
+ intentionally faulty C code will be inserted.
+*/
+
+/* The minimum requirement of xorriso towards the libisoburn header
+ at compile time is defined in xorriso/xorrisoburn.h
+ xorriso_libisoburn_req_major
+ xorriso_libisoburn_req_minor
+ xorriso_libisoburn_req_micro
+ It gets compared against the version macros in libburn/libburn.h :
+ isoburn_header_version_major
+ isoburn_header_version_minor
+ isoburn_header_version_micro
+ If the header is too old then the following code shall cause failure of
+ cdrskin compilation rather than to allow production of a program with
+ unpredictable bugs or memory corruption.
+ The compiler messages supposed to appear in this case are:
+ error: 'LIBISOBURN_MISCONFIGURATION' undeclared (first use in this function)
+ error: 'INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisoburn_dot_h_TOO_OLD__SEE_xorrisoburn_dot_c' undeclared (first use in this function)
+ error: 'LIBISOBURN_MISCONFIGURATION_' undeclared (first use in this function)
+*/
+/* The indendation is an advise of man gcc to help old compilers ignoring */
+ #if xorriso_libisoburn_req_major > isoburn_header_version_major
+ #define Isoburn_libisoburn_dot_h_too_olD 1
+ #endif
+ #if xorriso_libisoburn_req_major == isoburn_header_version_major && xorriso_libisoburn_req_minor > isoburn_header_version_minor
+ #define Isoburn_libisoburn_dot_h_too_olD 1
+ #endif
+ #if xorriso_libisoburn_req_minor == isoburn_header_version_minor && xorriso_libisoburn_req_micro > isoburn_header_version_micro
+ #define Isoburn_libisoburn_dot_h_too_olD 1
+ #endif
+
+#ifdef Isoburn_libisoburn_dot_h_too_olD
+LIBISOBURN_MISCONFIGURATION = 0;
+INTENTIONAL_ABORT_OF_COMPILATION__HEADERFILE_libisoburn_dot_h_TOO_OLD__SEE_xorrisoburn_dot_c = 0;
+LIBISOBURN_MISCONFIGURATION_ = 0;
+#endif
+
+/* End of ugly compile time test (scroll up for explanation) */
+
+
+ sprintf(xorriso->info_text, "Starting up libraries ...\n");
+ Xorriso_info(xorriso, 0);
+
+ handler_prefix= calloc(strlen(xorriso->progname)+3+1, 1);
+ if(handler_prefix==NULL) {
+ sprintf(xorriso->info_text,
+ "Cannot allocate memory for initializing libraries");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(-1);
+ }
+ reason[0]= 0;
+ ret= isoburn_initialize(reason, 0);
+ if(ret==0) {
+ sprintf(xorriso->info_text, "Cannot initialize libraries");
+ if(reason[0])
+ sprintf(xorriso->info_text+strlen(xorriso->info_text),
+ ". Reason given:\n%s", reason);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ free(handler_prefix);
+ return(0);
+ }
+ ret= isoburn_is_compatible(isoburn_header_version_major,
+ isoburn_header_version_minor,
+ isoburn_header_version_micro, 0);
+ if(ret<=0) {
+ isoburn_version(&major, &minor, µ);
+ sprintf(xorriso->info_text,
+ "libisoburn version too old: %d.%d.%d . Need at least: %d.%d.%d .\n",
+ major, minor, micro,
+ isoburn_header_version_major, isoburn_header_version_minor,
+ isoburn_header_version_micro);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(-1);
+ }
+
+ xorriso->libs_are_started= 1;
+
+ queue_sev= "ALL";
+ if(xorriso->library_msg_direct_print) {
+
+ /* >>> need option for controlling this in XorrisO.
+ See also Xorriso_msgs_submit */;
+
+ print_sev= xorriso->report_about_text;
+ } else
+ print_sev= "NEVER";
+
+ iso_set_msgs_severities(queue_sev, print_sev, "libsofs : ");
+ burn_msgs_set_severities(queue_sev, print_sev, "libburn : ");
+
+ /* ??? >>> do we want united queues ? */
+ /* burn_set_messenger(iso_get_messenger()); */
+
+ sprintf(handler_prefix, "%s : ", xorriso->progname);
+ burn_set_signal_handling(handler_prefix, NULL, 0);
+
+ Xorriso_process_msg_queues(xorriso,0);
+ if(reason[0]) {
+ sprintf(xorriso->info_text, "%s", reason);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
+ }
+
+ sprintf(xorriso->info_text, "Library startup done.\n");
+ Xorriso_info(xorriso, 0);
+ free(handler_prefix);
+ return(1);
+}
+
+
+/* @param flag bit0= global shutdown of libraries */
+int Xorriso_detach_libraries(struct XorrisO *xorriso, int flag)
+{
+ Xorriso_give_up_drive(xorriso, 3);
+ if(xorriso->in_volset_handle!=NULL) { /* standalone image */
+ iso_image_unref((IsoImage *) xorriso->in_volset_handle);
+ xorriso->in_volset_handle= NULL;
+ }
+ if(flag&1) {
+ if(xorriso->libs_are_started==0)
+ return(0);
+ isoburn_finish();
+ }
+ return(1);
+}
+
+
+/* @param flag bit1= obtain outdrive, else indrive */
+int Xorriso_get_drive_handles(struct XorrisO *xorriso,
+ struct burn_drive_info **dinfo,
+ struct burn_drive **drive,
+ char *attempt, int flag)
+{
+ if(flag&2)
+ *dinfo= (struct burn_drive_info *) xorriso->out_drive_handle;
+ else
+ *dinfo= (struct burn_drive_info *) xorriso->in_drive_handle;
+ if(*dinfo==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text, "No %s drive aquired %s",
+ (flag&2 ? "output" : "input"), attempt);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+ *drive= (*dinfo)[0].drive;
+ return((*drive)!=NULL);
+}
+
+
+/* >>> todo: throw out the copies of libdax_msgs entrails */
+
+/* <<< to be replaced by libburn-0.4.3 API call burn_sev_to_text().
+ This is a copy of libdax_msgs__sev_to_text() which is not exposed
+ by the API of of libburn-0.4.2 . As soon as xorriso gets based on
+ libburn-0.4.4 this redundancy is to be removed.
+ It is safe, nevertheless, because the severity codes are eternal.
+*/
+#define LIBDAX_MSGS_SEV_ALL 0x00000000
+#define LIBDAX_MSGS_SEV_ERRFILE 0x08000000
+#define LIBDAX_MSGS_SEV_DEBUG 0x10000000
+#define LIBDAX_MSGS_SEV_UPDATE 0x20000000
+#define LIBDAX_MSGS_SEV_NOTE 0x30000000
+#define LIBDAX_MSGS_SEV_HINT 0x40000000
+#define LIBDAX_MSGS_SEV_WARNING 0x50000000
+#define LIBDAX_MSGS_SEV_SORRY 0x60000000
+#define LIBDAX_MSGS_SEV_MISHAP 0x64000000
+#define LIBDAX_MSGS_SEV_FAILURE 0x68000000
+#define LIBDAX_MSGS_SEV_FATAL 0x70000000
+#define LIBDAX_MSGS_SEV_ABORT 0x71000000
+#define LIBDAX_MSGS_SEV_NEVER 0x7fffffff
+
+
+int Xorriso__sev_to_text(int severity, char **severity_name,
+ int flag)
+{
+#ifdef Xorriso_on_libisofs_after_0_6_2
+ int ret;
+#else
+#ifdef Xorriso_on_libburn_after_0_4_2
+ int ret;
+#endif
+#endif
+
+#ifdef Xorriso_on_libisofs_after_0_6_2
+ ret= iso_sev_to_text(severity, severity_name);
+ if(ret>0)
+ return(ret);
+#endif /* Xorriso_on_libisofs_after_0_6_2 */
+#ifdef Xorriso_on_libburn_after_0_4_2
+ ret= burn_sev_to_text(severity, severity_name, 0);
+ if(ret>0)
+ return(ret);
+#endif
+
+ if(flag&1) {
+ *severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
+ return(1);
+ }
+ *severity_name= "";
+ if(severity>=LIBDAX_MSGS_SEV_NEVER)
+ *severity_name= "NEVER";
+ else if(severity>=LIBDAX_MSGS_SEV_ABORT)
+ *severity_name= "ABORT";
+ else if(severity>=LIBDAX_MSGS_SEV_FATAL)
+ *severity_name= "FATAL";
+ else if(severity>=LIBDAX_MSGS_SEV_FAILURE)
+ *severity_name= "FAILURE";
+ else if(severity>=LIBDAX_MSGS_SEV_MISHAP)
+ *severity_name= "MISHAP";
+ else if(severity>=LIBDAX_MSGS_SEV_SORRY)
+ *severity_name= "SORRY";
+ else if(severity>=LIBDAX_MSGS_SEV_WARNING)
+ *severity_name= "WARNING";
+ else if(severity>=LIBDAX_MSGS_SEV_HINT)
+ *severity_name= "HINT";
+ else if(severity>=LIBDAX_MSGS_SEV_NOTE)
+ *severity_name= "NOTE";
+ else if(severity>=LIBDAX_MSGS_SEV_UPDATE)
+ *severity_name= "UPDATE";
+ else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
+ *severity_name= "DEBUG";
+ else if(severity>=LIBDAX_MSGS_SEV_ERRFILE)
+ *severity_name= "ERRFILE";
+ else if(severity>=LIBDAX_MSGS_SEV_ALL)
+ *severity_name= "ALL";
+ else {
+ *severity_name= "";
+ return(0);
+ }
+ return(1);
+}
+
+
+int Xorriso__text_to_sev(char *severity_name, int *severity_number, int flag)
+{
+ int ret= 1;
+
+#ifdef Xorriso_on_libisofs_after_0_6_2
+ ret= iso_text_to_sev(severity_name, severity_number);
+ if(ret>0)
+ return(ret);
+#endif /* Xorriso_on_libisofs_after_0_6_2 */
+
+#ifndef Xorriso_on_libburn_after_0_4_2
+ if(severity_name[0]==0)
+ *severity_number= 0;
+ else if(strcmp(severity_name, "MISHAP")==0)
+ *severity_number= LIBDAX_MSGS_SEV_MISHAP;
+ else if(strcmp(severity_name, "ERRFILE")==0)
+ *severity_number= LIBDAX_MSGS_SEV_ERRFILE;
+ else
+#endif /* ! Xorriso_on_libburn_after_0_4_2 */
+
+ ret= burn_text_to_sev(severity_name, severity_number, 0);
+ return(ret);
+}
+
+
+/* @param flag bit0= report libisofs error text
+ bit1= victim is disk_path
+*/
+int Xorriso_report_iso_error(struct XorrisO *xorriso, char *victim,
+ int iso_error_code, char msg_text[], int os_errno,
+ char min_severity[], int flag)
+{
+ int error_code, iso_sev, min_sev, ret;
+ char *sev_text_pt, *msg_text_pt= NULL;
+ char sfe[6*SfileadrL];
+ static int sorry_sev= -1;
+
+ if(sorry_sev<0)
+ Xorriso__text_to_sev("SORRY", &sorry_sev, 0);
+
+ error_code= iso_error_get_code(iso_error_code);
+ if(error_code < 0x00030000 || error_code >= 0x00040000)
+ error_code= (error_code & 0xffff) | 0x00050000;
+
+ if(flag&1)
+ msg_text_pt= (char *) iso_error_to_msg(iso_error_code);
+ if(msg_text_pt==NULL)
+ msg_text_pt= msg_text;
+ iso_sev= iso_error_get_severity(iso_error_code);
+
+ if(iso_sev >= sorry_sev && (flag & 2) && victim[0])
+ Xorriso_msgs_submit(xorriso, 0, victim, 0, "ERRFILE", 0);
+ sev_text_pt= min_severity;
+ Xorriso__text_to_sev(min_severity, &min_sev, 0);
+ if(min_sev < iso_sev)
+ Xorriso__sev_to_text(iso_sev, &sev_text_pt, 0);
+ strcpy(sfe, msg_text_pt);
+ if(victim[0]) {
+ strcat(sfe, ": ");
+ Text_shellsafe(victim, sfe+strlen(sfe), 0);
+ }
+ ret= Xorriso_msgs_submit(xorriso, error_code, sfe, os_errno, sev_text_pt, 4);
+ return(ret);
+}
+
+
+/* @param flag bit0= suppress messages below UPDATE
+ bit1= suppress messages below FAILURE
+*/
+int Xorriso_set_image_severities(struct XorrisO *xorriso, int flag)
+{
+ char *queue_sev, *print_sev;
+
+ if(flag&2)
+ queue_sev= "FAILURE";
+ else if(flag&1)
+ queue_sev= "UPDATE";
+ else
+ queue_sev= "ALL";
+ if(xorriso->library_msg_direct_print)
+ print_sev= xorriso->report_about_text;
+ else
+ print_sev= "NEVER";
+ iso_set_msgs_severities(queue_sev, print_sev, "libisofs : ");
+ return(1);
+}
+
+
+int Xorriso_update_volid(struct XorrisO *xorriso, int flag)
+{
+ int gret, sret= 1;
+
+ gret= Xorriso_get_volid(xorriso, xorriso->loaded_volid, 0);
+ if(gret<=0 || (!xorriso->volid_default) || xorriso->loaded_volid[0]==0)
+ sret= Xorriso_set_volid(xorriso, xorriso->volid, 1);
+ return(gret>0 && sret>0);
+}
+
+
+int Xorriso_create_empty_iso(struct XorrisO *xorriso, int flag)
+{
+ int ret;
+ IsoImage *volset;
+ struct isoburn_read_opts *ropts;
+ struct burn_drive_info *dinfo= NULL;
+ struct burn_drive *drive= NULL;
+
+ if(xorriso->out_drive_handle != NULL) {
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to attach volset to drive", 2);
+ if(ret<=0)
+ return(ret);
+ }
+ if(xorriso->in_volset_handle!=NULL) {
+ iso_image_unref((IsoImage *) xorriso->in_volset_handle);
+ xorriso->in_volset_handle= NULL;
+ xorriso->loaded_volid[0]= 0;
+ xorriso->volset_change_pending= 0;
+ }
+
+ ret= isoburn_ropt_new(&ropts, 0);
+ if(ret<=0)
+ return(ret);
+ /* Note: no return before isoburn_ropt_destroy() */
+ isoburn_ropt_set_extensions(ropts, isoburn_ropt_pretend_blank);
+ isoburn_ropt_set_input_charset(ropts, NULL);
+ isoburn_set_read_pacifier(drive, NULL, NULL);
+ ret= isoburn_read_image(drive, ropts, &volset);
+ Xorriso_process_msg_queues(xorriso,0);
+ isoburn_ropt_destroy(&ropts, 0);
+ if(ret<=0) {
+ sprintf(xorriso->info_text, "Failed to create new empty ISO image object");
+ Xorriso_report_iso_error(xorriso, "", ret, xorriso->info_text, 0, "FATAL",
+ 0);
+ return(-1);
+ }
+ xorriso->in_volset_handle= (void *) volset;
+ Xorriso_update_volid(xorriso, 0);
+ xorriso->volset_change_pending= 0;
+ return(1);
+}
+
+
+/* @param flag bit0= aquire as isoburn input drive
+ bit1= aquire as libburn output drive (as isoburn drive if bit0)
+ bit2= regard overwriteable media as blank
+ bit3= if the drive is a regular disk file: truncate it to
+ the write start address
+ @return <=0 failure , 1= ok
+ 2=success, but not writeable with bit1
+ 3=success, but not blank and not ISO with bit0
+*/
+int Xorriso_aquire_drive(struct XorrisO *xorriso, char *adr, int flag)
+{
+ int ret, hret, not_writeable= 0, has_what;
+ uint32_t size;
+ struct burn_drive_info *dinfo= NULL, *out_dinfo, *in_dinfo;
+ struct burn_drive *drive, *out_drive, *in_drive;
+ enum burn_disc_status state;
+ IsoImage *volset = NULL;
+ struct isoburn_read_opts *ropts= NULL;
+ char adr_data[SfileadrL], *libburn_adr, *boot_fate;
+
+ if((flag&3)==0) {
+ sprintf(xorriso->info_text,
+ "XORRISOBURN program error : Xorriso_aquire_drive bit0+bit1 not set");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(-1);
+ }
+ ret= Xorriso_give_up_drive(xorriso, (flag&3)|8);
+ if(ret<=0)
+ return(ret);
+
+ libburn_adr= adr;
+ if(strcmp(adr,"stdio:/dev/fd/1")==0) {
+ if(xorriso->dev_fd_1<0) {
+ sprintf(xorriso->info_text,
+ "-*dev \"stdio:/dev/fd/1\" was not a start argument. Cannot use it now.");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ {ret= 0; goto ex;}
+ } else {
+ sprintf(adr_data, "stdio:/dev/fd/%d", xorriso->dev_fd_1);
+ libburn_adr= adr_data;
+ }
+ }
+
+ if((flag&3)==1 && xorriso->out_drive_handle!=NULL) {
+ ret= Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive,
+ "on attempt to compare new indev with outdev", 2);
+ if(ret<=0)
+ goto ex;
+ ret= burn_drive_equals_adr(out_drive, libburn_adr, 1);
+ if(ret==1)
+ dinfo= out_dinfo;
+ } else if((flag&3)==2 && xorriso->in_drive_handle!=NULL) {
+ ret= Xorriso_get_drive_handles(xorriso, &in_dinfo, &in_drive,
+ "on attempt to compare new indev with outdev", 0);
+ if(ret<=0)
+ goto ex;
+ ret= burn_drive_equals_adr(in_drive, libburn_adr, 1);
+ if(ret==1)
+ dinfo= in_dinfo;
+ }
+
+ if(dinfo==NULL) {
+ ret= isoburn_drive_aquire(&dinfo, libburn_adr, 1|((flag&(8|4))>>1));
+ Xorriso_process_msg_queues(xorriso,0);
+ if(ret<=0) {
+ sprintf(xorriso->info_text,"Cannot aquire drive '%s'", adr);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+ }
+ drive= dinfo[0].drive;
+ state= isoburn_disc_get_status(drive);
+ Xorriso_process_msg_queues(xorriso,0);
+ if(flag&1) {
+ volset= isoburn_get_attached_image(drive);
+ if(volset != NULL) { /* The image object is already created */
+ iso_image_unref(volset);
+ }
+ }
+
+ if(flag&2) {
+ xorriso->out_drive_handle= dinfo;
+ if(Sfile_str(xorriso->outdev, adr, 0)<=0)
+ {ret= -1; goto ex;}
+ if(state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE) {
+ sprintf(xorriso->info_text, "Disc status unsuitable for writing");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
+ not_writeable= 1;
+ }
+ }
+ if(flag&1) {
+ xorriso->in_drive_handle= dinfo;
+ if(Sfile_str(xorriso->indev, adr, 0)<=0)
+ {ret= -1; goto ex;}
+ } else if(flag&2) {
+ if(xorriso->in_volset_handle==NULL) {
+ /* No volume loaded: create empty one */
+ ret= Xorriso_create_empty_iso(xorriso, 0);
+ if(ret<=0)
+ goto ex;
+ } else {
+ iso_image_ref((IsoImage *) xorriso->in_volset_handle);
+ ret= isoburn_attach_image(drive, (IsoImage *) xorriso->in_volset_handle);
+ if(ret<=0) {
+ sprintf(xorriso->info_text,
+ "Failed to attach ISO image object to outdev");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ {ret= -1; goto ex;}
+ }
+ }
+ Xorriso_toc(xorriso, 1|2);
+ {ret= 1+not_writeable; goto ex;}
+ }
+
+ if(xorriso->in_volset_handle!=NULL)
+ iso_image_unref((IsoImage *) xorriso->in_volset_handle);
+ xorriso->in_volset_handle= NULL;
+
+ /* check for invalid state */
+ if(state != BURN_DISC_BLANK && state != BURN_DISC_APPENDABLE &&
+ state != BURN_DISC_FULL) {
+ sprintf(xorriso->info_text,
+ "Disc status not blank and unsuitable for reading");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
+ {ret= 0; goto ex;}
+ }
+ /* fill read opts */
+ ret= isoburn_ropt_new(&ropts, 0);
+ if(ret<=0)
+ goto ex;
+ isoburn_ropt_set_extensions(ropts, isoburn_ropt_noiso1999);
+ isoburn_ropt_set_default_perms(ropts, (uid_t) 0, (gid_t) 0, (mode_t) 0555);
+ isoburn_ropt_set_input_charset(ropts, NULL);
+
+ Xorriso_set_image_severities(xorriso, 1); /* No DEBUG messages */
+ Xorriso_pacifier_reset(xorriso, 0);
+ isoburn_set_read_pacifier(drive, Xorriso__read_pacifier, (void *) xorriso);
+ if(isoburn_read_image(drive, ropts, &volset) <= 0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_set_image_severities(xorriso, 0);
+ sprintf(xorriso->info_text,"Cannot read ISO image volset");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 3; goto ex;
+ }
+ Xorriso_pacifier_callback(xorriso, "nodes read", xorriso->pacifier_count, 0,
+ "", 1); /* report end count */
+ xorriso->in_volset_handle= (void *) volset;
+ Xorriso_set_image_severities(xorriso, 0);
+ Xorriso_update_volid(xorriso, 0);
+
+ if(xorriso->out_drive_handle != NULL &&
+ xorriso->out_drive_handle != xorriso->in_drive_handle) {
+ ret= Xorriso_get_drive_handles(xorriso, &out_dinfo, &out_drive,
+ "on attempt to attach ISO image volset to outdev", 2);
+ if(ret<=0)
+ goto ex;
+ iso_image_ref((IsoImage *) xorriso->in_volset_handle);
+ isoburn_attach_image(out_drive, xorriso->in_volset_handle);
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+ isoburn_ropt_get_size_what(ropts, &size, &has_what);
+ if(has_what & isoburn_ropt_has_el_torito) {
+ if(xorriso->patch_isolinux_image)
+ boot_fate= "patched as isolinux image";
+ else if(xorriso->keep_boot_image)
+ boot_fate= "kept unchanged";
+ else
+ boot_fate= "discarded";
+ sprintf(xorriso->info_text,
+ "Detected El-Torito boot information which currently is set to be %s",
+ boot_fate);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ }
+
+ Xorriso_toc(xorriso, 1);
+ if(xorriso->loaded_volid[0]!=0) {
+ sprintf(xorriso->result_line,"Volume id : '%s'\n",xorriso->loaded_volid);
+ Xorriso_result(xorriso,0);
+ if(strcmp(xorriso->loaded_volid, xorriso->volid)!=0 &&
+ !xorriso->volid_default) {
+ sprintf(xorriso->result_line, "New volume id: '%s'\n", xorriso->volid);
+ Xorriso_result(xorriso,0);
+ }
+ }
+ ret= 1+not_writeable;
+ex:
+ Xorriso_process_msg_queues(xorriso,0);
+ if(ret<=0) {
+ hret= Xorriso_give_up_drive(xorriso, flag&3);
+ if(hretin_drive_handle == xorriso->out_drive_handle);
+ if((flag&4) && in_is_out_too && (flag&(1|2))) {
+ if((flag&3)!=3) {
+ sprintf(xorriso->info_text,"Giving up for -eject whole -dev %s",
+ Text_shellsafe(xorriso->indev, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ }
+ flag|= 3; /* give up in/out drive to eject it */
+ }
+
+ if((flag&1) && xorriso->in_drive_handle != NULL) {
+ Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to give up drive", 0);
+
+ if(!in_is_out_too) {
+ if(drive!=NULL && !in_is_out_too)
+ isoburn_drive_release(drive,!!(flag&4));
+ if(dinfo!=NULL && !in_is_out_too)
+ burn_drive_info_free(dinfo);
+ }
+ xorriso->in_drive_handle= NULL;
+ xorriso->indev[0]= 0;
+
+ if(xorriso->in_volset_handle!=NULL)
+ iso_image_unref((IsoImage *) xorriso->in_volset_handle);
+ xorriso->in_volset_handle= NULL;
+ xorriso->loaded_volid[0]= 0;
+ xorriso->volset_change_pending= 0;
+
+ in_is_out_too= 0;
+ }
+ if((flag&2) && xorriso->out_drive_handle!=NULL) {
+ Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to give up drive", 2);
+ if(!in_is_out_too) {
+ if(drive!=NULL)
+ isoburn_drive_release(drive,!!(flag&4));
+ if(dinfo!=NULL)
+ burn_drive_info_free(dinfo);
+ }
+ xorriso->out_drive_handle= NULL;
+ xorriso->outdev[0]= 0;
+ } else if((flag&1) && xorriso->out_drive_handle!=NULL) {
+ ret= Xorriso_create_empty_iso(xorriso, 0);
+ if(ret<=0)
+ return(ret);
+ if(!(flag&8)) {
+ sprintf(xorriso->info_text,
+ "Only the output drive remains. Created empty ISO image.\n");
+ Xorriso_info(xorriso, 0);
+ Xorriso_toc(xorriso, 1|2);
+ }
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1);
+}
+
+
+int Xorriso_make_write_options(
+ struct XorrisO *xorriso, struct burn_drive *drive,
+ struct burn_write_opts **burn_options, int flag)
+{
+ int drive_role;
+
+ *burn_options= burn_write_opts_new(drive);
+ if(*burn_options==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"Cannot allocate option set");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+ burn_write_opts_set_simulate(*burn_options, !!xorriso->do_dummy);
+ drive_role= burn_drive_get_drive_role(drive);
+ burn_write_opts_set_multi(*burn_options,
+ !(xorriso->do_close || drive_role==0 || drive_role==3));
+ burn_drive_set_speed(drive, xorriso->speed, xorriso->speed);
+ burn_write_opts_set_underrun_proof(*burn_options, 1);
+ return(1);
+}
+
+
+/* @param flag bit0= do not write but only prepare and return size in sectors
+ bit1= do not use isoburn wrappers
+*/
+int Xorriso_sanitize_image_size(struct XorrisO *xorriso,
+ struct burn_drive *drive, struct burn_disc *disc,
+ struct burn_write_opts *burn_options, int flag)
+{
+ int ret, img_sectors, num_sessions= 0, num_tracks= 0, padding= 0, profile;
+ int media_space;
+ char profile_name[80];
+ struct burn_session **sessions;
+ struct burn_track **tracks;
+
+ img_sectors= burn_disc_get_sectors(disc);
+
+ sessions= burn_disc_get_sessions(disc, &num_sessions);
+ if(sessions==NULL || num_sessions < 1) {
+no_track:;
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"Program error : no track in prepared disc");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ {ret= -1; goto ex;}
+ }
+ tracks= burn_session_get_tracks(sessions[0], &num_tracks);
+ if(tracks==NULL || num_tracks < 1)
+ goto no_track;
+
+ padding= 0;
+ ret= burn_disc_get_profile(drive, &profile, profile_name);
+ padding= xorriso->padding / 2048;
+ if(xorriso->padding > padding * 2048)
+ padding++;
+ if(img_sectors>0 && (profile==0x09 || profile==0x0a)) { /* CD-R , CD-RW */
+ if(img_sectors + padding < Xorriso_cd_min_track_sizE) {
+ padding= Xorriso_cd_min_track_sizE - img_sectors;
+ sprintf(xorriso->info_text,
+ "Expanded track to minimum size of %d sectors",
+ Xorriso_cd_min_track_sizE);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ }
+ }
+ burn_track_define_data(tracks[0], 0, padding * 2048, 0, BURN_MODE1);
+ Xorriso_process_msg_queues(xorriso,0);
+
+ if(flag&2)
+ media_space= burn_disc_available_space(drive, burn_options) /
+ (off_t) 2048;
+ else
+ media_space= isoburn_disc_available_space(drive, burn_options) /
+ (off_t) 2048;
+ if(media_space < img_sectors + padding) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"Image size %ds exceeds free space on media %ds",
+ img_sectors + padding, media_space);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ {ret= 0; goto ex;}
+ }
+ if(flag&1) {
+ ret= img_sectors+padding;
+ } else
+ ret= 1;
+ex:;
+ return(ret);
+}
+
+
+/* @param flag bit0= do not write but only prepare and return size in sectors
+*/
+int Xorriso_write_session(struct XorrisO *xorriso, int flag)
+{
+ int ret, relax= 0, i;
+ int major, minor, micro;
+ char xorriso_id[256], *img_id;
+ struct isoburn_imgen_opts *sopts= NULL;
+ struct burn_drive_info *dinfo, *source_dinfo;
+ struct burn_drive *drive, *source_drive;
+ struct burn_disc *disc= NULL;
+ struct burn_write_opts *burn_options;
+ off_t readcounter= 0,writecounter= 0;
+ int num_sessions= 0, num_tracks= 0;
+ struct burn_session **sessions;
+ struct burn_track **tracks;
+ enum burn_disc_status s;
+ IsoImage *image = NULL;
+ ElToritoBootImage *bootimg;
+
+#ifdef NIX
+ char profile_name[80];
+ int padding= 0, img_sectors, media_space, profile;
+#endif
+
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to write", 2);
+ if(ret<=0)
+ return(0);
+
+ if(xorriso->out_drive_handle == xorriso->in_drive_handle) {
+ source_drive= drive;
+ } else {
+ if(xorriso->in_drive_handle == NULL) {
+ source_drive= drive;
+ } else {
+ ret= Xorriso_get_drive_handles(xorriso, &source_dinfo, &source_drive,
+ "on attempt to get source for write", 0);
+ if(ret<=0)
+ goto ex;
+ }
+ s= isoburn_disc_get_status(drive);
+ if(s!=BURN_DISC_BLANK) {
+ s= burn_disc_get_status(drive);
+ if(s!=BURN_DISC_BLANK)
+ sprintf(xorriso->info_text,
+ "-indev differs from -outdev and -outdev media is not blank");
+ else
+ sprintf(xorriso->info_text,
+ "-indev differs from -outdev and -outdev media holds valid ISO image");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ {ret= 0; goto ex;}
+ }
+ }
+
+ ret= isoburn_igopt_new(&sopts, 0);
+ if(ret<=0)
+ return(ret);
+ relax= isoburn_igopt_allow_deep_paths;
+
+ /* Adjust or discard boot image */
+ image= isoburn_get_attached_image(source_drive);
+ /* >>> ??? move down to libisoburn ? */
+ if(image!=NULL && !(flag&1)) {
+ ret= iso_image_get_boot_image(image, &bootimg, NULL, NULL);
+ if(xorriso->patch_isolinux_image) {
+ if(ret==1) {
+ relax|= isoburn_igopt_allow_full_ascii;
+ sprintf(xorriso->info_text, "Patching alleged isolinux boot image");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ el_torito_patch_isolinux_image(bootimg);
+ } else {
+ sprintf(xorriso->info_text,
+ "Could not find any boot image for -boot_image isolinux patch");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
+ }
+ } else if(xorriso->keep_boot_image && ret==1) {
+ relax|= isoburn_igopt_allow_full_ascii;
+ sprintf(xorriso->info_text, "Keeping boot image unchanged");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ } else if(ret==1) {
+ iso_image_remove_boot_image(image);
+ sprintf(xorriso->info_text, "Discarded boot image from old session");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ }
+ }
+ isoburn_igopt_set_level(sopts, 2);
+ isoburn_igopt_set_extensions(sopts, 1|((!!xorriso->do_joliet)<<1));
+ isoburn_igopt_set_relaxed(sopts, isoburn_igopt_allow_deep_paths);
+ isoburn_igopt_set_sort_files(sopts, 1);
+ isoburn_igopt_set_over_mode(sopts, 0, 0, (mode_t) 0, (mode_t) 0);
+ isoburn_igopt_set_over_ugid(sopts, 0, 0, (uid_t) 0, (gid_t) 0);
+ isoburn_igopt_set_out_charset(sopts, NULL);
+ isoburn_igopt_set_fifo_size(sopts, xorriso->fs * 2048);
+
+ if(image!=NULL &&
+ strlen(Xorriso_program_versioN)+strlen(Xorriso_timestamP)<80) {
+ sprintf(xorriso_id, "XORRISO-%s %s",
+ Xorriso_program_versioN, Xorriso_timestamP);
+ isoburn_version(&major, &minor, µ);
+ if(strlen(xorriso_id)<80)
+ sprintf(xorriso_id+strlen(xorriso_id),
+ ", LIBISOBURN-%d.%d.%d", major, minor, micro);
+ iso_lib_version(&major, &minor, µ);
+ if(strlen(xorriso_id)<80)
+ sprintf(xorriso_id+strlen(xorriso_id),
+ ", LIBISOFS-%d.%d.%d", major, minor, micro);
+ burn_version(&major, &minor, µ);
+ if(strlen(xorriso_id)<80)
+ sprintf(xorriso_id+strlen(xorriso_id),
+ ", LIBBURN-%d.%d.%d", major, minor, micro);
+ xorriso_id[128]= 0;
+ img_id= (char *) iso_image_get_data_preparer_id(image);
+ if(img_id!=NULL) {
+ for(i= strlen(img_id)-1; i>=0 && img_id[i]==' '; i--);
+ if(i>0) {
+ sprintf(xorriso->info_text, "Overwrote previous preparer id '%s'",
+ img_id);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
+ }
+ }
+ iso_image_set_data_preparer_id(image, xorriso_id);
+ }
+
+ /* Make final abort check before starting expensive activities */
+ ret= Xorriso_eval_problem_status(xorriso, 1, 0);
+ if(ret<0)
+ {ret= 0; goto ex;}
+ Xorriso_set_abort_severity(xorriso, 1);
+ if(xorriso->out_drive_handle == xorriso->in_drive_handle ||
+ xorriso->in_drive_handle == NULL) {
+ ret= isoburn_prepare_disc(source_drive, &disc, sopts);
+ } else {
+ ret= isoburn_prepare_new_image(source_drive, &disc, sopts, drive);
+ }
+ if (ret <= 0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"Failed to prepare session write run");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ {ret= 0; goto ex;}
+ }
+
+ ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0);
+ if(ret<=0)
+ goto ex;
+
+#ifndef NIX
+
+ ret= Xorriso_sanitize_image_size(xorriso, drive, disc, burn_options, flag&1);
+ if(ret<=0 || (flag&1)) {
+ Xorriso_process_msg_queues(xorriso,0);
+ if(flag&1) /* set queue severity to FAILURE */
+ Xorriso_set_image_severities(xorriso, 2);
+ isoburn_cancel_prepared_write(source_drive, drive, 0);
+ if(flag&1) /* reset queue severity */
+ Xorriso_set_image_severities(xorriso, 0);
+ goto ex;
+ }
+
+#else
+
+ ret= img_sectors= burn_disc_get_sectors(disc);
+ if(flag&1)
+ goto ex;
+
+ sessions= burn_disc_get_sessions(disc, &num_sessions);
+ if(sessions==NULL || num_sessions < 1) {
+no_track:;
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"Program error : no track in prepared disc");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ isoburn_cancel_prepared_write(source_drive, drive, 0);
+ {ret= -1; goto ex;}
+ }
+ tracks= burn_session_get_tracks(sessions[0], &num_tracks);
+ if(tracks==NULL || num_tracks < 1)
+ goto no_track;
+
+ padding= 0;
+ ret= burn_disc_get_profile(drive, &profile, profile_name);
+ padding= xorriso->padding / 2048;
+ if(xorriso->padding > padding * 2048)
+ padding++;
+ if(profile==0x09 || profile==0x0a) { /* CD-R , CD-RW */
+ if(img_sectors + padding < Xorriso_cd_min_track_sizE) {
+ padding= Xorriso_cd_min_track_sizE - img_sectors;
+ sprintf(xorriso->info_text,
+ "Expanded track to minimum size of %d sectors",
+ Xorriso_cd_min_track_sizE);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ }
+ }
+ burn_track_define_data(tracks[0], 0, padding * 2048, 0, BURN_MODE1);
+ Xorriso_process_msg_queues(xorriso,0);
+
+ media_space= isoburn_disc_available_space(drive, burn_options) / (off_t) 2048;
+ if(media_space < img_sectors + padding) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"Image size %ds exceeds free space on media %ds",
+ img_sectors + padding, media_space);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ isoburn_cancel_prepared_write(source_drive, drive, 0);
+ {ret= 0; goto ex;}
+ }
+
+#endif /* NIX */
+
+ xorriso->run_state= 1; /* Indicate that burning has started */
+ isoburn_disc_write(burn_options, disc);
+ burn_write_opts_free(burn_options);
+
+ ret= Xorriso_pacifier_loop(xorriso, drive, 0);
+ if(ret<=0)
+ goto ex;
+ if(!isoburn_drive_wrote_well(drive)) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,
+ "libburn indicates failure with writing.");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+
+ sessions= burn_disc_get_sessions(disc, &num_sessions);
+ if(num_sessions>0) {
+ tracks= burn_session_get_tracks(sessions[0], &num_tracks);
+ if(tracks!=NULL && num_tracks>0) {
+ burn_track_get_counters(tracks[0],&readcounter,&writecounter);
+ sprintf(xorriso->info_text,
+ "ISO image produced: %d sectors. Written to media: %d sectors\n",
+ (int) (readcounter/ (off_t) 2048),
+ (int) (writecounter/ (off_t) 2048));
+ Xorriso_info(xorriso, 0);
+ }
+ }
+
+ ret= isoburn_activate_session(drive);
+ Xorriso_process_msg_queues(xorriso,0);
+ if(ret<=0) {
+ sprintf(xorriso->info_text,
+ "Could not write new set of volume descriptors");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ goto ex;
+ }
+ /* Done early to free any reference to the libisofs resources via disc */
+ if(disc!=NULL)
+ burn_disc_free(disc);
+ disc= NULL;
+ /* To wait for the end of the libisofs threads and their messages. */
+ isoburn_sync_after_write(source_drive, drive, 0);
+ Xorriso_process_msg_queues(xorriso,0);
+
+ sprintf(xorriso->info_text, "Writing completed sucessfully.\n\n");
+ Xorriso_info(xorriso, 0);
+ ret= 1;
+ex:;
+ xorriso->run_state= 0; /* Indicate that burning has ended */
+ Xorriso_set_abort_severity(xorriso, 0);
+
+ if(ret<=0) {
+ /* >>> ??? revive discarded boot image */;
+ }
+
+ if(disc!=NULL)
+ burn_disc_free(disc);
+ isoburn_igopt_destroy(&sopts, 0);
+ Xorriso_process_msg_queues(xorriso,0);
+ return(ret);
+}
+
+
+int Xorriso_check_burn_abort(struct XorrisO *xorriso, int flag)
+{
+ int ret;
+ struct burn_drive_info *dinfo;
+ struct burn_drive *drive;
+
+ if(xorriso->run_state!=1)
+ return(0);
+ ret= Xorriso_eval_problem_status(xorriso, 1, 1);
+ if(ret>=0)
+ return(0);
+ sprintf(xorriso->info_text,
+ "-abort_on '%s' encountered '%s' during image writing",
+ xorriso->abort_on_text, xorriso->problem_status_text);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0,
+ xorriso->problem_status_text, 0);
+
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to abort burn run", 2);
+ if(ret<=0)
+ return(0);
+
+ burn_drive_cancel(drive);
+ sprintf(xorriso->info_text,
+ "libburn has now been urged to cancel its operation");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ return(1);
+}
+
+
+/* This loop watches burn runs until they end.
+ It issues pacifying update messages to the user.
+ @param flag bit0-3 = emulation mode
+ 0= xorriso
+ 1= cdrskin
+ bit4= report speed in CD units
+*/
+int Xorriso_pacifier_loop(struct XorrisO *xorriso, struct burn_drive *drive,
+ int flag)
+{
+ int ret, size, free_bytes, i, aborting= 0, emul, buffer_fill= 50, last_sector;
+ struct burn_progress progress;
+ char *status_text;
+ enum burn_drive_status drive_status;
+ double start_time, current_time, last_time;
+ double measured_speed, speed_factor= 1385000;
+
+ start_time= Sfile_microtime(0);
+ while(burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
+ usleep(100002);
+
+ emul= flag&15;
+ if(flag&16)
+ speed_factor= 150.0*1024;
+ progress.sector= 0;
+ current_time= Sfile_microtime(0);
+ while(1) {
+ last_time= current_time;
+ last_sector= progress.sector;
+ drive_status= burn_drive_get_status(drive, &progress);
+ if(drive_status == BURN_DRIVE_IDLE)
+ break;
+ current_time= Sfile_microtime(0);
+ if(drive_status == BURN_DRIVE_WRITING && progress.sectors > 0) {
+ if(emul==1) {
+ if(progress.sector<=progress.sectors)
+ sprintf(xorriso->info_text, "%4d of %4d MB written",
+ progress.sector / 512, progress.sectors / 512);
+ else
+ sprintf(xorriso->info_text, "%4d MB written",
+ progress.sector / 512);
+
+ if(xorriso->pacifier_fifo!=NULL) {
+ ret= burn_fifo_inquire_status(xorriso->pacifier_fifo,
+ &size, &free_bytes, &status_text);
+ if(ret>0 )
+ sprintf(xorriso->info_text+strlen(xorriso->info_text),
+ " (fifo %2d%%)",
+ (int) (100.0-100.0*((double) free_bytes)/(double) size));
+ }
+
+ buffer_fill= 50;
+ if(progress.buffer_capacity>0)
+ buffer_fill= (double) (progress.buffer_capacity
+ - progress.buffer_available) * 100.0
+ / (double) progress.buffer_capacity;
+ sprintf(xorriso->info_text+strlen(xorriso->info_text), " [buf %3d%%]",
+ buffer_fill);
+
+ if(current_time-last_time>0.2) {
+ measured_speed= (progress.sector - last_sector) * 2048.0 /
+ (current_time - last_time);
+ sprintf(xorriso->info_text+strlen(xorriso->info_text), " %4.1fx.",
+ measured_speed/speed_factor);
+ }
+
+ } else {
+ if(progress.sector<=progress.sectors)
+ sprintf(xorriso->info_text, "Writing: sector %d of %d",
+ progress.sector, progress.sectors);
+ else
+ sprintf(xorriso->info_text, "Writing: sector %d", progress.sector);
+ ret= isoburn_get_fifo_status(drive, &size, &free_bytes, &status_text);
+ if(ret>0 )
+ sprintf(xorriso->info_text+strlen(xorriso->info_text),
+ " [fifo %s, %2d%% fill]", status_text,
+ (int) (100.0-100.0*((double) free_bytes)/(double) size));
+ }
+ } else if(drive_status == BURN_DRIVE_CLOSING_SESSION ||
+ drive_status == BURN_DRIVE_CLOSING_TRACK)
+ sprintf(xorriso->info_text,
+ "Closing track/session. Working since %.f seconds",
+ current_time-start_time);
+ else if(drive_status == BURN_DRIVE_FORMATTING)
+ sprintf(xorriso->info_text, "Formatting. Working since %.f seconds",
+ current_time-start_time);
+ else
+ sprintf(xorriso->info_text,
+ "Thank you for being patient since %.f seconds",
+ current_time-start_time);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0);
+
+ for(i= 0; i<10; i++) {
+ Xorriso_process_msg_queues(xorriso, 0);
+ if(aborting<=0)
+ aborting= Xorriso_check_burn_abort(xorriso, 0);
+ usleep(100000);
+ }
+ }
+ return(1);
+}
+
+
+int Xorriso__read_pacifier(IsoImage *image, IsoFileSource *filesource)
+{
+ struct XorrisO *xorriso;
+
+ xorriso= (struct XorrisO *) iso_image_get_attached_data(image);
+ if(xorriso==NULL)
+ return(1);
+ xorriso->pacifier_count++;
+ if(xorriso->pacifier_count%10)
+ return(1);
+ Xorriso_pacifier_callback(xorriso, "nodes read", xorriso->pacifier_count, 0,
+ "", 0);
+ return(1);
+}
+
+
+int Xorriso_get_volume(struct XorrisO *xorriso, IsoImage **volume,
+ int flag)
+{
+ if(xorriso->in_volset_handle==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"No ISO image present.");
+ if(xorriso->indev[0]==0 && xorriso->outdev[0]==0)
+ sprintf(xorriso->info_text+strlen(xorriso->info_text),
+ " No -dev, -indev, or -outdev selected.");
+ else
+ sprintf(xorriso->info_text+strlen(xorriso->info_text),
+ " Possible program error with drive '%s'.", xorriso->indev);
+
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+ *volume= (IsoImage *) xorriso->in_volset_handle;
+ return(*volume != NULL);
+}
+
+
+/* @param flag bit0=do not complain about non existent node */
+int Xorriso_node_from_path(struct XorrisO *xorriso, IsoImage *volume,
+ char *path, IsoNode **node, int flag)
+{
+ int ret;
+ char sfe[5*SfileadrL], *path_pt;
+
+ path_pt= path;
+ if(path[0]==0)
+ path_pt= "/";
+ *node= NULL;
+ ret= iso_tree_path_to_node(volume, path_pt, node);
+ Xorriso_process_msg_queues(xorriso,0);
+ if(ret<=0) {
+ if(!(flag&1)) {
+ sprintf(xorriso->info_text, "Cannot find path %s in loaded ISO image",
+ Text_shellsafe(path_pt, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ }
+ return(0);
+ }
+ return(1);
+}
+
+
+/* @param eff_path returns resulting effective path.
+ Must provide at least SfileadrL bytes of storage.
+ @param flag bit0= do not produce problem events (unless faulty path format)
+ bit1= work purely literally, do not use libisofs
+ bit2= (with bit1) this is an address in the disk world
+ @return -1 = faulty path format, 0 = not found ,
+ 1 = found simple node , 2 = found directory
+*/
+int Xorriso_normalize_img_path(struct XorrisO *xorriso, char *wd,
+ char *img_path, char eff_path[], int flag)
+{
+ int ret, is_dir= 0, done= 0;
+ IsoImage *volume;
+ IsoDir *dir= NULL;
+ IsoNode *node= NULL;
+ char path[SfileadrL], *apt, *npt, sfe[5*SfileadrL], *cpt;
+
+ eff_path[0]= 0;
+ if(img_path[0]==0)
+ return(2); /* root directory */
+
+ if(!(flag&2)) {
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+ }
+
+ apt= npt= path;
+ if(img_path[0]!='/') {
+ strcpy(path, wd);
+ ret= Sfile_add_to_path(path, img_path, 0);
+ if(ret<=0)
+ goto much_too_long;
+ } else
+ if(Sfile_str(path, img_path, 0)<=0)
+ return(-1);
+
+ if(path[0]!='/') {
+ sprintf(xorriso->info_text,
+ "Internal error: Unresolvable relative addressing in iso_rr_path '%s'",
+ img_path);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FATAL", 0);
+ return(-1);
+ } else if(path[1]==0)
+ return(2); /* root directory */
+
+ for(npt= apt; !done; apt= npt+1) {
+ npt= strchr(apt, '/');
+ if(npt==NULL) {
+ npt= apt+strlen(apt);
+ done= 1;
+ } else
+ *npt= 0;
+ if(*apt==0) {
+ *apt= '/';
+ apt++;
+ if(done)
+ break;
+ continue;
+ }
+ if(strcmp(apt,".")==0) {
+ is_dir= 1;
+ continue;
+ }
+ if(strcmp(apt,"..")==0) {
+ if(!(flag&2)) {
+ node= (IsoNode *) dir;
+ if(node==NULL) {
+bonked_root:;
+ sprintf(xorriso->info_text,
+ "Relative addressing in path exceeds root directory: %s",
+ Text_shellsafe(img_path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(-1);
+ }
+ dir= iso_node_get_parent(node);
+ }
+ /* truncate eff_path */;
+ cpt= strrchr(eff_path, '/');
+ if(cpt==NULL) /* ??? if not flag&2 then this is a bug */
+ goto bonked_root;
+ *cpt= 0;
+ is_dir= 1;
+ continue;
+ }
+ ret= Sfile_add_to_path(eff_path, apt, 0);
+ if(ret<=0) {
+much_too_long:;
+ sprintf(xorriso->info_text, "Effective path gets much too long (%d)",
+ (int) (strlen(eff_path)+strlen(apt)+1));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(-1);
+ }
+ if(!(flag&2)) {
+ dir= (IsoDir *) node;
+ ret= Xorriso_node_from_path(xorriso, volume, eff_path, &node, flag&1);
+ if(ret<=0)
+ return(0);
+ if(dir==NULL) /* could be false with "/dir/.." */
+ dir= iso_node_get_parent(node);
+ is_dir= LIBISO_ISDIR(node);
+ }
+ }
+ return(1+!!is_dir);
+}
+
+
+int Xorriso_get_node_by_path(struct XorrisO *xorriso,
+ char *in_path, char *eff_path,
+ IsoNode **node, int flag)
+{
+ int ret;
+ char path[SfileadrL];
+ IsoImage *volume;
+
+ ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, in_path, path, 0);
+ if(ret<=0)
+ return(ret);
+ if(eff_path!=NULL)
+ strcpy(eff_path, path);
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+ ret= Xorriso_node_from_path(xorriso, volume, path, node, 0);
+ if(ret<=0)
+ return(0);
+ return(1);
+}
+
+
+int Xorriso_transfer_properties(struct XorrisO *xorriso, struct stat *stbuf,
+ IsoNode *node, int flag)
+{
+ iso_node_set_permissions(node, stbuf->st_mode & 07777);
+ iso_node_set_uid(node, stbuf->st_uid);
+ iso_node_set_gid(node, stbuf->st_gid);
+ iso_node_set_atime(node, stbuf->st_atime);
+ iso_node_set_mtime(node, stbuf->st_mtime);
+ iso_node_set_ctime(node, stbuf->st_ctime);
+ return(1);
+}
+
+
+/* Ticket 132 : Workaround for missing feature iso_tree_add_new_node() */
+int Xorriso_tree_graft_node(struct XorrisO *xorriso, IsoImage *volume,
+ IsoDir *dir, char *disk_path, char *img_name,
+ char *nominal_source, char *nominal_target,
+ IsoNode **node, int flag)
+{
+ int ret;
+
+#ifdef Xorriso_workaround_ticket_132
+
+ int wa_ret, i;
+ char wa_name[256];
+ IsoDir *hdir;
+
+ ret= iso_tree_add_node(volume, dir, disk_path, node);
+ if(ret==ISO_NODE_NAME_NOT_UNIQUE) {
+ wa_ret= ISO_NODE_NAME_NOT_UNIQUE;
+ for(i= 0; wa_ret==ISO_NODE_NAME_NOT_UNIQUE && i<2000000000; i++) {
+ sprintf(wa_name, "xorriso_works_around_what_is_not_a_bug_try_%d", i);
+ wa_ret= iso_tree_add_new_dir(dir, wa_name, &hdir);
+ }
+ if(wa_ret<0)
+ goto cannot_add;
+ ret= iso_tree_add_node(volume, hdir, disk_path, node);
+ if(ret>0) {
+ ret= iso_node_set_name(*node, img_name);
+ if(ret<0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_report_iso_error(xorriso, nominal_target, 0,
+ "Cannot set name", 0, "FAILURE", 1);
+ return(ret);
+ }
+ iso_node_take(*node);
+ ret= iso_dir_add_node(dir, *node, 0);
+ }
+ iso_node_remove((IsoNode *) hdir);
+ }
+
+#else /* Xorriso_workaround_ticket_132 */
+
+ ret= iso_tree_add_new_node(volume, dir, img_name, disk_path, node);
+
+#endif /* Xorriso_workaround_ticket_132 */
+
+ if(ret<0) {
+
+#ifdef Xorriso_workaround_ticket_132
+cannot_add:;
+#endif /* Xorriso_workaround_ticket_132 */
+
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_report_iso_error(xorriso, nominal_source, ret,
+ "Cannot add node to tree", 0, "FAILURE", 1|2);
+ return(ret);
+ }
+ return(1);
+}
+
+
+/* @param flag bit0= recursion is active
+ bit1= do not report added files
+*/
+int Xorriso_add_tree(struct XorrisO *xorriso, IsoDir *dir,
+ char *img_dir_path, char *disk_dir_path,
+ struct LinkiteM *link_stack, int flag)
+{
+ IsoImage *volume;
+ IsoNode *node;
+ IsoSymlink *iso_symlink;
+ int ret, target_is_dir, source_is_dir, source_is_link, fret, was_failure= 0;
+ int do_not_dive;
+ struct DirseQ *dirseq= NULL;
+ char *name, *img_name, *srcpt, *stbuf_src= "";
+ struct stat stbuf, hstbuf;
+ dev_t dir_dev;
+ struct LinkiteM *own_link_stack;
+
+#ifdef Xorriso_fat_local_meM
+ char sfe[5*SfileadrL], sfe2[5*SfileadrL];
+ char disk_path[2*SfileadrL], img_path[2*SfileadrL], link_target[SfileadrL];
+#else /* Xorriso_fat_local_meM */
+
+ char *sfe= NULL, *sfe2= NULL;
+ char *disk_path= NULL, *img_path= NULL, *link_target= NULL;
+
+ /* Avoiding large local memory objects in order to save stack space */
+ sfe= malloc(5*SfileadrL);
+ sfe2= malloc(5*SfileadrL);
+ disk_path= malloc(2*SfileadrL);
+ img_path= malloc(2*SfileadrL);
+ link_target= malloc(SfileadrL);
+ if(sfe==NULL || sfe2==NULL || disk_path==NULL || img_path==NULL ||
+ link_target==NULL) {
+ Xorriso_no_malloc_memory(xorriso, &sfe, 0);
+ {ret= -1; goto ex;}
+ }
+
+#endif /* ! Xorriso_fat_local_meM */
+
+ own_link_stack= link_stack;
+
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ goto ex;
+
+ stbuf_src= disk_dir_path;
+ if(lstat(disk_dir_path, &stbuf)==-1)
+ goto cannot_open_dir;
+ dir_dev= stbuf.st_dev;
+ if(S_ISLNK(stbuf.st_mode)) {
+ if(!(xorriso->do_follow_links || (xorriso->do_follow_param && !(flag&1))))
+ {ret= 2; goto ex;}
+ stbuf_src= disk_dir_path;
+ if(stat(disk_dir_path, &stbuf)==-1)
+ goto cannot_open_dir;
+ if(dir_dev != stbuf.st_dev &&
+ !(xorriso->do_follow_mount || (xorriso->do_follow_param && !(flag&1))))
+ {ret= 2; goto ex;}
+ }
+ ret= Dirseq_new(&dirseq, disk_dir_path, 1);
+ if(ret<0) {
+ sprintf(xorriso->info_text,"Failed to create source filesystem iterator");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ {ret= -1; goto ex;}
+ }
+ if(ret==0) {
+cannot_open_dir:;
+ Xorriso_msgs_submit(xorriso, 0, disk_dir_path, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text,"Cannot open as source directory: %s",
+ Text_shellsafe(disk_dir_path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ {ret= 0; goto ex;}
+ }
+
+ if(Sfile_str(disk_path, disk_dir_path,0)<=0)
+ {ret= -1; goto ex;}
+ if(disk_path[0]==0 || disk_path[strlen(disk_path)-1]!='/')
+ strcat(disk_path,"/");
+ name= disk_path+strlen(disk_path);
+ if(Sfile_str(img_path, img_dir_path, 0)<=0)
+ {ret= -1; goto ex;}
+ if(img_path[0] || img_path[strlen(img_path)-1]!='/')
+ strcat(img_path,"/");
+ img_name= img_path+strlen(img_path);
+
+ while(1) { /* loop over directory content */
+ stbuf_src= "";
+ Linkitem_reset_stack(&own_link_stack, link_stack, 0);
+ srcpt= disk_path;
+ Xorriso_process_msg_queues(xorriso,0);
+ ret= Dirseq_next_adr(dirseq,name,0);
+ if(ret==0)
+ break;
+ if(ret<0) {
+ sprintf(xorriso->info_text,"Failed to obtain next directory entry");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ {ret= -1; goto ex;}
+ }
+ strcpy(img_name, name);
+ if(Xorriso_much_too_long(xorriso, strlen(img_path), 0)<=0)
+ {ret= 0; goto was_problem;}
+ if(Xorriso_much_too_long(xorriso, strlen(srcpt), 0)<=0)
+ {ret= 0; goto was_problem;}
+ stbuf_src= srcpt;
+ if(lstat(srcpt, &stbuf)==-1) {
+cannot_lstat:;
+ Xorriso_msgs_submit(xorriso, 0, srcpt, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text,
+ "Cannot determine attributes of source file %s",
+ Text_shellsafe(srcpt, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
+ ret= 0; goto was_problem;
+ }
+ source_is_dir= 0;
+ source_is_link= S_ISLNK(stbuf.st_mode);
+ if(xorriso->do_follow_links && source_is_link) {
+ /* Xorriso_hop_link checks for wide link loops */
+ ret= Xorriso_hop_link(xorriso, srcpt, &own_link_stack, &hstbuf, 0);
+ if(ret<0)
+ goto was_problem;
+ if(ret==1) {
+ ret= Xorriso_resolve_link(xorriso, srcpt, link_target, 0);
+ if(ret<=0)
+ goto was_problem;
+ srcpt= link_target;
+ stbuf_src= srcpt;
+ if(lstat(srcpt, &stbuf)==-1)
+ goto cannot_lstat;
+ } else {
+ if(Xorriso_eval_problem_status(xorriso, 0, 1|2)<0)
+ {ret= 0; goto was_problem;}
+ }
+ } else if (S_ISLNK(stbuf.st_mode)) {
+ ret= Xorriso_resolve_link(xorriso, srcpt, link_target, 1);
+ if(ret<=0)
+ goto was_problem;
+ }
+ do_not_dive= 0;
+ if(S_ISDIR(stbuf.st_mode)) {
+ source_is_dir= 1;
+ if(dir_dev != stbuf.st_dev && !xorriso->do_follow_mount)
+ do_not_dive= 1;
+ }
+
+ /* does a node exist with this name ? */
+ node= NULL;
+ ret= Xorriso_node_from_path(xorriso, volume, img_path, &node, 1);
+ if(ret>0) {
+ target_is_dir= LIBISO_ISDIR(node);
+ if(!(target_is_dir && source_is_dir)) {
+ Xorriso_process_msg_queues(xorriso,0);
+
+ /* handle overwrite situation */;
+ if(xorriso->do_overwrite==1 ||
+ (xorriso->do_overwrite==2 && !target_is_dir)) {
+ ret= Xorriso_rmi(xorriso, NULL, (off_t) 0, img_path, 1|8);
+ if(ret<=0)
+ goto was_problem;
+ if(ret==3) {
+ sprintf(xorriso->info_text, "User revoked adding of: %s",
+ Text_shellsafe(img_path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ ret= 0; goto was_problem;
+ }
+ node= NULL;
+ } else {
+ Xorriso_msgs_submit(xorriso, 0, srcpt, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text,
+ "While grafting %s : file object exists and may not be overwritten by %s",
+ Text_shellsafe(img_path,sfe,0), Text_shellsafe(stbuf_src,sfe2,0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto was_problem;
+ }
+ }
+ }
+
+ if(node==NULL) {
+ if(S_ISLNK(stbuf.st_mode)) {
+
+ /* ??? NG : A80107 : is this solved now ? */
+ /* <<< One should rather change libisofs so that iso_tree_add_node()
+ adds a disk_link as RR link, if RR is enabled */
+
+ ret= iso_tree_add_new_symlink(dir, img_name, link_target, &iso_symlink);
+ node= (IsoNode *) iso_symlink;
+ if(ret>0) {
+ ret= Xorriso_transfer_properties(xorriso, &stbuf, node, 0);
+ if(ret<=0)
+ goto was_problem;
+ } else {
+ Xorriso_report_iso_error(xorriso, stbuf_src, ret,
+ "Cannot create symbolic link", 0, "FAILURE", 1|2);
+ {ret= 0; goto was_problem;}
+ }
+ } else {
+#ifdef NIX
+ ret= iso_tree_add_node(volume, dir, srcpt, &node);
+ if(ret<0) {
+ Xorriso_report_iso_error(xorriso, stbuf_src, ret,
+ "Cannot add node to tree", 0, "FAILURE", 1|2);
+ goto was_problem;
+ }
+#else
+ ret= Xorriso_tree_graft_node(xorriso, volume, dir, srcpt, img_name,
+ stbuf_src, img_path,
+ &node, 0);
+#endif
+ }
+ }
+ if(node==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_msgs_submit(xorriso, 0, stbuf_src, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text, "Grafting failed: %s = %s",
+ Text_shellsafe(img_path,sfe,0), Text_shellsafe(stbuf_src,sfe2,0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret=0; goto was_problem;
+ }
+
+ xorriso->pacifier_count++;
+ if((xorriso->pacifier_count%100)==0)
+ Xorriso_pacifier_callback(xorriso, "files added", xorriso->pacifier_count,
+ xorriso->pacifier_total, "", 0);
+
+ xorriso->volset_change_pending= 1;
+ if(source_is_dir) {
+ if(do_not_dive) {
+ sprintf(xorriso->info_text, "Did not follow mount point : %s",
+ Text_shellsafe(disk_path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ } else {
+ ret= Xorriso_add_tree(xorriso, (IsoDir *) node,
+ img_path, disk_path, own_link_stack, 1|(flag&2));
+ }
+ if(ret<=0)
+ goto was_problem;
+ }
+
+ continue; /* regular bottom of loop */
+was_problem:;
+ was_failure= 1;
+ fret= Xorriso_eval_problem_status(xorriso, ret, 1|2);
+ if(fret<0)
+ goto ex;
+ }
+
+ ret= 1;
+ex:
+
+#ifndef Xorriso_fat_local_meM
+ if(sfe!=NULL)
+ free(sfe);
+ if(sfe2!=NULL)
+ free(sfe2);
+ if(disk_path!=NULL)
+ free(disk_path);
+ if(img_path!=NULL)
+ free(img_path);
+ if(link_target!=NULL)
+ free(link_target);
+#endif /* ! Xorriso_fat_local_meM */
+
+ Xorriso_process_msg_queues(xorriso,0);
+ Linkitem_reset_stack(&own_link_stack, link_stack, 0);
+ Dirseq_destroy(&dirseq, 0);
+ if(ret<=0)
+ return(ret);
+ return(!was_failure);
+}
+
+
+int Xorriso_copy_implict_properties(struct XorrisO *xorriso, IsoDir *dir,
+ char *full_img_path, char *img_path, char *full_disk_path, int flag)
+{
+ int ret, nfic, nic, nfdc, d, i;
+ char nfi[SfileadrL], ni[SfileadrL], nfd[SfileadrL], *cpt;
+ char sfe[5*SfileadrL];
+ struct stat stbuf;
+
+ ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, full_img_path, nfi,
+ 1|2);
+ if(ret<=0)
+ return(ret);
+ ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, img_path, ni, 1|2);
+ if(ret<=0)
+ return(ret);
+ ret= Xorriso_normalize_img_path(xorriso, xorriso->wdx, full_disk_path, nfd,
+ 1|2|4);
+ if(ret<=0)
+ return(ret);
+ nfic= Sfile_count_components(nfi, 0);
+ nic= Sfile_count_components(ni, 0);
+ nfdc= Sfile_count_components(nfd, 0);
+ d= nfic-nic;
+ if(d<0)
+ return(-1);
+ if(d>nfdc)
+ return(0);
+ for(i= 0; iinfo_text,
+ "Copied properties for %s", Text_shellsafe(ni, sfe, 0));
+ sprintf(xorriso->info_text+strlen(xorriso->info_text),
+ " from %s", Text_shellsafe(nfd, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
+ return(1);
+}
+
+
+/* @param bit0= copy link target properties rather than link properties
+*/
+int Xorriso_copy_properties(struct XorrisO *xorriso,
+ char *disk_path, char *img_path, int flag)
+{
+ int ret;
+ IsoNode *node;
+ struct stat stbuf;
+
+ ret= Xorriso_get_node_by_path(xorriso, img_path, NULL, &node, 0);
+ if(ret<=0)
+ return(ret);
+ if(lstat(disk_path, &stbuf)==-1)
+ return(0);
+ Xorriso_transfer_properties(xorriso, &stbuf, node, 0);
+ xorriso->volset_change_pending= 1;
+ return(1);
+}
+
+
+/* @param boss_iter Opaque handle to be forwarded to actions in ISO image
+ Set to NULL if calling this function from outside ISO world
+ @param flag bit0= mkdir: graft in as empty directory, not as copy from disk
+ bit1= do not report added files
+ bit2= -follow: this is not a command parameter
+ @return <=0 = error , 1 = added simple node , 2 = added directory
+*/
+int Xorriso_graft_in(struct XorrisO *xorriso, void *boss_iter,
+ char *disk_path, char *img_path, int flag)
+{
+ IsoImage *volume;
+ char path[SfileadrL], *apt, *npt, *cpt, sfe[5*SfileadrL], sfe2[5*SfileadrL];
+ char *disk_path_pt, resolved_disk_path[SfileadrL];
+ IsoDir *dir, *hdir;
+ IsoNode *node;
+ int done= 0, is_dir= 0, l, ret, target_is_dir, source_is_dir, resolve_link= 0;
+ struct stat stbuf;
+
+ for(cpt= img_path; 1; cpt++) {
+/*
+ if(cpt[0]!='/')
+ break;
+*/
+ cpt= strstr(cpt,"/.");
+ if(cpt==NULL)
+ break;
+ if(cpt[2]=='.') {
+ if(cpt[3]=='/' || cpt[3]==0)
+ break;
+ } else if(cpt[2]=='/' || cpt[2]==0)
+ break;
+ }
+ if(cpt!=NULL) {
+ Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text,
+ "Unsupported relative addressing in iso_rr_path %s (disk: %s)",
+ Text_shellsafe(img_path, sfe, 0), Text_shellsafe(disk_path, sfe2, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
+ return(0);
+ }
+
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+
+ strncpy(path, img_path, sizeof(path)-1);
+ path[sizeof(path)-1]= 0;
+ apt= npt= path;
+
+ if(!(flag&1)) {
+ ret= lstat(disk_path, &stbuf);
+ if(ret!=-1) {
+ if(S_ISDIR(stbuf.st_mode))
+ is_dir= 1;
+ else if((stbuf.st_mode&S_IFMT)==S_IFLNK &&
+ (xorriso->do_follow_links ||
+ (xorriso->do_follow_param && !(flag&4)))) {
+ resolve_link= 1;
+ ret= stat(disk_path, &stbuf);
+ if(ret!=-1) {
+ if(S_ISDIR(stbuf.st_mode))
+ is_dir= 1;
+ }
+ }
+ }
+ if(ret == -1) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text,
+ "Cannot determine attributes of source file %s",
+ Text_shellsafe(disk_path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
+ return(0);
+ }
+ if(S_ISDIR(stbuf.st_mode)) {
+ is_dir= 1;
+
+#ifdef NIX
+ } else if(!(S_ISREG(stbuf.st_mode) || S_ISLNK(stbuf.st_mode))) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text,
+ "Source file '%s' is of non-supported file type", disk_path);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+#endif /* NIX */
+
+ } else {
+ l= strlen(img_path);
+ if(l>0)
+ if(img_path[l-1]=='/')
+ l= 0;
+ if(l==0) {
+ Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text,
+ "Source '%s' is not a directory. Target '%s' would be.",
+ Text_shellsafe(disk_path, sfe, 0), Text_shellsafe(img_path, sfe2, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+ }
+ }
+
+ dir= iso_image_get_root(volume);
+ if(dir==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,
+ "While grafting '%s' : no root node available", img_path);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(0);
+ }
+ for(npt= apt; !done; apt= npt+1) {
+ npt= strchr(apt, '/');
+ if(npt==NULL) {
+ npt= apt+strlen(apt);
+ done= 1;
+ } else
+ *npt= 0;
+ if(*apt==0) {
+ *apt= '/';
+ apt++;
+ if(done)
+ goto attach_source;
+ continue;
+ }
+ source_is_dir= (is_dir || (flag&1) || !done);
+ ret= Xorriso_node_from_path(xorriso, volume, path, &node, 1);
+ if(ret>0) {
+ target_is_dir= LIBISO_ISDIR(node);
+ if(!(target_is_dir && source_is_dir)) {
+ Xorriso_process_msg_queues(xorriso,0);
+
+ /* handle overwrite situation */;
+ if(xorriso->do_overwrite==1 ||
+ (xorriso->do_overwrite==2 && !target_is_dir)) {
+ ret= Xorriso_rmi(xorriso, boss_iter, (off_t) 0, path, 1|8);
+ if(ret<=0)
+ return(ret);
+ if(ret==3) {
+ sprintf(xorriso->info_text, "User revoked adding of: %s",
+ Text_shellsafe(disk_path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ return(0);
+ }
+ node= NULL;
+ goto handle_path_node;
+ }
+
+ Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text,
+ "While grafting '%s' : '%s' exists and may not be overwritten",
+ img_path, path);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+ dir= (IsoDir *) node;
+ }
+
+handle_path_node:;
+ if(node==NULL && source_is_dir) { /* make a directory */
+ ret= iso_tree_add_new_dir(dir, apt, &hdir);
+ if(ret<0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
+ Xorriso_report_iso_error(xorriso, img_path, ret,
+ "Cannot create directory", 0, "FAILURE", 1);
+ sprintf(xorriso->info_text,
+ "While grafting '%s' : could not insert '%s'", img_path, path);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+ dir= hdir;
+ xorriso->volset_change_pending= 1;
+ iso_node_set_ctime((IsoNode *) dir, time(NULL));
+ iso_node_set_uid((IsoNode *) dir, geteuid());
+ iso_node_set_gid((IsoNode *) dir, getegid());
+
+ if(disk_path!=NULL && !done)
+ Xorriso_copy_implict_properties(xorriso, dir, img_path, path, disk_path,
+ 0);
+
+ }
+ if(done) {
+attach_source:;
+ xorriso->pacifier_count++;
+ if(xorriso->pacifier_count%100 && !(flag&2))
+ Xorriso_pacifier_callback(xorriso, "files added",
+ xorriso->pacifier_count,
+ xorriso->pacifier_total, "", 0);
+ if(flag&1) {
+ /* directory node was created above */;
+
+ } else if(is_dir) {
+ Xorriso_transfer_properties(xorriso, &stbuf, (IsoNode *) dir, 0);
+ ret= Xorriso_add_tree(xorriso, dir, img_path, disk_path, NULL, flag&2);
+ if(ret<=0)
+ return(ret);
+
+ } else {
+ if(resolve_link) {
+ ret= Xorriso_resolve_link(xorriso, disk_path, resolved_disk_path, 0);
+ if(ret<=0)
+ return(ret);
+ disk_path_pt= resolved_disk_path;
+ } else
+ disk_path_pt= disk_path;
+
+#ifdef NIX
+ ret= iso_tree_add_node(volume, dir, disk_path_pt, &node);
+ if(ret<0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
+ Xorriso_report_iso_error(xorriso, img_path, ret, "Cannot create node",
+ 0, "FAILURE", 1);
+ sprintf(xorriso->info_text, "Grafting failed: %s = %s",
+ Text_shellsafe(img_path,sfe,0), Text_shellsafe(disk_path,sfe2,0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+#else
+ ret= Xorriso_tree_graft_node(xorriso, volume, dir, disk_path_pt, apt,
+ disk_path, img_path, &node, 0);
+ if(ret<0) {
+ Xorriso_msgs_submit(xorriso, 0, disk_path, 0, "ERRFILE", 0);
+ sprintf(xorriso->info_text, "Grafting failed: %s = %s",
+ Text_shellsafe(img_path,sfe,0), Text_shellsafe(disk_path,sfe2,0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+#endif
+ xorriso->volset_change_pending= 1;
+ iso_node_set_name(node, apt);
+ }
+ } else
+ *npt= '/';
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1+!!is_dir);
+}
+
+
+int Xorriso_process_msg_queues(struct XorrisO *xorriso, int flag)
+{
+ int ret, error_code= 0, os_errno= 0, count= 0, pass, imgid, tunneled;
+ char severity[80];
+
+ if(!xorriso->libs_are_started)
+ return(1);
+ for(pass= 0; pass< 2; pass++) {
+ while(1) {
+ tunneled= 0;
+ if(pass==0)
+ ret= iso_obtain_msgs("ALL", &error_code, &imgid,
+ xorriso->info_text, severity);
+ else {
+ ret= burn_msgs_obtain("ALL", &error_code, xorriso->info_text, &os_errno,
+ severity);
+ if((error_code>=0x00030000 && error_code<0x00040000) ||
+ (error_code>=0x00050000 && error_code<0x00060000))
+ tunneled= -1; /* "libisofs:" */
+ else if(error_code>=0x00060000 && error_code<0x00070000)
+ tunneled= 1; /* "libisoburn:" */
+ }
+ if(ret<=0)
+ break;
+
+ /* <<< tunneled MISHAP from libisoburn through libburn
+ or well known error codes of MISHAP events
+ With libburn-0.4.4 this is not necessary */
+ if(error_code==0x5ff73 || error_code==0x3ff73 ||
+ error_code==0x3feb9 || error_code==0x3feb2)
+ strcpy(severity, "MISHAP");
+ else if(error_code==0x51001)
+ strcpy(severity, "ERRFILE");
+
+ Xorriso_msgs_submit(xorriso, error_code, xorriso->info_text, os_errno,
+ severity, ((pass+tunneled)+1)<<2);
+ count++;
+ }
+ }
+ if(xorriso->library_msg_direct_print && count>0) {
+ sprintf(xorriso->info_text," (%d library messages repeated by xorriso)\n",
+ count);
+ Xorriso_info(xorriso, 0);
+ }
+ return(1);
+}
+
+
+/* @param flag bit0=short report form
+ bit1=report about output drive
+*/
+int Xorriso_toc(struct XorrisO *xorriso, int flag)
+{
+ int num_sessions= 0, num_tracks= 0, lba= 0, nwa= -1, pmin, psec, pframe, ret;
+ int track_count= 0, session_no, track_no, profile_no= -1;
+ int last_track_start= 0, last_track_size= -1, num_data= 0, is_data= 0;
+ int is_inout_drive= 0, drive_role;
+ char profile_name[80],*respt,*devadr;
+ struct burn_disc *disc= NULL;
+ struct burn_session **sessions;
+ struct burn_track **tracks;
+ struct burn_toc_entry toc_entry;
+ struct burn_drive_info *dinfo;
+ struct burn_drive *drive;
+ enum burn_disc_status s;
+ char mem_text[80];
+
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to print Table Of Content", flag&2);
+ if(ret<=0)
+ return(0);
+
+ respt= xorriso->result_line;
+
+ if(strcmp(xorriso->indev, xorriso->outdev)==0)
+ is_inout_drive= 1;
+ if(flag&2)
+ devadr= xorriso->outdev;
+ else
+ devadr= xorriso->indev;
+ sprintf(respt, "Drive current: %s '%s'\n",
+ (is_inout_drive ? "-dev" : (flag&2 ? "-outdev" : "-indev")),
+ devadr);
+ Xorriso_result(xorriso,0);
+ sprintf(respt, "Drive type : vendor '%s' product '%s' revision '%s'\n",
+ dinfo[0].vendor, dinfo[0].product, dinfo[0].revision);
+ if(!(flag&1))
+ Xorriso_result(xorriso,0);
+
+ sprintf(respt, "Media current: ");
+ ret= burn_disc_get_profile(drive, &profile_no, profile_name);
+ if (profile_no > 0 && ret > 0) {
+ if (profile_name[0])
+ sprintf(respt+strlen(respt), "%s", profile_name);
+ else
+ sprintf(respt+strlen(respt), "%4.4Xh", profile_no);
+ drive_role= burn_drive_get_drive_role(drive);
+ if(drive_role==2)
+ sprintf(respt+strlen(respt), ", overwriteable");
+ else if(drive_role==0 || drive_role==3)
+ sprintf(respt+strlen(respt), ", sequential");
+ strcat(respt, "\n");
+ } else
+ sprintf(respt+strlen(respt), "is not recognizable\n");
+ Xorriso_result(xorriso,0);
+
+ sprintf(respt, "Media status : ");
+ s= isoburn_disc_get_status(drive);
+ if (s == BURN_DISC_FULL) {
+ sprintf(respt+strlen(respt), "is written , is closed\n");
+ } else if (s == BURN_DISC_APPENDABLE) {
+ sprintf(respt+strlen(respt), "is written , is appendable\n");
+ } else if (s == BURN_DISC_BLANK) {
+ sprintf(respt+strlen(respt), "is blank\n");
+ } else if (s == BURN_DISC_EMPTY)
+ sprintf(respt+strlen(respt), "is not present\n");
+ else
+ sprintf(respt+strlen(respt), "is not recognizable\n");
+ Xorriso_result(xorriso,0);
+
+ if(s != BURN_DISC_FULL && s != BURN_DISC_APPENDABLE)
+ return(1);
+
+ if(xorriso->request_to_abort)
+ return(1);
+
+ disc= burn_drive_get_disc(drive);
+ if (disc==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+
+#define Xorriso_with_isoburn_get_min_start_bytE 1
+#ifdef Xorriso_with_isoburn_get_min_start_bytE
+ { off_t start_byte= 0;
+ ret= isoburn_get_min_start_byte(drive, &start_byte, 0);
+ nwa= start_byte / 2048;
+ }
+#else
+ ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
+#endif
+
+ if(ret<=0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ if(flag&1)
+ return(0);
+ sprintf(xorriso->info_text, "Cannot obtain Table Of Content");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
+ return(0);
+ }
+ /* fabricate TOC */
+ sprintf(respt, "Media content: session %2d ", 1);
+ sprintf(respt+strlen(respt), "track %2d %s lba: %9d\n", 1, "data ", 0);
+ if(!(flag&1))
+ Xorriso_result(xorriso,0);
+ last_track_start= lba;
+ sprintf(respt, "Media content: session %2d ", 1);
+ sprintf(respt+strlen(respt), "leadout lba: %9d\n", nwa);
+ if(!(flag&1))
+ Xorriso_result(xorriso,0);
+ num_data= last_track_size= nwa;
+ num_sessions= 1;
+ } else {
+ sessions= burn_disc_get_sessions(disc, &num_sessions);
+ for (session_no= 0; session_norequest_to_abort);
+ session_no++) {
+ tracks = burn_session_get_tracks(sessions[session_no], &num_tracks);
+ if (tracks==NULL)
+ continue;
+ for(track_no= 0; track_norequest_to_abort);
+ track_no++) {
+ track_count++;
+ is_data= 0;
+ burn_track_get_entry(tracks[track_no], &toc_entry);
+ if (toc_entry.extensions_valid & 1) {
+ /* DVD extension valid */
+ lba= toc_entry.start_lba;
+ } else {
+ lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec, toc_entry.pframe);
+ }
+ sprintf(respt, "Media content: session %2d ", session_no+1);
+ sprintf(respt+strlen(respt), "track %2d %s lba: %9d\n",
+ track_count, ((toc_entry.control&7)<4?"audio":"data "), lba);
+ if(!(flag&1))
+ Xorriso_result(xorriso,0);
+ last_track_start= lba;
+ if((toc_entry.control&7)>=4) /* data track */
+ is_data= 1;
+ }
+ burn_session_get_leadout_entry(sessions[session_no], &toc_entry);
+ if (toc_entry.extensions_valid & 1) {
+ lba= toc_entry.start_lba;
+ burn_lba_to_msf(lba, &pmin, &psec, &pframe);
+ } else {
+ lba= burn_msf_to_lba(pmin, psec, pframe);
+ lba= burn_msf_to_lba(toc_entry.pmin, toc_entry.psec, toc_entry.pframe);
+ }
+ sprintf(respt, "Media content: session %2d ", session_no+1);
+ sprintf(respt+strlen(respt), "leadout lba: %9d\n", lba);
+ if(!(flag&1))
+ Xorriso_result(xorriso,0);
+ last_track_size= lba - last_track_start;
+ if(is_data)
+ num_data+= last_track_size;
+ }
+ }
+ if(xorriso->request_to_abort)
+ return(1);
+ Sfile_scale(((double) num_data) * 2048.0, mem_text,5,1e4,1);
+ sprintf(respt, "Media summary: %d session%s, %d data blocks, %s\n",
+ num_sessions, (num_sessions==1 ? "" : "s"), num_data, mem_text);
+ Xorriso_result(xorriso,0);
+
+ if (s == BURN_DISC_APPENDABLE && nwa!=0) {
+ ret= isoburn_disc_track_lba_nwa(drive, NULL, 0, &lba, &nwa);
+ if(ret>0) {
+ sprintf(respt, "Media nwa : %ds\n", nwa);
+ if(!(flag&1))
+ Xorriso_result(xorriso,0);
+ }
+ }
+
+ if (disc!=NULL)
+ burn_disc_free(disc);
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1);
+}
+
+
+int Xorriso_show_devices(struct XorrisO *xorriso, int flag)
+{
+ char adr[BURN_DRIVE_ADR_LEN];
+ int i;
+ struct burn_drive_info *drive_list= NULL;
+ unsigned int drive_count;
+ char *respt, perms[8];
+ struct stat stbuf;
+
+ sprintf(xorriso->info_text, "Beginning to scan for devices ...\n");
+ Xorriso_info(xorriso,0);
+
+ burn_drive_clear_whitelist();
+ while(!burn_drive_scan(&drive_list, &drive_count)) {
+ Xorriso_process_msg_queues(xorriso,0);
+ usleep(100000);
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+ if(drive_count <= 0) {
+
+ /* >>> was a drive_list created at all ? */
+ /* >>> must it be freed ? */
+
+ sprintf(xorriso->info_text, "No drives found");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
+ return(0);
+ }
+ sprintf(xorriso->info_text, "Full drive scan done\n");
+ Xorriso_info(xorriso,0);
+
+ respt= xorriso->result_line;
+ for(i= 0; i < drive_count && !(xorriso->request_to_abort); i++) {
+ if(burn_drive_get_adr(&(drive_list[i]), adr)<=0)
+ strcpy(adr, "-get_adr_failed-");
+ Xorriso_process_msg_queues(xorriso,0);
+ if(stat(adr,&stbuf)==-1) {
+ sprintf(perms,"errno=%d",errno);
+ } else {
+ strcpy(perms,"------");
+ if(stbuf.st_mode&S_IRUSR) perms[0]= 'r';
+ if(stbuf.st_mode&S_IWUSR) perms[1]= 'w';
+ if(stbuf.st_mode&S_IRGRP) perms[2]= 'r';
+ if(stbuf.st_mode&S_IWGRP) perms[3]= 'w';
+ if(stbuf.st_mode&S_IROTH) perms[4]= 'r';
+ if(stbuf.st_mode&S_IWOTH) perms[5]= 'w';
+ }
+ sprintf(respt, "%d -dev '%s' %s : '%-8.8s' '%s' \n",
+ i, adr, perms, drive_list[i].vendor, drive_list[i].product);
+ Xorriso_result(xorriso,0);
+ }
+ burn_drive_info_free(drive_list);
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1);
+}
+
+
+int Xorriso_tell_media_space(struct XorrisO *xorriso,
+ int *media_space, int *free_space, int flag)
+{
+ int ret;
+ struct burn_drive_info *dinfo;
+ struct burn_drive *drive;
+ struct burn_write_opts *burn_options;
+
+ (*free_space)= (*media_space)= 0;
+
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to -tell_media_space", 2);
+ if(ret<=0)
+ return(0);
+
+ ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0);
+ if(ret<=0)
+ return(-1);
+ (*free_space)= (*media_space)=
+ isoburn_disc_available_space(drive, burn_options) / (off_t) 2048;
+ burn_write_opts_free(burn_options);
+
+ if(xorriso->volset_change_pending) {
+ ret= Xorriso_write_session(xorriso, 1);
+ if(ret>0)
+ (*free_space)-= ret;
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1);
+}
+
+
+/* @param flag bit0=fast , bit1=deformat
+ @return 0=failure, did not touch media , -1=failure, altered media
+ 1=success, altered media , 2=success, did not touch media
+*/
+int Xorriso_blank_media(struct XorrisO *xorriso, int flag)
+{
+ int ret, do_deformat= 0;
+ struct burn_drive_info *dinfo;
+ struct burn_drive *drive;
+ enum burn_disc_status disc_state;
+ struct burn_progress p;
+ double percent = 1.0;
+ int current_profile;
+ char current_profile_name[80];
+ char mode_names[4][80]= {"all", "fast", "deformat", "deformat_quickest"};
+
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to -blank", 2);
+ if(ret<=0)
+ return(0);
+
+ burn_disc_get_profile(drive, ¤t_profile, current_profile_name);
+
+ /* >>> */;
+
+ disc_state = isoburn_disc_get_status(drive);
+ if(current_profile == 0x13) { /* overwriteable DVD-RW */
+ /* Depending on flag bit1 formatted DVD-RW will get blanked to sequential
+ state or pseudo blanked by invalidating an eventual ISO image. */
+ if(flag&2)
+ do_deformat= 1;
+ } else if(current_profile == 0x14) { /* sequential DVD-RW */
+ if((flag&1) && !(flag&2)) {
+ sprintf(xorriso->info_text,
+ "-blank: DVD-RW present. Mode 'fast' defaulted to mode 'all'.");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ sprintf(xorriso->info_text,
+ "Mode 'deformat_quickest' produces single-session-only media.");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
+ flag&= ~1;
+ }
+ } else if(disc_state == BURN_DISC_BLANK) {
+ sprintf(xorriso->info_text,"Blank media detected. Will leave it untouched");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ return 2;
+ } else if(disc_state==BURN_DISC_FULL || disc_state==BURN_DISC_APPENDABLE) {
+ ;
+ } else if(disc_state == BURN_DISC_EMPTY) {
+ sprintf(xorriso->info_text,"No media detected in drive");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return 0;
+ } else {
+ sprintf(xorriso->info_text, "Unsuitable drive and media state");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return 0;
+ }
+ if(!isoburn_disc_erasable(drive)) {
+ sprintf(xorriso->info_text, "Media is not of erasable type");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return 0;
+ }
+ if(xorriso->do_dummy) {
+ sprintf(xorriso->info_text,
+ "-dummy mode prevents blanking of media in mode '%s'.",
+ mode_names[flag&3]);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ return(1);
+ }
+ sprintf(xorriso->info_text, "Beginning to blank media in mode '%s'.\n",
+ mode_names[flag&3]);
+ Xorriso_info(xorriso,0);
+
+ if(do_deformat)
+ burn_disc_erase(drive, (flag&1));
+ else
+ isoburn_disc_erase(drive, (flag&1));
+ usleep(1000000);
+ while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
+ if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
+ percent = 1.0 + ((double) p.sector+1.0) / ((double) p.sectors) * 98.0;
+ sprintf(xorriso->info_text, "Blanking ( %.1f%% done )", percent);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "UPDATE", 0);
+ usleep(1000000);
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text, "Blanking done\n");
+ Xorriso_info(xorriso,0);
+ return(1);
+}
+
+/* @return 0=failure, did not touch media , -1=failure, altered media
+ 1=success, altered media , 2=success, did not touch media
+*/
+int Xorriso_format_media(struct XorrisO *xorriso, int flag)
+{
+ int ret, mode_flag= 0;
+ struct burn_drive_info *dinfo;
+ struct burn_drive *drive;
+ int current_profile;
+ char current_profile_name[80];
+
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to -format", 2);
+ if(ret<=0)
+ return(0);
+
+ burn_disc_get_profile(drive, ¤t_profile, current_profile_name);
+ if(current_profile == 0x14) {
+ ; /* ok DVD-RW sequential */
+ } else if(current_profile == 0x1a) {
+ mode_flag= 2;
+ } else {
+ sprintf(xorriso->info_text,
+ "Can only -format DVD+RW and sequential DVD-RW");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ sprintf(xorriso->info_text,"Media current: %s (%4.4xh)",
+ current_profile_name, current_profile);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ return 0;
+ }
+
+ if(xorriso->do_dummy) {
+ sprintf(xorriso->info_text, "-dummy mode prevents formatting of media.");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ return(1);
+ }
+ sprintf(xorriso->info_text, "Beginning to format media.\n");
+ Xorriso_info(xorriso, 0);
+ burn_disc_format(drive, (off_t) 0, mode_flag);
+
+ ret= Xorriso_pacifier_loop(xorriso, drive, 0);
+ if(ret<=0)
+ return(ret);
+
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text, "Formatting done\n");
+ Xorriso_info(xorriso,0);
+ return(1);
+}
+
+
+int Xorriso_cannot_create_iter(struct XorrisO *xorriso, int iso_error,int flag)
+{
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_report_iso_error(xorriso, "", iso_error, "Cannot create iter", 0,
+ "FATAL", 1);
+ sprintf(xorriso->info_text, "Cannot create IsoDirIter object");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(1);
+}
+
+
+int Xorriso__node_lba_cmp(const void *node1, const void *node2)
+{
+ uint32_t lba1= 0, lba2= 0;
+ int ret;
+
+ ret = iso_node_get_old_image_lba(*((IsoNode **) node1), &lba1, 0);
+ if(ret!=1)
+ lba1= 0;
+ ret = iso_node_get_old_image_lba(*((IsoNode **) node2), &lba2, 0);
+ if(ret!=1)
+ lba1= 0;
+ return(lba1-lba2);
+}
+
+/* The caller shall make no assumptions about the meaning of iter, node_array,
+ node_count, node_idx ! They are just opaque handles for which the caller
+ provides the memory of proper type.
+ @param flag bit0= initialize iteration
+ bit1= action needs full freedom of object manipulation
+ bit2= action needs LBA sorted iteration
+ bit31= end iteration (mandatory !)
+*/
+int Xorriso_findi_iter(struct XorrisO *xorriso, IsoDir *dir_node, off_t *mem,
+ IsoDirIter **iter,
+ IsoNode ***node_array, int *node_count, int *node_idx,
+ IsoNode **iterated_node, int flag)
+{
+ int ret, i;
+ IsoNode *node;
+ off_t new_mem= 0;
+ char mem_text[80], limit_text[80];
+
+ if(flag&1) {
+ *node_array= NULL;
+ *node_count= -1;
+ *node_idx= 0;
+ *iter= NULL;
+ ret= iso_dir_get_children(dir_node, iter);
+ if(ret<0) {
+cannot_iter:;
+ Xorriso_cannot_create_iter(xorriso, ret, 0);
+ return(-1);
+ }
+ if((flag&2)|(flag&4)) {
+ /* copy list of nodes and prepare soft iterator */
+ *node_count= 0;
+ while(iso_dir_iter_next(*iter, &node) == 1)
+ (*node_count)++;
+ iso_dir_iter_free(*iter);
+ *iter= NULL;
+
+ new_mem= ((*node_count)+1) * sizeof(IsoNode *);
+ if(new_mem > xorriso->temp_mem_limit) {
+ Sfile_scale((double) new_mem, mem_text, 5,1e4, 0);
+ Sfile_scale((double) xorriso->temp_mem_limit, limit_text, 5,1e4, 0);
+ sprintf(xorriso->info_text,
+ "Stacked directory snapshots exceed -temp_mem_limit (%s > %s)",
+ mem_text, limit_text);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ *node_count= -1;
+ return(-1);
+ }
+ (*node_array)= (IsoNode **) calloc((*node_count)+1, sizeof(IsoNode *));
+ if(*node_array == NULL) {
+ sprintf(xorriso->info_text,
+ "Could not allocate inode list of %.f bytes",
+ ((double) (*node_count)+1) * (double) sizeof(IsoNode *));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ *node_count= -1;
+ return(-1);
+ }
+ *mem= new_mem;
+ ret= iso_dir_get_children(dir_node, iter);
+ if(ret<0)
+ goto cannot_iter;
+ while(iso_dir_iter_next(*iter, &node) == 1 && *node_idx < *node_count) {
+ (*node_array)[*node_idx]= node;
+ iso_node_ref(node);
+ (*node_idx)++;
+ }
+ iso_dir_iter_free(*iter);
+ *iter= NULL;
+ *node_count= *node_idx;
+ *node_idx= 0;
+ if((flag&4) && *node_count>1)
+ qsort(*node_array, *node_count, sizeof(IsoNode *),
+ Xorriso__node_lba_cmp);
+ }
+ }
+
+ if(flag&(1<<31)) {
+ if(*node_count>=0 && *node_array!=NULL) {
+ for(i= 0; i<*node_count; i++)
+ iso_node_unref((*node_array)[i]);
+ free(*node_array);
+ *node_array= NULL;
+ *node_count= -1;
+ *node_idx= 0;
+ } else {
+ if(*iter!=NULL)
+ iso_dir_iter_free(*iter);
+ *iter= NULL;
+ }
+ }
+
+ if(flag&(1|(1<<31)))
+ return(1);
+ if(*node_count>=0) {
+ /* return next node_array element */
+ if(*node_idx>=*node_count)
+ return(0);
+ *iterated_node= (*node_array)[*node_idx];
+ (*node_idx)++;
+ } else {
+ ret= iso_dir_iter_next(*iter, iterated_node);
+ return(ret == 1);
+ }
+ return(1);
+}
+
+
+/*
+*/
+#define Xorriso_rmi_findi_iteR yes
+
+/* @param boss_iter If not NULL then this is an iterator suitable for
+ iso_dir_iter_remove() which is then to be used instead
+ of iso_node_remove().
+ @param flag bit0= remove whole sub tree: rm -r
+ bit1= remove empty directory: rmdir
+ bit2= recursion: do not reassure in mode 2 "tree"
+ bit3= this is for overwriting and not for plain removal
+ bit4= count deleted files in xorriso->pacifier_count
+ bit5= with bit0 only remove directory content, not the directory
+ @return <=0 = error
+ 1 = removed simple node
+ 2 = removed directory or tree
+ 3 = did not remove on user revocation
+*/
+int Xorriso_rmi(struct XorrisO *xorriso, void *boss_iter, off_t boss_mem,
+ char *path, int flag)
+{
+ int ret, is_dir= 0, pl, not_removed= 0, fret;
+ IsoNode *victim_node, *node;
+ IsoDir *boss_node, *root_dir;
+ IsoDirIter *iter= NULL;
+ IsoImage *volume;
+ char *sub_name, *name;
+
+#ifdef Xorriso_fat_local_meM
+ char sfe[5*SfileadrL], sub_path[2*SfileadrL];
+#else
+
+ char *sfe= NULL, *sub_path= NULL;
+ off_t mem;
+
+#ifdef Xorriso_rmi_findi_iteR
+ IsoNode **node_array= NULL;
+ int node_count, node_idx;
+#endif /* ! Xorriso_rmi_findi_iteR */
+
+ /* Avoiding large local memory objects in order to save stack space */
+ sfe= malloc(5*SfileadrL);
+ sub_path= malloc(2*SfileadrL);
+ if(sfe==NULL || sub_path==NULL) {
+ Xorriso_no_malloc_memory(xorriso, &sfe, 0);
+ {ret= -1; goto ex;}
+ }
+#endif /* ! Xorriso_fat_local_meM */
+
+#ifndef Libisofs_iso_dir_iter_sufficienT
+ /* Ticket 127: A80301 - A80302
+ I do not not deem IsoDirIter safe for node list manipulations.
+ The parameter boss_iter once was intended to allow such but
+ has now been downgraded to a mere check for eventual programming bugs.
+ */
+ if(boss_iter!=NULL) {
+ sprintf(xorriso->info_text,
+ "Program error: Xorriso_rmi() was requested to delete iterated node %s",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ ret= -1; goto ex;
+ }
+#endif /* Libisofs_iso_dir_iter_sufficienT */
+
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ goto ex;
+
+ if(Xorriso_much_too_long(xorriso, strlen(path), 0)<=0)
+ {ret= 0; goto ex;}
+ ret= Xorriso_node_from_path(xorriso, volume, path, &victim_node, 0);
+ if(ret<=0)
+ goto ex;
+ root_dir= iso_image_get_root(volume);
+ if(((void *) root_dir) == ((void *) victim_node)) {
+ sprintf(xorriso->info_text, "May not delete root directory");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ {ret= 0; goto ex;}
+ }
+
+ if(LIBISO_ISDIR(victim_node))
+ is_dir= 1;
+ if(!is_dir) {
+ if(flag&2) { /* rmdir */
+ sprintf(xorriso->info_text, "%s in loaded ISO image is not a directory",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+ } else {
+ if(flag&1) { /* rm -r */
+ if((xorriso->do_reassure==1 && !xorriso->request_not_to_ask) ||
+ (flag&32)) {
+ /* Iterate over subordinates and delete them */
+ mem= boss_mem;
+
+#ifdef Xorriso_rmi_findi_iteR
+ ret= Xorriso_findi_iter(xorriso, (IsoDir *) victim_node, &mem,
+ &iter, &node_array, &node_count, &node_idx,
+ &node, 1|2);
+ if(ret<=0) {
+#else
+ ret= iso_dir_get_children((IsoDir *) victim_node, &iter);
+ Xorriso_process_msg_queues(xorriso,0);
+ if(ret<0) {
+#endif /* ! Xorriso_rmi_findi_iteR */
+
+cannot_create_iter:;
+ Xorriso_cannot_create_iter(xorriso, ret, 0);
+ ret= -1; goto ex;
+ }
+ pl= strlen(path);
+ strcpy(sub_path, path);
+ if(pl==0 || sub_path[pl-1]!='/') {
+ sub_path[pl++]= '/';
+ sub_path[pl]= 0;
+ }
+ sub_name= sub_path+pl;
+
+#ifdef Xorriso_rmi_findi_iteR
+ while(1) {
+ ret= Xorriso_findi_iter(xorriso, (IsoDir *) victim_node, &mem, &iter,
+ &node_array, &node_count, &node_idx, &node, 0);
+ if(ret<0)
+ goto ex;
+ if(ret==0 || xorriso->request_to_abort)
+ break;
+#else
+ while(iso_dir_iter_next(iter, &node) == 1
+ && !xorriso->request_to_abort) {
+#endif
+
+ name= (char *) iso_node_get_name(node);
+ if(Xorriso_much_too_long(xorriso, pl+1+strlen(name), 0)<=0)
+ {ret= 0; goto rm_r_problem_handler;}
+ strcpy(sub_name, name);
+ ret= Xorriso_rmi(xorriso, iter, mem, sub_path, (flag&(1|2|8|16))|4);
+ if(ret==3 || ret<=0 || xorriso->request_to_abort) {
+rm_r_problem_handler:;
+ not_removed= 1;
+ fret= Xorriso_eval_problem_status(xorriso, ret, 1|2);
+ if(fret<0)
+ goto dir_not_removed;
+ }
+ }
+ if(flag&32)
+ {ret= 2; goto ex;}
+
+ if(not_removed) {
+dir_not_removed:;
+ sprintf(xorriso->info_text, "Directory not removed: %s",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ if(ret>0)
+ ret= 3;
+ goto ex;
+ }
+ }
+ } else {
+ if(!(flag&2)) { /* not rmdir */
+ sprintf(xorriso->info_text, "%s in loaded ISO image is a directory",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+
+ ret= iso_dir_get_children((IsoDir *) victim_node, &iter);
+ Xorriso_process_msg_queues(xorriso,0);
+ if(ret<0)
+ goto cannot_create_iter;
+ if(ret>0) {
+ if(iso_dir_iter_next(iter, &node) == 1) {
+ sprintf(xorriso->info_text,
+ "Directory not empty on attempt to delete: %s",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+ }
+ }
+ }
+
+ if(xorriso->request_to_abort)
+ {ret= 3; goto ex;}
+ boss_node= iso_node_get_parent(victim_node);
+ Xorriso_process_msg_queues(xorriso,0);
+ if(boss_node==NULL) {
+ sprintf(xorriso->info_text,
+ "Cannot find parent node of %s in loaded ISO image",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+
+ while((xorriso->do_reassure==1 || (xorriso->do_reassure==2 && !(flag&4)))
+ && !xorriso->request_not_to_ask) {
+ /* ls -ld */
+ Xorriso_ls_filev(xorriso, xorriso->wdi, 1, &path, (off_t) 0, 1|2|8);
+ if(is_dir) /* du -s */
+ Xorriso_ls_filev(xorriso, xorriso->wdi, 1, &path, (off_t) 0, 2|4);
+ if(flag&8)
+ sprintf(xorriso->info_text,
+ "File exists. Remove ? n= keep old, y= remove, x= abort, @= stop asking\n");
+ else
+ sprintf(xorriso->info_text,
+ "Remove above file ? n= keep it, y= remove it, x= abort, @= stop asking\n");
+ Xorriso_info(xorriso, 4);
+ ret= Xorriso_request_confirmation(xorriso, 1|2|4|16);
+ if(ret<=0)
+ goto ex;
+ if(xorriso->request_to_abort) {
+ sprintf(xorriso->info_text,
+ "Removal operation aborted by user before file: %s",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ ret= 3; goto ex;
+ }
+ if(ret==3)
+ continue;
+ if(ret==6) /* yes */
+ break;
+ if(ret==4) { /* yes, do not ask again */
+ xorriso->request_not_to_ask= 1;
+ break;
+ }
+ if(ret==1) { /* no */
+ sprintf(xorriso->info_text, "Kept in existing state: %s",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ ret= 3; goto ex;
+ }
+ }
+
+#ifdef Libisofs_iso_dir_iter_sufficienT
+
+ if(boss_iter!=NULL) {
+ ret= iso_dir_iter_remove((IsoDirIter *) boss_iter);
+ if(ret<0)
+ ret= -1;
+ } else
+ ret= iso_node_remove(victim_node);
+
+#else /* ! Libisofs_iso_dir_iter_sufficienT */
+
+ ret= iso_node_remove(victim_node);
+
+#endif /* Libisofs_iso_dir_iter_sufficienT */
+
+ Xorriso_process_msg_queues(xorriso,0);
+ if(ret<0) {
+ Xorriso_report_iso_error(xorriso, path, ret, "Cannot remove node", 0,
+ "FATAL", 1);
+ sprintf(xorriso->info_text,
+ "Internal failure to remove %s from loaded ISO image",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ ret= -1; goto ex;
+ }
+ if(flag&16)
+ xorriso->pacifier_count++;
+ xorriso->volset_change_pending= 1;
+ ret= 1+!!is_dir;
+ex:;
+
+#ifndef Xorriso_fat_local_meM
+ if(sfe!=NULL)
+ free(sfe);
+ if(sub_path!=NULL)
+ free(sub_path);
+#endif /* ! Xorriso_fat_local_meM */
+
+#ifdef Xorriso_rmi_findi_iteR
+ Xorriso_findi_iter(xorriso, (IsoDir *) victim_node, &mem, &iter,
+ &node_array, &node_count, &node_idx, &node, (1<<31));
+#else
+ if(iter!=NULL)
+ iso_dir_iter_free(iter);
+#endif /* ! Xorriso_rmi_findi_iteR */
+
+ return(ret);
+}
+
+
+int Xorriso__node_name_cmp(const void *node1, const void *node2)
+{
+ char *name1, *name2;
+
+ name1= (char *) iso_node_get_name(*((IsoNode **) node1));
+ name2= (char *) iso_node_get_name(*((IsoNode **) node2));
+ return(strcmp(name1,name2));
+}
+
+
+/* @param flag bit0= only accept directory nodes
+ bit1= do not report memory usage as DEBUG
+ bit2= do not apply search pattern but accept any node
+*/
+int Xorriso_sorted_node_array(struct XorrisO *xorriso,
+ IsoDir *dir_node,
+ int *nodec, IsoNode ***node_array,
+ off_t boss_mem, int flag)
+{
+ int i, ret, failed_at;
+ char *npt;
+ IsoDirIter *iter= NULL;
+ IsoNode *node;
+ off_t mem;
+
+ mem= ((*nodec)+1)*sizeof(IsoNode *);
+ ret= Xorriso_check_temp_mem_limit(xorriso, mem+boss_mem, flag&2);
+ if(ret<=0)
+ return(ret);
+
+ *node_array= calloc(sizeof(IsoNode *), (*nodec)+1);
+ if(*node_array==NULL) {
+ sprintf(xorriso->info_text,
+ "Cannot allocate memory for %d directory entries", *nodec);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(-1);
+ }
+
+ ret= iso_dir_get_children(dir_node, &iter);
+ if(ret<0) {
+ Xorriso_cannot_create_iter(xorriso, ret, 0);
+ return(-1);
+ }
+
+ for(i= 0; iso_dir_iter_next(iter, &node) == 1 && i<*nodec; ) {
+ npt= (char *) iso_node_get_name(node);
+ if(!(flag&4)) {
+ ret= Xorriso_regexec(xorriso, npt, &failed_at, 0);
+ if(ret)
+ continue; /* no match */
+ }
+ if(flag&1)
+ if(!LIBISO_ISDIR(node))
+ continue;
+ (*node_array)[i++]= node;
+ }
+ iso_dir_iter_free(iter);
+ *nodec= i;
+ if(*nodec<=0)
+ return(1);
+ qsort(*node_array, *nodec, sizeof(IsoNode *), Xorriso__node_name_cmp);
+ return(1);
+}
+
+
+/* @param flag bit0= do not only sum up sizes but also print subdirs
+*/
+int Xorriso_show_du_subs(struct XorrisO *xorriso, IsoDir *dir_node,
+ char *abs_path, char *rel_path, off_t *size,
+ off_t boss_mem, int flag)
+{
+ int i, ret, no_sort= 0, filec= 0, l;
+ IsoDirIter *iter= NULL;
+ IsoNode *node, **node_array= NULL;
+ char *name;
+ off_t sub_size, report_size, mem= 0;
+
+#ifdef Xorriso_fat_local_meM
+ char path[SfileadrL], show_path[SfileadrL], sfe[5*SfileadrL];
+#else /* Xorriso_fat_local_meM */
+ char *path= NULL, *show_path= NULL, *sfe= NULL;
+
+ sfe= malloc(5*SfileadrL);
+ path= malloc(SfileadrL);
+ show_path= malloc(SfileadrL);
+ if(path==NULL || show_path==NULL || sfe==NULL) {
+ Xorriso_no_malloc_memory(xorriso, &sfe, 0);
+ {ret= -1; goto ex;}
+ }
+
+#endif /* ! Xorriso_fat_local_meM */
+
+ *size= 0;
+ ret= iso_dir_get_children(dir_node, &iter);
+ if(ret<0) {
+cannot_create_iter:;
+ Xorriso_cannot_create_iter(xorriso, ret, 0);
+ {ret= -1; goto ex;}
+ }
+ for(i= 0; iso_dir_iter_next(iter, &node) == 1; ) {
+ sub_size= 0;
+ name= (char *) iso_node_get_name(node);
+ strcpy(show_path, rel_path);
+ if(Sfile_add_to_path(show_path, name, 0)<=0)
+ goto much_too_long;
+ if(LIBISO_ISDIR(node)) {
+ strcpy(path, abs_path);
+ if(Sfile_add_to_path(path, name, 0)<=0) {
+much_too_long:;
+ Xorriso_much_too_long(xorriso, strlen(path)+strlen(name)+1, 2);
+ {ret= -1; goto ex;}
+ }
+ filec++;
+ l= strlen(rel_path)+1;
+ mem+= l;
+ if(l % sizeof(char *))
+ mem+= sizeof(char *)-(l % sizeof(char *));
+ if(flag&1) /* diving and counting is done further below */
+ continue;
+ ret= Xorriso_show_du_subs(xorriso, (IsoDir *) node,
+ path, show_path, &sub_size, boss_mem, 0);
+ if(ret<0)
+ goto ex;
+ if(ret==0)
+ continue;
+ }
+
+ if(LIBISO_ISREG(node)) {
+ sub_size+= iso_file_get_size((IsoFile *) node)+2048;
+/*
+ sub_size+= iso_file_get_size((IsoFile *) node)+strlen(name)+1;
+*/
+ }
+
+ if(sub_size>0)
+ (*size)+= sub_size;
+ Xorriso_process_msg_queues(xorriso,0);
+ }
+
+ if(filec<=0 || !(flag&1))
+ {ret= 1; goto ex;}
+
+ /* Reset iteration */
+ iso_dir_iter_free(iter);
+ iter= NULL;
+ Xorriso_process_msg_queues(xorriso,0);
+
+ ret= Xorriso_sorted_node_array(xorriso, dir_node, &filec, &node_array,
+ boss_mem, 1|2|4);
+ if(ret<0)
+ goto ex;
+ if(ret==0) {
+ no_sort= 1;
+ ret= iso_dir_get_children(dir_node, &iter);
+ if(ret<0)
+ goto cannot_create_iter;
+ }
+
+ for(i= 0; (no_sort || irequest_to_abort); i++) {
+ if(no_sort) {
+ ret= iso_dir_iter_next(iter, &node);
+ if(ret!=1)
+ break;
+ if(!LIBISO_ISDIR(node))
+ continue;
+ } else
+ node= node_array[i];
+
+ sub_size= 0;
+ name= (char *) iso_node_get_name(node);
+ strcpy(show_path, rel_path);
+ if(Sfile_add_to_path(show_path, name, 0)<=0)
+ goto much_too_long;
+ strcpy(path, abs_path);
+ if(Sfile_add_to_path(path, name, 0)<=0)
+ goto much_too_long;
+ ret= Xorriso_show_du_subs(xorriso, (IsoDir *) node,
+ path, show_path, &sub_size, boss_mem+mem, flag&1);
+ if(ret<0)
+ goto ex;
+
+ if(LIBISO_ISREG(node)) {
+ sub_size+= iso_file_get_size((IsoFile *) node)+2048;
+/*
+ sub_size+= iso_tree_node_get_size((IsoFile *) node)+strlen(name)+1;
+*/
+ }
+ if(sub_size>0)
+ (*size)+= sub_size;
+ report_size= sub_size/1024;
+ if(report_size*1024result_line, "%7.f ",(double) (report_size));
+ sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s\n",
+ Text_shellsafe(show_path, sfe, 0));
+ Xorriso_result(xorriso, 0);
+ }
+ ret= 1;
+ex:;
+
+#ifndef Xorriso_fat_local_meM
+ if(sfe!=NULL)
+ free(sfe);
+ if(path!=NULL)
+ free(path);
+ if(show_path!=NULL)
+ free(show_path);
+#endif /* ! Xorriso_fat_local_meM */
+
+ if(iter!=NULL)
+ iso_dir_iter_free(iter);
+ if(node_array!=NULL)
+ free((char *) node_array);
+ Xorriso_process_msg_queues(xorriso,0);
+ return(ret);
+}
+
+
+/* @param flag bit0= *node is already valid
+ bit1= add extra block for size estimation
+*/
+int Xorriso_fake_stbuf(struct XorrisO *xorriso, char *path, struct stat *stbuf,
+ IsoNode **node, int flag)
+{
+ int ret;
+ IsoImage *volume;
+
+ memset((char *) stbuf, 0, sizeof(struct stat));
+ if(!(flag&1)) {
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(-1);
+ ret= Xorriso_node_from_path(xorriso, volume, path, node, 1);
+ if(ret<=0)
+ *node= NULL;
+ }
+ if(*node==NULL)
+ return(0);
+
+ /* >>> stbuf->st_dev */
+ /* >>> stbuf->st_ino */
+
+ stbuf->st_mode= iso_node_get_permissions(*node) & 07777;
+ if(LIBISO_ISDIR(*node))
+ stbuf->st_mode|= S_IFDIR;
+ else if(LIBISO_ISREG(*node))
+ stbuf->st_mode|= S_IFREG;
+ else if(LIBISO_ISLNK(*node))
+ stbuf->st_mode|= S_IFLNK;
+ else if(LIBISO_ISLNK(*node))
+ stbuf->st_mode|= S_IFCHR;
+ else if(LIBISO_ISBLK(*node))
+ stbuf->st_mode|= S_IFBLK;
+ else if(LIBISO_ISFIFO(*node))
+ stbuf->st_mode|= S_IFIFO;
+ else if(LIBISO_ISSOCK(*node))
+ stbuf->st_mode|= S_IFSOCK;
+
+ /* >>> NG How to represent LIBISO_BOOT ? */
+
+
+ /* >>> With directories this should be : number of subdirs + 2 */
+ /* >>> ??? How to obtain RR hardlink number for other types ? */
+ stbuf->st_nlink= 1;
+
+ stbuf->st_uid= iso_node_get_uid(*node);
+ stbuf->st_gid= iso_node_get_gid(*node);
+
+ /* >>> stbuf->st_rdev */
+
+ if(LIBISO_ISREG(*node))
+ stbuf->st_size= iso_file_get_size((IsoFile *) *node)+ (2048 * !!(flag&2));
+ else
+ stbuf->st_size= 0;
+
+ stbuf->st_blksize= 2048;
+ stbuf->st_blocks= stbuf->st_size / (off_t) 2048;
+ if(stbuf->st_blocks * (off_t) 2048 != stbuf->st_size)
+ stbuf->st_blocks++;
+
+ stbuf->st_atime= iso_node_get_atime(*node);
+ stbuf->st_mtime= iso_node_get_mtime(*node);
+ stbuf->st_ctime= iso_node_get_ctime(*node);
+ return(1);
+}
+
+
+int Xorriso_iso_lstat(struct XorrisO *xorriso, char *path, struct stat *stbuf,
+ int flag)
+{
+ int ret;
+ IsoNode *node;
+
+ ret= Xorriso_fake_stbuf(xorriso, path, stbuf, &node, 0);
+ if(ret>0)
+ return(0);
+ return(-1);
+}
+
+
+int Xorriso_sorted_dir_i(struct XorrisO *xorriso, IsoDir *dir_node,
+ int *filec, char ***filev, off_t boss_mem, int flag)
+{
+ int i,j,ret;
+ IsoDirIter *iter= NULL;
+ IsoNode *node;
+ char *name;
+ off_t mem;
+
+ (*filec)= 0;
+ (*filev)= NULL;
+
+ ret= iso_dir_get_children(dir_node, &iter);
+ if(ret<0) {
+cannot_iter:;
+ Xorriso_cannot_create_iter(xorriso, ret, 0);
+ {ret= -1; goto ex;}
+ }
+ mem= 0;
+ for(i= 0; iso_dir_iter_next(iter, &node) == 1; ) {
+ name= (char *) iso_node_get_name(node);
+ mem+= sizeof(char *)+strlen(name)+8;
+ (*filec)++;
+ }
+ iso_dir_iter_free(iter);
+ iter= NULL;
+ if(*filec==0)
+ {ret= 1; goto ex;}
+
+ ret= Xorriso_check_temp_mem_limit(xorriso, mem+boss_mem, 2);
+ if(ret<=0)
+ goto ex;
+ (*filev)= (char **) calloc(*filec, sizeof(char *));
+ if(*filev==NULL)
+ {ret= -1; goto ex; }
+ ret= iso_dir_get_children(dir_node, &iter);
+ if(ret<0)
+ goto cannot_iter;
+ for(i= 0; i<*filec; i++) {
+ ret= iso_dir_iter_next(iter, &node);
+ if(ret!=1)
+ break;
+ name= (char *) iso_node_get_name(node);
+ (*filev)[i]= strdup(name);
+ if((*filev)[i]==NULL) {
+ for(j= 0; jresult_line;
+
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+
+ Sort_argv(filec, filev, 0);
+
+ /* Count valid nodes, warn of invalid ones */
+ for(i= 0; iinfo_text, "Not found in ISO image: %s",
+ Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
+ was_error++;
+ continue;
+ }
+ }
+
+ if((flag&8) && !(flag&(2|4))) {
+ sprintf(xorriso->info_text, "Valid ISO nodes found: %d\n", filec-was_error);
+ Xorriso_info(xorriso,1);
+ if(filec-was_error<=0)
+ return(!was_error);
+ }
+
+ passes= 1+!(flag&(4|8));
+ for(pass= 0; passrequest_to_abort); i++) {
+ rpt[0]= 0;
+ ret= Xorriso_make_abs_adr(xorriso, wd, filev[i], path, 1|2|4);
+ if(ret<=0)
+ continue;
+ ret= Xorriso_fake_stbuf(xorriso, path, &stbuf, &node, (flag&4)>>1);
+ if(ret<=0)
+ continue;
+ if(LIBISO_ISDIR(node) && !(flag&(4|8))) {
+ if(pass==0)
+ continue;
+ if(filec>1) {
+ strcpy(xorriso->result_line, "\n");
+ Xorriso_result(xorriso,0);
+ sprintf(xorriso->result_line, "%s:\n", Text_shellsafe(filev[i], sfe,0));
+ Xorriso_result(xorriso,0);
+ }
+ ret= Xorriso_sorted_dir_i(xorriso,
+ (IsoDir *) node, &dfilec, &dfilev, boss_mem, 0);
+ if(ret<=0) {
+
+ /* >>> libisofs iterator loop and single item Xorriso_lsx_filev() */;
+
+ } else {
+ if(flag&1) {
+ sprintf(xorriso->result_line, "total %d\n", dfilec);
+ Xorriso_result(xorriso,0);
+ }
+ Xorriso_ls_filev(xorriso, path,
+ dfilec, dfilev, boss_mem, (flag&1)|2|8);
+ }
+ if(dfilec>0)
+ Sfile_destroy_argv(&dfilec, &dfilev, 0);
+ continue;
+ } else
+ if(pass>0)
+ continue;
+ link_target[0]= 0;
+ if((flag&5)==1) { /* -ls_l */
+ ret= Xorriso_format_ls_l(xorriso, &stbuf, 0);
+ if(ret<=0)
+ continue;
+ if(LIBISO_ISLNK(node)) {
+ if(Sfile_str(link_target, (char *) iso_symlink_get_dest(
+ (IsoSymlink *) node), 0)<=0)
+ link_target[0]= 0;
+ }
+ } else if(flag&4) { /* -du or -dus */
+ size= stbuf.st_size;
+ if(S_ISDIR(stbuf.st_mode)) {
+ ret= Xorriso_show_du_subs(xorriso, (IsoDir *) node,
+ path, filev[i], &size, boss_mem, flag&1);
+ if(ret<0)
+ return(-1);
+ if(ret==0)
+ continue;
+ }
+ sprintf(rpt, "%7.f ",(double) (size/1024));
+ }
+ if(link_target[0] && (flag&5)==1)
+ sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s -> %s\n",
+ Text_shellsafe(filev[i], sfe, 0),
+ Text_shellsafe(link_target, sfe2, 0));
+ else
+ sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s\n",
+ Text_shellsafe(filev[i], sfe, 0));
+ Xorriso_result(xorriso, 0);
+ }
+ return(!was_error);
+}
+
+
+/* This function needs less buffer memory than Xorriso_ls_filev() but cannot
+ perform structured pattern matching as done by Xorriso_expand_pattern()
+ for subsequent Xorriso_ls_filev().
+ @param flag bit0= long format
+ bit1= only check for directory existence
+ bit2= do not apply search pattern but accept any file
+ bit3= just count nodes and return number
+*/
+int Xorriso_ls(struct XorrisO *xorriso, int flag)
+{
+ int ret, is_dir= 0, i, filec= 0, failed_at, no_sort= 0;
+ IsoNode *node, **node_array= NULL;
+ IsoDir *dir_node;
+ IsoImage *volume;
+ IsoDirIter *iter= NULL;
+ char sfe[5*SfileadrL], sfe2[5*SfileadrL], link_target[SfileadrL], *npt, *rpt;
+ struct stat stbuf;
+
+ rpt= xorriso->result_line;
+
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+
+ ret= Xorriso_node_from_path(xorriso, volume, xorriso->wdi, &node, 0);
+ if(ret<=0)
+ goto wdi_is_not_a_dir;
+ if(LIBISO_ISDIR(node))
+ is_dir= 1;
+ if(!is_dir) {
+wdi_is_not_a_dir:;
+ sprintf(xorriso->info_text,
+ "Working directory path does not lead to a directory in ISO image");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+ if(flag&2)
+ {ret= 1; goto ex;}
+
+ dir_node= (IsoDir *) node;
+ ret= iso_dir_get_children(dir_node, &iter);
+ if(ret<0) {
+cannot_create_iter:;
+ Xorriso_cannot_create_iter(xorriso, ret, 0);
+ {ret= -1; goto ex;}
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+
+ for(i= 0; iso_dir_iter_next(iter, &node) == 1; ) {
+ npt= (char *) iso_node_get_name(node);
+ if(!(flag&4)) {
+ ret= Xorriso_regexec(xorriso, npt, &failed_at, 0);
+ if(ret)
+ continue; /* no match */
+ }
+ filec++;
+ }
+ /* Reset iteration */
+ iso_dir_iter_free(iter);
+ iter= NULL;
+ Xorriso_process_msg_queues(xorriso,0);
+ if(flag&8)
+ {ret= filec; goto ex;}
+ sprintf(xorriso->info_text, "Valid ISO nodes found: %d\n", filec);
+ Xorriso_info(xorriso,1);
+
+ ret= Xorriso_sorted_node_array(xorriso, dir_node, &filec, &node_array, 0,
+ flag&4);
+ if(ret<0)
+ goto ex;
+ if(ret==0) {
+ no_sort= 1;
+ ret= iso_dir_get_children(dir_node, &iter);
+ if(ret<0)
+ goto cannot_create_iter;
+ }
+
+ for(i= 0; irequest_to_abort); i++) {
+ if(no_sort) {
+ ret= iso_dir_iter_next(iter, &node);
+ if(ret!=1)
+ break;
+ npt= (char *) iso_node_get_name(node);
+ if(!(flag&4)) {
+ ret= Xorriso_regexec(xorriso, npt, &failed_at, 0);
+ if(ret)
+ continue; /* no match */
+ }
+ } else
+ node= node_array[i];
+
+ npt= (char *) iso_node_get_name(node);
+ link_target[0]= 0;
+ if(LIBISO_ISLNK(node)) {
+ if(Sfile_str(link_target, (char *) iso_symlink_get_dest(
+ (IsoSymlink *) node), 0)<=0)
+ link_target[0]= 0;
+ }
+ rpt[0]= 0;
+ if(flag&1) {
+ ret= Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1);
+ if(ret<=0)
+ continue;
+ ret= Xorriso_format_ls_l(xorriso, &stbuf, 0);
+ if(ret<=0)
+ continue;
+ }
+ if(link_target[0] && (flag&1))
+ sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s -> %s\n",
+ Text_shellsafe(npt, sfe, 0),
+ Text_shellsafe(link_target, sfe2, 0));
+ else
+ sprintf(xorriso->result_line+strlen(xorriso->result_line), "%s\n",
+ Text_shellsafe(npt, sfe, 0));
+ Xorriso_result(xorriso, 0);
+ }
+
+ ret= 1;
+ex:;
+ if(iter!=NULL)
+ iso_dir_iter_free(iter);
+ Xorriso_process_msg_queues(xorriso,0);
+ if(node_array!=NULL)
+ free((char *) node_array);
+ return(ret);
+}
+
+/* @param boss_iter Opaque handle to be forwarded to actions in ISO image
+ Set to NULL if calling this function from outside ISO world
+*/
+int Xorriso_rename(struct XorrisO *xorriso, void *boss_iter,
+ char *origin, char *dest, int flag)
+{
+ int ret, ol, dest_ret;
+ char sfe[5*SfileadrL], eff_dest[SfileadrL], dir_adr[SfileadrL], *cpt;
+ char *leafname, eff_origin[SfileadrL], sfe2[5*SfileadrL], *old_leafname;
+ IsoImage *volume;
+ IsoDir *origin_dir, *dest_dir;
+ IsoNode *node, *iso_node;
+
+#ifndef Libisofs_iso_dir_iter_sufficienT
+ /* Ticket 127: A80301 - A80302
+ I do not not deem IsoDirIter safe for node list manipulations.
+ The parameter boss_iter once was intended to allow such but
+ has now been downgraded to a mere check for eventual programming bugs.
+ */
+ if(boss_iter!=NULL) {
+ sprintf(xorriso->info_text,
+ "Program error: Xorriso_rename() was requested to delete iterated node %s",
+ Text_shellsafe(origin, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(-1);
+ }
+#endif /* Libisofs_iso_dir_iter_sufficienT */
+
+ ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, origin, eff_origin, 0);
+ if(ret<=0)
+ return(ret);
+ dest_ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, dest, eff_dest,1);
+ if(dest_ret<0)
+ return(dest_ret);
+ if(dest_ret==0) { /* obtain eff_dest address despite it does not exist */
+ ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, dest, eff_dest, 2);
+ if(ret<=0)
+ return(ret);
+ }
+
+ /* Prevent that destination is a subordinate of origin
+ (that would be a black hole plopping out of the universe) */
+ ol= strlen(eff_origin);
+ if(ol==0) {
+ sprintf(xorriso->info_text, "May not rename root directory");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ } else if(strcmp(eff_origin, eff_dest)==0) {
+ sprintf(xorriso->info_text, "Ignored attempt to rename %s to itself",
+ Text_shellsafe(eff_origin,sfe,0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "WARNING", 0);
+ return(0);
+ } else if(strncmp(eff_origin, eff_dest, ol)==0 &&
+ (eff_dest[ol]==0 || eff_dest[ol]=='/')) {
+ sprintf(xorriso->info_text,
+ "May not rename %s to its own sub address %s",
+ Text_shellsafe(eff_origin,sfe,0), Text_shellsafe(eff_dest,sfe2,0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+
+ /* Check whether destination exists and may be not overwriteable */
+ if(dest_ret==2 && xorriso->do_overwrite!=1) {
+ sprintf(xorriso->info_text, "Renaming may not overwrite directory: %s",
+ Text_shellsafe(eff_dest, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ } else if (dest_ret==1 && !xorriso->do_overwrite) {
+ sprintf(xorriso->info_text, "Renaming may not overwite: %s",
+ Text_shellsafe(eff_dest, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ } else if(dest_ret>0) {
+ ret= Xorriso_rmi(xorriso, boss_iter, (off_t) 0, eff_dest, 1|8);
+ if(ret<=0)
+ return(0);
+ if(ret==3) {
+ sprintf(xorriso->info_text, "User revoked renaming of: %s",
+ Text_shellsafe(eff_origin, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "NOTE", 0);
+ return(0);
+ }
+ }
+
+ /* Ensure existence of destination directory */
+ strcpy(dir_adr, eff_dest);
+ cpt= strrchr(dir_adr, '/');
+ if(cpt==NULL)
+ cpt= dir_adr+strlen(dir_adr);
+ *cpt= 0;
+ if(dir_adr[0]!=0) {
+ ret= Xorriso_graft_in(xorriso, boss_iter, NULL, dir_adr, 1);
+ if(ret<=0)
+ return(ret);
+ }
+
+ /* Move node */
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+ Xorriso_node_from_path(xorriso, volume, dir_adr, &iso_node, 0);
+ dest_dir= (IsoDir *) iso_node;
+ strcpy(dir_adr, eff_origin);
+ cpt= strrchr(dir_adr, '/');
+ if(cpt==NULL)
+ cpt= dir_adr+strlen(dir_adr);
+ *cpt= 0;
+ Xorriso_node_from_path(xorriso, volume, dir_adr, &iso_node, 0);
+ origin_dir= (IsoDir *) iso_node;
+ Xorriso_node_from_path(xorriso, volume, eff_origin, &node, 0);
+ if(dest_dir==NULL || origin_dir==NULL || node==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,
+ "Internal error on rename: confirmed node turns out as NULL");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(-1);
+ }
+ ret= iso_node_take(node);
+ if(ret<0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_report_iso_error(xorriso, eff_dest, 0, "Cannot take", 0, "FATAL",1);
+ sprintf(xorriso->info_text,
+ "Internal error on rename: failed to take node");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(-1);
+ }
+ leafname= strrchr(eff_dest, '/');
+ if(leafname==NULL)
+ leafname= eff_dest;
+ else
+ leafname++;
+
+ old_leafname= (char *) iso_node_get_name(node);
+ if(strcmp(leafname, old_leafname)!=0)
+ ret= iso_node_set_name(node, leafname);
+ else
+ ret= 1;
+ if(ret<0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_report_iso_error(xorriso, eff_dest, 0, "Cannot set name", 0,
+ "FAILURE", 1);
+ return(-1);
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+ ret= iso_dir_add_node(dest_dir, node, 0);
+ if(ret<0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ Xorriso_report_iso_error(xorriso, eff_dest, 0, "Cannot add", 0, "FATAL", 1);
+ sprintf(xorriso->info_text,
+ "Internal error on rename: failed to insert node");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ return(-1);
+ }
+ return(1);
+}
+
+
+/* @param flag bit0= do not produce info message on success
+ @return 1=success,
+ 0=was already directory, -1=was other type, -2=other error
+*/
+int Xorriso_mkdir(struct XorrisO *xorriso, char *path, int flag)
+{
+ int ret;
+ char eff_path[SfileadrL], sfe[5*SfileadrL];
+
+ ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, path, eff_path, 1);
+ if(ret<0)
+ return(-2);
+ if(ret>0) {
+ sprintf(xorriso->info_text,"-mkdir: Address already existing %s",
+ Text_shellsafe(eff_path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0,
+ (ret==2 ? "WARNING" : "FAILURE"), 0);
+ return(-1+(ret==2));
+ }
+ ret= Xorriso_normalize_img_path(xorriso, xorriso->wdi, path, eff_path, 2);
+ if(ret<0)
+ return(-2);
+ ret= Xorriso_graft_in(xorriso, NULL, NULL, eff_path, 1);
+ if(ret<=0)
+ return(-2);
+ if(!(flag&1)) {
+ sprintf(xorriso->info_text, "Created directory in ISO image: %s\n",
+ Text_shellsafe(eff_path,sfe,0));
+ Xorriso_info(xorriso, 0);
+ }
+ return(1);
+}
+
+
+/* @param flag bit0= count results rather than storing them
+ bit1= this is a recursion
+ bit2= prepend wd (automatically done if wd[0]!=0)
+*/
+int Xorriso_obtain_pattern_files_i(
+ struct XorrisO *xorriso, char *wd, IsoDir *dir,
+ int *filec, char **filev, int count_limit, off_t *mem,
+ int *dive_count, int flag)
+{
+ int ret, failed_at;
+ IsoDirIter *iter= NULL;
+ IsoNode *node;
+ char *name;
+
+#ifdef Xorriso_fat_local_meM
+ char adr[SfileadrL];
+#else /* Xorriso_fat_local_meM */
+ char *adr= NULL;
+
+ adr= malloc(SfileadrL);
+ if(adr==NULL) {
+ Xorriso_no_malloc_memory(xorriso, &adr, 0);
+ {ret= -1; goto ex;}
+ }
+#endif /* ! Xorriso_fat_local_meM */
+
+
+ if(!(flag&2))
+ *dive_count= 0;
+ else
+ (*dive_count)++;
+ ret= Xorriso_check_for_root_pattern(xorriso, filec, filev, count_limit,
+ mem, (flag&1)|2);
+ if(ret!=2)
+ goto ex;
+
+ ret= iso_dir_get_children(dir, &iter);
+ if(ret<0) {
+ Xorriso_cannot_create_iter(xorriso, ret, 0);
+ {ret= -1; goto ex;}
+ }
+ while(iso_dir_iter_next(iter, &node) == 1) {
+ name= (char *) iso_node_get_name(node);
+ ret= Xorriso_make_abs_adr(xorriso, wd, name, adr, flag&4);
+ if(ret<=0)
+ goto ex;
+ ret= Xorriso_regexec(xorriso, adr, &failed_at, 1);
+ if(ret) { /* no match */
+ if(failed_at <= *dive_count) /* no hope for a match */
+ continue;
+
+ if(!LIBISO_ISDIR(node)) {
+
+ /* >>> How to deal with softlinks ? */
+
+ continue;
+ }
+ /* dive deeper */
+ ret= Xorriso_obtain_pattern_files_i(
+ xorriso, adr, (IsoDir *) node,
+ filec, filev, count_limit, mem, dive_count, flag|2);
+ if(ret<=0)
+ goto ex;
+ } else {
+ ret= Xorriso_register_matched_adr(xorriso, adr, count_limit,
+ filec, filev, mem, (flag&1)|2);
+ if(ret<=0)
+ goto ex;
+ }
+ }
+ ret= 1;
+ex:;
+
+#ifndef Xorriso_fat_local_meM
+ if(adr!=NULL)
+ free(adr);
+#endif /* ! Xorriso_fat_local_meM */
+
+ if(flag&2)
+ (*dive_count)--;
+ return(ret);
+}
+
+
+/* @param flag bit0= a match count !=1 is a FAILURE event
+ bit1= with bit0 tolerate 0 matches if pattern is a constant
+*/
+int Xorriso_expand_pattern(struct XorrisO *xorriso,
+ int num_patterns, char **patterns, int extra_filec,
+ int *filec, char ***filev, off_t *mem, int flag)
+{
+ int ret, count= 0, abs_adr= 0, i, was_count, was_filec;
+ int nonconst_mismatches= 0, dive_count= 0;
+ char sfe[5*SfileadrL];
+ IsoImage *volume;
+ IsoDir *dir= NULL, *root_dir;
+ IsoNode *iso_node;
+
+ *filec= 0;
+ *filev= NULL;
+
+ xorriso->search_mode= 3;
+ xorriso->structured_search= 1;
+
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+ root_dir= iso_image_get_root(volume);
+ if(root_dir==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,
+ "While expanding pattern : Cannot obtain root node of ISO image");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ ret= -1; goto ex;
+ }
+
+ for(i= 0; iwdi does not exist yet, but one may
+ not use it as base for relative address searches.
+ */
+ ret= Xorriso_node_from_path(xorriso, volume, xorriso->wdi, &iso_node, 1);
+ dir= (IsoDir *) iso_node;
+ if(ret<=0) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,
+ "While expanding pattern %s : Working directory does not exist in ISO image",
+ Text_shellsafe(patterns[i], sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+ if(!LIBISO_ISDIR((IsoNode *) dir)) {
+ sprintf(xorriso->info_text,
+ "Working directory path does not lead to a directory in ISO image");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+ }
+
+ /* count the matches */
+ was_count= count;
+ ret= Xorriso_obtain_pattern_files_i(xorriso, "", dir, &count, NULL, 0,
+ mem, &dive_count, 1 | abs_adr);
+ if(ret<=0)
+ goto ex;
+ if(was_count==count && strcmp(patterns[i],"*")!=0 && (flag&3)!=1) {
+ count++;
+ Xorriso_eval_nonmatch(xorriso, patterns[i], &nonconst_mismatches, mem, 0);
+ }
+ }
+
+ ret= Xorriso_check_matchcount(xorriso, count, nonconst_mismatches,
+ num_patterns, patterns, (flag&1)|2);
+ if(ret<=0)
+ goto ex;
+ count+= extra_filec;
+ mem+= extra_filec*sizeof(char *);
+ if(count<=0)
+ {ret= 0; goto ex;}
+ ret= Xorriso_alloc_pattern_mem(xorriso, *mem, count, filev, 0);
+ if(ret<=0)
+ goto ex;
+ /* now store addresses */
+ for(i= 0; iinfo_text,"Permissions now: %-5.5o %s",
+ mode, Text_shellsafe(path, sfe, 0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
+ xorriso->volset_change_pending= 1;
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1);
+}
+
+
+int Xorriso_set_uid(struct XorrisO *xorriso, char *in_path, uid_t uid,
+ int flag)
+{
+ int ret;
+ IsoNode *node;
+
+ ret= Xorriso_get_node_by_path(xorriso, in_path, NULL, &node, 0);
+ if(ret<=0)
+ return(ret);
+ iso_node_set_uid(node, uid);
+ iso_node_set_ctime(node, time(NULL));
+ xorriso->volset_change_pending= 1;
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1);
+}
+
+
+int Xorriso_set_gid(struct XorrisO *xorriso, char *in_path, gid_t gid,
+ int flag)
+{
+ int ret;
+ IsoNode *node;
+
+ ret= Xorriso_get_node_by_path(xorriso, in_path, NULL, &node, 0);
+ if(ret<=0)
+ return(ret);
+ iso_node_set_gid(node, gid);
+ iso_node_set_ctime(node, time(NULL));
+ xorriso->volset_change_pending= 1;
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1);
+}
+
+
+/* @parm flag bit0= atime, bit1= ctime, bit2= mtime, bit8=no auto ctime */
+int Xorriso_set_time(struct XorrisO *xorriso, char *in_path, time_t t,
+ int flag)
+{
+ int ret;
+ IsoNode *node;
+
+ ret= Xorriso_get_node_by_path(xorriso, in_path, NULL, &node, 0);
+ if(ret<=0)
+ return(ret);
+ if(flag&1)
+ iso_node_set_atime(node, t);
+ if(flag&2)
+ iso_node_set_ctime(node, t);
+ if(flag&4)
+ iso_node_set_mtime(node, t);
+ if(!(flag&(2|256)))
+ iso_node_set_ctime(node, time(NULL));
+ xorriso->volset_change_pending= 1;
+ Xorriso_process_msg_queues(xorriso,0);
+ return(1);
+}
+
+
+/* @param flag bit0= not a command parameter (directory iteration or recursion)
+ bit1= do not count deleted files with rm and rm_r
+ @return <=0 error, 1=ok, 2=ok, node has been deleted
+*/
+int Xorriso_findi_action(struct XorrisO *xorriso, struct FindjoB *job,
+ IsoDirIter *boss_iter, off_t boss_mem,
+ char *abs_path, char *show_path,
+ IsoNode *node, int depth, int flag)
+{
+ int ret= 0, type, action= 0, hflag, deleted= 0;
+ uid_t user= 0;
+ gid_t group= 0;
+ time_t date= 0;
+ mode_t mode_or= 0, mode_and= ~1;
+ char *target, sfe[5*SfileadrL], *iso_prefix;
+ struct FindjoB *subjob;
+ struct stat dir_stbuf;
+
+ action= Findjob_get_action_parms(job, &target, &user, &group,
+ &mode_and, &mode_or, &type, &date, &subjob, 0);
+ if(action<0)
+ action= 0;
+
+ hflag= 16*!(flag&2);
+ if(action==1) { /* rm (including rmdir) */
+ ret= Xorriso_fake_stbuf(xorriso, abs_path, &dir_stbuf, &node, 1);
+ if(ret>0) {
+ if(S_ISDIR(dir_stbuf.st_mode))
+ hflag= 2;
+ ret= Xorriso_rmi(xorriso, boss_iter, boss_mem, abs_path, hflag);
+ deleted= 1;
+ }
+ } else if(action==2) { /* rm_r */
+ ret= Xorriso_rmi(xorriso, boss_iter, boss_mem, abs_path, 1|hflag);
+ deleted= 1;
+ } else if(action==3) {
+
+ /* >>> mv target */;
+
+ } else if(action==4) { /* chown */
+ ret= Xorriso_set_uid(xorriso, abs_path, user, 0);
+ } else if(action==5) { /* chgrp */
+ ret= Xorriso_set_gid(xorriso, abs_path, group, 0);
+ } else if(action==6) { /* chmod */
+ ret= Xorriso_set_st_mode(xorriso, abs_path, mode_and, mode_or, 0);
+ } else if(action==7) { /* alter_date */
+ ret= Xorriso_set_time(xorriso, abs_path, date, type&7);
+ } else if(action==8) { /* lsdl */
+ ret= Xorriso_ls_filev(xorriso, "", 1, &abs_path, (off_t) 0, 1|2|8);
+ } else if(action>=9 && action<=13) { /* actions which have own findjobs */
+ Findjob_set_start_path(subjob, abs_path, 0);
+ ret= Xorriso_findi(xorriso, subjob, boss_iter, boss_mem, NULL,
+ abs_path, &dir_stbuf, depth, 1);
+ } else if(action==14 || action==17) { /* compare , update */
+ Findjob_get_start_path(job, &iso_prefix, 0);
+ ret= Xorriso_find_compare(xorriso, (void *) boss_iter, abs_path,
+ iso_prefix, target, (action==17)|((flag&1)<<1));
+ if(ret==2)
+ deleted= 1;
+ if(ret>=0)
+ ret= 1;
+ } else if(action==16 || action==18) { /* not_in_iso , add_missing */
+ ;
+ } else { /* includes : 15 in_iso */
+ sprintf(xorriso->result_line, "%s\n", Text_shellsafe(show_path, sfe, 0));
+ Xorriso_result(xorriso, 0);
+ ret= 1;
+ }
+ if(ret<=0)
+ return(ret);
+ if(deleted)
+ return(2);
+ return(1);
+}
+
+
+/* @param flag bit0= recursion
+ bit1= do not count deleted files with rm and rm_r
+ @return <=0 error, 1= ok , 2= dir node and path has been deleted
+*/
+int Xorriso_findi(struct XorrisO *xorriso, struct FindjoB *job,
+ void *boss_iter, off_t boss_mem,
+ void *dir_node_generic, char *dir_path,
+ struct stat *dir_stbuf, int depth, int flag)
+{
+ int ret, action= 0, hflag, deleted= 0;
+ IsoDirIter *iter= NULL;
+ IsoDir *dir_node= NULL;
+ IsoNode *node, *iso_node;
+ IsoImage *volume;
+ struct stat stbuf;
+ char *name;
+ off_t mem;
+ IsoNode **node_array= NULL;
+ int node_count, node_idx;
+#ifdef Xorriso_fat_local_meM
+ char path[SfileadrL], abs_path[SfileadrL];
+#else /* Xorriso_fat_local_meM */
+ char *path= NULL, *abs_path= NULL;
+
+ path= malloc(SfileadrL);
+ abs_path= malloc(SfileadrL);
+ if(path==NULL || abs_path==NULL) {
+ Xorriso_no_malloc_memory(xorriso, &path, 0);
+ {ret= -1; goto ex;}
+ }
+#endif /* ! Xorriso_fat_local_meM */
+
+ action= Findjob_get_action(job, 0);
+ if(action<0)
+ action= 0;
+
+ dir_node= (IsoDir *) dir_node_generic;
+ if(dir_node==NULL) {
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ {ret= -1; goto ex;}
+ ret= Xorriso_make_abs_adr(xorriso, xorriso->wdi, dir_path, path, 1|2|4);
+ if(ret<=0)
+ goto ex;
+ ret= Xorriso_node_from_path(xorriso, volume, path, &iso_node, 0);
+ dir_node= (IsoDir *) iso_node;
+ if(ret<=0)
+ {ret= 0; goto ex;}
+ ret= Xorriso_fake_stbuf(xorriso, "", dir_stbuf, &iso_node, 1);
+ dir_node= (IsoDir *) iso_node;
+ if(ret<=0)
+ goto ex;
+
+ name= strrchr(dir_path, '/');
+ if(name==NULL)
+ name= dir_path;
+ else
+ name++;
+ ret= Findjob_test(job, name, NULL, dir_stbuf, depth, 0);
+ if(ret<0)
+ goto ex;
+ if(ret>0) {
+ ret= Xorriso_findi_action(xorriso, job,
+ (IsoDirIter *) boss_iter, boss_mem,
+ path, dir_path, (IsoNode *) dir_node, depth,
+ flag&(1|2));
+ if(ret<=0)
+ goto ex;
+ if(ret==2) {
+ deleted= 1;
+ goto ex;
+ }
+ }
+ }
+ if(!LIBISO_ISDIR((IsoNode *) dir_node))
+ {ret= 1; goto ex;}
+
+ mem= boss_mem;
+ hflag= 1;
+ if(action==1 || action==2 || action==3 || action==14)
+ hflag|= 2; /* need freedom to manipulate image */
+ if(action==14 || action==17)
+ hflag|= 4; /* need LBA sorted iteration for good data reading performance */
+ ret= Xorriso_findi_iter(xorriso, dir_node, &mem,
+ &iter, &node_array, &node_count, &node_idx,
+ &node, hflag);
+ if(ret<=0)
+ goto ex;
+ while(1) {
+ ret= Xorriso_findi_iter(xorriso, dir_node, &mem, &iter,
+ &node_array, &node_count, &node_idx, &node, 0);
+ if(ret<0)
+ goto ex;
+ if(ret==0 || xorriso->request_to_abort)
+ break;
+ name= (char *) iso_node_get_name(node);
+ ret= Xorriso_make_abs_adr(xorriso, dir_path, name, path, 4);
+ if(ret<=0)
+ goto ex;
+ ret= Xorriso_fake_stbuf(xorriso, "", &stbuf, &node, 1);
+ if(ret<0)
+ goto ex;
+ if(ret==0)
+ continue;
+
+/* ??? This seems to be redundant with the single test above
+ ??? Should i dive in unconditionally and leave out test and action here ?
+ ??? Then do above test unconditionally ?
+ --- Seems that the current configuration represents the special
+ handling of the find start path with mount points. Dangerous to change.
+*/
+ ret= Findjob_test(job, name, dir_stbuf, &stbuf, depth, 0);
+ if(ret<0)
+ goto ex;
+ if(ret>0) {
+ ret= Xorriso_make_abs_adr(xorriso, xorriso->wdi, path, abs_path, 1|2|4);
+ if(ret<=0)
+ goto ex;
+ ret= Xorriso_findi_action(xorriso, job, iter, mem,
+ abs_path, path, node, depth, 1|(flag&2));
+ if(ret==2) /* node has been deleted */
+ continue;
+ if(ret<=0) {
+ if(Xorriso_eval_problem_status(xorriso, ret, 1|2)<0)
+ goto ex;
+ }
+ }
+
+ if(S_ISDIR(stbuf.st_mode)) {
+ ret= Xorriso_findi(xorriso, job, (void *) iter, mem,
+ (void *) node, path, &stbuf, depth+1, flag|1);
+ if(ret<0)
+ goto ex;
+ }
+ }
+
+ ret= 1;
+ex:;
+
+#ifndef Xorriso_fat_local_meM
+ if(path!=NULL)
+ free(path);
+ if(abs_path!=NULL)
+ free(abs_path);
+#endif /* ! Xorriso_fat_local_meM */
+
+ Xorriso_process_msg_queues(xorriso,0);
+
+ Xorriso_findi_iter(xorriso, dir_node, &mem, &iter, &node_array, &node_count,
+ &node_idx, &node, (1<<31));
+ if(ret<=0)
+ return(ret);
+ if(deleted)
+ return(2);
+ return(1);
+}
+
+
+/* @param flag bit0= do not mark image as changed */
+int Xorriso_set_volid(struct XorrisO *xorriso, char *volid, int flag)
+{
+ int ret;
+ IsoImage *volume;
+
+ if(xorriso->in_volset_handle == NULL)
+ return(2);
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+ iso_image_set_volume_id(volume, volid);
+ if(!(flag&1))
+ xorriso->volset_change_pending= 1;
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"Volume ID: '%s'",iso_image_get_volume_id(volume));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
+ return(1);
+}
+
+
+int Xorriso_get_volid(struct XorrisO *xorriso, char volid[33], int flag)
+{
+ int ret;
+ IsoImage *volume;
+
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+ strncpy(volid, iso_image_get_volume_id(volume), 32);
+ volid[32]= 0;
+ return(1);
+}
+
+
+/* @param flag bit0= do not mark image as changed */
+int Xorriso_set_publisher(struct XorrisO *xorriso, char *name, int flag)
+{
+ int ret;
+ IsoImage *volume;
+
+ if(xorriso->in_volset_handle == NULL)
+ return(2);
+ ret= Xorriso_get_volume(xorriso, &volume, 0);
+ if(ret<=0)
+ return(ret);
+ iso_image_set_publisher_id(volume, name);
+ if(!(flag&1))
+ xorriso->volset_change_pending= 1;
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,"Publisher: '%s'",
+ iso_image_get_publisher_id(volume));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
+ return(1);
+}
+
+
+/* @param flag bit0=prepare for a burn run */
+int Xorriso_set_abort_severity(struct XorrisO *xorriso, int flag)
+{
+ int ret;
+
+ /* ??? <<< On MISHAP use FAILURE as abort severity known to libisofs.
+ On ERRFILE use NEVER.
+ The pacifier loop will care for canceling libburn on MISHAP
+ and thus also cancel the image generation.
+ with libisofs-0.6.4 this should not be necessary
+ Shall it be uphold anyway ?
+ */
+ if((flag&1) && strcmp(xorriso->abort_on_text, "MISHAP")==0)
+ ret= iso_set_abort_severity("FAILURE");
+ else if((flag&1) && strcmp(xorriso->abort_on_text, "ERRFILE")==0)
+ ret= iso_set_abort_severity("NEVER");
+ else
+ ret= iso_set_abort_severity(xorriso->abort_on_text);
+ return(ret>=0);
+}
+
+
+int Xorriso_report_lib_versions(struct XorrisO *xorriso, int flag)
+{
+ int major, minor, micro;
+ int req_major, req_minor, req_micro;
+
+ iso_lib_version(&major, &minor, µ);
+ isoburn_libisofs_req(&req_major, &req_minor, &req_micro);
+ sprintf(xorriso->result_line,
+ "libisofs in use : %d.%d.%d (min. %d.%d.%d)\n",
+ major, minor, micro, req_major, req_minor, req_micro);
+ Xorriso_result(xorriso, 0);
+ burn_version(&major, &minor, µ);
+ isoburn_libburn_req(&req_major, &req_minor, &req_micro);
+ sprintf(xorriso->result_line,
+ "libburn in use : %d.%d.%d (min. %d.%d.%d)\n",
+ major, minor, micro, req_major, req_minor, req_micro);
+ Xorriso_result(xorriso, 0);
+ isoburn_version(&major, &minor, µ);
+ sprintf(xorriso->result_line,
+ "libisoburn in use : %d.%d.%d (min. %d.%d.%d)\n",
+ major, minor, micro,
+ isoburn_header_version_major, isoburn_header_version_minor,
+ isoburn_header_version_micro);
+ Xorriso_result(xorriso, 0);
+ return(1);
+}
+
+
+/* @param flag bit0= -inq
+ bit1= -checkdrive
+*/
+int Xorriso_atip(struct XorrisO *xorriso, int flag)
+{
+ int ret, profile_number= 0;
+ char *respt, profile_name[80];
+ double x_speed_max, x_speed_min= -1.0;
+ struct burn_drive_info *dinfo;
+ struct burn_drive *drive;
+ enum burn_disc_status s;
+
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to print drive and media info", 2);
+ if(ret<=0)
+ return(0);
+ respt= xorriso->result_line;
+ sprintf(respt, "Device type :");
+ ret= burn_drive_get_drive_role(drive);
+ if(ret==0)
+ sprintf(respt+strlen(respt), "%s\n", "Emulated (null-drive)");
+ else if(ret==2)
+ sprintf(respt+strlen(respt), "%s\n",
+ "Emulated (stdio-drive, 2k random read-write)");
+ else if(ret==3)
+ sprintf(respt+strlen(respt), "%s\n",
+ "Emulated (stdio-drive, sequential write-only)");
+ else if(ret!=1)
+ sprintf(respt+strlen(respt), "%s\n","Emulated (stdio-drive)");
+ else
+ sprintf(respt+strlen(respt), "%s\n","Removable CD-ROM");
+ sprintf(respt+strlen(respt), "Vendor_info : '%s'\n",dinfo->vendor);
+ sprintf(respt+strlen(respt), "Identifikation : '%s'\n",dinfo->product);
+ sprintf(respt+strlen(respt), "Revision : '%s'\n",dinfo->revision);
+ Xorriso_result(xorriso,1);
+ if(flag&1)
+ return(1);
+ sprintf(respt, "Driver flags : BURNFREE\n");
+ sprintf(respt+strlen(respt), "Supported modes: SAO TAO\n");
+ Xorriso_result(xorriso,1);
+ if(flag&2)
+ return(1);
+
+ s= burn_disc_get_status(drive);
+ ret= burn_disc_get_profile(drive,&profile_number,profile_name);
+ if(ret<=0) {
+ profile_number= 0;
+ strcpy(profile_name, "-unidentified-");
+ }
+ if(s != BURN_DISC_UNSUITABLE) {
+ ret= burn_disc_read_atip(drive);
+ if(ret>0) {
+ ret= burn_drive_get_min_write_speed(drive);
+ x_speed_min= ((double) ret)/176.4;
+ }
+ }
+ if(s==BURN_DISC_EMPTY) {
+ sprintf(respt, "Current: none\n");
+ Xorriso_result(xorriso,1);
+ return(1);
+ } else
+ sprintf(respt, "Current: %s\n",profile_name);
+ Xorriso_result(xorriso,1);
+ if(strstr(profile_name,"DVD")==profile_name) {
+ sprintf(respt, "book type: %s (emulated booktype)\n", profile_name);
+ Xorriso_result(xorriso,1);
+ sprintf(respt, "xorriso: message for sdvdbackup: \"(growisofs mode Restricted Overwrite)\"\n");
+ Xorriso_result(xorriso,1);
+ } else {
+ sprintf(respt, "ATIP info from disk:\n");
+ Xorriso_result(xorriso,1);
+ if(burn_disc_erasable(drive))
+ sprintf(respt, " Is erasable\n");
+ else
+ sprintf(respt, " Is not erasable\n");
+ Xorriso_result(xorriso,1);
+ { int start_lba,end_lba,min,sec,fr;
+ ret= burn_drive_get_start_end_lba(drive,&start_lba,&end_lba,0);
+ if(ret>0) {
+ burn_lba_to_msf(start_lba,&min,&sec,&fr);
+ sprintf(respt, " ATIP start of lead in: %d (%-2.2d:%-2.2d/%-2.2d)\n",
+ start_lba,min,sec,fr);
+ Xorriso_result(xorriso,1);
+ burn_lba_to_msf(end_lba,&min,&sec,&fr);
+ sprintf(respt, " ATIP start of lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n",
+ end_lba,min,sec,fr);
+ Xorriso_result(xorriso,1);
+ }
+ }
+ ret= burn_drive_get_write_speed(drive);
+ x_speed_max= ((double) ret)/176.4;
+ if(x_speed_min<0)
+ x_speed_min= x_speed_max;
+ sprintf(respt,
+ " 1T speed low: %.f 1T speed high: %.f\n",x_speed_min,x_speed_max);
+ Xorriso_result(xorriso,1);
+ }
+ return(1);
+}
+
+
+int Xorriso_burn_track(struct XorrisO *xorriso, char *track_source, int flag)
+{
+ int ret, fd, unpredicted_size, profile_number, is_cd= 0;
+ struct burn_drive_info *dinfo;
+ struct burn_drive *drive;
+ struct burn_write_opts *burn_options;
+ struct burn_disc *disc= NULL;
+ struct burn_session *session;
+ struct burn_track *track;
+ struct stat stbuf;
+ off_t fixed_size= 0;
+ struct burn_source *data_src, *fifo_src;
+ enum burn_disc_status disc_state;
+ char reasons[BURN_REASONS_LEN], sfe[5*SfileadrL], profile_name[80];
+
+
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to burn track", 2);
+ if(ret<=0)
+ return(0);
+ ret= Xorriso_make_write_options(xorriso, drive, &burn_options, 0);
+ if(ret<=0)
+ goto ex;
+
+ disc= burn_disc_create();
+ session= burn_session_create();
+ ret= burn_disc_add_session(disc,session,BURN_POS_END);
+ if(ret==0) {
+ /* >>> */;
+ goto ex;
+ }
+ track= burn_track_create();
+ if(track_source[0] == '-' && track_source[1] == 0) {
+ fd= 0;
+ } else {
+ fd= open(track_source, O_RDONLY);
+ if(fd>=0)
+ if(fstat(fd,&stbuf)!=-1)
+ if((stbuf.st_mode&S_IFMT)==S_IFREG)
+ fixed_size= stbuf.st_size;
+ }
+ if(fixed_size==0)
+ unpredicted_size= 1;
+
+ data_src= NULL;
+ if(fd>=0)
+ data_src= burn_fd_source_new(fd, -1, fixed_size);
+ if(data_src==NULL) {
+ sprintf(xorriso->info_text, "Could not open data source %s",
+ Text_shellsafe(track_source,sfe,0));
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+ fifo_src= burn_fifo_source_new(data_src, 2048, xorriso->fs, 0);
+ if(fifo_src == NULL) {
+ sprintf(xorriso->info_text, "Could not create fifo object of 4 MB");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ ret= 0; goto ex;
+ }
+ xorriso->pacifier_fifo= fifo_src;
+ if(burn_track_set_source(track, fifo_src)!=BURN_SOURCE_OK) {
+ sprintf(xorriso->info_text,
+ "Cannot attach source object to track object");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
+ ret= 0; goto ex;
+ }
+ burn_session_add_track(session, track, BURN_POS_END);
+ burn_source_free(data_src);
+
+ disc_state = burn_disc_get_status(drive);
+ if(disc_state == BURN_DISC_BLANK) {
+ /* ok */;
+ } else if(disc_state == BURN_DISC_APPENDABLE) {
+ if(!isoburn_needs_emulation(drive)) {
+ sprintf(xorriso->info_text,
+ "Appendable media with data detected. Need blank media.");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+ } else {
+ if(disc_state == BURN_DISC_FULL) {
+ sprintf(xorriso->info_text,
+ "Closed media with data detected. Need blank media.");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ if(burn_disc_erasable(drive)) {
+ sprintf(xorriso->info_text, "Try --blank_fast\n");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "HINT", 0);
+ }
+ } else if(disc_state == BURN_DISC_EMPTY) {
+ sprintf(xorriso->info_text, "No media detected in drive");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ } else {
+ sprintf(xorriso->info_text,
+ "Cannot recognize state of drive and media");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ }
+ ret= 0; goto ex;
+ }
+ if(burn_write_opts_auto_write_type(burn_options, disc, reasons, 0) ==
+ BURN_WRITE_NONE) {
+ sprintf(xorriso->info_text,
+ "Failed to find a suitable write mode with this media.\n");
+ sprintf(xorriso->info_text+strlen(xorriso->info_text),
+ "Reasons given:\n%s", reasons);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+
+ ret= Xorriso_get_profile(xorriso, &profile_number, profile_name, 2);
+ is_cd= (ret==2);
+ if(isoburn_needs_emulation(drive))
+ burn_write_opts_set_start_byte(burn_options, (off_t) 0);
+ ret= Xorriso_sanitize_image_size(xorriso, drive, disc, burn_options, 2);
+ if(ret<=0)
+ goto ex;
+
+ xorriso->run_state= 1; /* Indicate that burning has started */
+ burn_disc_write(burn_options, disc);
+
+ ret= Xorriso_pacifier_loop(xorriso, drive, 1|(is_cd<<4));
+ if(ret<=0)
+ goto ex;
+ if(!burn_drive_wrote_well(drive)) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,
+ "libburn indicates failure with writing.");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ ret= 0; goto ex;
+ }
+
+ sprintf(xorriso->info_text, "Writing completed sucessfully.\n\n");
+ Xorriso_info(xorriso, 0);
+ ret= 1;
+ex:;
+ Xorriso_process_msg_queues(xorriso,0);
+ if(disc!=NULL)
+ burn_disc_free(disc);
+ if(xorriso->pacifier_fifo!=NULL)
+ burn_source_free(xorriso->pacifier_fifo);
+ xorriso->pacifier_fifo= NULL;
+ xorriso->run_state= 0; /* Indicate that burning has ended */
+ return(ret);
+}
+
+
+
+/* @param flag bit1= outdev rather than indev
+ @return <0 error, 0 = no profile to see , 1= ok , 2= ok, is CD profile
+*/
+int Xorriso_get_profile(struct XorrisO *xorriso, int *profile_number,
+ char profile_name[80], int flag)
+{
+ int ret;
+ struct burn_drive_info *dinfo;
+ struct burn_drive *drive;
+
+ *profile_number= 0;
+ profile_name[0]= 0;
+ if(xorriso->out_drive_handle==NULL)
+ return(0);
+ ret= Xorriso_get_drive_handles(xorriso, &dinfo, &drive,
+ "on attempt to determine media type", flag&2);
+ if(ret<=0)
+ return(0);
+ ret=burn_disc_get_profile(drive, profile_number, profile_name);
+ if(ret<=0)
+ return(ret);
+ if(*profile_number==0x08 || *profile_number==0x09 || *profile_number==0x0a)
+ return(2);
+ return(0);
+}
+
+
+int Xorriso_iso_file_open(struct XorrisO *xorriso, char *pathname,
+ void **stream, int flag)
+{
+ int ret;
+ char eff_path[SfileadrL];
+ IsoNode *node= NULL;
+ IsoFile *filenode= NULL;
+ IsoStream *iso_stream= NULL;
+
+#ifdef Libisofs_lba_tesT
+ uint32_t lba;
+#endif
+
+ *stream= NULL;
+ ret= Xorriso_get_node_by_path(xorriso, pathname, eff_path, &node, 0);
+ if(ret<=0)
+ return(ret);
+ if(!LIBISO_ISREG(node)) {
+ sprintf(xorriso->info_text,
+ "Given path does not lead to a regular data file in the image");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+
+#ifdef Libisofs_lba_tesT
+ ret = iso_node_get_old_image_lba(node, &lba, 0);
+ sprintf(xorriso->info_text, "%s : ret= %d , LBA= %lx",
+ pathname, ret, (unsigned long) lba);
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "DEBUG", 0);
+#endif
+
+ filenode= (IsoFile *) node;
+ iso_stream= iso_file_get_stream(filenode);
+ if(iso_stream==NULL) {
+ Xorriso_process_msg_queues(xorriso,0);
+ sprintf(xorriso->info_text,
+ "Could not obtain source stream of file in the image for reading");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+ ret= iso_stream_open(iso_stream);
+ if(ret<0) {
+ sprintf(xorriso->info_text,
+ "Could not open data file in the image for reading");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ return(0);
+ }
+ if(!iso_stream_is_repeatable(iso_stream)) {
+ sprintf(xorriso->info_text,
+ "The data production of the file in the image is one-time only");
+ Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
+ iso_stream_close(iso_stream);
+ return(0);
+ }
+ Xorriso_process_msg_queues(xorriso,0);
+ *stream= iso_stream;
+ return(1);
+}
+
+
+int Xorriso_iso_file_read(struct XorrisO *xorriso, void *stream, char *buf,
+ int count, int flag)
+{
+ int ret, rcnt= 0;
+ IsoStream *stream_pt;
+
+ stream_pt= (IsoStream *) stream;
+
+ while(rcnt
+
+ Provided under GPL version 2.
+
+ This file contains the inner isofs- and burn-library interface of xorriso.
+*/
+
+#ifndef Xorrisoburn_includeD
+#define Xorrisoburn_includeD yes
+
+struct XorrisO;
+struct FindjoB;
+
+/* The minimum version of libisoburn to be used with this version of xorriso
+*/
+#define xorriso_libisoburn_req_major 0
+#define xorriso_libisoburn_req_minor 1
+#define xorriso_libisoburn_req_micro 0
+
+int Xorriso_startup_libraries(struct XorrisO *xorriso, int flag);
+
+/* @param flag bit0= global shutdown of libraries */
+int Xorriso_detach_libraries(struct XorrisO *xorriso, int flag);
+
+int Xorriso_create_empty_iso(struct XorrisO *xorriso, int flag);
+
+/* @param flag bit0=aquire as isoburn input drive
+ bit1=aquire as libburn output drive (as isoburn drive if bit0)
+ @return <=0 failure , 1=success , 2=neither readable or writeable
+*/
+int Xorriso_aquire_drive(struct XorrisO *xorriso, char *adr, int flag);
+
+int Xorriso_give_up_drive(struct XorrisO *xorriso, int flag);
+
+int Xorriso_write_session(struct XorrisO *xorriso, int flag);
+
+/* @param boss_iter Opaque handle to be forwarded to actions in ISO image
+ Set to NULL if calling this function from outside ISO world
+ @param flag bit0= mkdir: graft in as empty directory, not as copy from disk
+ bit1= do not report added files
+ @return <=0 = error , 1 = added simple node , 2 = added directory
+*/
+int Xorriso_graft_in(struct XorrisO *xorriso, void *boss_iter,
+ char *disk_path, char *img_path, int flag);
+
+int Xorriso__text_to_sev(char *severity_name, int *severity_number,int flag);
+
+/* @param flag bit0=report about output drive
+ bit1=short report form
+*/
+int Xorriso_toc(struct XorrisO *xorriso, int flag);
+
+int Xorriso_show_devices(struct XorrisO *xorriso, int flag);
+
+int Xorriso_tell_media_space(struct XorrisO *xorriso,
+ int *media_space, int *free_space, int flag);
+
+int Xorriso_blank_media(struct XorrisO *xorriso, int flag);
+
+int Xorriso_format_media(struct XorrisO *xorriso, int flag);
+
+/* @param boss_iter Opaque internal handle. Use NULL outside xorrisoburn.c :
+ If not NULL then this is an iterator suitable for
+ iso_dir_iter_remove() which is then to be used instead
+ of iso_node_remove().
+ @param flag bit0= remove whole sub tree: rm -r
+ bit1= remove empty directory: rmdir
+ bit2= recursion: do not reassure in mode 2 "tree"
+ bit3= this is for overwriting and not for plain removal
+ @return <=0 = error
+ 1 = removed simple node
+ 2 = removed directory or tree
+ 3 = did not remove on user revocation
+*/
+int Xorriso_rmi(struct XorrisO *xorriso, void *boss_iter, off_t boss_mem,
+ char *path, int flag);
+
+/* @param flag bit0= long format
+ bit1= do not print count of nodes
+ bit2= du format
+ bit3= print directories as themselves (ls -d)
+*/
+int Xorriso_ls_filev(struct XorrisO *xorriso, char *wd,
+ int filec, char **filev, off_t boss_mem, int flag);
+
+/* This function needs less buffer memory than Xorriso_ls_filev() but cannot
+ perform structured pattern matching.
+ @param flag bit0= long format
+ bit1= only check for directory existence
+ bit2= do not apply search pattern but accept any file
+ bit3= just count nodes and return number
+*/
+int Xorriso_ls(struct XorrisO *xorriso, int flag);
+
+/* @param wd Path to prepend in case img_path is not absolute
+ @param img_path Absolute or relative path to be normalized
+ @param eff_path returns resulting effective path.
+ Must provide at least SfileadrL bytes of storage.
+ @param flag bit0= do not produce problem events (unless faulty path format)
+ bit1= work purely literally, do not use libisofs
+ bit2= (with bit1) this is an address in the disk world
+ @return -1 = faulty path format, 0 = not found ,
+ 1 = found simple node , 2 = found directory
+*/
+int Xorriso_normalize_img_path(struct XorrisO *xorriso, char *wd,
+ char *img_path, char eff_path[], int flag);
+
+/* @param boss_iter Opaque handle to be forwarded to actions in ISO image
+ Set to NULL if calling this function from outside ISO world
+*/
+int Xorriso_rename(struct XorrisO *xorriso, void *boss_iter,
+ char *origin, char *dest, int flag);
+
+/* @param flag bit0= do not produce info message on success
+ @return 1=success, 0=was already directory, -1=was other type, -2=bad path
+*/
+int Xorriso_mkdir(struct XorrisO *xorriso, char *img_path, int flag);
+
+/* @param flag bit0= a match count !=1 is a SORRY event */
+int Xorriso_expand_pattern(struct XorrisO *xorriso,
+ int num_patterns, char **patterns, int extra_filec,
+ int *filec, char ***filev, off_t *mem, int flag);
+
+int Xorriso_set_st_mode(struct XorrisO *xorriso, char *path,
+ mode_t mode_and, mode_t mode_or, int flag);
+
+int Xorriso_set_uid(struct XorrisO *xorriso, char *in_path, uid_t uid,
+ int flag);
+
+int Xorriso_set_gid(struct XorrisO *xorriso, char *in_path, gid_t gid,
+ int flag);
+
+/* @parm flag bit0= atime, bit1= ctime, bit2= mtime, bit8=no auto ctime */
+int Xorriso_set_time(struct XorrisO *xorriso, char *in_path, time_t t,
+ int flag);
+
+/* @param flag bit0= recursion
+ bit1= do not count deleted files with rm and rm_r
+*/
+int Xorriso_findi(struct XorrisO *xorriso, struct FindjoB *job,
+ void *boss_iter, off_t boss_mem,
+ void *dir_node_generic, char *dir_path,
+ struct stat *dir_stbuf, int depth, int flag);
+
+/* @param flag bit0= do not mark image as changed */
+int Xorriso_set_volid(struct XorrisO *xorriso, char *volid, int flag);
+
+int Xorriso_get_volid(struct XorrisO *xorriso, char volid[33], int flag);
+
+int Xorriso_set_abort_severity(struct XorrisO *xorriso, int flag);
+
+int Xorriso_report_lib_versions(struct XorrisO *xorriso, int flag);
+
+/* @return 0= stbuf content is valid , -1 = path not found */
+int Xorriso_iso_lstat(struct XorrisO *xorriso, char *path, struct stat *stbuf,
+ int flag);
+
+/* @param flag bit0= -inq
+ bit1= -checkdrive
+*/
+int Xorriso_atip(struct XorrisO *xorriso, int flag);
+
+int Xorriso_burn_track(struct XorrisO *xorriso, char *track_source, int flag);
+
+/* @param flag bit1= outdev rather than indev
+ @return <=0 = failure , 1= ok , 2= ok, is CD profile
+*/
+int Xorriso_get_profile(struct XorrisO *xorriso, int *profile_number,
+ char profile_name[80], int flag);
+
+/* @param flag bit0= do not mark image as changed */
+int Xorriso_set_publisher(struct XorrisO *xorriso, char *name, int flag);
+
+
+int Xorriso_iso_file_open(struct XorrisO *xorriso, char *pathname,
+ void **stream, int flag);
+
+int Xorriso_iso_file_read(struct XorrisO *xorriso, void *stream, char *buf,
+ int count, int flag);
+
+int Xorriso_iso_file_close(struct XorrisO *xorriso, void **stream, int flag);
+
+/* @param bit0= copy link target properties rather than link properties
+*/
+int Xorriso_copy_properties(struct XorrisO *xorriso,
+ char *disk_path, char *img_path, int flag);
+
+#endif /* Xorrisoburn_includeD */
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/AUTHORS b/libisofs/tags/ForXorrisoZeroOneTwo/AUTHORS
new file mode 100644
index 00000000..4b186770
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/AUTHORS
@@ -0,0 +1,3 @@
+Vreixo Formoso
+Mario Danic
+Thomas Schmitt
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/COPYING b/libisofs/tags/ForXorrisoZeroOneTwo/COPYING
new file mode 100644
index 00000000..5a965fbc
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/COPYING
@@ -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
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/COPYRIGHT b/libisofs/tags/ForXorrisoZeroOneTwo/COPYRIGHT
new file mode 100644
index 00000000..8d562a3d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/COPYRIGHT
@@ -0,0 +1,19 @@
+Vreixo Formoso ,
+Mario Danic ,
+Thomas Schmitt
+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
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/ChangeLog b/libisofs/tags/ForXorrisoZeroOneTwo/ChangeLog
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/ChangeLog
@@ -0,0 +1 @@
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/INSTALL b/libisofs/tags/ForXorrisoZeroOneTwo/INSTALL
new file mode 100644
index 00000000..5458714e
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/INSTALL
@@ -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.
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/Makefile.am b/libisofs/tags/ForXorrisoZeroOneTwo/Makefile.am
new file mode 100644
index 00000000..6101ec9c
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/Makefile.am
@@ -0,0 +1,191 @@
+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/find.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/filter.h \
+ libisofs/filter.c \
+ libisofs/filters/xor_encrypt.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
+libisofs_libisofs_la_LIBADD= \
+ $(THREAD_LIBS)
+libinclude_HEADERS = \
+ libisofs/libisofs.h
+
+## ========================================================================= ##
+
+## Build demo applications
+noinst_PROGRAMS = \
+ demo/lsl \
+ demo/cat \
+ demo/catbuffer \
+ demo/tree \
+ demo/find \
+ 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_find_CPPFLAGS = -Ilibisofs
+demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
+demo_find_SOURCES = demo/find.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
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/NEWS b/libisofs/tags/ForXorrisoZeroOneTwo/NEWS
new file mode 100644
index 00000000..8acff7bc
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/NEWS
@@ -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
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/README b/libisofs/tags/ForXorrisoZeroOneTwo/README
new file mode 100644
index 00000000..1ead917f
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/README
@@ -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
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/Roadmap b/libisofs/tags/ForXorrisoZeroOneTwo/Roadmap
new file mode 100644
index 00000000..926ecef6
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/Roadmap
@@ -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
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/TODO b/libisofs/tags/ForXorrisoZeroOneTwo/TODO
new file mode 100644
index 00000000..bad313fc
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/TODO
@@ -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
+=====
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/acinclude.m4 b/libisofs/tags/ForXorrisoZeroOneTwo/acinclude.m4
new file mode 100644
index 00000000..861847bb
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/acinclude.m4
@@ -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])
+])
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/bootstrap b/libisofs/tags/ForXorrisoZeroOneTwo/bootstrap
new file mode 100755
index 00000000..86709bfc
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/bootstrap
@@ -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
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/configure.ac b/libisofs/tags/ForXorrisoZeroOneTwo/configure.ac
new file mode 100644
index 00000000..69b7dc5e
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/configure.ac
@@ -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 ])
+
+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 ])
+
+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 ])
+
+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
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/cat.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/cat.c
new file mode 100644
index 00000000..a95eebc3
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/cat.c
@@ -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
+#include
+
+/*
+ * 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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/cat_buffer.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/cat_buffer.c
new file mode 100644
index 00000000..74657ee2
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/cat_buffer.c
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * 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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/ecma119_tree.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/ecma119_tree.c
new file mode 100644
index 00000000..e1c4dbec
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/ecma119_tree.c
@@ -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
+#include
+#include
+#include
+#include
+#include
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso.c
new file mode 100644
index 00000000..f3783b08
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso.c
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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 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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_cat.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_cat.c
new file mode 100644
index 00000000..452d1b12
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_cat.c
@@ -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
+#include
+
+#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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_grow.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_grow.c
new file mode 100644
index 00000000..951aec1b
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_grow.c
@@ -0,0 +1,257 @@
+/*
+ * Very simple program to show how to grow an iso image.
+ */
+
+#include "libisofs.h"
+#include "libburn/libburn.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_modify.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_modify.c
new file mode 100644
index 00000000..85404ce4
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_modify.c
@@ -0,0 +1,109 @@
+/*
+ * Little program to show how to modify an iso image.
+ */
+
+#include "libisofs.h"
+#include "libburn/libburn.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_ms.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_ms.c
new file mode 100644
index 00000000..563c9d4d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_ms.c
@@ -0,0 +1,114 @@
+/*
+ * Little program to show how to create a multisession iso image.
+ */
+
+#include "libisofs.h"
+#include "libburn/libburn.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_read.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_read.c
new file mode 100644
index 00000000..de30717a
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/iso_read.c
@@ -0,0 +1,167 @@
+/*
+ * Little program to output the contents of an iso image.
+ */
+
+
+#include
+#include
+#include
+#include
+
+#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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/lsl.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/lsl.c
new file mode 100644
index 00000000..17659f75
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/lsl.c
@@ -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
+#include
+#include
+
+/*
+ * 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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/demo/tree.c b/libisofs/tags/ForXorrisoZeroOneTwo/demo/tree.c
new file mode 100644
index 00000000..6dddbb99
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/demo/tree.c
@@ -0,0 +1,107 @@
+/*
+ * Little program that import a directory and prints the resulting iso tree.
+ */
+
+#include "libisofs.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/Tutorial b/libisofs/tags/ForXorrisoZeroOneTwo/doc/Tutorial
new file mode 100755
index 00000000..6de705bd
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/Tutorial
@@ -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
+-------------------------------------------------------------------------------
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/Wiki b/libisofs/tags/ForXorrisoZeroOneTwo/doc/Wiki
new file mode 100755
index 00000000..c9f6f8e1
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/Wiki
@@ -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.
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/1. Overview b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/1. Overview
new file mode 100644
index 00000000..e69de29b
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/2. Features b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/2. Features
new file mode 100644
index 00000000..89501e38
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/2. Features
@@ -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
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/3. Use Cases b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/3. Use Cases
new file mode 100644
index 00000000..e6e17f0f
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/3. Use Cases
@@ -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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/4. Design b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/4. Design
new file mode 100644
index 00000000..e69de29b
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/5. Implementation b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/5. Implementation
new file mode 100644
index 00000000..e69de29b
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/README b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/README
new file mode 100644
index 00000000..75face44
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/README
@@ -0,0 +1,7 @@
+Index
+=====
+
+1. Overview
+2. Features
+3. Design
+4. Implementation
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/BuilderSec.png b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/BuilderSec.png
new file mode 100644
index 00000000..a89203ee
Binary files /dev/null and b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/BuilderSec.png differ
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/BuilderSec.violet b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/BuilderSec.violet
new file mode 100644
index 00000000..c7e7fbf5
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/BuilderSec.violet
@@ -0,0 +1,821 @@
+
+
+
+
+
+
+
+ fs:Filesystem
+
+
+
+
+
+ 160.0
+ 73.0
+
+
+
+
+
+
+
+
+
+ file:FileSource
+
+
+
+
+
+
+
+
+
+
+ 192.0
+ 209.0
+
+
+
+
+
+
+
+ 274.0
+ 202.0
+
+
+
+
+
+
+
+ User
+
+
+
+
+
+ 34.86475730998367
+ 0.0
+
+
+
+
+
+
+
+
+
+
+
+
+ b:TNBuilder
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ftn:FileTN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ fs:FileStream
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ d:DirTreeNode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 66.86475730998367
+ 80.0
+
+
+
+
+
+
+
+ 539.756828460011
+ 126.0
+
+
+
+
+
+
+
+ 651.0
+ 0.0
+
+
+
+
+
+
+
+ 683.0
+ 305.0
+
+
+
+
+
+
+
+ 571.756828460011
+ 328.0
+
+
+
+
+
+
+
+ 306.0
+ 351.0
+
+
+
+
+
+
+
+ 331.97135964975513
+ 374.0
+
+
+
+
+
+
+
+ 363.97135964975513
+ 457.0
+
+
+
+
+
+
+
+ 418.8259109283281
+ 480.0
+
+
+
+
+
+
+
+ 363.97135964975513
+ 563.0
+
+
+
+
+
+
+
+ 1. User wants to add a file to a dir in the iso node
+
+
+
+
+
+ 143.89406091532933
+ 16.868736840587744
+
+
+
+
+
+
+
+ 2. It creates the source filesystem and the
+ custom builder
+
+
+
+
+
+ 317.51829970572646
+ 74.92004824517142
+
+
+
+
+
+
+
+ 570.819415201306
+ 142.7048538003265
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 570.819415201306
+ 142.7048538003265
+
+
+
+
+
+
+
+ 218.81410916050066
+ 114.16388304026121
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 218.81410916050066
+ 114.16388304026121
+
+
+
+
+
+
+
+ 3. It gets the file from the filesystem
+and add it to parent dir
+
+
+
+
+
+ 379.1320632384976
+ 217.4323774110454
+
+
+
+
+
+
+
+ 327.03195662574825
+ 218.46075295682857
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 327.03195662574825
+ 218.46075295682857
+
+
+
+
+
+
+
+ 4. The dir delegates in the builder.
+5. The builder stat's the source file. In
+ this example it's a reg. file
+
+
+
+
+
+ 767.038589176755
+ 206.92203801047344
+
+
+
+
+
+
+
+ 694.4969551615891
+ 312.7614712457156
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 694.4969551615891
+ 312.7614712457156
+
+
+
+
+
+
+
+ 314.9148790283507
+ 359.23720542189034
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 314.9148790283507
+ 359.23720542189034
+
+
+
+
+
+
+
+ 6. The conversion is not needed, so
+the builder just creates a FileTreeNode
+
+
+
+
+
+ 762.2817607167442
+ 335.3564064307673
+
+
+
+
+
+
+
+ 522.2869299335649
+ 399.9594286575042
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 522.2869299335649
+ 399.9594286575042
+
+
+
+
+
+
+
+ 7. Sets the attributes from source
+
+
+
+
+
+ 774.1738318667714
+ 413.8440760209469
+
+
+
+
+
+
+
+ 8 ...and a FileStream to read contents
+ from the FileSource
+
+
+
+
+
+ 762.2817607167442
+ 478.0612602310938
+
+
+
+
+
+
+
+ 534.9181953038541
+ 453.1845675071054
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 534.9181953038541
+ 453.1845675071054
+
+
+
+
+
+
+
+ 482.368075796364
+ 524.8261757327898
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 482.368075796364
+ 524.8261757327898
+
+
+
+
+
+
+
+ 9. Finally, the FileTreeNode is added to
+ the parent dir, and returned to the user
+
+
+
+
+
+ 757.5249322567332
+ 556.5489298212734
+
+
+
+
+
+
+
+ 689.7401267015781
+ 614.8200784564067
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 689.7401267015781
+ 614.8200784564067
+
+
+
+
+
+
+
+ 363.97135964975513
+ 656.0
+
+
+
+
+
+
+
+ 10. The user can change any attribute
+ on the FileTreeNode
+
+
+
+
+
+ 735.3910524340093
+ 659.0235200658623
+
+
+
+
+
+
+
+ 373.3523804664971
+ 666.0945878777277
+ 0.0
+ 0.0
+
+
+
+
+
+
+
+
+ 373.3523804664971
+ 666.0945878777277
+
+
+
+
+
+
+ «create»
+
+
+
+
+
+
+
+
+ «create»
+
+
+
+
+
+
+
+
+
+
+
+ file
+
+
+
+
+
+
+
+
+ add_file(file,b)
+
+
+
+
+
+
+
+
+ create_file(file)
+
+
+
+
+
+
+
+
+ lstat()
+
+
+
+
+
+
+
+
+ S_IFREG
+
+
+
+
+
+
+
+
+ «create»
+
+
+
+
+
+
+
+
+ set attributes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ftn
+
+
+
+
+
+
+
+
+ «create»
+
+
+
+
+
+
+
+
+ set stream (fs)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ftn
+
+
+
+
+
+
+
+
+ «create»
+
+
+
+
+
+
+
+
+ get(path)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ set_permission()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/builder.violet b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/builder.violet
new file mode 100644
index 00000000..3dba303d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/builder.violet
@@ -0,0 +1,884 @@
+
+
+
+
+
+
+
+ get_root()
+get_from_path(char *)
+
+
+
+
+ «interface»
+Filesystem
+
+
+
+
+
+ 159.04005306497305
+ 489.4913761627291
+
+
+
+
+
+
+
+ MountedFilesytem
+
+
+
+
+
+ 56.38849919058573
+ 630.9884605487425
+
+
+
+
+
+
+
+ IsoImage
+
+
+
+
+
+ 258.8562868808994
+ 766.3563832139356
+
+
+
+
+
+
+
+ lstat()
+read()
+close()
+open()
+readdir()
+
+
+
+
+ «interface»
+SourceFile
+
+
+
+
+
+ 481.55979910778467
+ 464.84194569982117
+
+
+
+
+
+
+
+ TarFile
+
+
+
+
+
+ 176.58261638364775
+ 701.0593878047844
+
+
+
+
+
+
+
+ read()
+size()
+open()
+close()
+
+
+
+
+ «interface»
+Stream
+
+
+
+
+
+ 779.894860994415
+ 340.36024540554786
+
+
+
+
+
+
+
+ FdStream
+
+
+
+
+
+ 907.9433913981195
+ 505.6600343909271
+
+
+
+
+
+
+
+ FileStream
+
+
+
+
+
+ 646.2536512193697
+ 514.5953286599063
+
+
+
+
+
+
+
+ TransformStream
+
+
+
+
+
+ 774.6238447615127
+ 513.9203093177954
+
+
+
+
+
+
+
+ create_file()
+create_symlink()
+create_dir()
+
+
+
+
+ «interface»
+TreeNodeBuilder
+
+
+
+
+
+ 469.51180397870456
+ 119.92057094444797
+
+
+
+
+
+
+
+ TreeNode
+
+
+
+
+
+ 777.5164467644091
+ 137.7586776694888
+
+
+
+
+
+
+
+ File
+
+
+
+
+
+ 776.3272396494064
+ 235.11044131455145
+
+
+
+
+
+
+
+ Dir
+
+
+
+
+
+ 899.7797731623193
+ 242.40651557378732
+
+
+
+
+
+
+
+ Symlink
+
+
+
+
+
+ 658.5957352641371
+ 237.4888555445569
+
+
+
+
+
+
+
+ «interface»
+FileBuilder
+
+
+
+
+
+ 68.74900622278733
+ 236.29964842955417
+
+
+
+
+
+
+
+ «interface»
+DirBuilder
+
+
+
+
+
+ 190.04813195306485
+ 236.2996484295542
+
+
+
+
+
+
+
+ «interface»
+SymlinkBuilder
+
+
+
+
+
+ 304.21201499332614
+ 236.29964842955417
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+ 154.8805850420814
+ 333.9382491299707
+
+
+
+
+
+
+
+ "Sources" for file contents
+
+
+
+
+
+ 587.0127806828101
+ 358.755499461917
+
+
+
+
+
+
+
+ CutOutStream
+
+
+
+
+
+ 845.6997102991108
+ 605.2834046956852
+
+
+
+
+
+
+
+ FilterStream
+
+
+
+
+
+ 721.2489168102784
+ 605.2834046956852
+
+
+
+
+
+
+
+ «interface»
+Filter
+
+
+
+
+
+ 715.5920625607861
+ 705.6925676241749
+
+
+
+
+
+
+
+ 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
+
+
+
+
+
+ 906.5108934811542
+ 328.0975464705584
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+ 654.7808793787427
+ 20.610173055266337
+
+
+
+
+
+
+
+ Together with the SourceFile encapsulates the
+access to a given filesystem and abstracts it to
+a POSIX interface.
+
+
+
+
+
+ 20.610173055266422
+ 403.050865276332
+
+
+
+
+
+
+
+ The TreeNodeBuilder can be created with
+the combination of different interfaces for
+each factory method
+
+
+
+
+
+ 149.90663761154804
+ 57.982756057296896
+
+
+
+
+
+
+
+ MountedSrc
+
+
+
+
+
+ 373.3523804664971
+ 634.9818895055197
+
+
+
+
+
+
+
+ TarSrc
+
+
+
+
+
+ 479.4183976444791
+ 695.7930726875627
+
+
+
+
+
+
+
+ IsoSrc
+
+
+
+
+
+ 578.4133470105959
+ 773.574818618083
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{create}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/builder.violet.png b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/builder.violet.png
new file mode 100644
index 00000000..6884fe9a
Binary files /dev/null and b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/builder.violet.png differ
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/burn_source.class.violet b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/burn_source.class.violet
new file mode 100644
index 00000000..f5b3654a
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/burn_source.class.violet
@@ -0,0 +1,634 @@
+
+
+
+
+
+
+
+
+
+ «interface»
+BurnSource
+
+
+
+
+
+ libburn
+
+
+
+
+ 600.0
+ 50.0
+
+
+
+
+
+
+
+ 612.4370214406964
+ 81.3237865499184
+
+
+
+
+
+
+
+ Ecma119Source
+
+
+
+
+
+ 604.1172144213822
+ 242.59825146055505
+
+
+
+
+
+
+
+ WriterState
+
+
+
+
+
+ 861.1034292438676
+ 244.31119796826698
+
+
+
+
+
+
+
+ FilesWriterSt
+
+
+
+
+
+ 984.2531292100068
+ 359.95094883087904
+
+
+
+
+
+
+
+ VolDescWriterSt
+
+
+
+
+
+ 717.2457054234224
+ 357.4185959653686
+
+
+
+
+
+
+
+ DirInfoWriterSt
+
+
+
+
+
+ 854.6043620021998
+ 355.85097462036043
+
+
+
+
+
+
+
+ Ecma119Image
+
+
+
+
+
+ 392.3294860655768
+ 240.39714472372754
+
+
+
+
+
+
+
+ The context data for image burn sources, contains
+references to the tree, creation options...
+
+
+
+
+
+ 261.45257180386454
+ 85.80450046553075
+
+
+
+
+
+
+
+ Ecma119Node
+
+
+
+
+
+ 291.8219414851778
+ 612.806815288254
+
+
+
+
+
+
+
+ init()
+write_voldesc()
+write_dir_info()
+
+
+
+
+ «interface»
+ImageWriter
+
+
+
+
+
+ 401.9520048709197
+ 344.8700633507891
+
+
+
+
+
+
+
+ JolietNode
+
+
+
+
+
+ 409.0872475609359
+ 614.8200784564067
+
+
+
+
+
+
+
+ FileRegistry
+
+
+
+
+
+ 718.2810974616434
+ 459.0339463910502
+
+
+
+
+
+
+
+ Ecma119Writer
+
+
+
+
+
+ 273.51763645062584
+ 489.95333138112096
+
+
+
+
+
+
+
+ JolietWriter
+
+
+
+
+
+ 404.3304191009253
+ 485.1965029211101
+
+
+
+
+
+
+
+ ElToritoWriter
+
+
+
+
+
+ 512.5482665661723
+ 485.19650292111
+
+
+
+
+
+
+
+ size : off_t
+block : uint32_t
+
+
+
+
+ IsoFile
+
+
+
+
+
+ 720.659511691649
+ 568.4410009713001
+
+
+
+
+
+
+
+ «interface»
+Stream
+
+
+
+
+
+ 909.7434429770816
+ 580.3330721213274
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+ 2.3784142300054896
+ 160.54296052536733
+
+
+
+
+
+
+
+ The files are registered into the file registry, that will take care
+about the written of content.
+
+
+
+
+
+ 286.59891471565567
+ 708.7674405416217
+
+
+
+
+
+
+
+ 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
+
+
+
+
+
+ 765.8493820617523
+ 132.001989765302
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ *
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ *
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/burn_source.png b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/burn_source.png
new file mode 100644
index 00000000..5786ab29
Binary files /dev/null and b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/burn_source.png differ
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/eltorito.violet b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/eltorito.violet
new file mode 100644
index 00000000..b8a7d01c
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/eltorito.violet
@@ -0,0 +1,552 @@
+
+
+
+
+
+
+
+ Volume
+
+
+
+
+
+ 479.2699858975891
+ 226.94112549695433
+
+
+
+
+
+
+
+ block : uint32_t
+
+
+
+
+ ElToritoCatalog
+
+
+
+
+
+ 472.58578643762684
+ 344.73506473629425
+
+
+
+
+
+
+
+ bootable : bool
+type : enum
+partition_type : enum
+load_seg : uint16
+load_size : uint16
+patch_isolinux : bool
+block: uint32_t
+
+
+
+
+ BootImage
+
+
+
+
+
+ 470.4142135623731
+ 487.3919189857866
+
+
+
+
+
+
+
+ In a future we can support several boot
+images
+
+
+
+
+
+ 251.63542622468316
+ 429.69343417595167
+
+
+
+
+
+
+
+ img : boolean
+
+
+
+
+ BootNode
+
+
+
+
+
+ 193.07106781186545
+ 334.49242404917493
+
+
+
+
+
+
+
+
+
+ TreeNode
+
+
+
+
+
+ iso_tree
+
+
+
+
+ 180.0
+ 40.0
+
+
+
+
+
+
+
+ 193.0
+ 69.0
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+ 57.81118318204312
+ 584.0458146424488
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+ 748.978906441031
+ 574.8973495522459
+
+
+
+
+
+
+
+ The block in both Catalog and BootImage is needed
+for multissession images
+
+
+
+
+
+ 629.3242465083424
+ 441.1316647878586
+
+
+
+
+
+
+
+ File
+
+
+
+
+
+ 188.09040379562163
+ 172.5340546095176
+
+
+
+
+
+
+
+ CatalogStream
+
+
+
+
+
+ 851.105100475371
+ 283.5127233261827
+
+
+
+
+
+
+
+ FileStream
+
+
+
+
+
+ 743.4055403867466
+ 284.4253525880894
+
+
+
+
+
+
+
+ TransformStream
+
+
+
+
+
+ 958.5987801403015
+ 279.8322618091961
+
+
+
+
+
+
+
+ «interface»
+Stream
+
+
+
+
+
+ 847.6728065449973
+ 157.05765855361264
+
+
+
+
+
+
+
+ IsoLinuxPatch
+
+
+
+
+
+ 968.73629022557
+ 384.6660889654818
+
+
+
+
+
+
+
+ Generates the content of the catalog on-the-fly
+
+
+
+
+
+ 517.6021638285529
+ 107.48023074035522
+
+
+
+
+
+
+
+ To apply the needed patch to isolinux
+images
+
+
+
+
+
+ 923.4814562296309
+ 509.1168824543143
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0..1 boot_cat
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0..1 node
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0..1 node
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/eltorito.violet.png b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/eltorito.violet.png
new file mode 100644
index 00000000..adc195c2
Binary files /dev/null and b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/eltorito.violet.png differ
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/iso_tree.violet b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/iso_tree.violet
new file mode 100644
index 00000000..a3fa2268
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/iso_tree.violet
@@ -0,0 +1,748 @@
+
+
+
+
+
+
+
+ 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*
+
+
+
+
+ Volume
+
+
+
+
+
+ 1160.4799402311673
+ 240.649943764645
+
+
+
+
+
+
+
+ sort_weight : int
+block : uint32_t
+
+
+
+
+ File
+
+
+
+
+
+ 687.5479565719912
+ 269.2931470368318
+
+
+
+
+
+
+
+ name : char *
+attribs : struct stat
+hidden : enum
+
+
+
+
+ TreeNode
+
+
+
+
+
+ 706.83671056434
+ 108.4726745515399
+
+
+
+
+
+
+
+ add(XXX)
+remove(Node)
+children()
+
+
+
+
+ Directory
+
+
+
+
+
+ 986.1687535943008
+ 267.29314703683184
+
+
+
+
+
+
+
+ dest : char*
+
+
+
+
+ Symlink
+
+
+
+
+
+ 571.9364350336367
+ 273.31078127658077
+
+
+
+
+
+
+
+ Special
+
+
+
+
+
+ 813.0651280884073
+ 272.20749521231266
+
+
+
+
+
+
+
+ name : char*
+
+
+
+
+ <<static>>new(id)
+<<static>>read(src, opts)
+create()
+grow()
+
+
+
+
+ Image
+
+
+
+
+
+ 1149.1980515339465
+ 455.5218613006981
+
+
+
+
+
+
+
+ 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
+
+
+
+
+
+ 322.02220861890066
+ 362.2044136147912
+
+
+
+
+
+
+
+ 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
+
+
+
+
+
+
+ 1212.7956394939486
+ 697.0920982847697
+
+
+
+
+
+
+
+ Ecma119Source
+
+
+
+
+
+ 1423.5617211564486
+ 483.61244144432396
+
+
+
+
+
+
+
+
+
+ «interface»
+BurnSource
+
+
+
+
+
+ Libburn
+
+
+
+
+ 1420.0
+ 280.0
+
+
+
+
+
+
+
+ 1431.4906533445824
+ 311.35760744838467
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+ 290.59037712396525
+ 9.859316379054544
+
+
+
+
+
+
+
+ «interface»
+DataSource
+
+
+
+
+
+ 1192.781692587207
+ 608.8954677283948
+
+
+
+
+
+
+
+
+
+ «interface»
+Filters
+
+
+
+
+
+ filters
+
+
+
+
+ 260.0
+ 710.0
+
+
+
+
+
+
+
+ 265.45434264405947
+ 743.9994422711634
+
+
+
+
+
+
+
+ TransformStream
+
+
+
+
+
+ 486.9335577265969
+ 640.636302316303
+
+
+
+
+
+
+
+ CutOutStream
+
+
+
+
+
+ 555.9916340674516
+ 750.220757440409
+
+
+
+
+
+
+
+ get_size()
+read()
+open()
+close()
+is_repeatable()
+
+
+
+
+ «interface»
+Stream
+
+
+
+
+
+ 688.5487814157467
+ 437.25152600545294
+
+
+
+
+
+
+
+ FdStream
+
+
+
+
+
+ 680.6673668471356
+ 637.245696021424
+
+
+
+
+
+
+
+ FileStream
+
+
+
+
+
+ 828.9404615480411
+ 642.40096597045
+
+
+
+
+
+
+
+ FilteredStream
+
+
+
+
+
+ 428.449880813367
+ 747.5389646099015
+
+
+
+
+
+
+
+ «interface»
+SourceFile
+
+
+
+
+
+ 1000.6667341519202
+ 639.0812755928229
+
+
+
+
+
+
+
+ For files, we need to know whethe they come
+from a previous session. That's the purpose of
+the block field
+
+
+
+
+
+ 818.829652614022
+ 414.36457377531684
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 volume
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {create}
+
+
+
+
+
+
+
+
+
+
+
+ 0..1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ * children
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 root
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 parent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 src
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/iso_tree.violet.png b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/iso_tree.violet.png
new file mode 100644
index 00000000..d445b4fe
Binary files /dev/null and b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/iso_tree.violet.png differ
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/nglibisofs.violet b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/nglibisofs.violet
new file mode 100644
index 00000000..fd6a247f
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/nglibisofs.violet
@@ -0,0 +1,1059 @@
+
+
+
+
+
+
+
+ addFilter(Filter)
+
+
+
+
+ Image
+
+
+
+
+
+ 1110.8240579870107
+ 412.38305701571016
+
+
+
+
+
+
+
+ Volume
+
+
+
+
+
+ 746.3823937606093
+ 414.32909259072375
+
+
+
+
+
+
+
+ TreeNode
+
+
+
+
+
+ 625.8940609153292
+ 195.78347904495376
+
+
+
+
+
+
+
+ File
+
+
+
+
+
+ 497.8940609153292
+ 296.78347904495376
+
+
+
+
+
+
+
+ dest
+
+
+
+
+ Symlink
+
+
+
+
+
+ 620.8940609153292
+ 296.78347904495376
+
+
+
+
+
+
+
+ Directory
+
+
+
+
+
+ 754.8940609153292
+ 301.78347904495376
+
+
+
+
+
+
+
+ «interface»
+
+FileSource
+
+
+
+
+
+ 567.7128002861876
+ 674.7337520453865
+
+
+
+
+
+
+
+ FilterFileSource
+
+
+
+
+
+ 404.71280028618764
+ 774.7337520453866
+
+
+
+
+
+
+
+ «interface»
+Filter
+
+
+
+
+
+ 254.78439895092293
+ 770.0234642237775
+
+
+
+
+
+
+
+ LocalFileSource
+
+
+
+
+
+ 556.36965453568
+ 774.2484706711477
+
+
+
+
+
+
+
+ PreviousImageSource
+
+
+
+
+
+ 709.0702627569951
+ 767.6450499937722
+
+
+
+
+
+
+
+ ExternalAppFilter
+
+
+
+
+
+ 110.5229299160843
+ 923.5005293319075
+
+
+
+
+
+
+
+ EncryptionFilter
+
+
+
+
+
+ 239.49694258624206
+ 916.3652866418913
+
+
+
+
+
+
+
+ CompressionFilter
+
+
+
+
+
+ 371.4989323515441
+ 917.5544937568939
+
+
+
+
+
+
+
+ SplittedFile
+
+
+
+
+
+ 287.78812183065844
+ 413.84407602094683
+
+
+
+
+
+
+
+ Special
+
+
+
+
+
+ 386.0027189390628
+ 302.28361365806154
+
+
+
+
+
+
+
+ DataSource
+
+
+
+
+
+ 731.4111571155465
+ 901.4839567978983
+
+
+
+
+
+
+
+ «interface»
+BurnSource
+
+
+
+
+
+ 1335.6119487863941
+ 398.7730655710078
+
+
+
+
+
+
+
+ ...
+
+
+
+
+
+ 1477.8641028983907
+ 783.298732945339
+
+
+
+
+
+
+
+ PVDWriter
+
+
+
+
+
+ 1198.964607961779
+ 781.9555871948312
+
+
+
+
+
+
+
+ WriterState
+
+
+
+
+
+ 1336.8762962072105
+ 661.712946507712
+
+
+
+
+
+
+
+
+
+ Libburn
+
+
+
+
+ 1330.0
+ 370.0
+
+
+
+
+
+
+
+ Ecma119Image
+
+
+
+
+
+ 1095.4640655004926
+ 540.6103494032706
+
+
+
+
+
+
+
+ Ecma119Source
+
+
+
+
+
+ 1326.9200188086058
+ 535.6052987693873
+
+
+
+
+
+
+
+ Ecma119Node
+
+
+
+
+
+ 881.981844994835
+ 577.6636135370297
+
+
+
+
+
+
+
+ DirectoryInfoWriter
+
+
+
+
+
+ 1316.10674358551
+ 783.9555871948312
+
+
+
+
+
+
+
+ LocalFile
+
+
+
+
+
+ 396.0059692959062
+ 407.89804044593336
+
+
+
+
+
+
+
+ FilteredFile
+
+
+
+
+
+ 505.41302387615644
+ 412.6548689059442
+
+
+
+
+
+
+
+ PrevImgFile
+
+
+
+
+
+ 617.1984926864122
+ 410.2764546759387
+
+
+
+
+
+
+
+ Ecma119File
+
+
+
+
+
+ 743.3186217548513
+ 674.795410727119
+
+
+
+
+
+
+
+ Ecma119Symlink
+
+
+
+
+
+ 874.2922359743702
+ 669.9419255760395
+
+
+
+
+
+
+
+ Ecma119Dir
+
+
+
+
+
+ 1037.9535936976897
+ 672.3203398060449
+
+
+
+
+
+
+
+ FileSourceRegistry
+
+
+
+
+
+ 550.129075763134
+ 551.543289325507
+
+
+
+
+
+
+
+ Base object for all interaction with user.
+Represents a context for image creation
+and manipulation.
+
+
+
+
+
+ 1042.275395468971
+ 308.29855659733465
+
+
+
+
+
+
+
+ Registry to ensure the same file is only
+written once to the image
+
+
+
+
+
+ 271.5290039756343
+ 521.8448045156721
+
+
+
+
+
+
+
+ The context data for image burn sources, contains
+references to the tree, creation options...
+
+
+
+
+
+ 770.7463914933367
+ 497.80317395532944
+
+
+
+
+
+
+
+ A filter to be applied to file contents. A single filter
+can be used to several files.
+
+
+
+
+
+ 151.32085117392114
+ 668.9230150024738
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ * children
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 root
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [create]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/stream.violet b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/stream.violet
new file mode 100644
index 00000000..d488940d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/stream.violet
@@ -0,0 +1,492 @@
+
+
+
+
+
+
+
+ TransformStream
+
+
+
+
+
+ 374.71280028618764
+ 246.7337520453866
+
+
+
+
+
+
+
+ get_size()
+read()
+open()
+close()
+is_repeatable()
+
+
+
+
+ «interface»
+Stream
+
+
+
+
+
+ 576.3280239753375
+ 43.34897573453627
+
+
+
+
+
+
+
+ FileStream
+
+
+
+
+
+ 741.9465965652432
+ 246.8166228690261
+
+
+
+
+
+
+
+
+
+ CompressionFilter
+
+
+
+
+
+
+
+
+ EncryptionFilter
+
+
+
+
+
+
+
+
+ ExtAppFilter
+
+
+
+
+
+
+
+
+ filter(in, out)
+
+
+
+
+ «interface»
+Filter
+
+
+
+
+
+ Filters
+
+
+
+
+ 270.0
+ 480.0
+
+
+
+
+
+
+
+ A Stream to read data from an abstract
+file represented by a SourceFile
+
+
+
+
+
+ 781.6101730552666
+ 137.2161620284267
+
+
+
+
+
+
+
+ A stream to get data from an arbitrary file
+descritor. size must be know in advance.
+
+
+
+
+
+ 580.8730162779191
+ 392.3137084989848
+
+
+
+
+
+
+
+ fd : int
+size : off_t
+
+
+
+
+ FdStream
+
+
+
+
+
+ 565.61818228198
+ 253.24264068711926
+
+
+
+
+
+
+
+ 281.2426406871193
+ 620.6274169979695
+
+
+
+
+
+
+
+ 429.51546936508925
+ 624.9910026589843
+
+
+
+
+
+
+
+ 568.2426406871186
+ 624.6274169979695
+
+
+
+
+
+
+
+ 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
+
+
+
+
+
+
+ 724.6274169979696
+ 510.3015151901651
+
+
+
+
+
+
+
+ FilteredStream
+
+
+
+
+
+ 439.0
+ 357.0
+
+
+
+
+
+
+
+ size : off_t
+lba: off_t
+
+
+
+
+ CutOutStream
+
+
+
+
+
+ 321.0
+ 358.0
+
+
+
+
+
+
+
+ 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.
+
+
+
+
+
+ 67.0
+ 276.0
+
+
+
+
+
+
+
+ A stream that applies some transformation
+to the contents of another stream.
+
+
+
+
+
+ 122.0
+ 183.0
+
+
+
+
+
+
+
+ 437.57046683437824
+ 509.23933115391503
+
+
+
+
+
+
+
+ «interface»
+SourceFile
+
+
+
+
+
+ 920.6530291048848
+ 248.90158697766475
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/stream.violet.png b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/stream.violet.png
new file mode 100644
index 00000000..f5215a50
Binary files /dev/null and b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/UML/stream.violet.png differ
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/codestyle.xml b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/codestyle.xml
new file mode 100644
index 00000000..ef965208
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/codestyle.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/cookbook/ISO 9660-1999 b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/cookbook/ISO 9660-1999
new file mode 100644
index 00000000..4b813b7b
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/devel/cookbook/ISO 9660-1999
@@ -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.
+
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/doc/doxygen.conf.in b/libisofs/tags/ForXorrisoZeroOneTwo/doc/doxygen.conf.in
new file mode 100644
index 00000000..fe1864fe
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/doc/doxygen.conf.in
@@ -0,0 +1,1298 @@
+# Doxyfile 1.5.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that
+# follow. The default is UTF-8 which is also the encoding used for all text before
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list
+# of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = @PACKAGE_NAME@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = @top_srcdir@
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = YES
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be extracted
+# and appear in the documentation as a namespace called 'anonymous_namespace{file}',
+# where file will be replaced with the base name of the file that contains the anonymous
+# namespace. By default anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command , where is the value of
+# the FILE_VERSION_FILTER tag, and is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text "
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = libisofs \
+ doc
+
+# This tag can be used to specify the character encoding of the source files that
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = libisofs.h \
+ comments
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the output.
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = test
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command , where
+# is the value of the INPUT_FILTER tag, and is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH
+# then you must also enable this option. If you don't then doxygen will produce
+# a warning and turn it on anyway
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX = OB \
+ OTK \
+ _
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = doc/html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 200
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = letter
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
+# be found in the default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = NO
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the number
+# of direct children of the root node in a graph is already larger than
+# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs-1.pc.in b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs-1.pc.in
new file mode 100644
index 00000000..4cf18c17
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs-1.pc.in
@@ -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
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/buffer.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/buffer.c
new file mode 100644
index 00000000..c59bad13
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/buffer.c
@@ -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
+#include
+
+#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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/buffer.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/buffer.h
new file mode 100644
index 00000000..c98e06cb
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/buffer.h
@@ -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
+#include
+
+#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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/builder.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/builder.c
new file mode 100644
index 00000000..9dbea875
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/builder.c
@@ -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
+#include
+#include
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/builder.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/builder.h
new file mode 100644
index 00000000..e0d3ff10
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/builder.h
@@ -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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/data_source.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/data_source.c
new file mode 100644
index 00000000..4d7c3cc2
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/data_source.c
@@ -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
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * 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_OPENED;
+ }
+
+ 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_OPENED;
+ }
+
+ /* 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_OPENED;
+ }
+
+ /* 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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119.c
new file mode 100644
index 00000000..e49ad8c0
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119.c
@@ -0,0 +1,1579 @@
+/*
+ * 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.
+ */
+
+#include "libisofs.h"
+#include "ecma119.h"
+#include "joliet.h"
+#include "iso1999.h"
+#include "eltorito.h"
+#include "ecma119_tree.h"
+#include "filesrc.h"
+#include "image.h"
+#include "writer.h"
+#include "messages.h"
+#include "rockridge.h"
+#include "util.h"
+
+#include "libburn/libburn.h"
+
+#include
+#include
+#include
+#include
+#include
+
+/*
+ * TODO #00011 : guard against bad path table usage with more than 65535 dirs
+ * image with more than 65535 directories have path_table related problems
+ * due to 16 bits parent id. Note that this problem only affects to folders
+ * that are parent of another folder.
+ */
+
+static
+void ecma119_image_free(Ecma119Image *t)
+{
+ size_t i;
+
+ ecma119_node_free(t->root);
+ iso_image_unref(t->image);
+ iso_rbtree_destroy(t->files, iso_file_src_free);
+ iso_ring_buffer_free(t->buffer);
+
+ for (i = 0; i < t->nwriters; ++i) {
+ IsoImageWriter *writer = t->writers[i];
+ writer->free_data(writer);
+ free(writer);
+ }
+ free(t->input_charset);
+ free(t->output_charset);
+ free(t->writers);
+ free(t);
+}
+
+/**
+ * Check if we should add version number ";" to the given node name.
+ */
+static
+int need_version_number(Ecma119Image *t, Ecma119Node *n)
+{
+ if (t->omit_version_numbers) {
+ return 0;
+ }
+ if (n->type == ECMA119_DIR || n->type == ECMA119_PLACEHOLDER) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+/**
+ * Compute the size of a directory entry for a single node
+ */
+static
+size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n)
+{
+ int ret = n->iso_name ? strlen(n->iso_name) + 33 : 34;
+ if (need_version_number(t, n)) {
+ ret += 2; /* take into account version numbers */
+ }
+ if (ret % 2)
+ ret++;
+ return ret;
+}
+
+/**
+ * Computes the total size of all directory entries of a single dir,
+ * acording to ECMA-119 6.8.1.1
+ *
+ * This also take into account the size needed for RR entries and
+ * SUSP continuation areas (SUSP, 5.1).
+ *
+ * @param ce
+ * Will be filled with the size needed for Continuation Areas
+ * @return
+ * The size needed for all dir entries of the given dir, without
+ * taking into account the continuation areas.
+ */
+static
+size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce)
+{
+ size_t i, len;
+ size_t ce_len = 0;
+
+ /* size of "." and ".." entries */
+ len = 34 + 34;
+ if (t->rockridge) {
+ len += rrip_calc_len(t, dir, 1, 255 - 34, &ce_len);
+ *ce += ce_len;
+ len += rrip_calc_len(t, dir, 2, 255 - 34, &ce_len);
+ *ce += ce_len;
+ }
+
+ for (i = 0; i < dir->info.dir->nchildren; ++i) {
+ size_t remaining;
+ Ecma119Node *child = dir->info.dir->children[i];
+ size_t dirent_len = calc_dirent_len(t, child);
+ if (t->rockridge) {
+ dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len);
+ *ce += ce_len;
+ }
+ remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
+ if (dirent_len > remaining) {
+ /* child directory entry doesn't fit on block */
+ len += remaining + dirent_len;
+ } else {
+ len += dirent_len;
+ }
+ }
+
+ /*
+ * The size of a dir is always a multiple of block size, as we must add
+ * the size of the unused space after the last directory record
+ * (ECMA-119, 6.8.1.3)
+ */
+ len = ROUND_UP(len, BLOCK_SIZE);
+
+ /* cache the len */
+ dir->info.dir->len = len;
+ return len;
+}
+
+static
+void calc_dir_pos(Ecma119Image *t, Ecma119Node *dir)
+{
+ size_t i, len;
+ size_t ce_len = 0;
+
+ t->ndirs++;
+ dir->info.dir->block = t->curblock;
+ len = calc_dir_size(t, dir, &ce_len);
+ t->curblock += DIV_UP(len, BLOCK_SIZE);
+ if (t->rockridge) {
+ t->curblock += DIV_UP(ce_len, BLOCK_SIZE);
+ }
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ Ecma119Node *child = dir->info.dir->children[i];
+ if (child->type == ECMA119_DIR) {
+ calc_dir_pos(t, child);
+ }
+ }
+}
+
+/**
+ * Compute the length of the path table, in bytes.
+ */
+static
+uint32_t calc_path_table_size(Ecma119Node *dir)
+{
+ uint32_t size;
+ size_t i;
+
+ /* size of path table for this entry */
+ size = 8;
+ size += dir->iso_name ? strlen(dir->iso_name) : 1;
+ size += (size % 2);
+
+ /* and recurse */
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ Ecma119Node *child = dir->info.dir->children[i];
+ if (child->type == ECMA119_DIR) {
+ size += calc_path_table_size(child);
+ }
+ }
+ return size;
+}
+
+static
+int ecma119_writer_compute_data_blocks(IsoImageWriter *writer)
+{
+ Ecma119Image *target;
+ uint32_t path_table_size;
+
+ if (writer == NULL) {
+ return ISO_ASSERT_FAILURE;
+ }
+
+ target = writer->target;
+
+ /* compute position of directories */
+ iso_msg_debug(target->image->id, "Computing position of dir structure");
+ target->ndirs = 0;
+ calc_dir_pos(target, target->root);
+
+ /* compute length of pathlist */
+ iso_msg_debug(target->image->id, "Computing length of pathlist");
+ path_table_size = calc_path_table_size(target->root);
+
+ /* compute location for path tables */
+ target->l_path_table_pos = target->curblock;
+ target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
+ target->m_path_table_pos = target->curblock;
+ target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
+ target->path_table_size = path_table_size;
+
+ return ISO_SUCCESS;
+}
+
+/**
+ * Write a single directory record (ECMA-119, 9.1)
+ *
+ * @param file_id
+ * if >= 0, we use it instead of the filename (for "." and ".." entries).
+ * @param len_fi
+ * Computed length of the file identifier. Total size of the directory
+ * entry will be len + 33 + padding if needed (ECMA-119, 9.1.12)
+ * @param info
+ * SUSP entries for the given directory record. It will be NULL for the
+ * root directory record in the PVD (ECMA-119, 8.4.18) (in order to
+ * distinguish it from the "." entry in the root directory)
+ */
+static
+void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
+ uint8_t *buf, size_t len_fi, struct susp_info *info)
+{
+ uint32_t len;
+ uint32_t block;
+ uint8_t len_dr; /*< size of dir entry without SUSP fields */
+ uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
+ : (uint8_t*)node->iso_name;
+
+ struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
+
+ len_dr = 33 + len_fi + (len_fi % 2 ? 0 : 1);
+
+ memcpy(rec->file_id, name, len_fi);
+
+ if (need_version_number(t, node)) {
+ len_dr += 2;
+ rec->file_id[len_fi++] = ';';
+ rec->file_id[len_fi++] = '1';
+ }
+
+ if (node->type == ECMA119_DIR) {
+ /* use the cached length */
+ len = node->info.dir->len;
+ block = node->info.dir->block;
+ } else if (node->type == ECMA119_FILE) {
+ len = iso_file_src_get_size(node->info.file);
+ block = node->info.file->block;
+ } else {
+ /*
+ * for nodes other than files and dirs, we set both
+ * len and block to 0
+ */
+ len = 0;
+ block = 0;
+ }
+
+ /*
+ * For ".." entry we need to write the parent info!
+ */
+ if (file_id == 1 && node->parent)
+ node = node->parent;
+
+ rec->len_dr[0] = len_dr + (info != NULL ? info->suf_len : 0);
+ iso_bb(rec->block, block, 4);
+ iso_bb(rec->length, len, 4);
+ iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
+ rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0;
+ iso_bb(rec->vol_seq_number, 1, 2);
+ rec->len_fi[0] = len_fi;
+
+ /* and finally write the SUSP fields */
+ if (info != NULL) {
+ rrip_write_susp_fields(t, info, buf + len_dr);
+ }
+}
+
+static
+char *get_relaxed_vol_id(Ecma119Image *t, const char *name)
+{
+ int ret;
+ if (name == NULL) {
+ return NULL;
+ }
+ if (strcmp(t->input_charset, t->output_charset)) {
+ /* charset conversion needed */
+ char *str;
+ ret = strconv(name, t->input_charset, t->output_charset, &str);
+ if (ret == ISO_SUCCESS) {
+ return str;
+ }
+ iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
+ "Charset conversion error. Can't convert %s from %s to %s",
+ name, t->input_charset, t->output_charset);
+ }
+ return strdup(name);
+}
+
+/**
+ * Write the Primary Volume Descriptor (ECMA-119, 8.4)
+ */
+static
+int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
+{
+ IsoImage *image;
+ Ecma119Image *t;
+ struct ecma119_pri_vol_desc vol;
+
+ char *vol_id, *pub_id, *data_id, *volset_id;
+ char *system_id, *application_id, *copyright_file_id;
+ char *abstract_file_id, *biblio_file_id;
+
+ if (writer == NULL) {
+ return ISO_ASSERT_FAILURE;
+ }
+
+ t = writer->target;
+ image = t->image;
+
+ iso_msg_debug(image->id, "Write Primary Volume Descriptor");
+
+ memset(&vol, 0, sizeof(struct ecma119_pri_vol_desc));
+
+ if (t->relaxed_vol_atts) {
+ vol_id = get_relaxed_vol_id(t, image->volume_id);
+ volset_id = get_relaxed_vol_id(t, image->volset_id);
+ } else {
+ str2d_char(t->input_charset, image->volume_id, &vol_id);
+ str2d_char(t->input_charset, image->volset_id, &volset_id);
+ }
+ str2a_char(t->input_charset, image->publisher_id, &pub_id);
+ str2a_char(t->input_charset, image->data_preparer_id, &data_id);
+ str2a_char(t->input_charset, image->system_id, &system_id);
+ str2a_char(t->input_charset, image->application_id, &application_id);
+ str2d_char(t->input_charset, image->copyright_file_id, ©right_file_id);
+ str2d_char(t->input_charset, image->abstract_file_id, &abstract_file_id);
+ str2d_char(t->input_charset, image->biblio_file_id, &biblio_file_id);
+
+ vol.vol_desc_type[0] = 1;
+ memcpy(vol.std_identifier, "CD001", 5);
+ vol.vol_desc_version[0] = 1;
+ strncpy_pad((char*)vol.system_id, system_id, 32);
+ strncpy_pad((char*)vol.volume_id, vol_id, 32);
+ iso_bb(vol.vol_space_size, t->vol_space_size, 4);
+ iso_bb(vol.vol_set_size, 1, 2);
+ iso_bb(vol.vol_seq_number, 1, 2);
+ iso_bb(vol.block_size, BLOCK_SIZE, 2);
+ iso_bb(vol.path_table_size, t->path_table_size, 4);
+ iso_lsb(vol.l_path_table_pos, t->l_path_table_pos, 4);
+ iso_msb(vol.m_path_table_pos, t->m_path_table_pos, 4);
+
+ write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL);
+
+ strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
+ strncpy_pad((char*)vol.publisher_id, pub_id, 128);
+ strncpy_pad((char*)vol.data_prep_id, data_id, 128);
+
+ strncpy_pad((char*)vol.application_id, application_id, 128);
+ strncpy_pad((char*)vol.copyright_file_id, copyright_file_id, 37);
+ strncpy_pad((char*)vol.abstract_file_id, abstract_file_id, 37);
+ strncpy_pad((char*)vol.bibliographic_file_id, biblio_file_id, 37);
+
+ iso_datetime_17(vol.vol_creation_time, t->now, t->always_gmt);
+ iso_datetime_17(vol.vol_modification_time, t->now, t->always_gmt);
+ iso_datetime_17(vol.vol_effective_time, t->now, t->always_gmt);
+ vol.file_structure_version[0] = 1;
+
+ free(vol_id);
+ free(volset_id);
+ free(pub_id);
+ free(data_id);
+ free(system_id);
+ free(application_id);
+ free(copyright_file_id);
+ free(abstract_file_id);
+ free(biblio_file_id);
+
+ /* Finally write the Volume Descriptor */
+ return iso_write(t, &vol, sizeof(struct ecma119_pri_vol_desc));
+}
+
+static
+int write_one_dir(Ecma119Image *t, Ecma119Node *dir)
+{
+ int ret;
+ uint8_t buffer[BLOCK_SIZE];
+ size_t i;
+ size_t fi_len, len;
+ struct susp_info info;
+
+ /* buf will point to current write position on buffer */
+ uint8_t *buf = buffer;
+
+ /* initialize buffer with 0s */
+ memset(buffer, 0, BLOCK_SIZE);
+
+ /*
+ * set susp_info to 0's, this way code for both plain ECMA-119 and
+ * RR is very similar
+ */
+ memset(&info, 0, sizeof(struct susp_info));
+ if (t->rockridge) {
+ /* initialize the ce_block, it might be needed */
+ info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len,
+ BLOCK_SIZE);
+ }
+
+ /* write the "." and ".." entries first */
+ if (t->rockridge) {
+ ret = rrip_get_susp_fields(t, dir, 1, 255 - 32, &info);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ len = 34 + info.suf_len;
+ write_one_dir_record(t, dir, 0, buf, 1, &info);
+ buf += len;
+
+ if (t->rockridge) {
+ ret = rrip_get_susp_fields(t, dir, 2, 255 - 32, &info);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ len = 34 + info.suf_len;
+ write_one_dir_record(t, dir, 1, buf, 1, &info);
+ buf += len;
+
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ Ecma119Node *child = dir->info.dir->children[i];
+
+ /* compute len of directory entry */
+ fi_len = strlen(child->iso_name);
+ len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
+ if (need_version_number(t, child)) {
+ len += 2;
+ }
+
+ /* get the SUSP fields if rockridge is enabled */
+ if (t->rockridge) {
+ ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info);
+ if (ret < 0) {
+ return ret;
+ }
+ len += info.suf_len;
+ }
+
+ if ( (buf + len - buffer) > BLOCK_SIZE) {
+ /* dir doesn't fit in current block */
+ ret = iso_write(t, buffer, BLOCK_SIZE);
+ if (ret < 0) {
+ return ret;
+ }
+ memset(buffer, 0, BLOCK_SIZE);
+ buf = buffer;
+ }
+ /* write the directory entry in any case */
+ write_one_dir_record(t, child, -1, buf, fi_len, &info);
+ buf += len;
+ }
+
+ /* write the last block */
+ ret = iso_write(t, buffer, BLOCK_SIZE);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* write the Continuation Area if needed */
+ if (info.ce_len > 0) {
+ ret = rrip_write_ce_fields(t, &info);
+ }
+
+ return ret;
+}
+
+static
+int write_dirs(Ecma119Image *t, Ecma119Node *root)
+{
+ int ret;
+ size_t i;
+
+ /* write all directory entries for this dir */
+ ret = write_one_dir(t, root);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* recurse */
+ for (i = 0; i < root->info.dir->nchildren; i++) {
+ Ecma119Node *child = root->info.dir->children[i];
+ if (child->type == ECMA119_DIR) {
+ ret = write_dirs(t, child);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+ return ISO_SUCCESS;
+}
+
+static
+int write_path_table(Ecma119Image *t, Ecma119Node **pathlist, int l_type)
+{
+ size_t i, len;
+ uint8_t buf[64]; /* 64 is just a convenient size larger enought */
+ struct ecma119_path_table_record *rec;
+ void (*write_int)(uint8_t*, uint32_t, int);
+ Ecma119Node *dir;
+ uint32_t path_table_size;
+ int parent = 0;
+ int ret= ISO_SUCCESS;
+
+ path_table_size = 0;
+ write_int = l_type ? iso_lsb : iso_msb;
+
+ for (i = 0; i < t->ndirs; i++) {
+ dir = pathlist[i];
+
+ /* find the index of the parent in the table */
+ while ((i) && pathlist[parent] != dir->parent) {
+ parent++;
+ }
+
+ /* write the Path Table Record (ECMA-119, 9.4) */
+ memset(buf, 0, 64);
+ rec = (struct ecma119_path_table_record*) buf;
+ rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->iso_name) : 1;
+ rec->len_xa[0] = 0;
+ write_int(rec->block, dir->info.dir->block, 4);
+ write_int(rec->parent, parent + 1, 2);
+ if (dir->parent) {
+ memcpy(rec->dir_id, dir->iso_name, rec->len_di[0]);
+ }
+ len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
+ ret = iso_write(t, buf, len);
+ if (ret < 0) {
+ /* error */
+ return ret;
+ }
+ path_table_size += len;
+ }
+
+ /* we need to fill the last block with zeros */
+ path_table_size %= BLOCK_SIZE;
+ if (path_table_size) {
+ uint8_t zeros[BLOCK_SIZE];
+ len = BLOCK_SIZE - path_table_size;
+ memset(zeros, 0, len);
+ ret = iso_write(t, zeros, len);
+ }
+ return ret;
+}
+
+static
+int write_path_tables(Ecma119Image *t)
+{
+ int ret;
+ size_t i, j, cur;
+ Ecma119Node **pathlist;
+
+ iso_msg_debug(t->image->id, "Writing ISO Path tables");
+
+ /* allocate temporal pathlist */
+ pathlist = malloc(sizeof(void*) * t->ndirs);
+ if (pathlist == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ pathlist[0] = t->root;
+ cur = 1;
+
+ for (i = 0; i < t->ndirs; i++) {
+ Ecma119Node *dir = pathlist[i];
+ for (j = 0; j < dir->info.dir->nchildren; j++) {
+ Ecma119Node *child = dir->info.dir->children[j];
+ if (child->type == ECMA119_DIR) {
+ pathlist[cur++] = child;
+ }
+ }
+ }
+
+ /* Write L Path Table */
+ ret = write_path_table(t, pathlist, 1);
+ if (ret < 0) {
+ goto write_path_tables_exit;
+ }
+
+ /* Write L Path Table */
+ ret = write_path_table(t, pathlist, 0);
+
+ write_path_tables_exit: ;
+ free(pathlist);
+ return ret;
+}
+
+/**
+ * Write both the directory structure (ECMA-119, 6.8) and the L and M
+ * Path Tables (ECMA-119, 6.9).
+ */
+static
+int ecma119_writer_write_data(IsoImageWriter *writer)
+{
+ int ret;
+ Ecma119Image *t;
+
+ if (writer == NULL) {
+ return ISO_ASSERT_FAILURE;
+ }
+ t = writer->target;
+
+ /* first of all, we write the directory structure */
+ ret = write_dirs(t, t->root);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* and write the path tables */
+ ret = write_path_tables(t);
+
+ return ret;
+}
+
+static
+int ecma119_writer_free_data(IsoImageWriter *writer)
+{
+ /* nothing to do */
+ return ISO_SUCCESS;
+}
+
+int ecma119_writer_create(Ecma119Image *target)
+{
+ int ret;
+ IsoImageWriter *writer;
+
+ writer = malloc(sizeof(IsoImageWriter));
+ if (writer == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ writer->compute_data_blocks = ecma119_writer_compute_data_blocks;
+ writer->write_vol_desc = ecma119_writer_write_vol_desc;
+ writer->write_data = ecma119_writer_write_data;
+ writer->free_data = ecma119_writer_free_data;
+ writer->data = NULL;
+ writer->target = target;
+
+ /* add this writer to image */
+ target->writers[target->nwriters++] = writer;
+
+ iso_msg_debug(target->image->id, "Creating low level ECMA-119 tree...");
+ ret = ecma119_tree_create(target);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* we need the volume descriptor */
+ target->curblock++;
+ return ISO_SUCCESS;
+}
+
+/** compute how many padding bytes are needed */
+static
+int pad_writer_compute_data_blocks(IsoImageWriter *writer)
+{
+ Ecma119Image *target;
+
+ if (writer == NULL) {
+ return ISO_ASSERT_FAILURE;
+ }
+
+ target = writer->target;
+ if (target->curblock < 32) {
+ target->pad_blocks = 32 - target->curblock;
+ target->curblock = 32;
+ }
+ return ISO_SUCCESS;
+}
+
+static
+int pad_writer_write_vol_desc(IsoImageWriter *writer)
+{
+ /* nothing to do */
+ return ISO_SUCCESS;
+}
+static
+int pad_writer_write_data(IsoImageWriter *writer)
+{
+ int ret;
+ Ecma119Image *t;
+ uint32_t pad[BLOCK_SIZE];
+ size_t i;
+
+ if (writer == NULL) {
+ return ISO_ASSERT_FAILURE;
+ }
+ t = writer->target;
+
+ if (t->pad_blocks == 0) {
+ return ISO_SUCCESS;
+ }
+
+ memset(pad, 0, BLOCK_SIZE);
+ for (i = 0; i < t->pad_blocks; ++i) {
+ ret = iso_write(t, pad, BLOCK_SIZE);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ return ISO_SUCCESS;
+}
+
+static
+int pad_writer_free_data(IsoImageWriter *writer)
+{
+ /* nothing to do */
+ return ISO_SUCCESS;
+}
+
+static
+int pad_writer_create(Ecma119Image *target)
+{
+ IsoImageWriter *writer;
+
+ writer = malloc(sizeof(IsoImageWriter));
+ if (writer == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ writer->compute_data_blocks = pad_writer_compute_data_blocks;
+ writer->write_vol_desc = pad_writer_write_vol_desc;
+ writer->write_data = pad_writer_write_data;
+ writer->free_data = pad_writer_free_data;
+ writer->data = NULL;
+ writer->target = target;
+
+ /* add this writer to image */
+ target->writers[target->nwriters++] = writer;
+ return ISO_SUCCESS;
+}
+
+static
+void *write_function(void *arg)
+{
+ int res;
+ size_t i;
+ uint8_t buf[BLOCK_SIZE];
+ IsoImageWriter *writer;
+
+ Ecma119Image *target = (Ecma119Image*)arg;
+ iso_msg_debug(target->image->id, "Starting image writing...");
+
+ target->bytes_written = (off_t) 0;
+ target->percent_written = 0;
+
+ /* Write System Area, 16 blocks of zeros (ECMA-119, 6.2.1) */
+ memset(buf, 0, BLOCK_SIZE);
+ for (i = 0; i < 16; ++i) {
+ res = iso_write(target, buf, BLOCK_SIZE);
+ if (res < 0) {
+ goto write_error;
+ }
+ }
+
+ /* write volume descriptors, one per writer */
+ iso_msg_debug(target->image->id, "Write volume descriptors");
+ for (i = 0; i < target->nwriters; ++i) {
+ writer = target->writers[i];
+ res = writer->write_vol_desc(writer);
+ if (res < 0) {
+ goto write_error;
+ }
+ }
+
+ /* write Volume Descriptor Set Terminator (ECMA-119, 8.3) */
+ {
+ struct ecma119_vol_desc_terminator *vol;
+ vol = (struct ecma119_vol_desc_terminator *) buf;
+
+ vol->vol_desc_type[0] = 255;
+ memcpy(vol->std_identifier, "CD001", 5);
+ vol->vol_desc_version[0] = 1;
+
+ res = iso_write(target, buf, BLOCK_SIZE);
+ if (res < 0) {
+ goto write_error;
+ }
+ }
+
+ /* write data for each writer */
+ for (i = 0; i < target->nwriters; ++i) {
+ writer = target->writers[i];
+ res = writer->write_data(writer);
+ if (res < 0) {
+ goto write_error;
+ }
+ }
+
+ iso_ring_buffer_writer_close(target->buffer, 0);
+ pthread_exit(NULL);
+
+ write_error: ;
+ if (res == ISO_CANCELED) {
+ /* canceled */
+ iso_msg_submit(target->image->id, ISO_IMAGE_WRITE_CANCELED, 0, NULL);
+ } else {
+ /* image write error */
+ iso_msg_submit(target->image->id, ISO_WRITE_ERROR, res,
+ "Image write error");
+ }
+ iso_ring_buffer_writer_close(target->buffer, 1);
+ pthread_exit(NULL);
+}
+
+static
+int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
+{
+ int ret, i, voldesc_size, nwriters;
+ Ecma119Image *target;
+
+ /* 1. Allocate target and copy opts there */
+ target = calloc(1, sizeof(Ecma119Image));
+ if (target == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ /* create the tree for file caching */
+ ret = iso_rbtree_new(iso_file_src_cmp, &(target->files));
+ if (ret < 0) {
+ free(target);
+ return ret;
+ }
+
+ target->image = src;
+ iso_image_ref(src);
+
+ target->iso_level = opts->level;
+ target->rockridge = opts->rockridge;
+ target->joliet = opts->joliet;
+ target->iso1999 = opts->iso1999;
+ target->always_gmt = opts->always_gmt;
+ target->ino = 0;
+ target->omit_version_numbers = opts->omit_version_numbers
+ | opts->max_37_char_filenames;
+ target->allow_deep_paths = opts->allow_deep_paths;
+ target->allow_longer_paths = opts->allow_longer_paths;
+ target->max_37_char_filenames = opts->max_37_char_filenames;
+ target->no_force_dots = opts->no_force_dots;
+ target->allow_lowercase = opts->allow_lowercase;
+ target->allow_full_ascii = opts->allow_full_ascii;
+ target->relaxed_vol_atts = opts->relaxed_vol_atts;
+ target->joliet_longer_paths = opts->joliet_longer_paths;
+ target->sort_files = opts->sort_files;
+
+ target->replace_uid = opts->replace_uid ? 1 : 0;
+ target->replace_gid = opts->replace_gid ? 1 : 0;
+ target->replace_dir_mode = opts->replace_dir_mode ? 1 : 0;
+ target->replace_file_mode = opts->replace_file_mode ? 1 : 0;
+
+ target->uid = opts->replace_uid == 2 ? opts->uid : 0;
+ target->gid = opts->replace_gid == 2 ? opts->gid : 0;
+ target->dir_mode = opts->replace_dir_mode == 2 ? opts->dir_mode : 0555;
+ target->file_mode = opts->replace_file_mode == 2 ? opts->file_mode : 0444;
+
+ target->now = time(NULL);
+ target->ms_block = opts->ms_block;
+ target->appendable = opts->appendable;
+
+ target->replace_timestamps = opts->replace_timestamps ? 1 : 0;
+ target->timestamp = opts->replace_timestamps == 2 ?
+ opts->timestamp : target->now;
+
+ /* el-torito? */
+ target->eltorito = (src->bootcat == NULL ? 0 : 1);
+ target->catalog = src->bootcat;
+
+ /* default to locale charset */
+ setlocale(LC_CTYPE, "");
+ target->input_charset = strdup(nl_langinfo(CODESET));
+ if (target->input_charset == NULL) {
+ iso_image_unref(src);
+ free(target);
+ return ISO_OUT_OF_MEM;
+ }
+
+ if (opts->output_charset != NULL) {
+ target->output_charset = strdup(opts->output_charset);
+ } else {
+ target->output_charset = strdup(target->input_charset);
+ }
+ if (target->output_charset == NULL) {
+ iso_image_unref(src);
+ free(target);
+ return ISO_OUT_OF_MEM;
+ }
+
+ /*
+ * 2. Based on those options, create needed writers: iso, joliet...
+ * Each writer inits its structures and stores needed info into
+ * target.
+ * If the writer needs an volume descriptor, it increments image
+ * current block.
+ * Finally, create Writer for files.
+ */
+ target->curblock = target->ms_block + 16;
+
+ /* the number of writers is dependent of the extensions */
+ nwriters = 1 + 1 + 1; /* ECMA-119 + padding + files */
+
+ if (target->eltorito) {
+ nwriters++;
+ }
+ if (target->joliet) {
+ nwriters++;
+ }
+ if (target->iso1999) {
+ nwriters++;
+ }
+
+ target->writers = malloc(nwriters * sizeof(void*));
+ if (target->writers == NULL) {
+ iso_image_unref(src);
+ free(target);
+ return ISO_OUT_OF_MEM;
+ }
+
+ /* create writer for ECMA-119 structure */
+ ret = ecma119_writer_create(target);
+ if (ret < 0) {
+ goto target_cleanup;
+ }
+
+ /* create writer for El-Torito */
+ if (target->eltorito) {
+ ret = eltorito_writer_create(target);
+ if (ret < 0) {
+ goto target_cleanup;
+ }
+ }
+
+ /* create writer for Joliet structure */
+ if (target->joliet) {
+ ret = joliet_writer_create(target);
+ if (ret < 0) {
+ goto target_cleanup;
+ }
+ }
+
+ /* create writer for ISO 9660:1999 structure */
+ if (target->iso1999) {
+ ret = iso1999_writer_create(target);
+ if (ret < 0) {
+ goto target_cleanup;
+ }
+ }
+
+ voldesc_size = target->curblock - target->ms_block - 16;
+
+ /* Volume Descriptor Set Terminator */
+ target->curblock++;
+
+ /*
+ * Create the writer for possible padding to ensure that in case of image
+ * growing we can safety overwrite the first 64 KiB of image.
+ */
+ ret = pad_writer_create(target);
+ if (ret < 0) {
+ goto target_cleanup;
+ }
+
+ /* create writer for file contents */
+ ret = iso_file_src_writer_create(target);
+ if (ret < 0) {
+ goto target_cleanup;
+ }
+
+ /*
+ * 3.
+ * Call compute_data_blocks() in each Writer.
+ * That function computes the size needed by its structures and
+ * increments image current block propertly.
+ */
+ for (i = 0; i < target->nwriters; ++i) {
+ IsoImageWriter *writer = target->writers[i];
+ ret = writer->compute_data_blocks(writer);
+ if (ret < 0) {
+ goto target_cleanup;
+ }
+ }
+
+ /* create the ring buffer */
+ ret = iso_ring_buffer_new(opts->fifo_size, &target->buffer);
+ if (ret < 0) {
+ goto target_cleanup;
+ }
+
+ /* check if we need to provide a copy of volume descriptors */
+ if (opts->overwrite) {
+
+ /*
+ * Get a copy of the volume descriptors to be written in a DVD+RW
+ * disc
+ */
+
+ uint8_t *buf;
+ struct ecma119_vol_desc_terminator *vol;
+ IsoImageWriter *writer;
+
+ /*
+ * In the PVM to be written in the 16th sector of the disc, we
+ * need to specify the full size.
+ */
+ target->vol_space_size = target->curblock;
+
+ /* write volume descriptor */
+ for (i = 0; i < target->nwriters; ++i) {
+ writer = target->writers[i];
+ ret = writer->write_vol_desc(writer);
+ if (ret < 0) {
+ iso_msg_debug(target->image->id,
+ "Error writing overwrite volume descriptors");
+ goto target_cleanup;
+ }
+ }
+
+ /* skip the first 16 blocks (system area) */
+ buf = opts->overwrite + 16 * BLOCK_SIZE;
+ voldesc_size *= BLOCK_SIZE;
+
+ /* copy the volume descriptors to the overwrite buffer... */
+ ret = iso_ring_buffer_read(target->buffer, buf, voldesc_size);
+ if (ret < 0) {
+ iso_msg_debug(target->image->id,
+ "Error reading overwrite volume descriptors");
+ goto target_cleanup;
+ }
+
+ /* ...including the vol desc terminator */
+ memset(buf + voldesc_size, 0, BLOCK_SIZE);
+ vol = (struct ecma119_vol_desc_terminator*) (buf + voldesc_size);
+ vol->vol_desc_type[0] = 255;
+ memcpy(vol->std_identifier, "CD001", 5);
+ vol->vol_desc_version[0] = 1;
+ }
+
+ /*
+ * The volume space size is just the size of the last session, in
+ * case of ms images.
+ */
+ target->vol_space_size = target->curblock - target->ms_block;
+ target->total_size = (off_t) target->vol_space_size * BLOCK_SIZE;
+
+ /* 4. Create and start writting thread */
+
+ /* ensure the thread is created joinable */
+ pthread_attr_init(&(target->th_attr));
+ pthread_attr_setdetachstate(&(target->th_attr), PTHREAD_CREATE_JOINABLE);
+
+ ret = pthread_create(&(target->wthread), &(target->th_attr),
+ write_function, (void *) target);
+ if (ret != 0) {
+ iso_msg_submit(target->image->id, ISO_THREAD_ERROR, 0,
+ "Cannot create writer thread");
+ ret = ISO_THREAD_ERROR;
+ goto target_cleanup;
+ }
+
+ /*
+ * Notice that once we reach this point, target belongs to the writer
+ * thread and should not be modified until the writer thread finished.
+ * There're however, specific fields in target that can be accessed, or
+ * even modified by the read thread (look inside bs_* functions)
+ */
+
+ *img = target;
+ return ISO_SUCCESS;
+
+ target_cleanup: ;
+ ecma119_image_free(target);
+ return ret;
+}
+
+static int bs_read(struct burn_source *bs, unsigned char *buf, int size)
+{
+ int ret;
+ Ecma119Image *t = (Ecma119Image*)bs->data;
+
+ ret = iso_ring_buffer_read(t->buffer, buf, size);
+ if (ret == ISO_SUCCESS) {
+ return size;
+ } else if (ret < 0) {
+ /* error */
+ iso_msg_submit(t->image->id, ISO_BUF_READ_ERROR, ret, NULL);
+ return -1;
+ } else {
+ /* EOF */
+ return 0;
+ }
+}
+
+static off_t bs_get_size(struct burn_source *bs)
+{
+ Ecma119Image *target = (Ecma119Image*)bs->data;
+ return target->total_size;
+}
+
+static void bs_free_data(struct burn_source *bs)
+{
+ int st;
+ Ecma119Image *target = (Ecma119Image*)bs->data;
+
+ st = iso_ring_buffer_get_status(bs, NULL, NULL);
+
+ /* was read already finished (i.e, canceled)? */
+ if (st < 4) {
+ /* forces writer to stop if it is still running */
+ iso_ring_buffer_reader_close(target->buffer, 0);
+
+ /* wait until writer thread finishes */
+ pthread_join(target->wthread, NULL);
+ iso_msg_debug(target->image->id, "Writer thread joined");
+ }
+
+ iso_msg_debug(target->image->id,
+ "Ring buffer was %d times full and %d times empty",
+ iso_ring_buffer_get_times_full(target->buffer),
+ iso_ring_buffer_get_times_empty(target->buffer));
+
+ /* now we can safety free target */
+ ecma119_image_free(target);
+}
+
+static
+int bs_cancel(struct burn_source *bs)
+{
+ int st;
+ size_t cap, free;
+ Ecma119Image *target = (Ecma119Image*)bs->data;
+
+ st = iso_ring_buffer_get_status(bs, &cap, &free);
+
+ if (free == cap && (st == 2 || st == 3)) {
+ /* image was already consumed */
+ iso_ring_buffer_reader_close(target->buffer, 0);
+ } else {
+ iso_msg_debug(target->image->id, "Reader thread being cancelled");
+
+ /* forces writer to stop if it is still running */
+ iso_ring_buffer_reader_close(target->buffer, ISO_CANCELED);
+ }
+
+ /* wait until writer thread finishes */
+ pthread_join(target->wthread, NULL);
+
+ iso_msg_debug(target->image->id, "Writer thread joined");
+ return ISO_SUCCESS;
+}
+
+static
+int bs_set_size(struct burn_source *bs, off_t size)
+{
+ Ecma119Image *target = (Ecma119Image*)bs->data;
+
+ /*
+ * just set the value to be returned by get_size. This is not used at
+ * all by libisofs, it is here just for helping libburn to correctly pad
+ * the image if needed.
+ */
+ target->total_size = size;
+ return 1;
+}
+
+int iso_image_create_burn_source(IsoImage *image, IsoWriteOpts *opts,
+ struct burn_source **burn_src)
+{
+ int ret;
+ struct burn_source *source;
+ Ecma119Image *target= NULL;
+
+ if (image == NULL || opts == NULL || burn_src == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ source = calloc(1, sizeof(struct burn_source));
+ if (source == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ ret = ecma119_image_new(image, opts, &target);
+ if (ret < 0) {
+ free(source);
+ return ret;
+ }
+
+ source->refcount = 1;
+ source->version = 1;
+ source->read = NULL;
+ source->get_size = bs_get_size;
+ source->set_size = bs_set_size;
+ source->free_data = bs_free_data;
+ source->read_xt = bs_read;
+ source->cancel = bs_cancel;
+ source->data = target;
+
+ *burn_src = source;
+ return ISO_SUCCESS;
+}
+
+int iso_write(Ecma119Image *target, void *buf, size_t count)
+{
+ int ret;
+
+ ret = iso_ring_buffer_write(target->buffer, buf, count);
+ if (ret == 0) {
+ /* reader cancelled */
+ return ISO_CANCELED;
+ }
+
+ /* total size is 0 when writing the overwrite buffer */
+ if (ret > 0 && (target->total_size != (off_t) 0)){
+ unsigned int kbw, kbt;
+ int percent;
+
+ target->bytes_written += (off_t) count;
+ kbw = (unsigned int) (target->bytes_written >> 10);
+ kbt = (unsigned int) (target->total_size >> 10);
+ percent = (kbw * 100) / kbt;
+
+ /* only report in 5% chunks */
+ if (percent >= target->percent_written + 5) {
+ iso_msg_debug(target->image->id, "Processed %u of %u KB (%d %%)",
+ kbw, kbt, percent);
+ target->percent_written = percent;
+ }
+ }
+
+ return ret;
+}
+
+int iso_write_opts_new(IsoWriteOpts **opts, int profile)
+{
+ IsoWriteOpts *wopts;
+
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (profile < 0 || profile > 2) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+
+ wopts = calloc(1, sizeof(IsoWriteOpts));
+ if (wopts == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ switch (profile) {
+ case 0:
+ wopts->level = 1;
+ break;
+ case 1:
+ wopts->level = 2;
+ wopts->rockridge = 1;
+ break;
+ case 2:
+ wopts->level = 2;
+ wopts->rockridge = 1;
+ wopts->joliet = 1;
+ wopts->replace_dir_mode = 1;
+ wopts->replace_file_mode = 1;
+ wopts->replace_uid = 1;
+ wopts->replace_gid = 1;
+ wopts->replace_timestamps = 1;
+ wopts->always_gmt = 1;
+ break;
+ default:
+ /* should never happen */
+ free(wopts);
+ return ISO_ASSERT_FAILURE;
+ break;
+ }
+ wopts->fifo_size = 1024; /* 2 MB buffer */
+ wopts->sort_files = 1; /* file sorting is always good */
+
+ *opts = wopts;
+ return ISO_SUCCESS;
+}
+
+void iso_write_opts_free(IsoWriteOpts *opts)
+{
+ if (opts == NULL) {
+ return;
+ }
+
+ free(opts->output_charset);
+ free(opts);
+}
+
+int iso_write_opts_set_iso_level(IsoWriteOpts *opts, int level)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (level != 1 && level != 2) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ opts->level = level;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_rockridge(IsoWriteOpts *opts, int enable)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->rockridge = enable ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_joliet(IsoWriteOpts *opts, int enable)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->joliet = enable ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_iso1999(IsoWriteOpts *opts, int enable)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->iso1999 = enable ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_omit_version_numbers(IsoWriteOpts *opts, int omit)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->omit_version_numbers = omit ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_allow_deep_paths(IsoWriteOpts *opts, int allow)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->allow_deep_paths = allow ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_allow_longer_paths(IsoWriteOpts *opts, int allow)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->allow_longer_paths = allow ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_max_37_char_filenames(IsoWriteOpts *opts, int allow)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->max_37_char_filenames = allow ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_no_force_dots(IsoWriteOpts *opts, int no)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->no_force_dots = no ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_allow_lowercase(IsoWriteOpts *opts, int allow)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->allow_lowercase = allow ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_allow_full_ascii(IsoWriteOpts *opts, int allow)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->allow_full_ascii = allow ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_relaxed_vol_atts(IsoWriteOpts *opts, int allow)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->relaxed_vol_atts = allow ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_joliet_longer_paths(IsoWriteOpts *opts, int allow)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->joliet_longer_paths = allow ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->sort_files = sort ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_replace_mode(IsoWriteOpts *opts, int dir_mode,
+ int file_mode, int uid, int gid)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (dir_mode < 0 || dir_mode > 2) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ if (file_mode < 0 || file_mode > 2) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ if (uid < 0 || uid > 2) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ if (gid < 0 || gid > 2) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ opts->replace_dir_mode = dir_mode;
+ opts->replace_file_mode = file_mode;
+ opts->replace_uid = uid;
+ opts->replace_gid = gid;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_default_dir_mode(IsoWriteOpts *opts, mode_t dir_mode)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->dir_mode = dir_mode;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_default_file_mode(IsoWriteOpts *opts, mode_t file_mode)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->file_mode = file_mode;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_default_uid(IsoWriteOpts *opts, uid_t uid)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->uid = uid;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_default_gid(IsoWriteOpts *opts, gid_t gid)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->gid = gid;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_replace_timestamps(IsoWriteOpts *opts, int replace)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (replace < 0 || replace > 2) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ opts->replace_timestamps = replace;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_default_timestamp(IsoWriteOpts *opts, time_t timestamp)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->timestamp = timestamp;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_always_gmt(IsoWriteOpts *opts, int gmt)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->always_gmt = gmt ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_output_charset(IsoWriteOpts *opts, const char *charset)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->output_charset = charset ? strdup(charset) : NULL;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_appendable(IsoWriteOpts *opts, int appendable)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->appendable = appendable ? 1 : 0;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_ms_block(IsoWriteOpts *opts, uint32_t ms_block)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->ms_block = ms_block;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_overwrite_buf(IsoWriteOpts *opts, uint8_t *overwrite)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->overwrite = overwrite;
+ return ISO_SUCCESS;
+}
+
+int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (fifo_size < 32) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ opts->fifo_size = fifo_size;
+ return ISO_SUCCESS;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119.h
new file mode 100644
index 00000000..ffb16116
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119.h
@@ -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
+#include
+
+#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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119_tree.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119_tree.c
new file mode 100644
index 00000000..943fa0a4
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119_tree.c
@@ -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
+#include
+#include
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119_tree.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119_tree.h
new file mode 100644
index 00000000..0cd05ee9
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/ecma119_tree.h
@@ -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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/eltorito.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/eltorito.c
new file mode 100644
index 00000000..441b5c15
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/eltorito.c
@@ -0,0 +1,908 @@
+/*
+ * 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
+#include
+
+/**
+ * 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_OPENED;
+ }
+
+ 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_OPENED;
+ }
+ 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_OPENED;
+ }
+
+ 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
+void catalog_free(IsoStream *stream)
+{
+ free(stream->data);
+}
+
+IsoStreamIface catalog_stream_class = {
+ 0,
+ "boot",
+ catalog_open,
+ catalog_close,
+ catalog_get_size,
+ catalog_read,
+ catalog_is_repeatable,
+ catalog_get_id,
+ 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;
+}
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/eltorito.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/eltorito.h
new file mode 100644
index 00000000..3c507997
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/eltorito.h
@@ -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 */
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filesrc.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filesrc.c
new file mode 100644
index 00000000..2c57ce53
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filesrc.c
@@ -0,0 +1,387 @@
+/*
+ * 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
+#include
+#include
+
+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[PATH_MAX];
+ 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);
+ iso_stream_get_file_name(file->stream, name);
+ if (res < 0) {
+ /*
+ * UPS, very ugly error, the best we can do is just to write
+ * 0's to image
+ */
+ 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);
+ 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) {
+ 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"));
+ if (res < 0) {
+ filesrc_close(file);
+ return res; /* aborted due to error severity */
+ }
+ }
+#ifdef LIBISOFS_VERBOSE_DEBUG
+ else {
+ iso_msg_debug(t->image->id, "Writing file %s", 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 */
+ 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);
+ }
+
+ 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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filesrc.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filesrc.h
new file mode 100644
index 00000000..5a3c03c8
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filesrc.h
@@ -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
+
+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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filter.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filter.c
new file mode 100644
index 00000000..a7f2be69
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filter.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2008 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 "filter.h"
+#include "node.h"
+
+
+void iso_filter_ref(FilterContext *filter)
+{
+ ++filter->refcount;
+}
+
+void iso_filter_unref(FilterContext *filter)
+{
+ if (--filter->refcount == 0) {
+ filter->free(filter);
+ free(filter);
+ }
+}
+
+int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag)
+{
+ int ret;
+ IsoStream *original, *filtered;
+ if (file == NULL || filter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ original = file->stream;
+
+ if (!iso_stream_is_repeatable(original)) {
+ /* TODO use custom error */
+ return ISO_WRONG_ARG_VALUE;
+ }
+
+ ret = filter->get_filter(filter, original, &filtered);
+ if (ret < 0) {
+ return ret;
+ }
+ iso_stream_unref(original);
+ file->stream = filtered;
+ return ISO_SUCCESS;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filter.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filter.h
new file mode 100644
index 00000000..f711fe31
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filter.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2008 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_FILTER_H_
+#define LIBISO_FILTER_H_
+
+/*
+ * Definitions of filters.
+ */
+
+/* dev_id for stream identification */
+#define XOR_ENCRYPT_DEV_ID 1
+
+typedef struct filter_context FilterContext;
+
+struct filter_context {
+ int version; /* reserved for future usage, set to 0 */
+ int refcount;
+
+ /** filter specific shared data */
+ void *data;
+
+ /**
+ * Factory method to create a filtered stream from another stream.
+ *
+ * @param original
+ * The original stream to be filtered. If the filter needs a ref to
+ * it (most cases), it should take a ref to it with iso_stream_ref().
+ * @param filtered
+ * Will be filled with the filtered IsoStream (reference belongs to
+ * caller).
+ * @return
+ * 1 on success, < 0 on error
+ */
+ int (*get_filter)(FilterContext *filter, IsoStream *original,
+ IsoStream **filtered);
+
+ /**
+ * Free implementation specific data. Should never be called by user.
+ * Use iso_filter_unref() instead.
+ */
+ void (*free)(FilterContext *filter);
+};
+
+/**
+ *
+ * @param flag
+ * Reserved for future usage, pass always 0 for now.
+ * TODO in a future a different value can mean filter caching, where
+ * the filter is applied once and the filtered file is stored in a temp
+ * dir. This prevent filter to be applied several times.
+ */
+int iso_file_add_filter(IsoFile *file, FilterContext *filter, int flag);
+
+void iso_filter_ref(FilterContext *filter);
+void iso_filter_unref(FilterContext *filter);
+
+#endif /*LIBISO_FILTER_H_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filters/xor_encrypt.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filters/xor_encrypt.c
new file mode 100644
index 00000000..be83f725
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/filters/xor_encrypt.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2008 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 "../filter.h"
+#include "../fsource.h"
+
+/*
+ * A simple Filter implementation for example purposes. It encrypts a file
+ * by XORing each byte by a given key.
+ */
+
+static ino_t xor_ino_id = 0;
+
+typedef struct
+{
+ IsoStream *orig;
+ uint8_t key;
+ ino_t id;
+} XorEncryptStreamData;
+
+static
+int xor_encrypt_stream_open(IsoStream *stream)
+{
+ XorEncryptStreamData *data;
+ if (stream == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = (XorEncryptStreamData*)stream->data;
+ return iso_stream_open(data->orig);
+}
+
+static
+int xor_encrypt_stream_close(IsoStream *stream)
+{
+ XorEncryptStreamData *data;
+ if (stream == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = stream->data;
+ return iso_stream_close(data->orig);
+}
+
+static
+off_t xor_encrypt_stream_get_size(IsoStream *stream)
+{
+ XorEncryptStreamData *data;
+ if (stream == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = stream->data;
+ return iso_stream_get_size(data->orig);
+}
+
+static
+int xor_encrypt_stream_read(IsoStream *stream, void *buf, size_t count)
+{
+ int ret, len;
+ XorEncryptStreamData *data;
+ uint8_t *buffer = buf;
+
+ if (stream == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = stream->data;
+ ret = iso_stream_read(data->orig, buf, count);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* xor */
+ for (len = 0; len < ret; ++len) {
+ buffer[len] = buffer[len] ^ data->key;
+ }
+
+ return ret;
+}
+
+static
+int xor_encrypt_stream_is_repeatable(IsoStream *stream)
+{
+ /* the filter can't be created if underlying stream is not repeatable */
+ return 1;
+}
+
+static
+void xor_encrypt_stream_get_id(IsoStream *stream, unsigned int *fs_id,
+ dev_t *dev_id, ino_t *ino_id)
+{
+ XorEncryptStreamData *data = stream->data;
+ *fs_id = ISO_FILTER_FS_ID;
+ *dev_id = XOR_ENCRYPT_DEV_ID;
+ *ino_id = data->id;
+}
+
+static
+void xor_encrypt_stream_free(IsoStream *stream)
+{
+ XorEncryptStreamData *data = stream->data;
+ iso_stream_unref(data->orig);
+ free(data);
+}
+
+IsoStreamIface xor_encrypt_stream_class = {
+ 0,
+ "xorf",
+ xor_encrypt_stream_open,
+ xor_encrypt_stream_close,
+ xor_encrypt_stream_get_size,
+ xor_encrypt_stream_read,
+ xor_encrypt_stream_is_repeatable,
+ xor_encrypt_stream_get_id,
+ xor_encrypt_stream_free
+};
+
+
+static
+void xor_encrypt_filter_free(FilterContext *filter)
+{
+ free(filter->data);
+}
+
+static
+int xor_encrypt_filter_get_filter(FilterContext *filter, IsoStream *original,
+ IsoStream **filtered)
+{
+ IsoStream *str;
+ XorEncryptStreamData *data;
+
+ if (filter == NULL || original == NULL || filtered == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ str = malloc(sizeof(IsoStream));
+ if (str == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ data = malloc(sizeof(XorEncryptStreamData));
+ if (str == NULL) {
+ free(str);
+ return ISO_OUT_OF_MEM;
+ }
+
+ /* fill data */
+ data->key = *((uint8_t*)filter->data);
+ data->id = xor_ino_id++;
+
+ /* get reference to the source */
+ data->orig = original;
+ iso_stream_ref(original);
+
+ str->refcount = 1;
+ str->data = data;
+ str->class = &xor_encrypt_stream_class;
+
+ *filtered = str;
+ return ISO_SUCCESS;
+}
+
+int create_xor_encrypt_filter(uint8_t key, FilterContext **filter)
+{
+ FilterContext *f;
+ uint8_t *data;
+
+ f = calloc(1, sizeof(FilterContext));
+ if (f == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ data = malloc(sizeof(uint8_t));
+ if (data == NULL) {
+ free(f);
+ return ISO_OUT_OF_MEM;
+ }
+ f->refcount = 1;
+ f->version = 0;
+ *data = key;
+ f->data = data;
+ f->free = xor_encrypt_filter_free;
+ f->get_filter = xor_encrypt_filter_get_filter;
+
+ return ISO_SUCCESS;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/find.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/find.c
new file mode 100644
index 00000000..797ef881
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/find.c
@@ -0,0 +1,629 @@
+/*
+ * Copyright (c) 2008 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
+#include
+
+struct iso_find_condition
+{
+ /*
+ * Check whether the given node matches this condition.
+ *
+ * @param cond
+ * The condition to check
+ * @param node
+ * The node that should be checked
+ * @return
+ * 1 if the node matches the condition, 0 if not
+ */
+ int (*matches)(IsoFindCondition *cond, IsoNode *node);
+
+ /**
+ * Free condition specific data
+ */
+ void (*free)(IsoFindCondition*);
+
+ /** condition specific data */
+ void *data;
+};
+
+struct find_iter_data
+{
+ IsoDirIter *iter;
+ IsoFindCondition *cond;
+};
+
+static
+int find_iter_next(IsoDirIter *iter, IsoNode **node)
+{
+ int ret;
+ IsoNode *n;
+ struct find_iter_data *data = iter->data;
+
+ while ((ret = iso_dir_iter_next(data->iter, &n)) == 1) {
+ if (data->cond->matches(data->cond, n)) {
+ *node = n;
+ break;
+ }
+ }
+ return ret;
+}
+
+static
+int find_iter_has_next(IsoDirIter *iter)
+{
+ struct find_iter_data *data = iter->data;
+
+ /*
+ * FIXME wrong implementation!!!! the underlying iter may have more nodes,
+ * but they may not match find conditions
+ */
+ return iso_dir_iter_has_next(data->iter);
+}
+
+static
+void find_iter_free(IsoDirIter *iter)
+{
+ struct find_iter_data *data = iter->data;
+ data->cond->free(data->cond);
+ free(data->cond);
+ iso_dir_iter_free(data->iter);
+ free(iter->data);
+}
+
+static
+int find_iter_take(IsoDirIter *iter)
+{
+ struct find_iter_data *data = iter->data;
+ return iso_dir_iter_take(data->iter);
+}
+
+static
+int find_iter_remove(IsoDirIter *iter)
+{
+ struct find_iter_data *data = iter->data;
+ return iso_dir_iter_remove(data->iter);
+}
+
+void find_notify_child_taken(IsoDirIter *iter, IsoNode *node)
+{
+ /* nothing to do */
+ return;
+}
+
+static
+struct iso_dir_iter_iface find_iter_class = {
+ find_iter_next,
+ find_iter_has_next,
+ find_iter_free,
+ find_iter_take,
+ find_iter_remove,
+ find_notify_child_taken
+};
+
+int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond,
+ IsoDirIter **iter)
+{
+ int ret;
+ IsoDirIter *children;
+ IsoDirIter *it;
+ struct find_iter_data *data;
+
+ if (dir == NULL || cond == NULL || iter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ it = malloc(sizeof(IsoDirIter));
+ if (it == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ data = malloc(sizeof(struct find_iter_data));
+ if (data == NULL) {
+ free(it);
+ return ISO_OUT_OF_MEM;
+ }
+ ret = iso_dir_get_children(dir, &children);
+ if (ret < 0) {
+ free(it);
+ free(data);
+ return ret;
+ }
+
+ it->class = &find_iter_class;
+ it->dir = (IsoDir*)dir;
+ data->iter = children;
+ data->cond = cond;
+ it->data = data;
+
+ if (iso_dir_iter_register(it) < 0) {
+ free(it);
+ return ISO_OUT_OF_MEM;
+ }
+
+ *iter = it;
+ return ISO_SUCCESS;
+}
+
+/*************** find by name wildcard condition *****************/
+
+static
+int cond_name_matches(IsoFindCondition *cond, IsoNode *node)
+{
+ char *pattern = (char*) cond->data;
+ int ret = fnmatch(pattern, node->name, 0);
+ return ret == 0 ? 1 : 0;
+}
+
+static
+void cond_name_free(IsoFindCondition *cond)
+{
+ free(cond->data);
+}
+
+/**
+ * Create a new condition that checks if the node name matches the given
+ * wildcard.
+ *
+ * @param wildcard
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_name(const char *wildcard)
+{
+ IsoFindCondition *cond;
+ if (wildcard == NULL) {
+ return NULL;
+ }
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ cond->data = strdup(wildcard);
+ cond->free = cond_name_free;
+ cond->matches = cond_name_matches;
+ return cond;
+}
+
+/*************** find by mode condition *****************/
+
+static
+int cond_mode_matches(IsoFindCondition *cond, IsoNode *node)
+{
+ mode_t *mask = (mode_t*) cond->data;
+ return node->mode & *mask ? 1 : 0;
+}
+
+static
+void cond_mode_free(IsoFindCondition *cond)
+{
+ free(cond->data);
+}
+
+/**
+ * Create a new condition that checks the node mode against a mode mask. It
+ * can be used to check both file type and permissions.
+ *
+ * For example:
+ *
+ * iso_new_find_conditions_mode(S_IFREG) : search for regular files
+ * iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character
+ * devices where owner has write permissions.
+ *
+ * @param mask
+ * Mode mask to AND against node mode.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_mode(mode_t mask)
+{
+ IsoFindCondition *cond;
+ mode_t *data;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ data = malloc(sizeof(mode_t));
+ if (data == NULL) {
+ free(cond);
+ return NULL;
+ }
+ *data = mask;
+ cond->data = data;
+ cond->free = cond_mode_free;
+ cond->matches = cond_mode_matches;
+ return cond;
+}
+
+/*************** find by gid condition *****************/
+
+static
+int cond_gid_matches(IsoFindCondition *cond, IsoNode *node)
+{
+ gid_t *gid = (gid_t*) cond->data;
+ return node->gid == *gid ? 1 : 0;
+}
+
+static
+void cond_gid_free(IsoFindCondition *cond)
+{
+ free(cond->data);
+}
+
+/**
+ * Create a new condition that checks the node gid.
+ *
+ * @param gid
+ * Desired Group Id.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_gid(gid_t gid)
+{
+ IsoFindCondition *cond;
+ gid_t *data;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ data = malloc(sizeof(gid_t));
+ if (data == NULL) {
+ free(cond);
+ return NULL;
+ }
+ *data = gid;
+ cond->data = data;
+ cond->free = cond_gid_free;
+ cond->matches = cond_gid_matches;
+ return cond;
+}
+
+/*************** find by uid condition *****************/
+
+static
+int cond_uid_matches(IsoFindCondition *cond, IsoNode *node)
+{
+ uid_t *uid = (uid_t*) cond->data;
+ return node->uid == *uid ? 1 : 0;
+}
+
+static
+void cond_uid_free(IsoFindCondition *cond)
+{
+ free(cond->data);
+}
+
+/**
+ * Create a new condition that checks the node uid.
+ *
+ * @param uid
+ * Desired User Id.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_uid(uid_t uid)
+{
+ IsoFindCondition *cond;
+ uid_t *data;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ data = malloc(sizeof(uid_t));
+ if (data == NULL) {
+ free(cond);
+ return NULL;
+ }
+ *data = uid;
+ cond->data = data;
+ cond->free = cond_uid_free;
+ cond->matches = cond_uid_matches;
+ return cond;
+}
+
+/*************** find by timestamps condition *****************/
+
+struct cond_times
+{
+ time_t time;
+ int what_time; /* 0 atime, 1 mtime, 2 ctime */
+ enum iso_find_comparisons comparison;
+};
+
+static
+int cond_time_matches(IsoFindCondition *cond, IsoNode *node)
+{
+ time_t node_time;
+ struct cond_times *data = cond->data;
+
+ switch (data->what_time) {
+ case 0: node_time = node->atime; break;
+ case 1: node_time = node->mtime; break;
+ default: node_time = node->ctime; break;
+ }
+
+ switch (data->comparison) {
+ case ISO_FIND_COND_GREATER:
+ return node_time > data->time ? 1 : 0;
+ case ISO_FIND_COND_GREATER_OR_EQUAL:
+ return node_time >= data->time ? 1 : 0;
+ case ISO_FIND_COND_EQUAL:
+ return node_time == data->time ? 1 : 0;
+ case ISO_FIND_COND_LESS:
+ return node_time < data->time ? 1 : 0;
+ case ISO_FIND_COND_LESS_OR_EQUAL:
+ return node_time <= data->time ? 1 : 0;
+ }
+ /* should never happen */
+ return 0;
+}
+
+static
+void cond_time_free(IsoFindCondition *cond)
+{
+ free(cond->data);
+}
+
+/**
+ * Create a new condition that checks the time of last access.
+ *
+ * @param time
+ * Time to compare against IsoNode atime.
+ * @param comparison
+ * Comparison to be done between IsoNode atime and submitted time.
+ * Note that ISO_FIND_COND_GREATER, for example, is true if the node
+ * time is greater than the submitted time.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_atime(time_t time,
+ enum iso_find_comparisons comparison)
+{
+ IsoFindCondition *cond;
+ struct cond_times *data;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ data = malloc(sizeof(struct cond_times));
+ if (data == NULL) {
+ free(cond);
+ return NULL;
+ }
+ data->time = time;
+ data->comparison = comparison;
+ data->what_time = 0; /* atime */
+ cond->data = data;
+ cond->free = cond_time_free;
+ cond->matches = cond_time_matches;
+ return cond;
+}
+
+/**
+ * Create a new condition that checks the time of last modification.
+ *
+ * @param time
+ * Time to compare against IsoNode mtime.
+ * @param comparison
+ * Comparison to be done between IsoNode mtime and submitted time.
+ * Note that ISO_FIND_COND_GREATER, for example, is true if the node
+ * time is greater than the submitted time.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_mtime(time_t time,
+ enum iso_find_comparisons comparison)
+{
+ IsoFindCondition *cond;
+ struct cond_times *data;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ data = malloc(sizeof(struct cond_times));
+ if (data == NULL) {
+ free(cond);
+ return NULL;
+ }
+ data->time = time;
+ data->comparison = comparison;
+ data->what_time = 1; /* mtime */
+ cond->data = data;
+ cond->free = cond_time_free;
+ cond->matches = cond_time_matches;
+ return cond;
+}
+
+/**
+ * Create a new condition that checks the time of last status change.
+ *
+ * @param time
+ * Time to compare against IsoNode ctime.
+ * @param comparison
+ * Comparison to be done between IsoNode ctime and submitted time.
+ * Note that ISO_FIND_COND_GREATER, for example, is true if the node
+ * time is greater than the submitted time.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_ctime(time_t time,
+ enum iso_find_comparisons comparison)
+{
+ IsoFindCondition *cond;
+ struct cond_times *data;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ data = malloc(sizeof(struct cond_times));
+ if (data == NULL) {
+ free(cond);
+ return NULL;
+ }
+ data->time = time;
+ data->comparison = comparison;
+ data->what_time = 2; /* ctime */
+ cond->data = data;
+ cond->free = cond_time_free;
+ cond->matches = cond_time_matches;
+ return cond;
+}
+
+/*************** logical operations on conditions *****************/
+
+struct logical_binary_conditions {
+ IsoFindCondition *a;
+ IsoFindCondition *b;
+};
+
+static
+void cond_logical_binary_free(IsoFindCondition *cond)
+{
+ struct logical_binary_conditions *data;
+ data = cond->data;
+ data->a->free(data->a);
+ free(data->a);
+ data->b->free(data->b);
+ free(data->b);
+ free(cond->data);
+}
+
+static
+int cond_logical_and_matches(IsoFindCondition *cond, IsoNode *node)
+{
+ struct logical_binary_conditions *data = cond->data;
+ return data->a->matches(data->a, node) && data->b->matches(data->b, node);
+}
+
+/**
+ * Create a new condition that check if the two given conditions are
+ * valid.
+ *
+ * @param a
+ * @param b
+ * IsoFindCondition to compare
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a,
+ IsoFindCondition *b)
+{
+ IsoFindCondition *cond;
+ struct logical_binary_conditions *data;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ data = malloc(sizeof(struct logical_binary_conditions));
+ if (data == NULL) {
+ free(cond);
+ return NULL;
+ }
+ data->a = a;
+ data->b = b;
+ cond->data = data;
+ cond->free = cond_logical_binary_free;
+ cond->matches = cond_logical_and_matches;
+ return cond;
+}
+
+static
+int cond_logical_or_matches(IsoFindCondition *cond, IsoNode *node)
+{
+ struct logical_binary_conditions *data = cond->data;
+ return data->a->matches(data->a, node) || data->b->matches(data->b, node);
+}
+
+/**
+ * Create a new condition that check if at least one the two given conditions
+ * is valid.
+ *
+ * @param a
+ * @param b
+ * IsoFindCondition to compare
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a,
+ IsoFindCondition *b)
+{
+ IsoFindCondition *cond;
+ struct logical_binary_conditions *data;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ data = malloc(sizeof(struct logical_binary_conditions));
+ if (data == NULL) {
+ free(cond);
+ return NULL;
+ }
+ data->a = a;
+ data->b = b;
+ cond->data = data;
+ cond->free = cond_logical_binary_free;
+ cond->matches = cond_logical_or_matches;
+ return cond;
+}
+
+static
+void cond_not_free(IsoFindCondition *cond)
+{
+ IsoFindCondition *negate = cond->data;
+ negate->free(negate);
+ free(negate);
+}
+
+static
+int cond_not_matches(IsoFindCondition *cond, IsoNode *node)
+{
+ IsoFindCondition *negate = cond->data;
+ return !(negate->matches(negate, node));
+}
+
+/**
+ * Create a new condition that check if the given conditions is false.
+ *
+ * @param negate
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate)
+{
+ IsoFindCondition *cond;
+ cond = malloc(sizeof(IsoFindCondition));
+ if (cond == NULL) {
+ return NULL;
+ }
+ cond->data = negate;
+ cond->free = cond_not_free;
+ cond->matches = cond_not_matches;
+ return cond;
+}
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fs_image.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fs_image.c
new file mode 100644
index 00000000..8394cfda
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fs_image.c
@@ -0,0 +1,2642 @@
+/*
+ * 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 an ISO image, using an
+ * IsoDataSource to read image data.
+ */
+
+#include "libisofs.h"
+#include "ecma119.h"
+#include "messages.h"
+#include "rockridge.h"
+#include "image.h"
+#include "tree.h"
+#include "eltorito.h"
+
+#include
+#include
+#include
+#include
+#include
+
+
+/**
+ * Options for image reading.
+ * There are four kind of options:
+ * - Related to multisession support.
+ * In most cases, an image begins at LBA 0 of the data source. However,
+ * in multisession discs, the later image begins in the last session on
+ * disc. The block option can be used to specify the start of that last
+ * session.
+ * - Related to the tree that will be read.
+ * As default, when Rock Ridge extensions are present in the image, that
+ * will be used to get the tree. If RR extensions are not present, libisofs
+ * will use the Joliet extensions if available. Finally, the plain ISO-9660
+ * tree is used if neither RR nor Joliet extensions are available. With
+ * norock, nojoliet, and preferjoliet options, you can change this
+ * default behavior.
+ * - Related to default POSIX attributes.
+ * When Rock Ridege extensions are not used, libisofs can't figure out what
+ * are the the permissions, uid or gid for the files. You should supply
+ * default values for that.
+ */
+struct iso_read_opts
+{
+ /**
+ * Block where the image begins, usually 0, can be different on a
+ * multisession disc.
+ */
+ uint32_t block;
+
+ unsigned int norock : 1; /*< Do not read Rock Ridge extensions */
+ unsigned int nojoliet : 1; /*< Do not read Joliet extensions */
+ unsigned int noiso1999 : 1; /*< Do not read ISO 9660:1999 enhanced tree */
+
+ /**
+ * When both Joliet and RR extensions are present, the RR tree is used.
+ * If you prefer using Joliet, set this to 1.
+ */
+ unsigned int preferjoliet : 1;
+
+ uid_t uid; /**< Default uid when no RR */
+ gid_t gid; /**< Default uid when no RR */
+ mode_t dir_mode; /**< Default mode when no RR (only permissions) */
+ mode_t file_mode;
+ /* TODO #00024 : option to convert names to lower case for iso reading */
+
+ /**
+ * Input charset for RR file names. NULL to use default locale charset.
+ */
+ char *input_charset;
+};
+
+/**
+ * Return information for image.
+ * Both size, hasRR and hasJoliet will be filled by libisofs with suitable
+ * values.
+ */
+struct iso_read_image_features
+{
+ /**
+ * Will be filled with the size (in 2048 byte block) of the image, as
+ * reported in the PVM.
+ */
+ uint32_t size;
+
+ /** It will be set to 1 if RR extensions are present, to 0 if not. */
+ unsigned int hasRR :1;
+
+ /** It will be set to 1 if Joliet extensions are present, to 0 if not. */
+ unsigned int hasJoliet :1;
+
+ /**
+ * It will be set to 1 if the image is an ISO 9660:1999, i.e. it has
+ * a version 2 Enhanced Volume Descriptor.
+ */
+ unsigned int hasIso1999 :1;
+
+ /** It will be set to 1 if El-Torito boot record is present, to 0 if not.*/
+ unsigned int hasElTorito :1;
+};
+
+static int ifs_fs_open(IsoImageFilesystem *fs);
+static int ifs_fs_close(IsoImageFilesystem *fs);
+static int iso_file_source_new_ifs(IsoImageFilesystem *fs,
+ IsoFileSource *parent, struct ecma119_dir_record *record,
+ IsoFileSource **src);
+
+/** unique identifier for each image */
+unsigned int fs_dev_id = 0;
+
+/**
+ * Should the RR extensions be read?
+ */
+enum read_rr_ext {
+ RR_EXT_NO = 0, /*< Do not use RR extensions */
+ RR_EXT_110 = 1, /*< RR extensions conforming version 1.10 */
+ RR_EXT_112 = 2 /*< RR extensions conforming version 1.12 */
+};
+
+/**
+ * Private data for the image IsoFilesystem
+ */
+typedef struct
+{
+ /** DataSource from where data will be read */
+ IsoDataSource *src;
+
+ /** unique id for the each image (filesystem instance) */
+ unsigned int id;
+
+ /**
+ * Counter of the times the filesystem has been openned still pending of
+ * close. It is used to keep track of when we need to actually open or
+ * close the IsoDataSource.
+ */
+ unsigned int open_count;
+
+ uid_t uid; /**< Default uid when no RR */
+ gid_t gid; /**< Default uid when no RR */
+ mode_t dir_mode; /**< Default mode when no RR (only permissions) */
+ mode_t file_mode;
+
+ int msgid;
+
+ char *input_charset; /**< Input charset for RR names */
+ char *local_charset; /**< For RR names, will be set to the locale one */
+
+ /**
+ * Will be filled with the block lba of the extend for the root directory
+ * of the hierarchy that will be read, either from the PVD (ISO, RR) or
+ * from the SVD (Joliet)
+ */
+ uint32_t iso_root_block;
+
+ /**
+ * Will be filled with the block lba of the extend for the root directory,
+ * as read from the PVM
+ */
+ uint32_t pvd_root_block;
+
+ /**
+ * Will be filled with the block lba of the extend for the root directory,
+ * as read from the SVD
+ */
+ uint32_t svd_root_block;
+
+ /**
+ * Will be filled with the block lba of the extend for the root directory,
+ * as read from the enhanced volume descriptor (ISO 9660:1999)
+ */
+ uint32_t evd_root_block;
+
+ /**
+ * If we need to read RR extensions. i.e., if the image contains RR
+ * extensions, and the user wants to read them.
+ */
+ enum read_rr_ext rr;
+
+ /**
+ * Bytes skipped within the System Use field of a directory record, before
+ * the beginning of the SUSP system user entries. See IEEE 1281, SUSP. 5.3.
+ */
+ uint8_t len_skp;
+
+ /* Volume attributes */
+ 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;
+
+ /* extension information */
+
+ /**
+ * RR version being used in image.
+ * 0 no RR extension, 1 RRIP 1.10, 2 RRIP 1.12
+ */
+ enum read_rr_ext rr_version;
+
+ /** If Joliet extensions are available on image */
+ unsigned int joliet : 1;
+
+ /** If ISO 9660:1999 is available on image */
+ unsigned int iso1999 : 1;
+
+ /**
+ * Number of blocks of the volume, as reported in the PVM.
+ */
+ uint32_t nblocks;
+
+ /* el-torito information */
+ unsigned int eltorito : 1; /* is el-torito available */
+ unsigned int bootable:1; /**< If the entry is bootable. */
+ 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. */
+ uint32_t imgblock; /**< Block for El-Torito boot image */
+ uint32_t catblock; /**< Block for El-Torito catalog */
+
+} _ImageFsData;
+
+typedef struct image_fs_data ImageFileSourceData;
+
+struct image_fs_data
+{
+ IsoImageFilesystem *fs; /**< reference to the image it belongs to */
+ IsoFileSource *parent; /**< reference to the parent (NULL if root) */
+
+ struct stat info; /**< filled struct stat */
+ char *name; /**< name of this file */
+
+ uint32_t block; /**< block of the extend */
+ unsigned int opened : 2; /**< 0 not opened, 1 opened file, 2 opened dir */
+
+ /* info for content reading */
+ struct
+ {
+ /**
+ * - For regular files, once opened it points to a temporary data
+ * buffer of 2048 bytes.
+ * - For dirs, once opened it points to a IsoFileSource* array with
+ * its children
+ * - For symlinks, it points to link destination
+ */
+ void *content;
+
+ /**
+ * - For regular files, number of bytes already read.
+ */
+ off_t offset;
+ } data;
+};
+
+struct child_list
+{
+ IsoFileSource *file;
+ struct child_list *next;
+};
+
+void child_list_free(struct child_list *list)
+{
+ struct child_list *temp;
+ struct child_list *next = list;
+ while (next != NULL) {
+ temp = next->next;
+ iso_file_source_unref(next->file);
+ free(next);
+ next = temp;
+ }
+}
+
+static
+char* ifs_get_path(IsoFileSource *src)
+{
+ ImageFileSourceData *data;
+ data = src->data;
+
+ if (data->parent == NULL) {
+ return strdup("");
+ } else {
+ char *path = ifs_get_path(data->parent);
+ int pathlen = strlen(path);
+ path = realloc(path, pathlen + strlen(data->name) + 2);
+ path[pathlen] = '/';
+ path[pathlen + 1] = '\0';
+ return strcat(path, data->name);
+ }
+}
+
+static
+char* ifs_get_name(IsoFileSource *src)
+{
+ ImageFileSourceData *data;
+ data = src->data;
+ return data->name == NULL ? NULL : strdup(data->name);
+}
+
+static
+int ifs_lstat(IsoFileSource *src, struct stat *info)
+{
+ ImageFileSourceData *data;
+
+ if (src == NULL || info == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = src->data;
+ *info = data->info;
+ return ISO_SUCCESS;
+}
+
+static
+int ifs_stat(IsoFileSource *src, struct stat *info)
+{
+ ImageFileSourceData *data;
+
+ if (src == NULL || info == NULL || src->data == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = (ImageFileSourceData*)src->data;
+
+ if (S_ISLNK(data->info.st_mode)) {
+ /* TODO #00012 : support follow symlinks on image filesystem */
+ return ISO_FILE_BAD_PATH;
+ }
+ *info = data->info;
+ return ISO_SUCCESS;
+}
+
+static
+int ifs_access(IsoFileSource *src)
+{
+ /* we always have access, it is controlled by DataSource */
+ return ISO_SUCCESS;
+}
+
+/**
+ * Read all directory records in a directory, and creates an IsoFileSource for
+ * each of them, storing them in the data field of the IsoFileSource for the
+ * given dir.
+ */
+static
+int read_dir(ImageFileSourceData *data)
+{
+ int ret;
+ uint32_t size;
+ uint32_t block;
+ IsoImageFilesystem *fs;
+ _ImageFsData *fsdata;
+ struct ecma119_dir_record *record;
+ uint8_t buffer[BLOCK_SIZE];
+ IsoFileSource *child = NULL;
+ uint32_t pos = 0;
+ uint32_t tlen = 0;
+
+ if (data == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ fs = data->fs;
+ fsdata = fs->data;
+
+ block = data->block;
+ ret = fsdata->src->read_block(fsdata->src, block, buffer);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* "." entry, get size of the dir and skip */
+ record = (struct ecma119_dir_record *)(buffer + pos);
+ size = iso_read_bb(record->length, 4, NULL);
+ tlen += record->len_dr[0];
+ pos += record->len_dr[0];
+
+ /* skip ".." */
+ record = (struct ecma119_dir_record *)(buffer + pos);
+ tlen += record->len_dr[0];
+ pos += record->len_dr[0];
+
+ while (tlen < size) {
+
+ record = (struct ecma119_dir_record *)(buffer + pos);
+ if (pos == 2048 || record->len_dr[0] == 0) {
+ /*
+ * The directory entries are splitted in several blocks
+ * read next block
+ */
+ ret = fsdata->src->read_block(fsdata->src, ++block, buffer);
+ if (ret < 0) {
+ return ret;
+ }
+ tlen += 2048 - pos;
+ pos = 0;
+ continue;
+ }
+
+ /*
+ * What about ignoring files with existence flag?
+ * if (record->flags[0] & 0x01)
+ * continue;
+ */
+
+ /*
+ * For a extrange reason, mkisofs relocates directories under
+ * a RR_MOVED dir. It seems that it is only used for that purposes,
+ * and thus it should be removed from the iso tree before
+ * generating a new image with libisofs, that don't uses it.
+ */
+ if (data->parent == NULL && record->len_fi[0] == 8
+ && !strncmp((char*)record->file_id, "RR_MOVED", 8)) {
+
+ iso_msg_debug(fsdata->msgid, "Skipping RR_MOVE entry.");
+
+ tlen += record->len_dr[0];
+ pos += record->len_dr[0];
+ continue;
+ }
+
+ /*
+ * We pass a NULL parent instead of dir, to prevent the circular
+ * reference from child to parent.
+ */
+ ret = iso_file_source_new_ifs(fs, NULL, record, &child);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* add to the child list */
+ if (ret != 0) {
+ struct child_list *node;
+ node = malloc(sizeof(struct child_list));
+ if (node == NULL) {
+ iso_file_source_unref(child);
+ return ISO_OUT_OF_MEM;
+ }
+ /*
+ * Note that we insert in reverse order. This leads to faster
+ * addition here, but also when adding to the tree, as insertion
+ * will be done, sorted, in the first position of the list.
+ */
+ node->next = data->data.content;
+ node->file = child;
+ data->data.content = node;
+ }
+
+ tlen += record->len_dr[0];
+ pos += record->len_dr[0];
+ }
+
+ return ISO_SUCCESS;
+}
+
+static
+int ifs_open(IsoFileSource *src)
+{
+ int ret;
+ ImageFileSourceData *data;
+
+ if (src == NULL || src->data == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = (ImageFileSourceData*)src->data;
+
+ if (data->opened) {
+ return ISO_FILE_ALREADY_OPENED;
+ }
+
+ if (S_ISDIR(data->info.st_mode)) {
+ /* ensure fs is openned */
+ ret = data->fs->open(data->fs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /*
+ * Cache all directory entries.
+ * This can waste more memory, but improves as disc is read in much more
+ * sequencially way, thus reducing jump between tracks on disc
+ */
+ ret = read_dir(data);
+ data->fs->close(data->fs);
+
+ if (ret < 0) {
+ /* free probably allocated children */
+ child_list_free((struct child_list*)data->data.content);
+ } else {
+ data->opened = 2;
+ }
+
+ return ret;
+ } else if (S_ISREG(data->info.st_mode)) {
+ /* ensure fs is openned */
+ ret = data->fs->open(data->fs);
+ if (ret < 0) {
+ return ret;
+ }
+ data->data.content = malloc(BLOCK_SIZE);
+ if (data->data.content == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ data->data.offset = 0;
+ data->opened = 1;
+ } else {
+ /* symlinks and special files inside image can't be openned */
+ return ISO_FILE_ERROR;
+ }
+ return ISO_SUCCESS;
+}
+
+static
+int ifs_close(IsoFileSource *src)
+{
+ ImageFileSourceData *data;
+
+ if (src == NULL || src->data == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = (ImageFileSourceData*)src->data;
+
+ if (!data->opened) {
+ return ISO_FILE_NOT_OPENED;
+ }
+
+ if (data->opened == 2) {
+ /*
+ * close a dir, free all pending pre-allocated children.
+ * not that we don't need to close the filesystem, it was already
+ * closed
+ */
+ child_list_free((struct child_list*) data->data.content);
+ data->data.content = NULL;
+ data->opened = 0;
+ } else if (data->opened == 1) {
+ /* close regular file */
+ free(data->data.content);
+ data->fs->close(data->fs);
+ data->data.content = NULL;
+ data->opened = 0;
+ } else {
+ /* TODO only dirs and files supported for now */
+ return ISO_ERROR;
+ }
+
+ return ISO_SUCCESS;
+}
+
+/**
+ * Attempts to read up to count bytes from the given source into
+ * the buffer starting at buf.
+ *
+ * The file src must be open() before calling this, and close() when no
+ * more needed. Not valid for dirs. On symlinks it reads the destination
+ * file.
+ *
+ * @return
+ * number of bytes read, 0 if EOF, < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_FILE_NOT_OPENED
+ * ISO_FILE_IS_DIR
+ * ISO_OUT_OF_MEM
+ * ISO_INTERRUPTED
+ */
+static
+int ifs_read(IsoFileSource *src, void *buf, size_t count)
+{
+ int ret;
+ ImageFileSourceData *data;
+ uint32_t read = 0;
+
+ if (src == NULL || src->data == NULL || buf == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (count == 0) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ data = (ImageFileSourceData*)src->data;
+
+ if (!data->opened) {
+ return ISO_FILE_NOT_OPENED;
+ } else if (data->opened != 1) {
+ return ISO_FILE_IS_DIR;
+ }
+
+ while (read < count && data->data.offset < data->info.st_size) {
+ size_t bytes;
+ uint8_t *orig;
+
+ if (data->data.offset % BLOCK_SIZE == 0) {
+ /* we need to buffer next block */
+ uint32_t block;
+ _ImageFsData *fsdata;
+
+ if (data->data.offset >= data->info.st_size) {
+ /* EOF */
+ break;
+ }
+ fsdata = data->fs->data;
+ block = data->block + (data->data.offset / BLOCK_SIZE);
+ ret = fsdata->src->read_block(fsdata->src, block,
+ data->data.content);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ /* how much can I read */
+ bytes = MIN(BLOCK_SIZE - (data->data.offset % BLOCK_SIZE),
+ count - read);
+ if (data->data.offset + (off_t)bytes > data->info.st_size) {
+ bytes = data->info.st_size - data->data.offset;
+ }
+ orig = data->data.content;
+ orig += data->data.offset % BLOCK_SIZE;
+ memcpy((uint8_t*)buf + read, orig, bytes);
+ read += bytes;
+ data->data.offset += (off_t)bytes;
+ }
+ return read;
+}
+
+static
+int ifs_readdir(IsoFileSource *src, IsoFileSource **child)
+{
+ ImageFileSourceData *data, *cdata;
+ struct child_list *children;
+
+ if (src == NULL || src->data == NULL || child == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = (ImageFileSourceData*)src->data;
+
+ if (!data->opened) {
+ return ISO_FILE_NOT_OPENED;
+ } else if (data->opened != 2) {
+ return ISO_FILE_IS_NOT_DIR;
+ }
+
+ /* return the first child and free it */
+ if (data->data.content == NULL) {
+ return 0; /* EOF */
+ }
+
+ children = (struct child_list*)data->data.content;
+ *child = children->file;
+ cdata = (ImageFileSourceData*)(*child)->data;
+
+ /* set the ref to the parent */
+ cdata->parent = src;
+ iso_file_source_ref(src);
+
+ /* free the first element of the list */
+ data->data.content = children->next;
+ free(children);
+
+ return ISO_SUCCESS;
+}
+
+/**
+ * Read the destination of a symlink. You don't need to open the file
+ * to call this.
+ *
+ * @param buf
+ * allocated buffer of at least bufsiz bytes.
+ * The dest. will be copied there, and it will be NULL-terminated
+ * @param bufsiz
+ * characters to be copied. Destination link will be truncated if
+ * it is larger than given size. This include the \0 character.
+ * @return
+ * 1 on success, < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_WRONG_ARG_VALUE -> if bufsiz <= 0
+ * ISO_FILE_IS_NOT_SYMLINK
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ *
+ */
+static
+int ifs_readlink(IsoFileSource *src, char *buf, size_t bufsiz)
+{
+ char *dest;
+ size_t len;
+ ImageFileSourceData *data;
+
+ if (src == NULL || buf == NULL || src->data == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ if (bufsiz <= 0) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+
+ data = (ImageFileSourceData*)src->data;
+
+ if (!S_ISLNK(data->info.st_mode)) {
+ return ISO_FILE_IS_NOT_SYMLINK;
+ }
+
+ dest = (char*)data->data.content;
+ len = strlen(dest);
+ if (bufsiz <= len) {
+ len = bufsiz - 1;
+ }
+
+ strncpy(buf, dest, len);
+ buf[len] = '\0';
+
+ return ISO_SUCCESS;
+}
+
+static
+IsoFilesystem* ifs_get_filesystem(IsoFileSource *src)
+{
+ ImageFileSourceData *data;
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ data = src->data;
+ return data->fs;
+}
+
+static
+void ifs_free(IsoFileSource *src)
+{
+ ImageFileSourceData *data;
+
+ data = src->data;
+
+ /* close the file if it is already openned */
+ if (data->opened) {
+ src->class->close(src);
+ }
+
+ /* free destination if it is a link */
+ if (S_ISLNK(data->info.st_mode)) {
+ free(data->data.content);
+ }
+ iso_filesystem_unref(data->fs);
+ if (data->parent != NULL) {
+ iso_file_source_unref(data->parent);
+ }
+ free(data->name);
+ free(data);
+}
+
+IsoFileSourceIface ifs_class = {
+ 0, /* version */
+ ifs_get_path,
+ ifs_get_name,
+ ifs_lstat,
+ ifs_stat,
+ ifs_access,
+ ifs_open,
+ ifs_close,
+ ifs_read,
+ ifs_readdir,
+ ifs_readlink,
+ ifs_get_filesystem,
+ ifs_free
+};
+
+/**
+ * Read a file name from a directory record, doing the needed charset
+ * conversion
+ */
+static
+char *get_name(_ImageFsData *fsdata, const char *str, size_t len)
+{
+ int ret;
+ char *name = NULL;
+ if (strcmp(fsdata->local_charset, fsdata->input_charset)) {
+ /* charset conversion needed */
+ ret = strnconv(str, fsdata->input_charset, fsdata->local_charset, len,
+ &name);
+ if (ret == 1) {
+ return name;
+ } else {
+ ret = iso_msg_submit(fsdata->msgid, ISO_FILENAME_WRONG_CHARSET, ret,
+ "Charset conversion error. Can't convert %s from %s to %s",
+ str, fsdata->input_charset, fsdata->local_charset);
+ if (ret < 0) {
+ return NULL; /* aborted */
+ }
+ /* fallback */
+ }
+ }
+
+ /* we reach here when the charset conversion is not needed or has failed */
+
+ name = malloc(len + 1);
+ if (name == NULL) {
+ return NULL;
+ }
+ memcpy(name, str, len);
+ name[len] = '\0';
+ return name;
+}
+
+/**
+ *
+ * @return
+ * 1 success, 0 record ignored (not an error, can be a relocated dir),
+ * < 0 error
+ */
+static
+int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent,
+ struct ecma119_dir_record *record,
+ IsoFileSource **src)
+{
+ int ret;
+ struct stat atts;
+ time_t recorded;
+ _ImageFsData *fsdata;
+ IsoFileSource *ifsrc = NULL;
+ ImageFileSourceData *ifsdata = NULL;
+
+ int namecont = 0; /* 1 if found a NM with CONTINUE flag */
+ char *name = NULL;
+
+ /* 1 if found a SL with CONTINUE flag,
+ * 2 if found a component with continue flag */
+ int linkdestcont = 0;
+ char *linkdest = NULL;
+
+ uint32_t relocated_dir = 0;
+
+ if (fs == NULL || fs->data == NULL || record == NULL || src == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ fsdata = (_ImageFsData*)fs->data;
+
+ memset(&atts, 0, sizeof(struct stat));
+
+ /*
+ * First of all, check for unsupported ECMA-119 features
+ */
+
+ /* check for unsupported multiextend */
+ if (record->flags[0] & 0x80) {
+ iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 0,
+ "Unsupported image. This image makes use of Multi-Extend"
+ " features, that are not supported at this time. If you "
+ "need support for that, please request us this feature.");
+ return ISO_UNSUPPORTED_ECMA119;
+ }
+
+ /* check for unsupported interleaved mode */
+ if (record->file_unit_size[0] || record->interleave_gap_size[0]) {
+ iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 0,
+ "Unsupported image. This image has at least one file recorded "
+ "in interleaved mode. We don't support this mode, as we think "
+ "it's not used. If you're reading this, then we're wrong :) "
+ "Please contact libisofs developers, so we can fix this.");
+ return ISO_UNSUPPORTED_ECMA119;
+ }
+
+ /*
+ * Check for extended attributes, that are not supported. Note that even
+ * if we don't support them, it is easy to ignore them.
+ */
+ if (record->len_xa[0]) {
+ iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_ECMA119, 0,
+ "Unsupported image. This image has at least one file with "
+ "Extended Attributes, that are not supported");
+ return ISO_UNSUPPORTED_ECMA119;
+ }
+
+ /* TODO #00013 : check for unsupported flags when reading a dir record */
+
+ /*
+ * The idea is to read all the RR entries (if we want to do that and RR
+ * extensions exist on image), storing the info we want from that.
+ * Then, we need some sanity checks.
+ * Finally, we select what kind of node it is, and set values properly.
+ */
+
+ if (fsdata->rr) {
+ struct susp_sys_user_entry *sue;
+ SuspIterator *iter;
+
+
+ iter = susp_iter_new(fsdata->src, record, fsdata->len_skp,
+ fsdata->msgid);
+ if (iter == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ while ((ret = susp_iter_next(iter, &sue)) > 0) {
+
+ /* ignore entries from different version */
+ if (sue->version[0] != 1)
+ continue;
+
+ if (SUSP_SIG(sue, 'P', 'X')) {
+ ret = read_rr_PX(sue, &atts);
+ if (ret < 0) {
+ /* notify and continue */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR_WARN, ret,
+ "Invalid PX entry");
+ }
+ } else if (SUSP_SIG(sue, 'T', 'F')) {
+ ret = read_rr_TF(sue, &atts);
+ if (ret < 0) {
+ /* notify and continue */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR_WARN, ret,
+ "Invalid TF entry");
+ }
+ } else if (SUSP_SIG(sue, 'N', 'M')) {
+ if (name != NULL && namecont == 0) {
+ /* ups, RR standard violation */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR_WARN, 0,
+ "New NM entry found without previous"
+ "CONTINUE flag. Ignored");
+ continue;
+ }
+ ret = read_rr_NM(sue, &name, &namecont);
+ if (ret < 0) {
+ /* notify and continue */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR_WARN, ret,
+ "Invalid NM entry");
+ }
+ } else if (SUSP_SIG(sue, 'S', 'L')) {
+ if (linkdest != NULL && linkdestcont == 0) {
+ /* ups, RR standard violation */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR_WARN, 0,
+ "New SL entry found without previous"
+ "CONTINUE flag. Ignored");
+ continue;
+ }
+ ret = read_rr_SL(sue, &linkdest, &linkdestcont);
+ if (ret < 0) {
+ /* notify and continue */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR_WARN, ret,
+ "Invalid SL entry");
+ }
+ } else if (SUSP_SIG(sue, 'R', 'E')) {
+ /*
+ * this directory entry refers to a relocated directory.
+ * We simply ignore it, as it will be correctly handled
+ * when found the CL
+ */
+ susp_iter_free(iter);
+ free(name);
+ return 0; /* it's not an error */
+ } else if (SUSP_SIG(sue, 'C', 'L')) {
+ /*
+ * This entry is a placeholder for a relocated dir.
+ * We need to ignore other entries, with the exception of NM.
+ * Then we create a directory node that represents the
+ * relocated dir, and iterate over its children.
+ */
+ relocated_dir = iso_read_bb(sue->data.CL.child_loc, 4, NULL);
+ if (relocated_dir == 0) {
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR, 0,
+ "Invalid SL entry, no child location");
+ break;
+ }
+ } else if (SUSP_SIG(sue, 'P', 'N')) {
+ ret = read_rr_PN(sue, &atts);
+ if (ret < 0) {
+ /* notify and continue */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR_WARN, ret,
+ "Invalid PN entry");
+ }
+ } else if (SUSP_SIG(sue, 'S', 'F')) {
+ ret = iso_msg_submit(fsdata->msgid, ISO_UNSUPPORTED_RR, 0,
+ "Sparse files not supported.");
+ break;
+ } else if (SUSP_SIG(sue, 'R', 'R')) {
+ /* TODO I've seen this RR on mkisofs images. what's this? */
+ continue;
+ } else if (SUSP_SIG(sue, 'S', 'P')) {
+ /*
+ * Ignore this, to prevent the hint message, if we are dealing
+ * with root node (SP is only valid in "." of root node)
+ */
+ if (parent != NULL) {
+ /* notify and continue */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR, 0,
+ "SP entry found in a directory entry other "
+ "than '.' entry of root node");
+ }
+ continue;
+ } else if (SUSP_SIG(sue, 'E', 'R')) {
+ /*
+ * Ignore this, to prevent the hint message, if we are dealing
+ * with root node (ER is only valid in "." of root node)
+ */
+ if (parent != NULL) {
+ /* notify and continue */
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR, 0,
+ "ER entry found in a directory entry other "
+ "than '.' entry of root node");
+ }
+ continue;
+ } else {
+ ret = iso_msg_submit(fsdata->msgid, ISO_SUSP_UNHANDLED, 0,
+ "Unhandled SUSP entry %c%c.", sue->sig[0], sue->sig[1]);
+ }
+ }
+
+ susp_iter_free(iter);
+
+ /* check for RR problems */
+
+ if (ret < 0) {
+ /* error was already submitted above */
+ iso_msg_debug(fsdata->msgid, "Error parsing RR entries");
+ } else if (!relocated_dir && atts.st_mode == (mode_t) 0 ) {
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR, 0, "Mandatory "
+ "Rock Ridge PX entry is not present or it "
+ "contains invalid values.");
+ } else {
+ /* ensure both name and link dest are finished */
+ if (namecont != 0) {
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR, 0,
+ "Incomplete RR name, last NM entry continues");
+ }
+ if (linkdestcont != 0) {
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR, 0,
+ "Incomplete link destination, last SL entry continues");
+ }
+ }
+
+ if (ret < 0) {
+ free(name);
+ return ret;
+ }
+
+ /* convert name to needed charset */
+ if (strcmp(fsdata->input_charset, fsdata->local_charset) && name) {
+ /* we need to convert name charset */
+ char *newname = NULL;
+ ret = strconv(name, fsdata->input_charset, fsdata->local_charset,
+ &newname);
+ if (ret < 0) {
+ /* its just a hint message */
+ ret = iso_msg_submit(fsdata->msgid, ISO_FILENAME_WRONG_CHARSET,
+ ret, "Charset conversion error. Can't "
+ "convert %s from %s to %s", name,
+ fsdata->input_charset, fsdata->local_charset);
+ free(newname);
+ if (ret < 0) {
+ free(name);
+ return ret;
+ }
+ } else {
+ free(name);
+ name = newname;
+ }
+ }
+
+ /* convert link destination to needed charset */
+ if (strcmp(fsdata->input_charset, fsdata->local_charset) && linkdest) {
+ /* we need to convert name charset */
+ char *newlinkdest = NULL;
+ ret = strconv(linkdest, fsdata->input_charset,
+ fsdata->local_charset, &newlinkdest);
+ if (ret < 0) {
+ ret = iso_msg_submit(fsdata->msgid, ISO_FILENAME_WRONG_CHARSET,
+ ret, "Charset conversion error. Can't "
+ "convert %s from %s to %s", name,
+ fsdata->input_charset, fsdata->local_charset);
+ free(newlinkdest);
+ if (ret < 0) {
+ free(name);
+ return ret;
+ }
+ } else {
+ free(linkdest);
+ linkdest = newlinkdest;
+ }
+ }
+
+ } else {
+ /* RR extensions are not read / used */
+ atts.st_gid = fsdata->gid;
+ atts.st_uid = fsdata->uid;
+ if (record->flags[0] & 0x02) {
+ atts.st_mode = S_IFDIR | fsdata->dir_mode;
+ } else {
+ atts.st_mode = S_IFREG | fsdata->file_mode;
+ }
+ }
+
+ /*
+ * if we haven't RR extensions, or no NM entry is present,
+ * we use the name in directory record
+ */
+ if (!name) {
+ size_t len;
+
+ if (record->len_fi[0] == 1 && record->file_id[0] == 0) {
+ /* "." entry, we can call this for root node, so... */
+ if (!(atts.st_mode & S_IFDIR)) {
+ return iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
+ "Wrong ISO file name. \".\" not dir");
+ }
+ } else {
+
+ name = get_name(fsdata, (char*)record->file_id, record->len_fi[0]);
+ if (name == NULL) {
+ return iso_msg_submit(fsdata->msgid, ISO_WRONG_ECMA119, 0,
+ "Can't retrieve file name");
+ }
+
+ /* remove trailing version number */
+ len = strlen(name);
+ if (len > 2 && name[len-2] == ';' && name[len-1] == '1') {
+ if (len > 3 && name[len-3] == '.') {
+ /*
+ * the "." is mandatory, so in most cases is included only
+ * for standard compliance
+ */
+ name[len-3] = '\0';
+ } else {
+ name[len-2] = '\0';
+ }
+ }
+ }
+ }
+
+ if (relocated_dir) {
+
+ /*
+ * We are dealing with a placeholder for a relocated dir.
+ * Thus, we need to read attributes for this directory from the "."
+ * entry of the relocated dir.
+ */
+ uint8_t buffer[BLOCK_SIZE];
+
+ ret = fsdata->src->read_block(fsdata->src, relocated_dir, buffer);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = iso_file_source_new_ifs(fs, parent, (struct ecma119_dir_record*)
+ buffer, src);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ /* but the real name is the name of the placeholder */
+ ifsdata = (ImageFileSourceData*) (*src)->data;
+ ifsdata->name = name;
+ return ISO_SUCCESS;
+ }
+
+ if (fsdata->rr != RR_EXT_112) {
+ /*
+ * Only RRIP 1.12 provides valid inode numbers. If not, it is not easy
+ * to generate those serial numbers, and we use extend block instead.
+ * It BREAKS POSIX SEMANTICS, but its suitable for our needs
+ */
+ atts.st_ino = (ino_t) iso_read_bb(record->block, 4, NULL);
+ if (fsdata->rr == 0) {
+ atts.st_nlink = 1;
+ }
+ }
+
+ /*
+ * if we haven't RR extensions, or a needed TF time stamp is not present,
+ * we use plain iso recording time
+ */
+ recorded = iso_datetime_read_7(record->recording_time);
+ if (atts.st_atime == (time_t) 0) {
+ atts.st_atime = recorded;
+ }
+ if (atts.st_ctime == (time_t) 0) {
+ atts.st_ctime = recorded;
+ }
+ if (atts.st_mtime == (time_t) 0) {
+ atts.st_mtime = recorded;
+ }
+
+ /* the size is read from iso directory record */
+ atts.st_size = iso_read_bb(record->length, 4, NULL);
+
+ /* Fill last entries */
+ atts.st_dev = fsdata->id;
+ atts.st_blksize = BLOCK_SIZE;
+ atts.st_blocks = DIV_UP(atts.st_size, BLOCK_SIZE);
+
+ /* TODO #00014 : more sanity checks to ensure dir record info is valid */
+ if (S_ISLNK(atts.st_mode) && (linkdest == NULL)) {
+ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR, 0,
+ "Link without destination.");
+ free(name);
+ return ret;
+ }
+
+ /* ok, we can now create the file source */
+ ifsdata = calloc(1, sizeof(ImageFileSourceData));
+ if (ifsdata == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto ifs_cleanup;
+ }
+ ifsrc = calloc(1, sizeof(IsoFileSource));
+ if (ifsrc == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto ifs_cleanup;
+ }
+
+ /* fill data */
+ ifsdata->fs = fs;
+ iso_filesystem_ref(fs);
+ if (parent != NULL) {
+ ifsdata->parent = parent;
+ iso_file_source_ref(parent);
+ }
+ ifsdata->info = atts;
+ ifsdata->name = name;
+ ifsdata->block = iso_read_bb(record->block, 4, NULL);
+
+ if (S_ISLNK(atts.st_mode)) {
+ ifsdata->data.content = linkdest;
+ }
+
+ ifsrc->class = &ifs_class;
+ ifsrc->data = ifsdata;
+ ifsrc->refcount = 1;
+
+ *src = ifsrc;
+ return ISO_SUCCESS;
+
+ifs_cleanup: ;
+ free(name);
+ free(linkdest);
+ free(ifsdata);
+ free(ifsrc);
+ return ret;
+}
+
+static
+int ifs_get_root(IsoFilesystem *fs, IsoFileSource **root)
+{
+ int ret;
+ _ImageFsData *data;
+ uint8_t buffer[BLOCK_SIZE];
+
+ if (fs == NULL || fs->data == NULL || root == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = (_ImageFsData*)fs->data;
+
+ /* open the filesystem */
+ ret = ifs_fs_open((IsoImageFilesystem*)fs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* read extend for root record */
+ ret = data->src->read_block(data->src, data->iso_root_block, buffer);
+ if (ret < 0) {
+ ifs_fs_close((IsoImageFilesystem*)fs);
+ return ret;
+ }
+
+ /* get root attributes from "." entry */
+ ret = iso_file_source_new_ifs((IsoImageFilesystem*)fs, NULL,
+ (struct ecma119_dir_record*) buffer, root);
+
+ ifs_fs_close((IsoImageFilesystem*)fs);
+ return ret;
+}
+
+/**
+ * Find a file inside a node.
+ *
+ * @param file
+ * it is not modified if requested file is not found
+ * @return
+ * 1 success, 0 not found, < 0 error
+ */
+static
+int ifs_get_file(IsoFileSource *dir, const char *name, IsoFileSource **file)
+{
+ int ret;
+ IsoFileSource *src;
+
+ ret = iso_file_source_open(dir);
+ if (ret < 0) {
+ return ret;
+ }
+ while ((ret = iso_file_source_readdir(dir, &src)) == 1) {
+ char *fname = iso_file_source_get_name(src);
+ if (!strcmp(name, fname)) {
+ free(fname);
+ *file = src;
+ ret = ISO_SUCCESS;
+ break;
+ }
+ free(fname);
+ iso_file_source_unref(src);
+ }
+ iso_file_source_close(dir);
+ return ret;
+}
+
+static
+int ifs_get_by_path(IsoFilesystem *fs, const char *path, IsoFileSource **file)
+{
+ int ret;
+ _ImageFsData *data;
+ IsoFileSource *src;
+ char *ptr, *brk_info, *component;
+
+ if (fs == NULL || fs->data == NULL || path == NULL || file == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ if (path[0] != '/') {
+ /* only absolute paths supported */
+ return ISO_FILE_BAD_PATH;
+ }
+
+ data = (_ImageFsData*)fs->data;
+
+ /* open the filesystem */
+ ret = ifs_fs_open((IsoImageFilesystem*)fs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = ifs_get_root(fs, &src);
+ if (ret < 0) {
+ return ret;
+ }
+ if (!strcmp(path, "/")) {
+ /* we are looking for root */
+ *file = src;
+ ret = ISO_SUCCESS;
+ goto get_path_exit;
+ }
+
+ ptr = strdup(path);
+ if (ptr == NULL) {
+ iso_file_source_unref(src);
+ ret = ISO_OUT_OF_MEM;
+ goto get_path_exit;
+ }
+
+ component = strtok_r(ptr, "/", &brk_info);
+ while (component) {
+ IsoFileSource *child = NULL;
+
+ ImageFileSourceData *fdata;
+ fdata = src->data;
+ if (!S_ISDIR(fdata->info.st_mode)) {
+ ret = ISO_FILE_BAD_PATH;
+ break;
+ }
+
+ ret = ifs_get_file(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) {
+ iso_file_source_unref(src);
+ } else if (ret == 0) {
+ ret = ISO_FILE_DOESNT_EXIST;
+ } else {
+ *file = src;
+ }
+
+ get_path_exit:;
+ ifs_fs_close((IsoImageFilesystem*)fs);
+ return ret;
+}
+
+unsigned int ifs_get_id(IsoFilesystem *fs)
+{
+ return ISO_IMAGE_FS_ID;
+}
+
+static
+int ifs_fs_open(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data;
+
+ if (fs == NULL || fs->data == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = (_ImageFsData*)fs->data;
+
+ if (data->open_count == 0) {
+ /* we need to actually open the data source */
+ int res = data->src->open(data->src);
+ if (res < 0) {
+ return res;
+ }
+ }
+ ++data->open_count;
+ return ISO_SUCCESS;
+}
+
+static
+int ifs_fs_close(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data;
+
+ if (fs == NULL || fs->data == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = (_ImageFsData*)fs->data;
+
+ if (--data->open_count == 0) {
+ /* we need to actually close the data source */
+ return data->src->close(data->src);
+ }
+ return ISO_SUCCESS;
+}
+
+static
+void ifs_fs_free(IsoFilesystem *fs)
+{
+ IsoImageFilesystem *ifs;
+ _ImageFsData *data;
+
+ ifs = (IsoImageFilesystem*)fs;
+ data = (_ImageFsData*) fs->data;
+
+ /* close data source if already openned */
+ if (data->open_count > 0) {
+ data->src->close(data->src);
+ }
+
+ /* free our ref to datasource */
+ iso_data_source_unref(data->src);
+
+ /* free volume atts */
+ free(data->volset_id);
+ free(data->volume_id);
+ free(data->publisher_id);
+ free(data->data_preparer_id);
+ free(data->system_id);
+ free(data->application_id);
+ free(data->copyright_file_id);
+ free(data->abstract_file_id);
+ free(data->biblio_file_id);
+
+ free(data->input_charset);
+ free(data->local_charset);
+ free(data);
+}
+
+/**
+ * Read the SUSP system user entries of the "." entry of the root directory,
+ * indentifying when Rock Ridge extensions are being used.
+ *
+ * @return
+ * 1 success, 0 ignored, < 0 error
+ */
+static
+int read_root_susp_entries(_ImageFsData *data, uint32_t block)
+{
+ int ret;
+ unsigned char buffer[2048];
+ struct ecma119_dir_record *record;
+ struct susp_sys_user_entry *sue;
+ SuspIterator *iter;
+
+ ret = data->src->read_block(data->src, block, buffer);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* record will be the "." directory entry for the root record */
+ record = (struct ecma119_dir_record *)buffer;
+
+ /*
+ * TODO #00015 : take care of CD-ROM XA discs when reading SP entry
+ * SUSP specification claims that for CD-ROM XA the SP entry
+ * is not at position BP 1, but at BP 15. Is that used?
+ * In that case, we need to set info->len_skp to 15!!
+ */
+
+ iter = susp_iter_new(data->src, record, data->len_skp, data->msgid);
+ if (iter == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ /* first entry must be an SP system use entry */
+ ret = susp_iter_next(iter, &sue);
+ if (ret < 0) {
+ /* error */
+ susp_iter_free(iter);
+ return ret;
+ } else if (ret == 0 || !SUSP_SIG(sue, 'S', 'P') ) {
+ iso_msg_debug(data->msgid, "SUSP/RR is not being used.");
+ susp_iter_free(iter);
+ return ISO_SUCCESS;
+ }
+
+ /* it is a SP system use entry */
+ if (sue->version[0] != 1 || sue->data.SP.be[0] != 0xBE
+ || sue->data.SP.ef[0] != 0xEF) {
+
+ susp_iter_free(iter);
+ return iso_msg_submit(data->msgid, ISO_UNSUPPORTED_SUSP, 0,
+ "SUSP SP system use entry seems to be wrong. "
+ "Ignoring Rock Ridge Extensions.");
+ }
+
+ iso_msg_debug(data->msgid, "SUSP/RR is being used.");
+
+ /*
+ * The LEN_SKP field, defined in IEEE 1281, SUSP. 5.3, specifies the
+ * number of bytes to be skipped within each System Use field.
+ * I think this will be always 0, but given that support this standard
+ * feature is easy...
+ */
+ data->len_skp = sue->data.SP.len_skp[0];
+
+ /*
+ * Ok, now search for ER entry.
+ * Just notice that the attributes for root dir are read elsewhere.
+ *
+ * TODO #00016 : handle non RR ER entries
+ *
+ * if several ER are present, we need to identify the position of
+ * what refers to RR, and then look for corresponding ES entry in
+ * each directory record. I have not implemented this (it's not used,
+ * no?), but if we finally need it, it can be easily implemented in
+ * the iterator, transparently for the rest of the code.
+ */
+ while ((ret = susp_iter_next(iter, &sue)) > 0) {
+
+ /* ignore entries from different version */
+ if (sue->version[0] != 1)
+ continue;
+
+ if (SUSP_SIG(sue, 'E', 'R')) {
+
+ if (data->rr_version) {
+ ret = iso_msg_submit(data->msgid, ISO_SUSP_MULTIPLE_ER, 0,
+ "More than one ER has found. This is not supported. "
+ "It will be ignored, but can cause problems. "
+ "Please notify us about this.");
+ if (ret < 0) {
+ break;
+ }
+ }
+
+ /*
+ * it seems that Rock Ridge can be identified with any
+ * of the following
+ */
+ if ( sue->data.ER.len_id[0] == 10 &&
+ !strncmp((char*)sue->data.ER.ext_id, "RRIP_1991A", 10) ) {
+
+ iso_msg_debug(data->msgid,
+ "Suitable Rock Ridge ER found. Version 1.10.");
+ data->rr_version = RR_EXT_110;
+
+ } else if ( (sue->data.ER.len_id[0] == 10 &&
+ !strncmp((char*)sue->data.ER.ext_id, "IEEE_P1282", 10))
+ || (sue->data.ER.len_id[0] == 9 &&
+ !strncmp((char*)sue->data.ER.ext_id, "IEEE_1282", 9)) ) {
+
+ iso_msg_debug(data->msgid,
+ "Suitable Rock Ridge ER found. Version 1.12.");
+ data->rr_version = RR_EXT_112;
+ } else {
+ ret = iso_msg_submit(data->msgid, ISO_SUSP_MULTIPLE_ER, 0,
+ "Not Rock Ridge ER found.\n"
+ "That will be ignored, but can cause problems in "
+ "image reading. Please notify us about this");
+ if (ret < 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ susp_iter_free(iter);
+
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ISO_SUCCESS;
+}
+
+static
+int read_pvm(_ImageFsData *data, uint32_t block)
+{
+ int ret;
+ struct ecma119_pri_vol_desc *pvm;
+ struct ecma119_dir_record *rootdr;
+ uint8_t buffer[BLOCK_SIZE];
+
+ /* read PVM */
+ ret = data->src->read_block(data->src, block, buffer);
+ if (ret < 0) {
+ return ret;
+ }
+
+ pvm = (struct ecma119_pri_vol_desc *)buffer;
+
+ /* sanity checks */
+ if (pvm->vol_desc_type[0] != 1 || pvm->vol_desc_version[0] != 1
+ || strncmp((char*)pvm->std_identifier, "CD001", 5)
+ || pvm->file_structure_version[0] != 1) {
+
+ return ISO_WRONG_PVD;
+ }
+
+ /* ok, it is a valid PVD */
+
+ /* fill volume attributes */
+ /* TODO take care of input charset */
+ data->volset_id = strcopy((char*)pvm->vol_set_id, 128);
+ data->volume_id = strcopy((char*)pvm->volume_id, 32);
+ data->publisher_id = strcopy((char*)pvm->publisher_id, 128);
+ data->data_preparer_id = strcopy((char*)pvm->data_prep_id, 128);
+ data->system_id = strcopy((char*)pvm->system_id, 32);
+ data->application_id = strcopy((char*)pvm->application_id, 128);
+ data->copyright_file_id = strcopy((char*)pvm->copyright_file_id, 37);
+ data->abstract_file_id = strcopy((char*)pvm->abstract_file_id, 37);
+ data->biblio_file_id = strcopy((char*)pvm->bibliographic_file_id, 37);
+
+ data->nblocks = iso_read_bb(pvm->vol_space_size, 4, NULL);
+
+ rootdr = (struct ecma119_dir_record*) pvm->root_dir_record;
+ data->pvd_root_block = iso_read_bb(rootdr->block, 4, NULL);
+
+ /*
+ * TODO #00017 : take advantage of other atts of PVD
+ * PVD has other things that could be interesting, but that don't have a
+ * member in IsoImage, such as creation date. In a multisession disc, we
+ * could keep the creation date and update the modification date, for
+ * example.
+ */
+
+ return ISO_SUCCESS;
+}
+
+/**
+ * @return
+ * 1 success, 0 ignored, < 0 error
+ */
+static
+int read_el_torito_boot_catalog(_ImageFsData *data, uint32_t block)
+{
+ int ret;
+ struct el_torito_validation_entry *ve;
+ struct el_torito_default_entry *entry;
+ unsigned char buffer[BLOCK_SIZE];
+
+ ret = data->src->read_block(data->src, block, buffer);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ve = (struct el_torito_validation_entry*)buffer;
+
+ /* check if it is a valid catalog (TODO: check also the checksum)*/
+ if ( (ve->header_id[0] != 1) || (ve->key_byte1[0] != 0x55)
+ || (ve->key_byte2[0] != 0xAA) ) {
+
+ return iso_msg_submit(data->msgid, ISO_WRONG_EL_TORITO, 0,
+ "Wrong or damaged El-Torito Catalog. El-Torito info "
+ "will be ignored.");
+ }
+
+ /* check for a valid platform */
+ if (ve->platform_id[0] != 0) {
+ return iso_msg_submit(data->msgid, ISO_UNSUPPORTED_EL_TORITO, 0,
+ "Unsupported El-Torito platform. Only 80x86 is "
+ "supported. El-Torito info will be ignored.");
+ }
+
+ /* ok, once we are here we assume it is a valid catalog */
+
+ /* parse the default entry */
+ entry = (struct el_torito_default_entry *)(buffer + 32);
+
+ data->eltorito = 1;
+ data->bootable = entry->boot_indicator[0] ? 1 : 0;
+ data->type = entry->boot_media_type[0];
+ data->partition_type = entry->system_type[0];
+ data->load_seg = iso_read_lsb(entry->load_seg, 2);
+ data->load_size = iso_read_lsb(entry->sec_count, 2);
+ data->imgblock = iso_read_lsb(entry->block, 4);
+
+ /* TODO #00018 : check if there are more entries in the boot catalog */
+
+ return ISO_SUCCESS;
+}
+
+int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts,
+ int msgid, IsoImageFilesystem **fs)
+{
+ int ret;
+ uint32_t block;
+ IsoImageFilesystem *ifs;
+ _ImageFsData *data;
+ uint8_t buffer[BLOCK_SIZE];
+
+ if (src == NULL || opts == NULL || fs == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = calloc(1, sizeof(_ImageFsData));
+ if (data == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ ifs = calloc(1, sizeof(IsoImageFilesystem));
+ if (ifs == NULL) {
+ free(data);
+ return ISO_OUT_OF_MEM;
+ }
+
+ /* get our ref to IsoDataSource */
+ data->src = src;
+ iso_data_source_ref(src);
+ data->open_count = 0;
+
+ /* get an id for the filesystem */
+ data->id = ++fs_dev_id;
+
+ /* fill data from opts */
+ data->gid = opts->gid;
+ data->uid = opts->uid;
+ data->file_mode = opts->file_mode & ~S_IFMT;
+ data->dir_mode = opts->dir_mode & ~S_IFMT;
+ data->msgid = msgid;
+
+ setlocale(LC_CTYPE, "");
+ data->local_charset = strdup(nl_langinfo(CODESET));
+ if (data->local_charset == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto fs_cleanup;
+ }
+
+ strncpy(ifs->type, "iso ", 4);
+ ifs->data = data;
+ ifs->refcount = 1;
+ ifs->version = 0;
+ ifs->get_root = ifs_get_root;
+ ifs->get_by_path = ifs_get_by_path;
+ ifs->get_id = ifs_get_id;
+ ifs->open = ifs_fs_open;
+ ifs->close = ifs_fs_close;
+ ifs->free = ifs_fs_free;
+
+ /* read Volume Descriptors and ensure it is a valid image */
+
+ /* 1. first, open the filesystem */
+ ifs_fs_open(ifs);
+
+ /* 2. read primary volume description */
+ ret = read_pvm(data, opts->block + 16);
+ if (ret < 0) {
+ goto fs_cleanup;
+ }
+
+ /* 3. read next volume descriptors */
+ block = opts->block + 17;
+ do {
+ ret = src->read_block(src, block, buffer);
+ if (ret < 0) {
+ /* cleanup and exit */
+ goto fs_cleanup;
+ }
+ switch (buffer[0]) {
+ case 0:
+ /* boot record */
+ {
+ struct ecma119_boot_rec_vol_desc *vol;
+ vol = (struct ecma119_boot_rec_vol_desc*)buffer;
+
+ /* some sanity checks */
+ if (strncmp((char*)vol->std_identifier, "CD001", 5)
+ || vol->vol_desc_version[0] != 1
+ || strncmp((char*)vol->boot_sys_id,
+ "EL TORITO SPECIFICATION", 23)) {
+
+ ret = iso_msg_submit(data->msgid,
+ ISO_UNSUPPORTED_EL_TORITO, 0,
+ "Unsupported Boot Vol. Desc. Only El-Torito "
+ "Specification, Version 1.0 Volume "
+ "Descriptors are supported. Ignoring boot info");
+ if (ret < 0) {
+ goto fs_cleanup;
+ }
+ break;
+ }
+ data->catblock = iso_read_lsb(vol->boot_catalog, 4);
+ ret = read_el_torito_boot_catalog(data, data->catblock);
+ if (ret < 0) {
+ goto fs_cleanup;
+ }
+ }
+ break;
+ case 2:
+ /* suplementary volume descritor */
+ {
+ struct ecma119_sup_vol_desc *sup;
+ struct ecma119_dir_record *root;
+
+ sup = (struct ecma119_sup_vol_desc*)buffer;
+ if (sup->esc_sequences[0] == 0x25 &&
+ sup->esc_sequences[1] == 0x2F &&
+ (sup->esc_sequences[2] == 0x40 ||
+ sup->esc_sequences[2] == 0x43 ||
+ sup->esc_sequences[2] == 0x45) ) {
+
+ /* it's a Joliet Sup. Vol. Desc. */
+ iso_msg_debug(data->msgid, "Found Joliet extensions");
+ data->joliet = 1;
+ root = (struct ecma119_dir_record*)sup->root_dir_record;
+ data->svd_root_block = iso_read_bb(root->block, 4, NULL);
+ /* TODO #00019 : set IsoImage attribs from Joliet SVD? */
+ /* TODO #00020 : handle RR info in Joliet tree */
+ } else if (sup->vol_desc_version[0] == 2) {
+ /*
+ * It is an Enhanced Volume Descriptor, image is an
+ * ISO 9660:1999
+ */
+ iso_msg_debug(data->msgid, "Found ISO 9660:1999");
+ data->iso1999 = 1;
+ root = (struct ecma119_dir_record*)sup->root_dir_record;
+ data->evd_root_block = iso_read_bb(root->block, 4, NULL);
+ /* TODO #00021 : handle RR info in ISO 9660:1999 tree */
+ } else {
+ ret = iso_msg_submit(data->msgid, ISO_UNSUPPORTED_VD, 0,
+ "Unsupported Sup. Vol. Desc found.");
+ if (ret < 0) {
+ goto fs_cleanup;
+ }
+ }
+ }
+ break;
+ case 255:
+ /*
+ * volume set terminator
+ * ignore, as it's checked in loop end condition
+ */
+ break;
+ default:
+ ret = iso_msg_submit(data->msgid, ISO_UNSUPPORTED_VD, 0,
+ "Ignoring Volume descriptor %x.", buffer[0]);
+ if (ret < 0) {
+ goto fs_cleanup;
+ }
+ break;
+ }
+ block++;
+ } while (buffer[0] != 255);
+
+ /* 4. check if RR extensions are being used */
+ ret = read_root_susp_entries(data, data->pvd_root_block);
+ if (ret < 0) {
+ goto fs_cleanup;
+ }
+
+ /* user doesn't want to read RR extensions */
+ if (opts->norock) {
+ data->rr = RR_EXT_NO;
+ } else {
+ data->rr = data->rr_version;
+ }
+
+ /* select what tree to read */
+ if (data->rr) {
+ /* RR extensions are available */
+ if (!opts->nojoliet && opts->preferjoliet && data->joliet) {
+ /* if user prefers joliet, that is used */
+ iso_msg_debug(data->msgid, "Reading Joliet extensions.");
+ data->input_charset = strdup("UCS-2BE");
+ data->rr = RR_EXT_NO;
+ data->iso_root_block = data->svd_root_block;
+ } else {
+ /* RR will be used */
+ iso_msg_debug(data->msgid, "Reading Rock Ridge extensions.");
+ data->iso_root_block = data->pvd_root_block;
+ }
+ } else {
+ /* RR extensions are not available */
+ if (!opts->nojoliet && data->joliet) {
+ /* joliet will be used */
+ iso_msg_debug(data->msgid, "Reading Joliet extensions.");
+ data->input_charset = strdup("UCS-2BE");
+ data->iso_root_block = data->svd_root_block;
+ } else if (!opts->noiso1999 && data->iso1999) {
+ /* we will read ISO 9660:1999 */
+ iso_msg_debug(data->msgid, "Reading ISO-9660:1999 tree.");
+ data->iso_root_block = data->evd_root_block;
+ } else {
+ /* default to plain iso */
+ iso_msg_debug(data->msgid, "Reading plain ISO-9660 tree.");
+ data->iso_root_block = data->pvd_root_block;
+ data->input_charset = strdup("ASCII");
+ }
+ }
+
+ if (data->input_charset == NULL) {
+ if (opts->input_charset != NULL) {
+ data->input_charset = strdup(opts->input_charset);
+ } else {
+ data->input_charset = strdup(data->local_charset);
+ }
+ }
+ if (data->input_charset == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto fs_cleanup;
+ }
+
+ /* and finally return. Note that we keep the DataSource opened */
+
+ *fs = ifs;
+ return ISO_SUCCESS;
+
+ fs_cleanup: ;
+ ifs_fs_free(ifs);
+ free(ifs);
+ return ret;
+}
+
+static
+int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image,
+ IsoFileSource *src, IsoNode **node)
+{
+ int ret;
+ struct stat info;
+ IsoNode *new;
+ char *name;
+ ImageFileSourceData *data;
+
+ if (builder == NULL || src == NULL || node == NULL || src->data == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = (ImageFileSourceData*)src->data;
+
+ name = iso_file_source_get_name(src);
+
+ /* get info about source */
+ ret = iso_file_source_lstat(src, &info);
+ if (ret < 0) {
+ return ret;
+ }
+
+ new = NULL;
+ switch (info.st_mode & S_IFMT) {
+ case S_IFREG:
+ {
+ /* source is a regular file */
+ _ImageFsData *fsdata = data->fs->data;
+
+ if (fsdata->eltorito && data->block == fsdata->catblock) {
+
+ if (image->bootcat->node != NULL) {
+ ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0,
+ "More than one catalog node has been found. "
+ "We can continue, but that could lead to "
+ "problems");
+ if (ret < 0) {
+ return ret;
+ }
+ iso_node_unref((IsoNode*)image->bootcat->node);
+ }
+
+ /* we create a placeholder for the catalog instead of
+ * a regular file */
+ new = calloc(1, sizeof(IsoBoot));
+ if (new == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ free(name);
+ return ret;
+ }
+
+ /* and set the image node */
+ image->bootcat->node = (IsoBoot*)new;
+ new->type = LIBISO_BOOT;
+ new->refcount = 1;
+ } else {
+ IsoStream *stream;
+ IsoFile *file;
+
+ ret = iso_file_source_stream_new(src, &stream);
+ if (ret < 0) {
+ free(name);
+ return ret;
+ }
+ /* take a ref to the src, as stream has taken our ref */
+ iso_file_source_ref(src);
+
+ file = calloc(1, sizeof(IsoFile));
+ if (file == NULL) {
+ free(name);
+ iso_stream_unref(stream);
+ return ISO_OUT_OF_MEM;
+ }
+
+ /* the msblock is taken from the image */
+ file->msblock = data->block;
+
+ /*
+ * and we set the sort weight based on the block on image, to
+ * improve performance on image modifying.
+ */
+ file->sort_weight = INT_MAX - data->block;
+
+ file->stream = stream;
+ file->node.type = LIBISO_FILE;
+ new = (IsoNode*) file;
+ new->refcount = 0;
+
+ if (fsdata->eltorito && data->block == fsdata->imgblock) {
+ /* it is boot image node */
+ if (image->bootcat->image->image != NULL) {
+ ret = iso_msg_submit(image->id, ISO_EL_TORITO_WARN, 0,
+ "More than one image node has been found.");
+ if (ret < 0) {
+ free(name);
+ iso_stream_unref(stream);
+ return ret;
+ }
+ } else {
+ /* and set the image node */
+ image->bootcat->image->image = file;
+ new->refcount++;
+ }
+ }
+ }
+ }
+ break;
+ case S_IFDIR:
+ {
+ /* source is a directory */
+ new = calloc(1, sizeof(IsoDir));
+ if (new == NULL) {
+ free(name);
+ return ISO_OUT_OF_MEM;
+ }
+ new->type = LIBISO_DIR;
+ new->refcount = 0;
+ }
+ 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) {
+ free(name);
+ return ret;
+ }
+ link = malloc(sizeof(IsoSymlink));
+ if (link == NULL) {
+ free(name);
+ return ISO_OUT_OF_MEM;
+ }
+ link->dest = strdup(dest);
+ link->node.type = LIBISO_SYMLINK;
+ new = (IsoNode*) link;
+ new->refcount = 0;
+ }
+ break;
+ case S_IFSOCK:
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ {
+ /* source is an special file */
+ IsoSpecial *special;
+ special = malloc(sizeof(IsoSpecial));
+ if (special == NULL) {
+ free(name);
+ return ISO_OUT_OF_MEM;
+ }
+ special->dev = info.st_rdev;
+ special->node.type = LIBISO_SPECIAL;
+ new = (IsoNode*) special;
+ new->refcount = 0;
+ }
+ break;
+ }
+
+ /* fill fields */
+ new->refcount++;
+ new->name = name;
+ new->mode = info.st_mode;
+ new->uid = info.st_uid;
+ new->gid = info.st_gid;
+ new->atime = info.st_atime;
+ new->mtime = info.st_mtime;
+ new->ctime = info.st_ctime;
+
+ new->hidden = 0;
+
+ new->parent = NULL;
+ new->next = NULL;
+
+ *node = new;
+ return ISO_SUCCESS;
+}
+
+/**
+ * Create a new builder, that is exactly a copy of an old builder, but where
+ * create_node() function has been replaced by image_builder_create_node.
+ */
+static
+int iso_image_builder_new(IsoNodeBuilder *old, 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 = old->create_file_data;
+ b->create_node_data = old->create_node_data;
+ b->create_file = old->create_file;
+ b->create_node = image_builder_create_node;
+ b->free = old->free;
+
+ *builder = b;
+ return ISO_SUCCESS;
+}
+
+/**
+ * Create a file source to access the El-Torito boot image, when it is not
+ * accessible from the ISO filesystem.
+ */
+static
+int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoFileSource **src)
+{
+ int ret;
+ struct stat atts;
+ _ImageFsData *fsdata;
+ IsoFileSource *ifsrc = NULL;
+ ImageFileSourceData *ifsdata = NULL;
+
+ if (fs == NULL || fs->data == NULL || src == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ fsdata = (_ImageFsData*)fs->data;
+
+ memset(&atts, 0, sizeof(struct stat));
+ atts.st_mode = S_IFREG;
+ atts.st_ino = fsdata->imgblock; /* not the best solution, but... */
+ atts.st_nlink = 1;
+
+ /*
+ * this is the greater problem. We don't know the size. For now, we
+ * just use a single block of data. In a future, maybe we could figure out
+ * a better idea. Another alternative is to use several blocks, that way
+ * is less probable that we throw out valid data.
+ */
+ atts.st_size = (off_t)BLOCK_SIZE;
+
+ /* Fill last entries */
+ atts.st_dev = fsdata->id;
+ atts.st_blksize = BLOCK_SIZE;
+ atts.st_blocks = DIV_UP(atts.st_size, BLOCK_SIZE);
+
+ /* ok, we can now create the file source */
+ ifsdata = calloc(1, sizeof(ImageFileSourceData));
+ if (ifsdata == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto boot_fs_cleanup;
+ }
+ ifsrc = calloc(1, sizeof(IsoFileSource));
+ if (ifsrc == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto boot_fs_cleanup;
+ }
+
+ /* fill data */
+ ifsdata->fs = fs;
+ iso_filesystem_ref(fs);
+ ifsdata->parent = NULL;
+ ifsdata->info = atts;
+ ifsdata->name = NULL;
+ ifsdata->block = fsdata->imgblock;
+
+ ifsrc->class = &ifs_class;
+ ifsrc->data = ifsdata;
+ ifsrc->refcount = 1;
+
+ *src = ifsrc;
+ return ISO_SUCCESS;
+
+boot_fs_cleanup: ;
+ free(ifsdata);
+ free(ifsrc);
+ return ret;
+}
+
+
+int iso_image_import(IsoImage *image, IsoDataSource *src,
+ struct iso_read_opts *opts,
+ IsoReadImageFeatures **features)
+{
+ int ret;
+ IsoImageFilesystem *fs;
+ IsoFilesystem *fsback;
+ IsoNodeBuilder *blback;
+ IsoDir *oldroot;
+ IsoFileSource *newroot;
+ _ImageFsData *data;
+ struct el_torito_boot_catalog *oldbootcat;
+
+ if (image == NULL || src == NULL || opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ ret = iso_image_filesystem_new(src, opts, image->id, &fs);
+ if (ret < 0) {
+ return ret;
+ }
+ data = fs->data;
+
+ /* get root from filesystem */
+ ret = fs->get_root(fs, &newroot);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* backup image filesystem, builder and root */
+ fsback = image->fs;
+ blback = image->builder;
+ oldroot = image->root;
+ oldbootcat = image->bootcat; /* could be NULL */
+
+ image->bootcat = NULL;
+
+ /* create new builder */
+ ret = iso_image_builder_new(blback, &image->builder);
+ if (ret < 0) {
+ goto import_revert;
+ }
+
+ image->fs = fs;
+
+ /* create new root, and set root attributes from source */
+ ret = iso_node_new_root(&image->root);
+ if (ret < 0) {
+ goto import_revert;
+ }
+ {
+ struct stat info;
+
+ /* I know this will not fail */
+ iso_file_source_lstat(newroot, &info);
+ image->root->node.mode = info.st_mode;
+ image->root->node.uid = info.st_uid;
+ image->root->node.gid = info.st_gid;
+ image->root->node.atime = info.st_atime;
+ image->root->node.mtime = info.st_mtime;
+ image->root->node.ctime = info.st_ctime;
+ }
+
+ /* if old image has el-torito, add a new catalog */
+ if (data->eltorito) {
+ struct el_torito_boot_catalog *catalog;
+ ElToritoBootImage *boot_image= NULL;
+
+ boot_image = calloc(1, sizeof(ElToritoBootImage));
+ if (boot_image == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto import_revert;
+ }
+ boot_image->bootable = data->bootable;
+ boot_image->type = data->type;
+ boot_image->partition_type = data->partition_type;
+ boot_image->load_seg = data->load_seg;
+ boot_image->load_size = data->load_size;
+
+ catalog = calloc(1, sizeof(struct el_torito_boot_catalog));
+ if (catalog == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto import_revert;
+ }
+ catalog->image = boot_image;
+ image->bootcat = catalog;
+ }
+
+ /* recursively add image */
+ ret = iso_add_dir_src_rec(image, image->root, newroot);
+
+ /* error during recursive image addition? */
+ if (ret < 0) {
+ iso_node_builder_unref(image->builder);
+ goto import_revert;
+ }
+
+ if (data->eltorito) {
+ /* if catalog and image nodes were not filled, we create them here */
+ if (image->bootcat->image->image == NULL) {
+ IsoFileSource *src;
+ IsoNode *node;
+ ret = create_boot_img_filesrc(fs, &src);
+ if (ret < 0) {
+ iso_node_builder_unref(image->builder);
+ goto import_revert;
+ }
+ ret = image_builder_create_node(image->builder, image, src, &node);
+ if (ret < 0) {
+ iso_node_builder_unref(image->builder);
+ goto import_revert;
+ }
+ image->bootcat->image->image = (IsoFile*)node;
+
+ /* warn about hidden images */
+ iso_msg_submit(image->id, ISO_EL_TORITO_HIDDEN, 0,
+ "Found hidden El-Torito image. Its size could not "
+ "be figure out, so image modify or boot image "
+ "patching may lead to bad results.");
+ }
+ if (image->bootcat->node == NULL) {
+ IsoNode *node = calloc(1, sizeof(IsoBoot));
+ if (node == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto import_revert;
+ }
+ node->type = LIBISO_BOOT;
+ node->mode = S_IFREG;
+ node->refcount = 1;
+ image->bootcat->node = (IsoBoot*)node;
+ }
+ }
+
+ iso_node_builder_unref(image->builder);
+
+ /* free old root */
+ iso_node_unref((IsoNode*)oldroot);
+
+ /* free old boot catalog */
+ el_torito_boot_catalog_free(oldbootcat);
+
+ /* set volume attributes */
+ iso_image_set_volset_id(image, data->volset_id);
+ iso_image_set_volume_id(image, data->volume_id);
+ iso_image_set_publisher_id(image, data->publisher_id);
+ iso_image_set_data_preparer_id(image, data->data_preparer_id);
+ iso_image_set_system_id(image, data->system_id);
+ iso_image_set_application_id(image, data->application_id);
+ iso_image_set_copyright_file_id(image, data->copyright_file_id);
+ iso_image_set_abstract_file_id(image, data->abstract_file_id);
+ iso_image_set_biblio_file_id(image, data->biblio_file_id);
+
+ if (features != NULL) {
+ *features = malloc(sizeof(IsoReadImageFeatures));
+ if (*features == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto import_cleanup;
+ }
+ (*features)->hasJoliet = data->joliet;
+ (*features)->hasRR = data->rr_version != 0;
+ (*features)->hasIso1999 = data->iso1999;
+ (*features)->hasElTorito = data->eltorito;
+ (*features)->size = data->nblocks;
+ }
+
+ ret = ISO_SUCCESS;
+ goto import_cleanup;
+
+ import_revert:;
+
+ iso_node_unref((IsoNode*)image->root);
+ el_torito_boot_catalog_free(image->bootcat);
+ image->root = oldroot;
+ image->fs = fsback;
+ image->bootcat = oldbootcat;
+
+ import_cleanup:;
+
+ /* recover backed fs and builder */
+ image->fs = fsback;
+ image->builder = blback;
+
+ iso_file_source_unref(newroot);
+ fs->close(fs);
+ iso_filesystem_unref(fs);
+
+ return ret;
+}
+
+const char *iso_image_fs_get_volset_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data = (_ImageFsData*) fs->data;
+ return data->volset_id;
+}
+
+const char *iso_image_fs_get_volume_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data = (_ImageFsData*) fs->data;
+ return data->volume_id;
+}
+
+const char *iso_image_fs_get_publisher_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data = (_ImageFsData*) fs->data;
+ return data->publisher_id;
+}
+
+const char *iso_image_fs_get_data_preparer_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data = (_ImageFsData*) fs->data;
+ return data->data_preparer_id;
+}
+
+const char *iso_image_fs_get_system_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data = (_ImageFsData*) fs->data;
+ return data->system_id;
+}
+
+const char *iso_image_fs_get_application_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data = (_ImageFsData*) fs->data;
+ return data->application_id;
+}
+
+const char *iso_image_fs_get_copyright_file_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data = (_ImageFsData*) fs->data;
+ return data->copyright_file_id;
+}
+
+const char *iso_image_fs_get_abstract_file_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data;
+ data = (_ImageFsData*) fs->data;
+ return data->abstract_file_id;
+}
+
+const char *iso_image_fs_get_biblio_file_id(IsoImageFilesystem *fs)
+{
+ _ImageFsData *data = (_ImageFsData*) fs->data;
+ return data->biblio_file_id;
+}
+
+int iso_read_opts_new(IsoReadOpts **opts, int profile)
+{
+ IsoReadOpts *ropts;
+
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (profile != 0) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+
+ ropts = calloc(1, sizeof(IsoReadOpts));
+ if (ropts == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ ropts->file_mode = 0444;
+ ropts->dir_mode = 0555;
+ *opts = ropts;
+ return ISO_SUCCESS;
+}
+
+void iso_read_opts_free(IsoReadOpts *opts)
+{
+ if (opts == NULL) {
+ return;
+ }
+
+ free(opts->input_charset);
+ free(opts);
+}
+
+int iso_read_opts_set_start_block(IsoReadOpts *opts, uint32_t block)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->block = block;
+ return ISO_SUCCESS;
+}
+
+int iso_read_opts_set_no_rockridge(IsoReadOpts *opts, int norr)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->norock = norr ? 1 :0;
+ return ISO_SUCCESS;
+}
+
+int iso_read_opts_set_no_joliet(IsoReadOpts *opts, int nojoliet)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->nojoliet = nojoliet ? 1 :0;
+ return ISO_SUCCESS;
+}
+
+int iso_read_opts_set_no_iso1999(IsoReadOpts *opts, int noiso1999)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->noiso1999 = noiso1999 ? 1 :0;
+ return ISO_SUCCESS;
+}
+
+int iso_read_opts_set_preferjoliet(IsoReadOpts *opts, int preferjoliet)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->preferjoliet = preferjoliet ? 1 :0;
+ return ISO_SUCCESS;
+}
+
+int iso_read_opts_set_default_uid(IsoReadOpts *opts, uid_t uid)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->uid = uid;
+ return ISO_SUCCESS;
+}
+
+int iso_read_opts_set_default_gid(IsoReadOpts *opts, gid_t gid)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->gid = gid;
+ return ISO_SUCCESS;
+}
+
+int iso_read_opts_set_default_permissions(IsoReadOpts *opts, mode_t file_perm,
+ mode_t dir_perm)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->file_mode = file_perm;
+ opts->dir_mode = dir_perm;
+ return ISO_SUCCESS;
+}
+
+int iso_read_opts_set_input_charset(IsoReadOpts *opts, const char *charset)
+{
+ if (opts == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ opts->input_charset = charset ? strdup(charset) : NULL;
+ return ISO_SUCCESS;
+}
+
+/**
+ * Destroy an IsoReadImageFeatures object obtained with iso_image_import.
+ */
+void iso_read_image_features_destroy(IsoReadImageFeatures *f)
+{
+ if (f) {
+ free(f);
+ }
+}
+
+/**
+ * Get the size (in 2048 byte block) of the image, as reported in the PVM.
+ */
+uint32_t iso_read_image_features_get_size(IsoReadImageFeatures *f)
+{
+ return f->size;
+}
+
+/**
+ * Whether RockRidge extensions are present in the image imported.
+ */
+int iso_read_image_features_has_rockridge(IsoReadImageFeatures *f)
+{
+ return f->hasRR;
+}
+
+/**
+ * Whether Joliet extensions are present in the image imported.
+ */
+int iso_read_image_features_has_joliet(IsoReadImageFeatures *f)
+{
+ return f->hasJoliet;
+}
+
+/**
+ * Whether the image is recorded according to ISO 9660:1999, i.e. it has
+ * a version 2 Enhanced Volume Descriptor.
+ */
+int iso_read_image_features_has_iso1999(IsoReadImageFeatures *f)
+{
+ return f->hasIso1999;
+}
+
+/**
+ * Whether El-Torito boot record is present present in the image imported.
+ */
+int iso_read_image_features_has_eltorito(IsoReadImageFeatures *f)
+{
+ return f->hasElTorito;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fs_local.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fs_local.c
new file mode 100644
index 00000000..bf37337f
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fs_local.c
@@ -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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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_OPENED;
+ }
+
+ /* 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_OPENED;
+ 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_OPENED;
+ }
+}
+
+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_OPENED;
+ }
+}
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fsource.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fsource.c
new file mode 100644
index 00000000..b6e5c5f6
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fsource.c
@@ -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
+
+/**
+ * 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);
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fsource.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fsource.h
new file mode 100644
index 00000000..1ee8b185
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/fsource.h
@@ -0,0 +1,33 @@
+/*
+ * 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
+#define ISO_FILTER_FS_ID 5
+
+/**
+ * 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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/image.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/image.c
new file mode 100644
index 00000000..4539ac9d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/image.c
@@ -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
+#include
+
+/**
+ * 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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/image.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/image.h
new file mode 100644
index 00000000..b86aca1e
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/image.h
@@ -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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/iso1999.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/iso1999.c
new file mode 100644
index 00000000..827d5ad6
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/iso1999.c
@@ -0,0 +1,1016 @@
+/*
+ * 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 "iso1999.h"
+#include "messages.h"
+#include "writer.h"
+#include "image.h"
+#include "filesrc.h"
+#include "eltorito.h"
+
+#include
+#include
+#include
+
+static
+int get_iso1999_name(Ecma119Image *t, const char *str, char **fname)
+{
+ int ret;
+ char *name;
+
+ if (fname == NULL) {
+ return ISO_ASSERT_FAILURE;
+ }
+
+ if (str == NULL) {
+ /* not an error, can be root node */
+ *fname = NULL;
+ return ISO_SUCCESS;
+ }
+
+ if (!strcmp(t->input_charset, t->output_charset)) {
+ /* no conversion needed */
+ name = strdup(str);
+ } else {
+ ret = strconv(str, t->input_charset, t->output_charset, &name);
+ if (ret < 0) {
+ ret = iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
+ "Charset conversion error. Can't convert %s from %s to %s",
+ str, t->input_charset, t->output_charset);
+ if (ret < 0) {
+ return ret; /* aborted */
+ }
+
+ /* use the original name, it's the best we can do */
+ name = strdup(str);
+ }
+ }
+
+ /* ISO 9660:1999 7.5.1 */
+ if (strlen(name) > 207) {
+ name[207] = '\0';
+ }
+
+ *fname = name;
+
+ return ISO_SUCCESS;
+}
+
+static
+void iso1999_node_free(Iso1999Node *node)
+{
+ if (node == NULL) {
+ return;
+ }
+ if (node->type == ISO1999_DIR) {
+ int i;
+ for (i = 0; i < node->info.dir->nchildren; i++) {
+ iso1999_node_free(node->info.dir->children[i]);
+ }
+ free(node->info.dir->children);
+ free(node->info.dir);
+ }
+ iso_node_unref(node->node);
+ free(node->name);
+ free(node);
+}
+
+/**
+ * Create a low level ISO 9660:1999 node
+ * @return
+ * 1 success, 0 ignored, < 0 error
+ */
+static
+int create_node(Ecma119Image *t, IsoNode *iso, Iso1999Node **node)
+{
+ int ret;
+ Iso1999Node *n;
+
+ n = calloc(1, sizeof(Iso1999Node));
+ if (n == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ if (iso->type == LIBISO_DIR) {
+ IsoDir *dir = (IsoDir*) iso;
+ n->info.dir = calloc(1, sizeof(struct iso1999_dir_info));
+ if (n->info.dir == NULL) {
+ free(n);
+ return ISO_OUT_OF_MEM;
+ }
+ n->info.dir->children = calloc(sizeof(void*), dir->nchildren);
+ if (n->info.dir->children == NULL) {
+ free(n->info.dir);
+ free(n);
+ return ISO_OUT_OF_MEM;
+ }
+ n->type = ISO1999_DIR;
+ } else if (iso->type == LIBISO_FILE) {
+ /* it's a file */
+ off_t size;
+ IsoFileSrc *src;
+ IsoFile *file = (IsoFile*) iso;
+
+ size = iso_stream_get_size(file->stream);
+ if (size > (off_t)0xffffffff) {
+ free(n);
+ return iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
+ "File \"%s\" can't be added to image because is "
+ "greater than 4GB", iso->name);
+ return 0;
+ }
+
+ ret = iso_file_src_create(t, file, &src);
+ if (ret < 0) {
+ free(n);
+ return ret;
+ }
+ n->info.file = src;
+ n->type = ISO1999_FILE;
+ } else if (iso->type == LIBISO_BOOT) {
+ /* it's a el-torito boot catalog, that we write as a file */
+ IsoFileSrc *src;
+
+ ret = el_torito_catalog_file_src_create(t, &src);
+ if (ret < 0) {
+ free(n);
+ return ret;
+ }
+ n->info.file = src;
+ n->type = ISO1999_FILE;
+ } else {
+ /* should never happen */
+ free(n);
+ return ISO_ASSERT_FAILURE;
+ }
+
+ /* take a ref to the IsoNode */
+ n->node = iso;
+ iso_node_ref(iso);
+
+ *node = n;
+ return ISO_SUCCESS;
+}
+
+/**
+ * Create the low level ISO 9660:1999 tree from the high level ISO tree.
+ *
+ * @return
+ * 1 success, 0 file ignored, < 0 error
+ */
+static
+int create_tree(Ecma119Image *t, IsoNode *iso, Iso1999Node **tree, int pathlen)
+{
+ int ret, max_path;
+ Iso1999Node *node = NULL;
+ char *iso_name = NULL;
+
+ if (t == NULL || iso == NULL || tree == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ if (iso->hidden & LIBISO_HIDE_ON_1999) {
+ /* file will be ignored */
+ return 0;
+ }
+ ret = get_iso1999_name(t, iso->name, &iso_name);
+ if (ret < 0) {
+ return ret;
+ }
+
+ max_path = pathlen + 1 + (iso_name ? strlen(iso_name): 0);
+ if (!t->allow_longer_paths && max_path > 255) {
+ free(iso_name);
+ return iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
+ "File \"%s\" can't be added to ISO 9660:1999 tree, "
+ "because its path length is larger than 255", iso->name);
+ }
+
+ switch (iso->type) {
+ case LIBISO_FILE:
+ ret = create_node(t, iso, &node);
+ break;
+ case LIBISO_DIR:
+ {
+ IsoNode *pos;
+ IsoDir *dir = (IsoDir*)iso;
+ ret = create_node(t, iso, &node);
+ if (ret < 0) {
+ free(iso_name);
+ return ret;
+ }
+ pos = dir->children;
+ while (pos) {
+ int cret;
+ Iso1999Node *child;
+ cret = create_tree(t, pos, &child, max_path);
+ if (cret < 0) {
+ /* error */
+ iso1999_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;
+ case LIBISO_BOOT:
+ if (t->eltorito) {
+ ret = create_node(t, iso, &node);
+ } else {
+ /* log and ignore */
+ ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
+ "El-Torito catalog found on a image without El-Torito.",
+ iso->name);
+ }
+ break;
+ case LIBISO_SYMLINK:
+ case LIBISO_SPECIAL:
+ ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
+ "Can't add %s to ISO 9660:1999 tree. This kind of files "
+ "can only be added to a Rock Ridget tree. Skipping.",
+ iso->name);
+ break;
+ default:
+ /* should never happen */
+ return ISO_ASSERT_FAILURE;
+ }
+ if (ret <= 0) {
+ free(iso_name);
+ return ret;
+ }
+ node->name = iso_name;
+ *tree = node;
+ return ISO_SUCCESS;
+}
+
+static int
+cmp_node(const void *f1, const void *f2)
+{
+ Iso1999Node *f = *((Iso1999Node**)f1);
+ Iso1999Node *g = *((Iso1999Node**)f2);
+
+ /**
+ * TODO #00027 Follow ISO 9660:1999 specs when sorting files
+ * strcmp do not does exactly what ISO 9660:1999, 9.3, as characters
+ * < 0x20 " " are allowed, so name len must be taken into accout
+ */
+ return strcmp(f->name, g->name);
+}
+
+/**
+ * Sort the entries inside an ISO 9660:1999 directory, according to
+ * ISO 9660:1999, 9.3
+ */
+static
+void sort_tree(Iso1999Node *root)
+{
+ size_t i;
+
+ qsort(root->info.dir->children, root->info.dir->nchildren,
+ sizeof(void*), cmp_node);
+ for (i = 0; i < root->info.dir->nchildren; i++) {
+ Iso1999Node *child = root->info.dir->children[i];
+ if (child->type == ISO1999_DIR)
+ sort_tree(child);
+ }
+}
+
+static
+int mangle_single_dir(Ecma119Image *img, Iso1999Node *dir)
+{
+ int ret;
+ int i, nchildren;
+ Iso1999Node **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]->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[208];
+ 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(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.
+ */
+ while (digits < 8) {
+ int ok, k;
+ char *dot;
+ int change = 0; /* number to be written */
+
+ /* copy name to buffer */
+ strcpy(full_name, children[i]->name);
+
+ /* compute name and extension */
+ dot = strrchr(full_name, '.');
+ if (dot != NULL && children[i]->type != ISO1999_DIR) {
+
+ /*
+ * File (not dir) with extension.
+ */
+ int extlen;
+ full_name[dot - full_name] = '\0';
+ name = full_name;
+ ext = dot + 1;
+
+ extlen = strlen(ext);
+ max = 207 - 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 = 207 - 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 == ISO1999_DIR) {
+ dot = NULL; /* dots have no meaning in dirs */
+ }
+ max = 207 - 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[208];
+ 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]->name, new);
+
+ iso_htable_remove_ptr(table, children[k]->name, NULL);
+ free(children[k]->name);
+ children[k]->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);
+ }
+
+ ret = ISO_SUCCESS;
+
+mangle_cleanup : ;
+ iso_htable_destroy(table, NULL);
+ return ret;
+}
+
+static
+int mangle_tree(Ecma119Image *t, Iso1999Node *dir)
+{
+ int ret;
+ size_t i;
+
+ ret = mangle_single_dir(t, dir);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* recurse */
+ for (i = 0; i < dir->info.dir->nchildren; ++i) {
+ if (dir->info.dir->children[i]->type == ISO1999_DIR) {
+ ret = mangle_tree(t, dir->info.dir->children[i]);
+ if (ret < 0) {
+ /* error */
+ return ret;
+ }
+ }
+ }
+ return ISO_SUCCESS;
+}
+
+static
+int iso1999_tree_create(Ecma119Image *t)
+{
+ int ret;
+ Iso1999Node *root;
+
+ if (t == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ ret = create_tree(t, (IsoNode*)t->image->root, &root, 0);
+ if (ret <= 0) {
+ if (ret == 0) {
+ /* unexpected error, root ignored!! This can't happen */
+ ret = ISO_ASSERT_FAILURE;
+ }
+ return ret;
+ }
+
+ /* the ISO 9660:1999 tree is stored in Ecma119Image target */
+ t->iso1999_root = root;
+
+ iso_msg_debug(t->image->id, "Sorting the ISO 9660:1999 tree...");
+ sort_tree(root);
+
+ iso_msg_debug(t->image->id, "Mangling ISO 9660:1999 names...");
+ ret = mangle_tree(t, t->iso1999_root);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ISO_SUCCESS;
+}
+
+/**
+ * Compute the size of a directory entry for a single node
+ */
+static
+size_t calc_dirent_len(Ecma119Image *t, Iso1999Node *n)
+{
+ int ret = n->name ? strlen(n->name) + 33 : 34;
+ if (ret % 2)
+ ret++;
+ return ret;
+}
+
+/**
+ * Computes the total size of all directory entries of a single dir, as
+ * stated in ISO 9660:1999, 6.8.1.3
+ */
+static
+size_t calc_dir_size(Ecma119Image *t, Iso1999Node *dir)
+{
+ size_t i, len;
+
+ /* size of "." and ".." entries */
+ len = 34 + 34;
+
+ for (i = 0; i < dir->info.dir->nchildren; ++i) {
+ size_t remaining;
+ Iso1999Node *child = dir->info.dir->children[i];
+ size_t dirent_len = calc_dirent_len(t, child);
+ remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
+ if (dirent_len > remaining) {
+ /* child directory entry doesn't fit on block */
+ len += remaining + dirent_len;
+ } else {
+ len += dirent_len;
+ }
+ }
+
+ /*
+ * The size of a dir is always a multiple of block size, as we must add
+ * the size of the unused space after the last directory record
+ * (ISO 9660:1999, 6.8.1.3)
+ */
+ len = ROUND_UP(len, BLOCK_SIZE);
+
+ /* cache the len */
+ dir->info.dir->len = len;
+ return len;
+}
+
+static
+void calc_dir_pos(Ecma119Image *t, Iso1999Node *dir)
+{
+ size_t i, len;
+
+ t->iso1999_ndirs++;
+ dir->info.dir->block = t->curblock;
+ len = calc_dir_size(t, dir);
+ t->curblock += DIV_UP(len, BLOCK_SIZE);
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ Iso1999Node *child = dir->info.dir->children[i];
+ if (child->type == ISO1999_DIR) {
+ calc_dir_pos(t, child);
+ }
+ }
+}
+
+/**
+ * Compute the length of the path table (ISO 9660:1999, 6.9), in bytes.
+ */
+static
+uint32_t calc_path_table_size(Iso1999Node *dir)
+{
+ uint32_t size;
+ size_t i;
+
+ /* size of path table for this entry */
+ size = 8;
+ size += dir->name ? strlen(dir->name) : 2;
+ size += (size % 2);
+
+ /* and recurse */
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ Iso1999Node *child = dir->info.dir->children[i];
+ if (child->type == ISO1999_DIR) {
+ size += calc_path_table_size(child);
+ }
+ }
+ return size;
+}
+
+static
+int iso1999_writer_compute_data_blocks(IsoImageWriter *writer)
+{
+ Ecma119Image *t;
+ uint32_t path_table_size;
+
+ if (writer == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ t = writer->target;
+
+ /* compute position of directories */
+ iso_msg_debug(t->image->id,
+ "Computing position of ISO 9660:1999 dir structure");
+ t->iso1999_ndirs = 0;
+ calc_dir_pos(t, t->iso1999_root);
+
+ /* compute length of pathlist */
+ iso_msg_debug(t->image->id, "Computing length of ISO 9660:1999 pathlist");
+ path_table_size = calc_path_table_size(t->iso1999_root);
+
+ /* compute location for path tables */
+ t->iso1999_l_path_table_pos = t->curblock;
+ t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
+ t->iso1999_m_path_table_pos = t->curblock;
+ t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
+ t->iso1999_path_table_size = path_table_size;
+
+ return ISO_SUCCESS;
+}
+
+/**
+ * Write a single directory record (ISO 9660:1999, 9.1).
+ *
+ * @param file_id
+ * if >= 0, we use it instead of the filename (for "." and ".." entries).
+ * @param len_fi
+ * Computed length of the file identifier.
+ */
+static
+void write_one_dir_record(Ecma119Image *t, Iso1999Node *node, int file_id,
+ uint8_t *buf, size_t len_fi)
+{
+ uint32_t len;
+ uint32_t block;
+ uint8_t len_dr; /*< size of dir entry */
+ uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
+ : (uint8_t*)node->name;
+
+ struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
+
+ len_dr = 33 + len_fi + (len_fi % 2 ? 0 : 1);
+
+ memcpy(rec->file_id, name, len_fi);
+
+ if (node->type == ISO1999_DIR) {
+ /* use the cached length */
+ len = node->info.dir->len;
+ block = node->info.dir->block;
+ } else if (node->type == ISO1999_FILE) {
+ len = iso_file_src_get_size(node->info.file);
+ block = node->info.file->block;
+ } else {
+ /*
+ * for nodes other than files and dirs, we set both
+ * len and block to 0
+ */
+ len = 0;
+ block = 0;
+ }
+
+ /*
+ * For ".." entry we need to write the parent info!
+ */
+ if (file_id == 1 && node->parent)
+ node = node->parent;
+
+ rec->len_dr[0] = len_dr;
+ iso_bb(rec->block, block, 4);
+ iso_bb(rec->length, len, 4);
+ iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
+ rec->flags[0] = (node->type == ISO1999_DIR) ? 2 : 0;
+ iso_bb(rec->vol_seq_number, 1, 2);
+ rec->len_fi[0] = len_fi;
+}
+
+/**
+ * Write the enhanced volume descriptor (ISO/IEC 9660:1999, 8.5)
+ */
+static
+int iso1999_writer_write_vol_desc(IsoImageWriter *writer)
+{
+ IsoImage *image;
+ Ecma119Image *t;
+
+ /* The enhanced volume descriptor is like the sup vol desc */
+ struct ecma119_sup_vol_desc vol;
+
+ char *vol_id = NULL, *pub_id = NULL, *data_id = NULL;
+ char *volset_id = NULL, *system_id = NULL, *application_id = NULL;
+ char *copyright_file_id = NULL, *abstract_file_id = NULL;
+ char *biblio_file_id = NULL;
+
+ if (writer == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ t = writer->target;
+ image = t->image;
+
+ iso_msg_debug(image->id, "Write Enhanced Vol Desc (ISO 9660:1999)");
+
+ memset(&vol, 0, sizeof(struct ecma119_sup_vol_desc));
+
+ get_iso1999_name(t, image->volume_id, &vol_id);
+ str2a_char(t->input_charset, image->publisher_id, &pub_id);
+ str2a_char(t->input_charset, image->data_preparer_id, &data_id);
+ get_iso1999_name(t, image->volset_id, &volset_id);
+
+ str2a_char(t->input_charset, image->system_id, &system_id);
+ str2a_char(t->input_charset, image->application_id, &application_id);
+ get_iso1999_name(t, image->copyright_file_id, ©right_file_id);
+ get_iso1999_name(t, image->abstract_file_id, &abstract_file_id);
+ get_iso1999_name(t, image->biblio_file_id, &biblio_file_id);
+
+ vol.vol_desc_type[0] = 2;
+ memcpy(vol.std_identifier, "CD001", 5);
+
+ /* descriptor version is 2 (ISO/IEC 9660:1999, 8.5.2) */
+ vol.vol_desc_version[0] = 2;
+ strncpy_pad((char*)vol.volume_id, vol_id, 32);
+
+ iso_bb(vol.vol_space_size, t->vol_space_size, 4);
+ iso_bb(vol.vol_set_size, 1, 2);
+ iso_bb(vol.vol_seq_number, 1, 2);
+ iso_bb(vol.block_size, BLOCK_SIZE, 2);
+ iso_bb(vol.path_table_size, t->iso1999_path_table_size, 4);
+ iso_lsb(vol.l_path_table_pos, t->iso1999_l_path_table_pos, 4);
+ iso_msb(vol.m_path_table_pos, t->iso1999_m_path_table_pos, 4);
+
+ write_one_dir_record(t, t->iso1999_root, 0, vol.root_dir_record, 1);
+
+ strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
+ strncpy_pad((char*)vol.publisher_id, pub_id, 128);
+ strncpy_pad((char*)vol.data_prep_id, data_id, 128);
+
+ strncpy_pad((char*)vol.system_id, system_id, 32);
+
+ strncpy_pad((char*)vol.application_id, application_id, 128);
+ strncpy_pad((char*)vol.copyright_file_id, copyright_file_id, 37);
+ strncpy_pad((char*)vol.abstract_file_id, abstract_file_id, 37);
+ strncpy_pad((char*)vol.bibliographic_file_id, biblio_file_id, 37);
+
+ iso_datetime_17(vol.vol_creation_time, t->now, t->always_gmt);
+ iso_datetime_17(vol.vol_modification_time, t->now, t->always_gmt);
+ iso_datetime_17(vol.vol_effective_time, t->now, t->always_gmt);
+ vol.file_structure_version[0] = 1;
+
+ free(vol_id);
+ free(volset_id);
+ free(pub_id);
+ free(data_id);
+ free(system_id);
+ free(application_id);
+ free(copyright_file_id);
+ free(abstract_file_id);
+ free(biblio_file_id);
+
+ /* Finally write the Volume Descriptor */
+ return iso_write(t, &vol, sizeof(struct ecma119_sup_vol_desc));
+}
+
+static
+int write_one_dir(Ecma119Image *t, Iso1999Node *dir)
+{
+ int ret;
+ uint8_t buffer[BLOCK_SIZE];
+ size_t i;
+ size_t fi_len, len;
+
+ /* buf will point to current write position on buffer */
+ uint8_t *buf = buffer;
+
+ /* initialize buffer with 0s */
+ memset(buffer, 0, BLOCK_SIZE);
+
+ /* write the "." and ".." entries first */
+ write_one_dir_record(t, dir, 0, buf, 1);
+ buf += 34;
+ write_one_dir_record(t, dir, 1, buf, 1);
+ buf += 34;
+
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ Iso1999Node *child = dir->info.dir->children[i];
+
+ /* compute len of directory entry */
+ fi_len = strlen(child->name);
+ len = fi_len + 33 + (fi_len % 2 ? 0 : 1);
+
+ if ( (buf + len - buffer) > BLOCK_SIZE) {
+ /* dir doesn't fit in current block */
+ ret = iso_write(t, buffer, BLOCK_SIZE);
+ if (ret < 0) {
+ return ret;
+ }
+ memset(buffer, 0, BLOCK_SIZE);
+ buf = buffer;
+ }
+ /* write the directory entry in any case */
+ write_one_dir_record(t, child, -1, buf, fi_len);
+ buf += len;
+ }
+
+ /* write the last block */
+ ret = iso_write(t, buffer, BLOCK_SIZE);
+ return ret;
+}
+
+static
+int write_dirs(Ecma119Image *t, Iso1999Node *root)
+{
+ int ret;
+ size_t i;
+
+ /* write all directory entries for this dir */
+ ret = write_one_dir(t, root);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* recurse */
+ for (i = 0; i < root->info.dir->nchildren; i++) {
+ Iso1999Node *child = root->info.dir->children[i];
+ if (child->type == ISO1999_DIR) {
+ ret = write_dirs(t, child);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+ return ISO_SUCCESS;
+}
+
+static
+int write_path_table(Ecma119Image *t, Iso1999Node **pathlist, int l_type)
+{
+ size_t i, len;
+ uint8_t buf[256]; /* 256 is just a convenient size larger enought */
+ struct ecma119_path_table_record *rec;
+ void (*write_int)(uint8_t*, uint32_t, int);
+ Iso1999Node *dir;
+ uint32_t path_table_size;
+ int parent = 0;
+ int ret= ISO_SUCCESS;
+
+ path_table_size = 0;
+ write_int = l_type ? iso_lsb : iso_msb;
+
+ for (i = 0; i < t->iso1999_ndirs; i++) {
+ dir = pathlist[i];
+
+ /* find the index of the parent in the table */
+ while ((i) && pathlist[parent] != dir->parent) {
+ parent++;
+ }
+
+ /* write the Path Table Record (ECMA-119, 9.4) */
+ memset(buf, 0, 256);
+ rec = (struct ecma119_path_table_record*) buf;
+ rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->name) : 1;
+ rec->len_xa[0] = 0;
+ write_int(rec->block, dir->info.dir->block, 4);
+ write_int(rec->parent, parent + 1, 2);
+ if (dir->parent) {
+ memcpy(rec->dir_id, dir->name, rec->len_di[0]);
+ }
+ len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
+ ret = iso_write(t, buf, len);
+ if (ret < 0) {
+ /* error */
+ return ret;
+ }
+ path_table_size += len;
+ }
+
+ /* we need to fill the last block with zeros */
+ path_table_size %= BLOCK_SIZE;
+ if (path_table_size) {
+ uint8_t zeros[BLOCK_SIZE];
+ len = BLOCK_SIZE - path_table_size;
+ memset(zeros, 0, len);
+ ret = iso_write(t, zeros, len);
+ }
+ return ret;
+}
+
+static
+int write_path_tables(Ecma119Image *t)
+{
+ int ret;
+ size_t i, j, cur;
+ Iso1999Node **pathlist;
+
+ iso_msg_debug(t->image->id, "Writing ISO 9660:1999 Path tables");
+
+ /* allocate temporal pathlist */
+ pathlist = malloc(sizeof(void*) * t->iso1999_ndirs);
+ if (pathlist == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ pathlist[0] = t->iso1999_root;
+ cur = 1;
+
+ for (i = 0; i < t->iso1999_ndirs; i++) {
+ Iso1999Node *dir = pathlist[i];
+ for (j = 0; j < dir->info.dir->nchildren; j++) {
+ Iso1999Node *child = dir->info.dir->children[j];
+ if (child->type == ISO1999_DIR) {
+ pathlist[cur++] = child;
+ }
+ }
+ }
+
+ /* Write L Path Table */
+ ret = write_path_table(t, pathlist, 1);
+ if (ret < 0) {
+ goto write_path_tables_exit;
+ }
+
+ /* Write L Path Table */
+ ret = write_path_table(t, pathlist, 0);
+
+ write_path_tables_exit: ;
+ free(pathlist);
+ return ret;
+}
+
+static
+int iso1999_writer_write_data(IsoImageWriter *writer)
+{
+ int ret;
+ Ecma119Image *t;
+
+ if (writer == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ t = writer->target;
+
+ /* first of all, we write the directory structure */
+ ret = write_dirs(t, t->iso1999_root);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* and write the path tables */
+ ret = write_path_tables(t);
+
+ return ret;
+}
+
+static
+int iso1999_writer_free_data(IsoImageWriter *writer)
+{
+ /* free the ISO 9660:1999 tree */
+ Ecma119Image *t = writer->target;
+ iso1999_node_free(t->iso1999_root);
+ return ISO_SUCCESS;
+}
+
+int iso1999_writer_create(Ecma119Image *target)
+{
+ int ret;
+ IsoImageWriter *writer;
+
+ writer = malloc(sizeof(IsoImageWriter));
+ if (writer == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ writer->compute_data_blocks = iso1999_writer_compute_data_blocks;
+ writer->write_vol_desc = iso1999_writer_write_vol_desc;
+ writer->write_data = iso1999_writer_write_data;
+ writer->free_data = iso1999_writer_free_data;
+ writer->data = NULL;
+ writer->target = target;
+
+ iso_msg_debug(target->image->id,
+ "Creating low level ISO 9660:1999 tree...");
+ ret = iso1999_tree_create(target);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* add this writer to image */
+ target->writers[target->nwriters++] = writer;
+
+ /* we need the volume descriptor */
+ target->curblock++;
+ return ISO_SUCCESS;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/iso1999.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/iso1999.h
new file mode 100644
index 00000000..5c986e7d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/iso1999.h
@@ -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 */
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/joliet.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/joliet.c
new file mode 100644
index 00000000..0b86f031
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/joliet.c
@@ -0,0 +1,1081 @@
+/*
+ * 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.
+ */
+
+#include "joliet.h"
+#include "messages.h"
+#include "writer.h"
+#include "image.h"
+#include "filesrc.h"
+#include "eltorito.h"
+
+#include
+#include
+#include
+
+static
+int get_joliet_name(Ecma119Image *t, IsoNode *iso, uint16_t **name)
+{
+ int ret;
+ uint16_t *ucs_name;
+ uint16_t *jname = NULL;
+
+ if (iso->name == NULL) {
+ /* it is not necessarily an error, it can be the root */
+ return ISO_SUCCESS;
+ }
+
+ ret = str2ucs(t->input_charset, iso->name, &ucs_name);
+ if (ret < 0) {
+ iso_msg_debug(t->image->id, "Can't convert %s", iso->name);
+ return ret;
+ }
+
+ /* TODO #00022 : support relaxed constraints in joliet filenames */
+ if (iso->type == LIBISO_DIR) {
+ jname = iso_j_dir_id(ucs_name);
+ } else {
+ jname = iso_j_file_id(ucs_name);
+ }
+ free(ucs_name);
+ if (jname != NULL) {
+ *name = jname;
+ 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
+void joliet_node_free(JolietNode *node)
+{
+ if (node == NULL) {
+ return;
+ }
+ if (node->type == JOLIET_DIR) {
+ int i;
+ for (i = 0; i < node->info.dir->nchildren; i++) {
+ joliet_node_free(node->info.dir->children[i]);
+ }
+ free(node->info.dir->children);
+ free(node->info.dir);
+ }
+ iso_node_unref(node->node);
+ free(node->name);
+ free(node);
+}
+
+/**
+ * Create a low level Joliet node
+ * @return
+ * 1 success, 0 ignored, < 0 error
+ */
+static
+int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node)
+{
+ int ret;
+ JolietNode *joliet;
+
+ joliet = calloc(1, sizeof(JolietNode));
+ if (joliet == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ if (iso->type == LIBISO_DIR) {
+ IsoDir *dir = (IsoDir*) iso;
+ joliet->info.dir = calloc(1, sizeof(struct joliet_dir_info));
+ if (joliet->info.dir == NULL) {
+ free(joliet);
+ return ISO_OUT_OF_MEM;
+ }
+ joliet->info.dir->children = calloc(sizeof(void*), dir->nchildren);
+ if (joliet->info.dir->children == NULL) {
+ free(joliet->info.dir);
+ free(joliet);
+ return ISO_OUT_OF_MEM;
+ }
+ joliet->type = JOLIET_DIR;
+ } else if (iso->type == LIBISO_FILE) {
+ /* it's a file */
+ off_t size;
+ IsoFileSrc *src;
+ IsoFile *file = (IsoFile*) iso;
+
+ size = iso_stream_get_size(file->stream);
+ if (size > (off_t)0xffffffff) {
+ free(joliet);
+ return iso_msg_submit(t->image->id, ISO_FILE_TOO_BIG, 0,
+ "File \"%s\" can't be added to image because is "
+ "greater than 4GB", iso->name);
+ }
+
+ ret = iso_file_src_create(t, file, &src);
+ if (ret < 0) {
+ free(joliet);
+ return ret;
+ }
+ joliet->info.file = src;
+ joliet->type = JOLIET_FILE;
+ } else if (iso->type == LIBISO_BOOT) {
+ /* it's a el-torito boot catalog, that we write as a file */
+ IsoFileSrc *src;
+
+ ret = el_torito_catalog_file_src_create(t, &src);
+ if (ret < 0) {
+ free(joliet);
+ return ret;
+ }
+ joliet->info.file = src;
+ joliet->type = JOLIET_FILE;
+ } else {
+ /* should never happen */
+ free(joliet);
+ return ISO_ASSERT_FAILURE;
+ }
+
+ /* take a ref to the IsoNode */
+ joliet->node = iso;
+ iso_node_ref(iso);
+
+ *node = joliet;
+ return ISO_SUCCESS;
+}
+
+/**
+ * Create the low level Joliet tree from the high level ISO tree.
+ *
+ * @return
+ * 1 success, 0 file ignored, < 0 error
+ */
+static
+int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen)
+{
+ int ret, max_path;
+ JolietNode *node = NULL;
+ uint16_t *jname = NULL;
+
+ if (t == NULL || iso == NULL || tree == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ if (iso->hidden & LIBISO_HIDE_ON_JOLIET) {
+ /* file will be ignored */
+ return 0;
+ }
+ ret = get_joliet_name(t, iso, &jname);
+ if (ret < 0) {
+ return ret;
+ }
+ max_path = pathlen + 1 + (jname ? ucslen(jname) * 2 : 0);
+ if (!t->joliet_longer_paths && max_path > 240) {
+ free(jname);
+ /*
+ * Wow!! Joliet is even more restrictive than plain ISO-9660,
+ * that allows up to 255 bytes!!
+ */
+ return iso_msg_submit(t->image->id, ISO_FILE_IMGPATH_WRONG, 0,
+ "File \"%s\" can't be added to Joliet tree, because "
+ "its path length is larger than 240", iso->name);
+ }
+
+ switch (iso->type) {
+ case LIBISO_FILE:
+ ret = create_node(t, iso, &node);
+ break;
+ case LIBISO_DIR:
+ {
+ IsoNode *pos;
+ IsoDir *dir = (IsoDir*)iso;
+ ret = create_node(t, iso, &node);
+ if (ret < 0) {
+ free(jname);
+ return ret;
+ }
+ pos = dir->children;
+ while (pos) {
+ int cret;
+ JolietNode *child;
+ cret = create_tree(t, pos, &child, max_path);
+ if (cret < 0) {
+ /* error */
+ joliet_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;
+ case LIBISO_BOOT:
+ if (t->eltorito) {
+ ret = create_node(t, iso, &node);
+ } else {
+ /* log and ignore */
+ ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
+ "El-Torito catalog found on a image without El-Torito.",
+ iso->name);
+ }
+ break;
+ case LIBISO_SYMLINK:
+ case LIBISO_SPECIAL:
+ ret = iso_msg_submit(t->image->id, ISO_FILE_IGNORED, 0,
+ "Can't add %s to Joliet tree. This kind of files can only"
+ " be added to a Rock Ridget tree. Skipping.", iso->name);
+ break;
+ default:
+ /* should never happen */
+ return ISO_ASSERT_FAILURE;
+ }
+ if (ret <= 0) {
+ free(jname);
+ return ret;
+ }
+ node->name = jname;
+ *tree = node;
+ return ISO_SUCCESS;
+}
+
+static int
+cmp_node(const void *f1, const void *f2)
+{
+ JolietNode *f = *((JolietNode**)f1);
+ JolietNode *g = *((JolietNode**)f2);
+ return ucscmp(f->name, g->name);
+}
+
+static
+void sort_tree(JolietNode *root)
+{
+ size_t i;
+
+ qsort(root->info.dir->children, root->info.dir->nchildren,
+ sizeof(void*), cmp_node);
+ for (i = 0; i < root->info.dir->nchildren; i++) {
+ JolietNode *child = root->info.dir->children[i];
+ if (child->type == JOLIET_DIR)
+ sort_tree(child);
+ }
+}
+
+static
+int cmp_node_name(const void *f1, const void *f2)
+{
+ JolietNode *f = *((JolietNode**)f1);
+ JolietNode *g = *((JolietNode**)f2);
+ return ucscmp(f->name, g->name);
+}
+
+static
+int joliet_create_mangled_name(uint16_t *dest, uint16_t *src, int digits,
+ int number, uint16_t *ext)
+{
+ int ret, pos;
+ uint16_t *ucsnumber;
+ char fmt[16];
+ char *nstr = alloca(digits + 1);
+
+ sprintf(fmt, "%%0%dd", digits);
+ sprintf(nstr, fmt, number);
+
+ ret = str2ucs("ASCII", nstr, &ucsnumber);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* copy name */
+ pos = ucslen(src);
+ ucsncpy(dest, src, pos);
+
+ /* copy number */
+ ucsncpy(dest + pos, ucsnumber, digits);
+ pos += digits;
+
+ if (ext[0] != (uint16_t)0) {
+ size_t extlen = ucslen(ext);
+ dest[pos++] = (uint16_t)0x2E00; /* '.' in big endian UCS */
+ ucsncpy(dest + pos, ext, extlen);
+ pos += extlen;
+ }
+ dest[pos] = (uint16_t)0;
+ free(ucsnumber);
+ return ISO_SUCCESS;
+}
+
+static
+int mangle_single_dir(Ecma119Image *t, JolietNode *dir)
+{
+ int ret;
+ int i, nchildren;
+ JolietNode **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)ucscmp, &table);
+ if (ret < 0) {
+ return ret;
+ }
+ for (i = 0; i < nchildren; ++i) {
+ uint16_t *name = children[i]->name;
+ ret = iso_htable_add(table, name, name);
+ if (ret < 0) {
+ goto mangle_cleanup;
+ }
+ }
+
+ for (i = 0; i < nchildren; ++i) {
+ uint16_t *name, *ext;
+ uint16_t full_name[66];
+ 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.
+ */
+ while (digits < 8) {
+ int ok, k;
+ uint16_t *dot;
+ int change = 0; /* number to be written */
+
+ /* copy name to buffer */
+ ucscpy(full_name, children[i]->name);
+
+ /* compute name and extension */
+ dot = ucsrchr(full_name, '.');
+ if (dot != NULL && children[i]->type != JOLIET_DIR) {
+
+ /*
+ * File (not dir) with extension
+ */
+ int extlen;
+ full_name[dot - full_name] = 0;
+ name = full_name;
+ ext = dot + 1;
+
+ extlen = ucslen(ext);
+ max = 65 - 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 = 66 - 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 == JOLIET_DIR) {
+ max = 65 - digits;
+ dot = NULL; /* dots have no meaning in dirs */
+ } else {
+ max = 65 - digits;
+ }
+ name = full_name;
+ if (max < ucslen(name)) {
+ name[max] = 0;
+ }
+ /* let ext be an empty string */
+ ext = name + ucslen(name);
+ }
+
+ ok = 1;
+ /* change name of each file */
+ for (k = i; k <= j; ++k) {
+ uint16_t tmp[66];
+ while (1) {
+ ret = joliet_create_mangled_name(tmp, name, digits,
+ change, ext);
+ if (ret < 0) {
+ goto mangle_cleanup;
+ }
+ ++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) {
+ uint16_t *new = ucsdup(tmp);
+ if (new == NULL) {
+ ret = ISO_OUT_OF_MEM;
+ goto mangle_cleanup;
+ }
+
+ iso_htable_remove_ptr(table, children[k]->name, NULL);
+ free(children[k]->name);
+ children[k]->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_tree(Ecma119Image *t, JolietNode *dir)
+{
+ int ret;
+ size_t i;
+
+ ret = mangle_single_dir(t, dir);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* recurse */
+ for (i = 0; i < dir->info.dir->nchildren; ++i) {
+ if (dir->info.dir->children[i]->type == JOLIET_DIR) {
+ ret = mangle_tree(t, dir->info.dir->children[i]);
+ if (ret < 0) {
+ /* error */
+ return ret;
+ }
+ }
+ }
+ return ISO_SUCCESS;
+}
+
+static
+int joliet_tree_create(Ecma119Image *t)
+{
+ int ret;
+ JolietNode *root;
+
+ if (t == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ ret = create_tree(t, (IsoNode*)t->image->root, &root, 0);
+ if (ret <= 0) {
+ if (ret == 0) {
+ /* unexpected error, root ignored!! This can't happen */
+ ret = ISO_ASSERT_FAILURE;
+ }
+ return ret;
+ }
+
+ /* the Joliet tree is stored in Ecma119Image target */
+ t->joliet_root = root;
+
+ iso_msg_debug(t->image->id, "Sorting the Joliet tree...");
+ sort_tree(root);
+
+ iso_msg_debug(t->image->id, "Mangling Joliet names...");
+ ret = mangle_tree(t, t->joliet_root);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ISO_SUCCESS;
+}
+
+/**
+ * Compute the size of a directory entry for a single node
+ */
+static
+size_t calc_dirent_len(Ecma119Image *t, JolietNode *n)
+{
+ /* note than name len is always even, so we always need the pad byte */
+ int ret = n->name ? ucslen(n->name) * 2 + 34 : 34;
+ if (n->type == JOLIET_FILE && !t->omit_version_numbers) {
+ /* take into account version numbers */
+ ret += 4;
+ }
+ return ret;
+}
+
+/**
+ * Computes the total size of all directory entries of a single joliet dir.
+ * This is like ECMA-119 6.8.1.1, but taking care that names are stored in
+ * UCS.
+ */
+static
+size_t calc_dir_size(Ecma119Image *t, JolietNode *dir)
+{
+ size_t i, len;
+
+ /* size of "." and ".." entries */
+ len = 34 + 34;
+
+ for (i = 0; i < dir->info.dir->nchildren; ++i) {
+ size_t remaining;
+ JolietNode *child = dir->info.dir->children[i];
+ size_t dirent_len = calc_dirent_len(t, child);
+ remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
+ if (dirent_len > remaining) {
+ /* child directory entry doesn't fit on block */
+ len += remaining + dirent_len;
+ } else {
+ len += dirent_len;
+ }
+ }
+
+ /*
+ * The size of a dir is always a multiple of block size, as we must add
+ * the size of the unused space after the last directory record
+ * (ECMA-119, 6.8.1.3)
+ */
+ len = ROUND_UP(len, BLOCK_SIZE);
+
+ /* cache the len */
+ dir->info.dir->len = len;
+ return len;
+}
+
+static
+void calc_dir_pos(Ecma119Image *t, JolietNode *dir)
+{
+ size_t i, len;
+
+ t->joliet_ndirs++;
+ dir->info.dir->block = t->curblock;
+ len = calc_dir_size(t, dir);
+ t->curblock += DIV_UP(len, BLOCK_SIZE);
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ JolietNode *child = dir->info.dir->children[i];
+ if (child->type == JOLIET_DIR) {
+ calc_dir_pos(t, child);
+ }
+ }
+}
+
+/**
+ * Compute the length of the joliet path table, in bytes.
+ */
+static
+uint32_t calc_path_table_size(JolietNode *dir)
+{
+ uint32_t size;
+ size_t i;
+
+ /* size of path table for this entry */
+ size = 8;
+ size += dir->name ? ucslen(dir->name) * 2 : 2;
+
+ /* and recurse */
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ JolietNode *child = dir->info.dir->children[i];
+ if (child->type == JOLIET_DIR) {
+ size += calc_path_table_size(child);
+ }
+ }
+ return size;
+}
+
+static
+int joliet_writer_compute_data_blocks(IsoImageWriter *writer)
+{
+ Ecma119Image *t;
+ uint32_t path_table_size;
+
+ if (writer == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ t = writer->target;
+
+ /* compute position of directories */
+ iso_msg_debug(t->image->id, "Computing position of Joliet dir structure");
+ t->joliet_ndirs = 0;
+ calc_dir_pos(t, t->joliet_root);
+
+ /* compute length of pathlist */
+ iso_msg_debug(t->image->id, "Computing length of Joliet pathlist");
+ path_table_size = calc_path_table_size(t->joliet_root);
+
+ /* compute location for path tables */
+ t->joliet_l_path_table_pos = t->curblock;
+ t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
+ t->joliet_m_path_table_pos = t->curblock;
+ t->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
+ t->joliet_path_table_size = path_table_size;
+
+ return ISO_SUCCESS;
+}
+
+/**
+ * Write a single directory record for Joliet. It is like (ECMA-119, 9.1),
+ * but file identifier is stored in UCS.
+ *
+ * @param file_id
+ * if >= 0, we use it instead of the filename (for "." and ".." entries).
+ * @param len_fi
+ * Computed length of the file identifier. Total size of the directory
+ * entry will be len + 34 (ECMA-119, 9.1.12), as padding is always needed
+ */
+static
+void write_one_dir_record(Ecma119Image *t, JolietNode *node, int file_id,
+ uint8_t *buf, size_t len_fi)
+{
+ uint32_t len;
+ uint32_t block;
+ uint8_t len_dr; /*< size of dir entry */
+ uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
+ : (uint8_t*)node->name;
+
+ struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
+
+ len_dr = 33 + len_fi + (len_fi % 2 ? 0 : 1);
+
+ memcpy(rec->file_id, name, len_fi);
+
+ if (node->type == JOLIET_FILE && !t->omit_version_numbers) {
+ len_dr += 4;
+ rec->file_id[len_fi++] = 0;
+ rec->file_id[len_fi++] = ';';
+ rec->file_id[len_fi++] = 0;
+ rec->file_id[len_fi++] = '1';
+ }
+
+ if (node->type == JOLIET_DIR) {
+ /* use the cached length */
+ len = node->info.dir->len;
+ block = node->info.dir->block;
+ } else if (node->type == JOLIET_FILE) {
+ len = iso_file_src_get_size(node->info.file);
+ block = node->info.file->block;
+ } else {
+ /*
+ * for nodes other than files and dirs, we set both
+ * len and block to 0
+ */
+ len = 0;
+ block = 0;
+ }
+
+ /*
+ * For ".." entry we need to write the parent info!
+ */
+ if (file_id == 1 && node->parent)
+ node = node->parent;
+
+ rec->len_dr[0] = len_dr;
+ iso_bb(rec->block, block, 4);
+ iso_bb(rec->length, len, 4);
+ iso_datetime_7(rec->recording_time, t->now, t->always_gmt);
+ rec->flags[0] = (node->type == JOLIET_DIR) ? 2 : 0;
+ iso_bb(rec->vol_seq_number, 1, 2);
+ rec->len_fi[0] = len_fi;
+}
+
+/**
+ * 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.
+ */
+static
+void ucsncpy_pad(uint16_t *dest, const uint16_t *src, size_t max)
+{
+ char *cdest, *csrc;
+ size_t len, i;
+
+ cdest = (char*)dest;
+ csrc = (char*)src;
+
+ if (src != NULL) {
+ len = MIN(ucslen(src) * 2, max);
+ } else {
+ len = 0;
+ }
+
+ for (i = 0; i < len; ++i)
+ cdest[i] = csrc[i];
+
+ for (i = len; i < max; i += 2) {
+ cdest[i] = '\0';
+ cdest[i + 1] = ' ';
+ }
+}
+
+static
+int joliet_writer_write_vol_desc(IsoImageWriter *writer)
+{
+ IsoImage *image;
+ Ecma119Image *t;
+ struct ecma119_sup_vol_desc vol;
+
+ uint16_t *vol_id = NULL, *pub_id = NULL, *data_id = NULL;
+ uint16_t *volset_id = NULL, *system_id = NULL, *application_id = NULL;
+ uint16_t *copyright_file_id = NULL, *abstract_file_id = NULL;
+ uint16_t *biblio_file_id = NULL;
+
+ if (writer == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ t = writer->target;
+ image = t->image;
+
+ iso_msg_debug(image->id, "Write SVD for Joliet");
+
+ memset(&vol, 0, sizeof(struct ecma119_sup_vol_desc));
+
+ str2ucs(t->input_charset, image->volume_id, &vol_id);
+ str2ucs(t->input_charset, image->publisher_id, &pub_id);
+ str2ucs(t->input_charset, image->data_preparer_id, &data_id);
+ str2ucs(t->input_charset, image->volset_id, &volset_id);
+
+ str2ucs(t->input_charset, image->system_id, &system_id);
+ str2ucs(t->input_charset, image->application_id, &application_id);
+ str2ucs(t->input_charset, image->copyright_file_id, ©right_file_id);
+ str2ucs(t->input_charset, image->abstract_file_id, &abstract_file_id);
+ str2ucs(t->input_charset, image->biblio_file_id, &biblio_file_id);
+
+ vol.vol_desc_type[0] = 2;
+ memcpy(vol.std_identifier, "CD001", 5);
+ vol.vol_desc_version[0] = 1;
+ ucsncpy_pad((uint16_t*)vol.volume_id, vol_id, 32);
+
+ /* make use of UCS-2 Level 3 */
+ memcpy(vol.esc_sequences, "%/E", 3);
+
+ iso_bb(vol.vol_space_size, t->vol_space_size, 4);
+ iso_bb(vol.vol_set_size, 1, 2);
+ iso_bb(vol.vol_seq_number, 1, 2);
+ iso_bb(vol.block_size, BLOCK_SIZE, 2);
+ iso_bb(vol.path_table_size, t->joliet_path_table_size, 4);
+ iso_lsb(vol.l_path_table_pos, t->joliet_l_path_table_pos, 4);
+ iso_msb(vol.m_path_table_pos, t->joliet_m_path_table_pos, 4);
+
+ write_one_dir_record(t, t->joliet_root, 0, vol.root_dir_record, 1);
+
+ ucsncpy_pad((uint16_t*)vol.vol_set_id, volset_id, 128);
+ ucsncpy_pad((uint16_t*)vol.publisher_id, pub_id, 128);
+ ucsncpy_pad((uint16_t*)vol.data_prep_id, data_id, 128);
+
+ ucsncpy_pad((uint16_t*)vol.system_id, system_id, 32);
+
+ ucsncpy_pad((uint16_t*)vol.application_id, application_id, 128);
+ ucsncpy_pad((uint16_t*)vol.copyright_file_id, copyright_file_id, 37);
+ ucsncpy_pad((uint16_t*)vol.abstract_file_id, abstract_file_id, 37);
+ ucsncpy_pad((uint16_t*)vol.bibliographic_file_id, biblio_file_id, 37);
+
+ iso_datetime_17(vol.vol_creation_time, t->now, t->always_gmt);
+ iso_datetime_17(vol.vol_modification_time, t->now, t->always_gmt);
+ iso_datetime_17(vol.vol_effective_time, t->now, t->always_gmt);
+ vol.file_structure_version[0] = 1;
+
+ free(vol_id);
+ free(volset_id);
+ free(pub_id);
+ free(data_id);
+ free(system_id);
+ free(application_id);
+ free(copyright_file_id);
+ free(abstract_file_id);
+ free(biblio_file_id);
+
+ /* Finally write the Volume Descriptor */
+ return iso_write(t, &vol, sizeof(struct ecma119_sup_vol_desc));
+}
+
+static
+int write_one_dir(Ecma119Image *t, JolietNode *dir)
+{
+ int ret;
+ uint8_t buffer[BLOCK_SIZE];
+ size_t i;
+ size_t fi_len, len;
+
+ /* buf will point to current write position on buffer */
+ uint8_t *buf = buffer;
+
+ /* initialize buffer with 0s */
+ memset(buffer, 0, BLOCK_SIZE);
+
+ /* write the "." and ".." entries first */
+ write_one_dir_record(t, dir, 0, buf, 1);
+ buf += 34;
+ write_one_dir_record(t, dir, 1, buf, 1);
+ buf += 34;
+
+ for (i = 0; i < dir->info.dir->nchildren; i++) {
+ JolietNode *child = dir->info.dir->children[i];
+
+ /* compute len of directory entry */
+ fi_len = ucslen(child->name) * 2;
+ len = fi_len + 34;
+ if (child->type == JOLIET_FILE && !t->omit_version_numbers) {
+ len += 4;
+ }
+
+ if ( (buf + len - buffer) > BLOCK_SIZE) {
+ /* dir doesn't fit in current block */
+ ret = iso_write(t, buffer, BLOCK_SIZE);
+ if (ret < 0) {
+ return ret;
+ }
+ memset(buffer, 0, BLOCK_SIZE);
+ buf = buffer;
+ }
+ /* write the directory entry in any case */
+ write_one_dir_record(t, child, -1, buf, fi_len);
+ buf += len;
+ }
+
+ /* write the last block */
+ ret = iso_write(t, buffer, BLOCK_SIZE);
+ return ret;
+}
+
+static
+int write_dirs(Ecma119Image *t, JolietNode *root)
+{
+ int ret;
+ size_t i;
+
+ /* write all directory entries for this dir */
+ ret = write_one_dir(t, root);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* recurse */
+ for (i = 0; i < root->info.dir->nchildren; i++) {
+ JolietNode *child = root->info.dir->children[i];
+ if (child->type == JOLIET_DIR) {
+ ret = write_dirs(t, child);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+ return ISO_SUCCESS;
+}
+
+static
+int write_path_table(Ecma119Image *t, JolietNode **pathlist, int l_type)
+{
+ size_t i, len;
+ uint8_t buf[256]; /* 256 is just a convenient size larger enought */
+ struct ecma119_path_table_record *rec;
+ void (*write_int)(uint8_t*, uint32_t, int);
+ JolietNode *dir;
+ uint32_t path_table_size;
+ int parent = 0;
+ int ret= ISO_SUCCESS;
+
+ path_table_size = 0;
+ write_int = l_type ? iso_lsb : iso_msb;
+
+ for (i = 0; i < t->joliet_ndirs; i++) {
+ dir = pathlist[i];
+
+ /* find the index of the parent in the table */
+ while ((i) && pathlist[parent] != dir->parent) {
+ parent++;
+ }
+
+ /* write the Path Table Record (ECMA-119, 9.4) */
+ memset(buf, 0, 256);
+ rec = (struct ecma119_path_table_record*) buf;
+ rec->len_di[0] = dir->parent ? (uint8_t) ucslen(dir->name) * 2 : 1;
+ rec->len_xa[0] = 0;
+ write_int(rec->block, dir->info.dir->block, 4);
+ write_int(rec->parent, parent + 1, 2);
+ if (dir->parent) {
+ memcpy(rec->dir_id, dir->name, rec->len_di[0]);
+ }
+ len = 8 + rec->len_di[0] + (rec->len_di[0] % 2);
+ ret = iso_write(t, buf, len);
+ if (ret < 0) {
+ /* error */
+ return ret;
+ }
+ path_table_size += len;
+ }
+
+ /* we need to fill the last block with zeros */
+ path_table_size %= BLOCK_SIZE;
+ if (path_table_size) {
+ uint8_t zeros[BLOCK_SIZE];
+ len = BLOCK_SIZE - path_table_size;
+ memset(zeros, 0, len);
+ ret = iso_write(t, zeros, len);
+ }
+ return ret;
+}
+
+static
+int write_path_tables(Ecma119Image *t)
+{
+ int ret;
+ size_t i, j, cur;
+ JolietNode **pathlist;
+
+ iso_msg_debug(t->image->id, "Writing Joliet Path tables");
+
+ /* allocate temporal pathlist */
+ pathlist = malloc(sizeof(void*) * t->joliet_ndirs);
+ if (pathlist == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ pathlist[0] = t->joliet_root;
+ cur = 1;
+
+ for (i = 0; i < t->joliet_ndirs; i++) {
+ JolietNode *dir = pathlist[i];
+ for (j = 0; j < dir->info.dir->nchildren; j++) {
+ JolietNode *child = dir->info.dir->children[j];
+ if (child->type == JOLIET_DIR) {
+ pathlist[cur++] = child;
+ }
+ }
+ }
+
+ /* Write L Path Table */
+ ret = write_path_table(t, pathlist, 1);
+ if (ret < 0) {
+ goto write_path_tables_exit;
+ }
+
+ /* Write L Path Table */
+ ret = write_path_table(t, pathlist, 0);
+
+ write_path_tables_exit: ;
+ free(pathlist);
+ return ret;
+}
+
+static
+int joliet_writer_write_data(IsoImageWriter *writer)
+{
+ int ret;
+ Ecma119Image *t;
+
+ if (writer == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ t = writer->target;
+
+ /* first of all, we write the directory structure */
+ ret = write_dirs(t, t->joliet_root);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* and write the path tables */
+ ret = write_path_tables(t);
+
+ return ret;
+}
+
+static
+int joliet_writer_free_data(IsoImageWriter *writer)
+{
+ /* free the Joliet tree */
+ Ecma119Image *t = writer->target;
+ joliet_node_free(t->joliet_root);
+ return ISO_SUCCESS;
+}
+
+int joliet_writer_create(Ecma119Image *target)
+{
+ int ret;
+ IsoImageWriter *writer;
+
+ writer = malloc(sizeof(IsoImageWriter));
+ if (writer == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ writer->compute_data_blocks = joliet_writer_compute_data_blocks;
+ writer->write_vol_desc = joliet_writer_write_vol_desc;
+ writer->write_data = joliet_writer_write_data;
+ writer->free_data = joliet_writer_free_data;
+ writer->data = NULL;
+ writer->target = target;
+
+ iso_msg_debug(target->image->id, "Creating low level Joliet tree...");
+ ret = joliet_tree_create(target);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* add this writer to image */
+ target->writers[target->nwriters++] = writer;
+
+ /* we need the volume descriptor */
+ target->curblock++;
+ return ISO_SUCCESS;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/joliet.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/joliet.h
new file mode 100644
index 00000000..a2db1890
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/joliet.h
@@ -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 */
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libiso_msgs.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libiso_msgs.c
new file mode 100644
index 00000000..6a60429d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libiso_msgs.c
@@ -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 ,
+ provided under GPL version 2
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* 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);
+}
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libiso_msgs.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libiso_msgs.h
new file mode 100644
index 00000000..17e8f9e5
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libiso_msgs.h
@@ -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 ,
+ 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
+#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 */
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libisofs.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libisofs.h
new file mode 100644
index 00000000..a5bd199b
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/libisofs.h
@@ -0,0 +1,3644 @@
+/*
+ * Copyright (c) 2007-2008 Vreixo Formoso, 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.
+ */
+#ifndef LIBISO_LIBISOFS_H_
+#define LIBISO_LIBISOFS_H_
+
+#include
+#include
+#include
+
+struct burn_source;
+
+/**
+ * Context for image creation. It holds the files that will be added to image,
+ * and several options to control libisofs behavior.
+ *
+ * @since 0.6.2
+ */
+typedef struct Iso_Image IsoImage;
+
+/*
+ * A node in the iso tree, i.e. a file that will be written to image.
+ *
+ * It can represent any kind of files. When needed, you can get the type with
+ * iso_node_get_type() and cast it to the appropiate subtype. Useful macros
+ * are provided, see below.
+ *
+ * @since 0.6.2
+ */
+typedef struct Iso_Node IsoNode;
+
+/**
+ * A directory in the iso tree. It is an special type of IsoNode and can be
+ * casted to it in any case.
+ *
+ * @since 0.6.2
+ */
+typedef struct Iso_Dir IsoDir;
+
+/**
+ * A symbolic link in the iso tree. It is an special type of IsoNode and can be
+ * casted to it in any case.
+ *
+ * @since 0.6.2
+ */
+typedef struct Iso_Symlink IsoSymlink;
+
+/**
+ * A regular file in the iso tree. It is an special type of IsoNode and can be
+ * casted to it in any case.
+ *
+ * @since 0.6.2
+ */
+typedef struct Iso_File IsoFile;
+
+/**
+ * An special file in the iso tree. This is used to represent any POSIX file
+ * other that regular files, directories or symlinks, i.e.: socket, block and
+ * character devices, and fifos.
+ * It is an special type of IsoNode and can be casted to it in any case.
+ *
+ * @since 0.6.2
+ */
+typedef struct Iso_Special IsoSpecial;
+
+/**
+ * The type of an IsoNode.
+ *
+ * When an user gets an IsoNode from an image, (s)he can use
+ * iso_node_get_type() to get the current type of the node, and then
+ * cast to the appropriate subtype. For example:
+ *
+ * ...
+ * IsoNode *node;
+ * res = iso_dir_iter_next(iter, &node);
+ * if (res == 1 && iso_node_get_type(node) == LIBISO_DIR) {
+ * IsoDir *dir = (IsoDir *)node;
+ * ...
+ * }
+ *
+ * @since 0.6.2
+ */
+enum IsoNodeType {
+ LIBISO_DIR,
+ LIBISO_FILE,
+ LIBISO_SYMLINK,
+ LIBISO_SPECIAL,
+ LIBISO_BOOT
+};
+
+/* macros to check node type */
+#define ISO_NODE_IS_DIR(n) (iso_node_get_type(n) == LIBISO_DIR)
+#define ISO_NODE_IS_FILE(n) (iso_node_get_type(n) == LIBISO_FILE)
+#define ISO_NODE_IS_SYMLINK(n) (iso_node_get_type(n) == LIBISO_SYMLINK)
+#define ISO_NODE_IS_SPECIAL(n) (iso_node_get_type(n) == LIBISO_SPECIAL)
+#define ISO_NODE_IS_BOOTCAT(n) (iso_node_get_type(n) == LIBISO_BOOT)
+
+/* macros for safe downcasting */
+#define ISO_DIR(n) ((IsoDir*)(ISO_NODE_IS_DIR(n) ? n : NULL))
+#define ISO_FILE(n) ((IsoFile*)(ISO_NODE_IS_FILE(n) ? n : NULL))
+#define ISO_SYMLINK(n) ((IsoSymlink*)(ISO_NODE_IS_SYMLINK(n) ? n : NULL))
+#define ISO_SPECIAL(n) ((IsoSpecial*)(ISO_NODE_IS_SPECIAL(n) ? n : NULL))
+
+#define ISO_NODE(n) ((IsoNode*)n)
+
+/**
+ * Context for iterate on directory children.
+ * @see iso_dir_get_children()
+ *
+ * @since 0.6.2
+ */
+typedef struct Iso_Dir_Iter IsoDirIter;
+
+/**
+ * It represents an El-Torito boot image.
+ *
+ * @since 0.6.2
+ */
+typedef struct el_torito_boot_image ElToritoBootImage;
+
+/**
+ * An special type of IsoNode that acts as a placeholder for an El-Torito
+ * boot catalog. Once written, it will appear as a regular file.
+ *
+ * @since 0.6.2
+ */
+typedef struct Iso_Boot IsoBoot;
+
+/**
+ * Flag used to hide a file in the RR/ISO or Joliet tree.
+ *
+ * @see iso_node_set_hidden
+ * @since 0.6.2
+ */
+enum IsoHideNodeFlag {
+ /** Hide the node in the ECMA-119 / RR tree */
+ LIBISO_HIDE_ON_RR = 1 << 0,
+ /** Hide the node in the Joliet tree, if Joliet extension are enabled */
+ LIBISO_HIDE_ON_JOLIET = 1 << 1,
+ /** Hide the node in the ISO-9660:1999 tree, if that format is enabled */
+ LIBISO_HIDE_ON_1999 = 1 << 2
+};
+
+/**
+ * El-Torito bootable image type.
+ *
+ * @since 0.6.2
+ */
+enum eltorito_boot_media_type {
+ ELTORITO_FLOPPY_EMUL,
+ ELTORITO_HARD_DISC_EMUL,
+ ELTORITO_NO_EMUL
+};
+
+/**
+ * Replace mode used when addding a node to a file.
+ * This controls how libisofs will act when you tried to add to a dir a file
+ * with the same name that an existing file.
+ *
+ * @since 0.6.2
+ */
+enum iso_replace_mode {
+ /**
+ * Never replace an existing node, and instead fail with
+ * ISO_NODE_NAME_NOT_UNIQUE.
+ */
+ ISO_REPLACE_NEVER,
+ /**
+ * Always replace the old node with the new.
+ */
+ ISO_REPLACE_ALWAYS,
+ /**
+ * Replace with the new node if it is the same file type
+ */
+ ISO_REPLACE_IF_SAME_TYPE,
+ /**
+ * Replace with the new node if it is the same file type and its ctime
+ * is newer than the old one.
+ */
+ ISO_REPLACE_IF_SAME_TYPE_AND_NEWER,
+ /**
+ * Replace with the new node if its ctime is newer than the old one.
+ */
+ ISO_REPLACE_IF_NEWER
+ /*
+ * TODO #00006 define more values
+ * -if both are dirs, add contents (and what to do with conflicts?)
+ */
+};
+
+/**
+ * Options for image written.
+ * @see iso_write_opts_new()
+ * @since 0.6.2
+ */
+typedef struct iso_write_opts IsoWriteOpts;
+
+/**
+ * Options for image reading or import.
+ * @see iso_read_opts_new()
+ * @since 0.6.2
+ */
+typedef struct iso_read_opts IsoReadOpts;
+
+/**
+ * Source for image reading.
+ *
+ * @see struct iso_data_source
+ * @since 0.6.2
+ */
+typedef struct iso_data_source IsoDataSource;
+
+/**
+ * Data source used by libisofs for reading an existing image.
+ *
+ * It offers homogeneous read access to arbitrary blocks to different sources
+ * for images, such as .iso files, CD/DVD drives, etc...
+ *
+ * To create a multisession image, libisofs needs a IsoDataSource, that the
+ * user must provide. The function iso_data_source_new_from_file() constructs
+ * an IsoDataSource that uses POSIX I/O functions to access data. You can use
+ * it with regular .iso images, and also with block devices that represent a
+ * drive.
+ *
+ * @since 0.6.2
+ */
+struct iso_data_source
+{
+
+ /* reserved for future usage, set to 0 */
+ int version;
+
+ /**
+ * Reference count for the data source. Should be 1 when a new source
+ * is created. Don't access it directly, but with iso_data_source_ref()
+ * and iso_data_source_unref() functions.
+ */
+ unsigned int refcount;
+
+ /**
+ * Opens the given source. You must open() the source before any attempt
+ * to read data from it. The open is the right place for grabbing the
+ * underlying resources.
+ *
+ * @return
+ * 1 if success, < 0 on error
+ */
+ int (*open)(IsoDataSource *src);
+
+ /**
+ * Close a given source, freeing all system resources previously grabbed in
+ * open().
+ *
+ * @return
+ * 1 if success, < 0 on error
+ */
+ int (*close)(IsoDataSource *src);
+
+ /**
+ * Read an arbitrary block (2048 bytes) of data from the source.
+ *
+ * @param lba
+ * Block to be read.
+ * @param buffer
+ * Buffer where the data will be written. It should have at least
+ * 2048 bytes.
+ * @return
+ * 1 if success, < 0 on error
+ */
+ int (*read_block)(IsoDataSource *src, uint32_t lba, uint8_t *buffer);
+
+ /**
+ * Clean up the source specific data. Never call this directly, it is
+ * automatically called by iso_data_source_unref() when refcount reach
+ * 0.
+ */
+ void (*free_data)(IsoDataSource *);
+
+ /** Source specific data */
+ void *data;
+};
+
+/**
+ * Return information for image. This is optionally allocated by libisofs,
+ * as a way to inform user about the features of an existing image, such as
+ * extensions present, size, ...
+ *
+ * @see iso_image_import()
+ * @since 0.6.2
+ */
+typedef struct iso_read_image_features IsoReadImageFeatures;
+
+/**
+ * POSIX abstraction for source files.
+ *
+ * @see struct iso_file_source
+ * @since 0.6.2
+ */
+typedef struct iso_file_source IsoFileSource;
+
+/**
+ * Abstract for source filesystems.
+ *
+ * @see struct iso_filesystem
+ * @since 0.6.2
+ */
+typedef struct iso_filesystem IsoFilesystem;
+
+/**
+ * Interface that defines the operations (methods) available for an
+ * IsoFileSource.
+ *
+ * @see struct IsoFileSource_Iface
+ * @since 0.6.2
+ */
+typedef struct IsoFileSource_Iface IsoFileSourceIface;
+
+/**
+ * IsoFilesystem implementation to deal with ISO images, and to offer a way to
+ * access specific information of the image, such as several volume attributes,
+ * extensions being used, El-Torito artifacts...
+ *
+ * @since 0.6.2
+ */
+typedef IsoFilesystem IsoImageFilesystem;
+
+/**
+ * See IsoFilesystem->get_id() for info about this.
+ * @since 0.6.2
+ */
+extern unsigned int iso_fs_global_id;
+
+/**
+ * An IsoFilesystem is a handler for a source of files, or a "filesystem".
+ * That is defined as a set of files that are organized in a hierarchical
+ * structure.
+ *
+ * A filesystem allows libisofs to access files from several sources in
+ * an homogeneous way, thus abstracting the underlying operations needed to
+ * access and read file contents. Note that this doesn't need to be tied
+ * to the disc filesystem used in the partition being accessed. For example,
+ * we have an IsoFilesystem implementation to access any mounted filesystem,
+ * using standard Linux functions. It is also legal, of course, to implement
+ * an IsoFilesystem to deal with a specific filesystem over raw partitions.
+ * That is what we do, for example, to access an ISO Image.
+ *
+ * Each file inside an IsoFilesystem is represented as an IsoFileSource object,
+ * that defines POSIX-like interface for accessing files.
+ *
+ * @since 0.6.2
+ */
+struct iso_filesystem
+{
+ /**
+ * Type of filesystem.
+ * "file" -> local filesystem
+ * "iso " -> iso image filesystem
+ */
+ char type[4];
+
+ /* reserved for future usage, set to 0 */
+ int version;
+
+ /**
+ * Get the root of a filesystem.
+ *
+ * @return
+ * 1 on success, < 0 on error
+ */
+ int (*get_root)(IsoFilesystem *fs, IsoFileSource **root);
+
+ /**
+ * Retrieve a file from its absolute path inside the filesystem.
+ *
+ * @return
+ * 1 success, < 0 error
+ * Error codes:
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ */
+ int (*get_by_path)(IsoFilesystem *fs, const char *path,
+ IsoFileSource **file);
+
+ /**
+ * Get filesystem identifier.
+ *
+ * If the filesystem is able to generate correct values of the st_dev
+ * and st_ino fields for the struct stat of each file, this should
+ * return an unique number, greater than 0.
+ *
+ * To get a identifier for your filesystem implementation you should
+ * use iso_fs_global_id, incrementing it by one each time.
+ *
+ * Otherwise, if you can't ensure values in the struct stat are valid,
+ * this should return 0.
+ */
+ unsigned int (*get_id)(IsoFilesystem *fs);
+
+ /**
+ * Opens the filesystem for several read operations. Calling this funcion
+ * is not needed at all, each time that the underlying system resource
+ * needs to be accessed, it is openned propertly.
+ * However, if you plan to execute several operations on the filesystem,
+ * it is a good idea to open it previously, to prevent several open/close
+ * operations to occur.
+ *
+ * @return 1 on success, < 0 on error
+ */
+ int (*open)(IsoFilesystem *fs);
+
+ /**
+ * Close the filesystem, thus freeing all system resources. You should
+ * call this function if you have previously open() it.
+ * Note that you can open()/close() a filesystem several times.
+ *
+ * @return 1 on success, < 0 on error
+ */
+ int (*close)(IsoFilesystem *fs);
+
+ /**
+ * Free implementation specific data. Should never be called by user.
+ * Use iso_filesystem_unref() instead.
+ */
+ void (*free)(IsoFilesystem *fs);
+
+ /* internal usage, do never access them directly */
+ unsigned int refcount;
+ void *data;
+};
+
+/**
+ * Interface definition for an IsoFileSource. Defines the POSIX-like function
+ * to access files and abstract underlying source.
+ *
+ * @since 0.6.2
+ */
+struct IsoFileSource_Iface
+{
+ /* reserved for future usage, set to 0 */
+ int version;
+
+ /**
+ * Get the path, relative to the filesystem this file source belongs to.
+ *
+ * @return
+ * the path of the FileSource inside the filesystem, it should be
+ * freed when no more needed.
+ */
+ char* (*get_path)(IsoFileSource *src);
+
+ /**
+ * Get the name of the file, with the dir component of the path.
+ *
+ * @return
+ * the name of the file, it should be freed when no more needed.
+ */
+ char* (*get_name)(IsoFileSource *src);
+
+ /**
+ * Get information about the file. It is equivalent to lstat(2).
+ *
+ * @return
+ * 1 success, < 0 error
+ * Error codes:
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ */
+ int (*lstat)(IsoFileSource *src, struct stat *info);
+
+ /**
+ * Get information about the file. If the file is a symlink, the info
+ * returned refers to the destination. It is equivalent to stat(2).
+ *
+ * @return
+ * 1 success, < 0 error
+ * Error codes:
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ */
+ int (*stat)(IsoFileSource *src, struct stat *info);
+
+ /**
+ * Check if the process has access to read file contents. Note that this
+ * is not necessarily related with (l)stat functions. For example, in a
+ * filesystem implementation to deal with an ISO image, if the user has
+ * read access to the image it will be able to read all files inside it,
+ * despite of the particular permission of each file in the RR tree, that
+ * are what the above functions return.
+ *
+ * @return
+ * 1 if process has read access, < 0 on error
+ * Error codes:
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ */
+ int (*access)(IsoFileSource *src);
+
+ /**
+ * Opens the source.
+ * @return 1 on success, < 0 on error
+ * Error codes:
+ * ISO_FILE_ALREADY_OPENED
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ */
+ int (*open)(IsoFileSource *src);
+
+ /**
+ * Close a previuously openned file
+ * @return 1 on success, < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_FILE_NOT_OPENED
+ */
+ int (*close)(IsoFileSource *src);
+
+ /**
+ * Attempts to read up to count bytes from the given source into
+ * the buffer starting at buf.
+ *
+ * The file src must be open() before calling this, and close() when no
+ * more needed. Not valid for dirs. On symlinks it reads the destination
+ * file.
+ *
+ * @return
+ * number of bytes read, 0 if EOF, < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_FILE_NOT_OPENED
+ * ISO_WRONG_ARG_VALUE -> if count == 0
+ * ISO_FILE_IS_DIR
+ * ISO_OUT_OF_MEM
+ * ISO_INTERRUPTED
+ */
+ int (*read)(IsoFileSource *src, void *buf, size_t count);
+
+ /**
+ * Read a directory.
+ *
+ * Each call to this function will return a new children, until we reach
+ * the end of file (i.e, no more children), in that case it returns 0.
+ *
+ * The dir must be open() before calling this, and close() when no more
+ * needed. Only valid for dirs.
+ *
+ * Note that "." and ".." children MUST NOT BE returned.
+ *
+ * @param child
+ * pointer to be filled with the given child. Undefined on error or OEF
+ * @return
+ * 1 on success, 0 if EOF (no more children), < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_FILE_NOT_OPENED
+ * ISO_FILE_IS_NOT_DIR
+ * ISO_OUT_OF_MEM
+ */
+ int (*readdir)(IsoFileSource *src, IsoFileSource **child);
+
+ /**
+ * Read the destination of a symlink. You don't need to open the file
+ * to call this.
+ *
+ * @param buf
+ * allocated buffer of at least bufsiz bytes.
+ * The dest. will be copied there, and it will be NULL-terminated
+ * @param bufsiz
+ * characters to be copied. Destination link will be truncated if
+ * it is larger than given size. This include the \0 character.
+ * @return
+ * 1 on success, < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_WRONG_ARG_VALUE -> if bufsiz <= 0
+ * ISO_FILE_IS_NOT_SYMLINK
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ *
+ */
+ int (*readlink)(IsoFileSource *src, char *buf, size_t bufsiz);
+
+ /**
+ * Get the filesystem for this source. No extra ref is added, so you
+ * musn't unref the IsoFilesystem.
+ *
+ * @return
+ * The filesystem, NULL on error
+ */
+ IsoFilesystem* (*get_filesystem)(IsoFileSource *src);
+
+ /**
+ * Free implementation specific data. Should never be called by user.
+ * Use iso_file_source_unref() instead.
+ */
+ void (*free)(IsoFileSource *src);
+
+ /*
+ * TODO #00004 Add a get_mime_type() function.
+ * This can be useful for GUI apps, to choose the icon of the file
+ */
+};
+
+/**
+ * An IsoFile Source is a POSIX abstraction of a file.
+ *
+ * @since 0.6.2
+ */
+struct iso_file_source
+{
+ const IsoFileSourceIface *class;
+ int refcount;
+ void *data;
+};
+
+/**
+ * Representation of file contents. It is an stream of bytes, functionally
+ * like a pipe.
+ *
+ * @since 0.6.4
+ */
+typedef struct iso_stream IsoStream;
+
+/**
+ * Interface that defines the operations (methods) available for an
+ * IsoStream.
+ *
+ * @see struct IsoStream_Iface
+ * @since 0.6.4
+ */
+typedef struct IsoStream_Iface IsoStreamIface;
+
+/**
+ * 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.
+ *
+ * @see IsoStreamIface->get_id()
+ * @since 0.6.4
+ */
+extern ino_t serial_id;
+
+/**
+ * Interface definition for IsoStream methods.
+ *
+ * @since 0.6.4
+ */
+struct IsoStream_Iface
+{
+ /* reserved for future usage, set to 0 */
+ int version;
+
+ /**
+ * Type of Stream.
+ * "fsrc" -> Read from file source
+ * "mem " -> Read from memory
+ * "boot" -> Boot catalog
+ * "user" -> User supplied stream
+ */
+ char type[4];
+
+ /**
+ * 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 IsoStream 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);
+
+ /**
+ * Free implementation specific data. Should never be called by user.
+ * Use iso_stream_unref() instead.
+ */
+ void (*free)(IsoStream *stream);
+};
+
+/**
+ * Representation of file contents as a stream of bytes.
+ *
+ * @since 0.6.4
+ */
+struct iso_stream
+{
+ IsoStreamIface *class;
+ int refcount;
+ void *data;
+};
+
+/**
+ * Initialize libisofs. You must call this before any usage of the library.
+ * @return 1 on success, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_init();
+
+/**
+ * Finalize libisofs.
+ *
+ * @since 0.6.2
+ */
+void iso_finish();
+
+/**
+ * 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
+ *
+ * @since 0.6.2
+ */
+int iso_image_new(const char *name, IsoImage **image);
+
+
+/**
+ * The following two functions three macros are utilities to help ensuring
+ * version match of application, compile time header, and runtime library.
+ */
+/**
+ * Get version of the libisofs library at runtime.
+ *
+ * @since 0.6.2
+ */
+void iso_lib_version(int *major, int *minor, int *micro);
+
+/**
+ * Check at runtime if the library is ABI compatible with the given version.
+ *
+ * @return
+ * 1 lib is compatible, 0 is not.
+ *
+ * @since 0.6.2
+ */
+int iso_lib_is_compatible(int major, int minor, int micro);
+
+
+/**
+ * These three release version numbers tell the revision of this header file
+ * and of the API it describes. They are memorized by applications at
+ * compile time.
+ * They must show the same values as these symbols in ./configure.ac
+ * LIBISOFS_MAJOR_VERSION=...
+ * LIBISOFS_MINOR_VERSION=...
+ * LIBISOFS_MICRO_VERSION=...
+ * Note to anybody who does own work inside libisofs:
+ * Any change of configure.ac or libisofs.h has to keep up this equality !
+ *
+ * Before usage of these macros on your code, please read the usage discussion
+ * below.
+ *
+ * @since 0.6.2
+ */
+#define iso_lib_header_version_major 0
+#define iso_lib_header_version_minor 6
+#define iso_lib_header_version_micro 3
+
+/**
+ * Usage discussion:
+ *
+ * Some developers of the libburnia project have differing opinions how to
+ * ensure the compatibility of libaries and applications.
+ *
+ * It is about whether to use at compile time and at runtime the version
+ * numbers provided here. Thomas Schmitt advises to use them. Vreixo Formoso
+ * advises to use other means.
+ *
+ * At compile time:
+ *
+ * Vreixo Formoso advises to leave proper version matching to properly
+ * programmed checks in the the application's build system, which will
+ * eventually refuse compilation.
+ *
+ * Thomas Schmitt advises to use the macros defined here for comparison with
+ * the application's requirements of library revisions and to eventually
+ * break compilation.
+ *
+ * Both advises are combinable. I.e. be master of your build system and have
+ * #if checks in the source code of your application, nevertheless.
+ *
+ * At runtime (via iso_lib_is_compatible()):
+ *
+ * Vreixo Formoso advises to compare the application's requirements of
+ * library revisions with the runtime library. This is to allow runtime
+ * libraries which are young enough for the application but too old for
+ * the lib*.h files seen at compile time.
+ *
+ * Thomas Schmitt advises to compare the header revisions defined here with
+ * the runtime library. This is to enforce a strictly monotonous chain of
+ * revisions from app to header to library, at the cost of excluding some older
+ * libraries.
+ *
+ * These two advises are mutually exclusive.
+ */
+
+
+/**
+ * Creates an IsoWriteOpts for writing an image. You should set the options
+ * desired with the correspondent setters.
+ *
+ * Options by default are determined by the selected profile. Fifo size is set
+ * by default to 2 MB.
+ *
+ * @param opts
+ * Pointer to the location where the newly created IsoWriteOpts will be
+ * stored. You should free it with iso_write_opts_free() when no more
+ * needed.
+ * @param profile
+ * Default profile for image creation. For now the following values are
+ * defined:
+ * ---> 0 [BASIC]
+ * No extensions are enabled, and ISO level is set to 1. Only suitable
+ * for usage for very old and limited systems (like MS-DOS), or by a
+ * start point from which to set your custom options.
+ * ---> 1 [BACKUP]
+ * POSIX compatibility for backup. Simple settings, ISO level is set to
+ * 2 and RR extensions are enabled. Useful for backup purposes.
+ * ---> 2 [DISTRIBUTION]
+ * Setting for information distribution. Both RR and Joliet are enabled
+ * to maximize compatibility with most systems. Permissions are set to
+ * default values, and timestamps to the time of recording.
+ * @return
+ * 1 success, < 0 error
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_new(IsoWriteOpts **opts, int profile);
+
+/**
+ * Free an IsoWriteOpts previously allocated with iso_write_opts_new().
+ *
+ * @since 0.6.2
+ */
+void iso_write_opts_free(IsoWriteOpts *opts);
+
+/**
+ * Set the ISO-9960 level to write at.
+ *
+ * @param level
+ * -> 1 for higher compatibility with old systems. With this level
+ * filenames are restricted to 8.3 characters.
+ * -> 2 to allow up to 31 filename characters.
+ * @return
+ * 1 success, < 0 error
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_iso_level(IsoWriteOpts *opts, int level);
+
+/**
+ * Whether to use or not Rock Ridge extensions.
+ *
+ * This are standard extensions to ECMA-119, intended to add POSIX filesystem
+ * features to ECMA-119 images. Thus, usage of this flag is highly recommended
+ * for images used on GNU/Linux systems. With the usage of RR extension, the
+ * resulting image will have long filenames (up to 255 characters), deeper
+ * directory structure, POSIX permissions and owner info on files and
+ * directories, support for symbolic links or special files... All that
+ * attributes can be modified/setted with the appropiate function.
+ *
+ * @param enable
+ * 1 to enable RR extension, 0 to not add them
+ * @return
+ * 1 success, < 0 error
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_rockridge(IsoWriteOpts *opts, int enable);
+
+/**
+ * Whether to add the non-standard Joliet extension to the image.
+ *
+ * This extensions are heavily used in Microsoft Windows systems, so if you
+ * plan to use your disc on such a system you should add this extension.
+ * Usage of Joliet supplies longer filesystem length (up to 64 unicode
+ * characters), and deeper directory structure.
+ *
+ * @param enable
+ * 1 to enable Joliet extension, 0 to not add them
+ * @return
+ * 1 success, < 0 error
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_joliet(IsoWriteOpts *opts, int enable);
+
+/**
+ * Whether to use newer ISO-9660:1999 version.
+ *
+ * This is the second version of ISO-9660. It allows longer filenames and has
+ * less restrictions than old ISO-9660. However, nobody is using it so there
+ * are no much reasons to enable this.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_iso1999(IsoWriteOpts *opts, int enable);
+
+/**
+ * Omit the version number (";1") at the end of the ISO-9660 identifiers.
+ * This breaks ECMA-119 specification, but version numbers are usually not
+ * used, so it should work on most systems. Use with caution.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_omit_version_numbers(IsoWriteOpts *opts, int omit);
+
+/**
+ * Allow ISO-9660 directory hierarchy to be deeper than 8 levels.
+ * This breaks ECMA-119 specification. Use with caution.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_allow_deep_paths(IsoWriteOpts *opts, int allow);
+
+/**
+ * Allow path in the ISO-9660 tree to have more than 255 characters.
+ * This breaks ECMA-119 specification. Use with caution.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_allow_longer_paths(IsoWriteOpts *opts, int allow);
+
+/**
+ * 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.
+ * This breaks ECMA-119 specification and could lead to buffer overflow
+ * problems on old systems. Use with caution.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_max_37_char_filenames(IsoWriteOpts *opts, int allow);
+
+/**
+ * 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.
+ * This breaks ECMA-119 specification. Use with caution.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_no_force_dots(IsoWriteOpts *opts, int no);
+
+/**
+ * Allow lowercase characters in ISO-9660 filenames. By default, only
+ * uppercase characters, numbers and a few other characters are allowed.
+ * This breaks ECMA-119 specification. Use with caution.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_allow_lowercase(IsoWriteOpts *opts, int allow);
+
+/**
+ * Allow all ASCII characters to be appear on an ISO-9660 filename. Note
+ * that "/" and "\0" characters are never allowed, even in RR names.
+ * This breaks ECMA-119 specification. Use with caution.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_allow_full_ascii(IsoWriteOpts *opts, int allow);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_relaxed_vol_atts(IsoWriteOpts *opts, int allow);
+
+/**
+ * Allow paths in the Joliet tree to have more than 240 characters.
+ * This breaks Joliet specification. Use with caution.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_joliet_longer_paths(IsoWriteOpts *opts, int allow);
+
+/**
+ * Whether to sort files based on their weight.
+ *
+ * @see iso_node_set_sort_weight
+ * @since 0.6.2
+ */
+int iso_write_opts_set_sort_files(IsoWriteOpts *opts, int sort);
+
+/**
+ * Whether to set 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 by the functioins
+ * below. Note that for mode attributes, only the permissions are set, the
+ * file type remains unchanged.
+ *
+ * @see iso_write_opts_set_default_dir_mode
+ * @see iso_write_opts_set_default_file_mode
+ * @see iso_write_opts_set_default_uid
+ * @see iso_write_opts_set_default_gid
+ * @since 0.6.2
+ */
+int iso_write_opts_set_replace_mode(IsoWriteOpts *opts, int dir_mode,
+ int file_mode, int uid, int gid);
+
+/**
+ * Set the mode to use on dirs when you set the replace_mode of dirs to 2.
+ *
+ * @see iso_write_opts_set_replace_mode
+ * @since 0.6.2
+ */
+int iso_write_opts_set_default_dir_mode(IsoWriteOpts *opts, mode_t dir_mode);
+
+/**
+ * Set the mode to use on files when you set the replace_mode of files to 2.
+ *
+ * @see iso_write_opts_set_replace_mode
+ * @since 0.6.2
+ */
+int iso_write_opts_set_default_file_mode(IsoWriteOpts *opts, mode_t file_mode);
+
+/**
+ * Set the uid to use when you set the replace_uid to 2.
+ *
+ * @see iso_write_opts_set_replace_mode
+ * @since 0.6.2
+ */
+int iso_write_opts_set_default_uid(IsoWriteOpts *opts, uid_t uid);
+
+/**
+ * Set the gid to use when you set the replace_gid to 2.
+ *
+ * @see iso_write_opts_set_replace_mode
+ * @since 0.6.2
+ */
+int iso_write_opts_set_default_gid(IsoWriteOpts *opts, gid_t gid);
+
+/**
+ * 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.
+ *
+ * @see iso_write_opts_set_default_timestamp
+ * @since 0.6.2
+ */
+int iso_write_opts_set_replace_timestamps(IsoWriteOpts *opts, int replace);
+
+/**
+ * Set the timestamp to use when you set the replace_timestamps to 2.
+ *
+ * @see iso_write_opts_set_replace_timestamps
+ * @since 0.6.2
+ */
+int iso_write_opts_set_default_timestamp(IsoWriteOpts *opts, time_t timestamp);
+
+/**
+ * Whether to always record timestamps in GMT.
+ *
+ * By default, libisofs stores local time information on image. You can set
+ * this to always store timestamps in GMT. This is useful if you want to hide
+ * your timezone, or you live in a timezone that can't be represented in
+ * ECMA-119. These are timezones whose offset from GMT is greater than +13
+ * hours, lower than -12 hours, or not a multiple of 15 minutes.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_always_gmt(IsoWriteOpts *opts, int gmt);
+
+/**
+ * Set the charset to use for the RR names of the files that will be created
+ * on the image.
+ * NULL to use default charset, that is the locale charset.
+ * You can obtain the list of charsets supported on your system executing
+ * "iconv -l" in a shell.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_output_charset(IsoWriteOpts *opts, const char *charset);
+
+/**
+ * Set 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.
+ *
+ * @param appendable
+ * 1 to create an appendable image, 0 for an stand-alone one.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_appendable(IsoWriteOpts *opts, int appendable);
+
+/**
+ * Set the 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.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_ms_block(IsoWriteOpts *opts, uint32_t ms_block);
+
+/**
+ * Sets the buffer where to store the descriptors that need to be written
+ * at the beginning of a overwriteable media to grow the image.
+ *
+ * @param overwrite
+ * 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.
+ *
+ * If you don't need this information, for example because you're creating a
+ * new image from scratch of because you will create an image for a true
+ * multisession media, just don't set this buffer or set it to NULL.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_overwrite_buf(IsoWriteOpts *opts, uint8_t *overwrite);
+
+/**
+ * Set the 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. Default value is set to 2MB, if that is ok for you, you
+ * don't need to call this function.
+ *
+ * @since 0.6.2
+ */
+int iso_write_opts_set_fifo_size(IsoWriteOpts *opts, size_t fifo_size);
+
+/**
+ * Create a burn_source to actually write the image. That burn_source can be
+ * used with libburn as a data source for a track.
+ *
+ * @param image
+ * The image to write.
+ * @param opts
+ * The options for image generation. All needed data will be copied, so
+ * you can free the given struct once this function returns.
+ * @param burn_src
+ * Location where the pointer to the burn_source will be stored
+ * @return
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_image_create_burn_source(IsoImage *image, IsoWriteOpts *opts,
+ struct burn_source **burn_src);
+
+/**
+ * Creates an IsoReadOpts for reading an existent image. You should set the
+ * options desired with the correspondent setters. Note that you may want to
+ * set the start block value.
+ *
+ * Options by default are determined by the selected profile.
+ *
+ * @param opts
+ * Pointer to the location where the newly created IsoReadOpts will be
+ * stored. You should free it with iso_read_opts_free() when no more
+ * needed.
+ * @param profile
+ * Default profile for image reading. For now the following values are
+ * defined:
+ * ---> 0 [STANDARD]
+ * Suitable for most situations. All extension are read. When both
+ * Joliet and RR extension are present, RR is used.
+ * @return
+ * 1 success, < 0 error
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_new(IsoReadOpts **opts, int profile);
+
+/**
+ * Free an IsoReadOpts previously allocated with iso_read_opts_new().
+ *
+ * @since 0.6.2
+ */
+void iso_read_opts_free(IsoReadOpts *opts);
+
+/**
+ * Set the block where the image begins. It is usually 0, but may be different
+ * on a multisession disc.
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_start_block(IsoReadOpts *opts, uint32_t block);
+
+/**
+ * Do not read Rock Ridge extensions.
+ * In most cases you don't want to use this. It could be useful if RR info
+ * is damaged, or if you want to use the Joliet tree.
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_no_rockridge(IsoReadOpts *opts, int norr);
+
+/**
+ * Do not read Joliet extensions.
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_no_joliet(IsoReadOpts *opts, int nojoliet);
+
+/**
+ * Do not read ISO 9660:1999 enhanced tree
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_no_iso1999(IsoReadOpts *opts, int noiso1999);
+
+/**
+ * Whether to prefer Joliet over RR. libisofs usually prefers RR over
+ * Joliet, as it give us much more info about files. So, if both extensions
+ * are present, RR is used. You can set this if you prefer Joliet, but
+ * note that this is not very recommended. This doesn't mean than RR
+ * extensions are not read: if no Joliet is present, libisofs will read
+ * RR tree.
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_preferjoliet(IsoReadOpts *opts, int preferjoliet);
+
+/**
+ * Set default uid for files when RR extensions are not present.
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_default_uid(IsoReadOpts *opts, uid_t uid);
+
+/**
+ * Set default gid for files when RR extensions are not present.
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_default_gid(IsoReadOpts *opts, gid_t gid);
+
+/**
+ * Set default permissions for files when RR extensions are not present.
+ *
+ * @param file_perm
+ * Permissions for files.
+ * @param dir_perm
+ * Permissions for directories.
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_default_permissions(IsoReadOpts *opts, mode_t file_perm,
+ mode_t dir_perm);
+
+/**
+ * Set the input charset of the file names on the image. NULL to use locale
+ * charset. You have to specify a charset if the image filenames are encoded
+ * in a charset different that the local one. This could happen, for example,
+ * if the image was created on a system with different charset.
+ *
+ * @param charset
+ * The charset to use as input charset. You can obtain the list of
+ * charsets supported on your system executing "iconv -l" in a shell.
+ *
+ * @since 0.6.2
+ */
+int iso_read_opts_set_input_charset(IsoReadOpts *opts, const char *charset);
+
+/**
+ * Import a previous session or image, for growing or modify.
+ *
+ * @param image
+ * The image context to which old image will be imported. Note that all
+ * files added to image, and image attributes, will be replaced with the
+ * contents of the old image.
+ * TODO #00025 support for merging old image files
+ * @param src
+ * Data Source from which old image will be read. A extra reference is
+ * added, so you still need to iso_data_source_unref() yours.
+ * @param opts
+ * Options for image import. All needed data will be copied, so you
+ * can free the given struct once this function returns.
+ * @param features
+ * If not NULL, a new IsoReadImageFeatures will be allocated and filled
+ * with the features of the old image. It should be freed with
+ * iso_read_image_features_destroy() when no more needed. You can pass
+ * NULL if you're not interested on them.
+ * @return
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_image_import(IsoImage *image, IsoDataSource *src, IsoReadOpts *opts,
+ IsoReadImageFeatures **features);
+
+/**
+ * Destroy an IsoReadImageFeatures object obtained with iso_image_import.
+ *
+ * @since 0.6.2
+ */
+void iso_read_image_features_destroy(IsoReadImageFeatures *f);
+
+/**
+ * Get the size (in 2048 byte block) of the image, as reported in the PVM.
+ *
+ * @since 0.6.2
+ */
+uint32_t iso_read_image_features_get_size(IsoReadImageFeatures *f);
+
+/**
+ * Whether RockRidge extensions are present in the image imported.
+ *
+ * @since 0.6.2
+ */
+int iso_read_image_features_has_rockridge(IsoReadImageFeatures *f);
+
+/**
+ * Whether Joliet extensions are present in the image imported.
+ *
+ * @since 0.6.2
+ */
+int iso_read_image_features_has_joliet(IsoReadImageFeatures *f);
+
+/**
+ * Whether the image is recorded according to ISO 9660:1999, i.e. it has
+ * a version 2 Enhanced Volume Descriptor.
+ *
+ * @since 0.6.2
+ */
+int iso_read_image_features_has_iso1999(IsoReadImageFeatures *f);
+
+/**
+ * Whether El-Torito boot record is present present in the image imported.
+ *
+ * @since 0.6.2
+ */
+int iso_read_image_features_has_eltorito(IsoReadImageFeatures *f);
+
+/**
+ * Increments the reference counting of the given image.
+ *
+ * @since 0.6.2
+ */
+void iso_image_ref(IsoImage *image);
+
+/**
+ * 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).
+ *
+ * @since 0.6.2
+ */
+void iso_image_unref(IsoImage *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 freed. It can be NULL if you don't need it.
+ * @return
+ * 1 on succes, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*));
+
+/**
+ * The the data previously attached with iso_image_attach_data()
+ *
+ * @since 0.6.2
+ */
+void *iso_image_get_attached_data(IsoImage *image);
+
+/**
+ * Get the root directory of the image.
+ * No extra ref is added to it, so you musn't unref it. Use iso_node_ref()
+ * if you want to get your own reference.
+ *
+ * @since 0.6.2
+ */
+IsoDir *iso_image_get_root(const IsoImage *image);
+
+/**
+ * Fill in the volset identifier for a image.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_volset_id(IsoImage *image, const char *volset_id);
+
+/**
+ * Get the volset identifier.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_volset_id(const IsoImage *image);
+
+/**
+ * Fill in the volume identifier for a image.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_volume_id(IsoImage *image, const char *volume_id);
+
+/**
+ * Get the volume identifier.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_volume_id(const IsoImage *image);
+
+/**
+ * Fill in the publisher for a image.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_publisher_id(IsoImage *image, const char *publisher_id);
+
+/**
+ * Get the publisher of a image.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_publisher_id(const IsoImage *image);
+
+/**
+ * Fill in the data preparer for a image.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_data_preparer_id(IsoImage *image,
+ const char *data_preparer_id);
+
+/**
+ * Get the data preparer of a image.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_data_preparer_id(const IsoImage *image);
+
+/**
+ * Fill in the system id for a image. Up to 32 characters.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_system_id(IsoImage *image, const char *system_id);
+
+/**
+ * Get the system id of a image.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_system_id(const IsoImage *image);
+
+/**
+ * Fill in the application id for a image. Up to 128 chars.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_application_id(IsoImage *image, const char *application_id);
+
+/**
+ * Get the application id of a image.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_application_id(const IsoImage *image);
+
+/**
+ * Fill copyright information for the image. Usually this refers
+ * to a file on disc. Up to 37 characters.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_copyright_file_id(IsoImage *image,
+ const char *copyright_file_id);
+
+/**
+ * Get the copyright information of a image.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_copyright_file_id(const IsoImage *image);
+
+/**
+ * Fill abstract information for the image. Usually this refers
+ * to a file on disc. Up to 37 characters.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_abstract_file_id(IsoImage *image,
+ const char *abstract_file_id);
+
+/**
+ * Get the abstract information of a image.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_abstract_file_id(const IsoImage *image);
+
+/**
+ * Fill biblio information for the image. Usually this refers
+ * to a file on disc. Up to 37 characters.
+ *
+ * @since 0.6.2
+ */
+void iso_image_set_biblio_file_id(IsoImage *image, const char *biblio_file_id);
+
+/**
+ * Get the biblio information of a image.
+ * The returned string is owned by the image and should not be freed nor
+ * changed.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_get_biblio_file_id(const IsoImage *image);
+
+/**
+ * Create a bootable image by adding a El-Torito boot image.
+ *
+ * This also add a catalog boot node to the image filesystem tree.
+ *
+ * @param image
+ * The image to make bootable. If it was already bootable this function
+ * returns an error and the image remains unmodified.
+ * @param image_path
+ * The path on the image tree of a regular file to use as default boot
+ * image.
+ * @param type
+ * The boot media type. This can be one of 3 types:
+ * - Floppy emulation: Boot image file must be exactly
+ * 1200 kB, 1440 kB or 2880 kB.
+ * - Hard disc emulation: The image must begin with a master
+ * boot record with a single image.
+ * - No emulation. You should specify load segment and load size
+ * of image.
+ * @param catalog_path
+ * The path on the image tree where the catalog will be stored. The
+ * directory component of this path must be a directory existent on the
+ * image tree, and the filename component must be unique among all
+ * children of that directory on image. Otherwise a correspodent error
+ * code will be returned. This function will add an IsoBoot node that acts
+ * as a placeholder for the real catalog, that will be generated at image
+ * creation time.
+ * @param boot
+ * Location where a pointer to the added boot image will be stored. 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(). A NULL value is allowed if you don't need a
+ * reference to the boot image.
+ * @return
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_image_set_boot_image(IsoImage *image, const char *image_path,
+ enum eltorito_boot_media_type type,
+ const char *catalog_path,
+ ElToritoBootImage **boot);
+
+/* TODO #00026 : add support for "hidden" bootable images. */
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+int iso_image_get_boot_image(IsoImage *image, ElToritoBootImage **boot,
+ IsoFile **imgnode, IsoBoot **catnode);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+void iso_image_remove_boot_image(IsoImage *image);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+void el_torito_set_load_seg(ElToritoBootImage *bootimg, short 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.
+ *
+ * @since 0.6.2
+ */
+void el_torito_set_load_size(ElToritoBootImage *bootimg, short sectors);
+
+/**
+ * Marks the specified boot image as not bootable
+ *
+ * @since 0.6.2
+ */
+void el_torito_set_no_bootable(ElToritoBootImage *bootimg);
+
+/**
+ * Specifies that this image needs to be patched. This involves the writting
+ * of a 56 bytes boot information table at offset 8 of the boot image file.
+ * The original boot image file won't be modified.
+ * This is needed for isolinux boot images.
+ *
+ * @since 0.6.2
+ */
+void el_torito_patch_isolinux_image(ElToritoBootImage *bootimg);
+
+/**
+ * Increments the reference counting of the given node.
+ *
+ * @since 0.6.2
+ */
+void iso_node_ref(IsoNode *node);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+void iso_node_unref(IsoNode *node);
+
+/**
+ * Get the type of an IsoNode.
+ *
+ * @since 0.6.2
+ */
+enum IsoNodeType iso_node_get_type(IsoNode *node);
+
+/**
+ * Set the name of a node. Note that if the node is already added to a dir
+ * this can fail if dir already contains a node with the new name.
+ *
+ * @param node
+ * The node whose name you want to change. Note that you can't change
+ * the name of the root.
+ * @param name
+ * The name for the node. If you supply an empty string or a
+ * name greater than 255 characters this returns with failure, and
+ * node name is not modified.
+ * @return
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_node_set_name(IsoNode *node, const char *name);
+
+/**
+ * Get the name 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.
+ *
+ * @since 0.6.2
+ */
+const char *iso_node_get_name(const IsoNode *node);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+void iso_node_set_permissions(IsoNode *node, mode_t mode);
+
+/**
+ * Get the permissions for the node
+ *
+ * @since 0.6.2
+ */
+mode_t iso_node_get_permissions(const IsoNode *node);
+
+/**
+ * Get the mode of the node, both permissions and file type, as specified in
+ * 'man 2 stat'.
+ *
+ * @since 0.6.2
+ */
+mode_t iso_node_get_mode(const IsoNode *node);
+
+/**
+ * Set the user id for the node. This attribute is only useful when
+ * Rock Ridge extensions are enabled.
+ *
+ * @since 0.6.2
+ */
+void iso_node_set_uid(IsoNode *node, uid_t uid);
+
+/**
+ * Get the user id of the node.
+ *
+ * @since 0.6.2
+ */
+uid_t iso_node_get_uid(const IsoNode *node);
+
+/**
+ * Set the group id for the node. This attribute is only useful when
+ * Rock Ridge extensions are enabled.
+ *
+ * @since 0.6.2
+ */
+void iso_node_set_gid(IsoNode *node, gid_t gid);
+
+/**
+ * Get the group id of the node.
+ *
+ * @since 0.6.2
+ */
+gid_t iso_node_get_gid(const IsoNode *node);
+
+/**
+ * Set the time of last modification of the file
+ *
+ * @since 0.6.2
+ */
+void iso_node_set_mtime(IsoNode *node, time_t time);
+
+/**
+ * Get the time of last modification of the file
+ *
+ * @since 0.6.2
+ */
+time_t iso_node_get_mtime(const IsoNode *node);
+
+/**
+ * Set the time of last access to the file
+ *
+ * @since 0.6.2
+ */
+void iso_node_set_atime(IsoNode *node, time_t time);
+
+/**
+ * Get the time of last access to the file
+ *
+ * @since 0.6.2
+ */
+time_t iso_node_get_atime(const IsoNode *node);
+
+/**
+ * Set the time of last status change of the file
+ *
+ * @since 0.6.2
+ */
+void iso_node_set_ctime(IsoNode *node, time_t time);
+
+/**
+ * Get the time of last status change of the file
+ *
+ * @since 0.6.2
+ */
+time_t iso_node_get_ctime(const IsoNode *node);
+
+/**
+ * Set if the node will be hidden in RR/ISO tree, Joliet tree or both.
+ *
+ * If the file is setted as hidden in one tree, it won't be included there, so
+ * it won't be visible in a OS accessing CD using that tree. For example,
+ * GNU/Linux systems access to Rock Ridge / ISO9960 tree in order to see
+ * what is recorded on CD, while MS Windows make use of the Joliet tree. If a
+ * file is hidden only in Joliet, it won't be visible in Windows systems,
+ * while still visible in Linux.
+ *
+ * If a file is hidden in both trees, it won't be written to image.
+ *
+ * @param node
+ * The node that is to be hidden.
+ * @param hide_attrs
+ * IsoHideNodeFlag's to set the trees in which file will be hidden.
+ *
+ * @since 0.6.2
+ */
+void iso_node_set_hidden(IsoNode *node, int 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
+ * Possible errors:
+ * ISO_NULL_POINTER, if dir or child are NULL
+ * ISO_NODE_ALREADY_ADDED, if child is already added to other dir
+ * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
+ * ISO_WRONG_ARG_VALUE, if child == dir, or replace != (0,1)
+ *
+ * @since 0.6.2
+ */
+int iso_dir_add_node(IsoDir *dir, IsoNode *child,
+ enum iso_replace_mode replace);
+
+/**
+ * Locate a node inside a given dir.
+ *
+ * @param dir
+ * The dir where to look for the node.
+ * @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
+ *
+ * @since 0.6.2
+ */
+int iso_dir_get_node(IsoDir *dir, const char *name, IsoNode **node);
+
+/**
+ * Get the number of children of a directory.
+ *
+ * @return
+ * >= 0 number of items, < 0 error
+ * Possible errors:
+ * ISO_NULL_POINTER, if dir is NULL
+ *
+ * @since 0.6.2
+ */
+int iso_dir_get_children_count(IsoDir *dir);
+
+/**
+ * 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
+ * Possible errors:
+ * ISO_NULL_POINTER, if node is NULL
+ * ISO_NODE_NOT_ADDED_TO_DIR, if node doesn't belong to a dir
+ *
+ * @since 0.6.2
+ */
+int iso_node_take(IsoNode *node);
+
+/**
+ * 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
+ *
+ * @since 0.6.2
+ */
+int iso_node_remove(IsoNode *node);
+
+/*
+ * 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).
+ *
+ * @since 0.6.2
+ */
+IsoDir *iso_node_get_parent(IsoNode *node);
+
+/**
+ * Get an iterator for the children of the given dir.
+ *
+ * You can iterate over the children with iso_dir_iter_next. When finished,
+ * you should free the iterator with iso_dir_iter_free.
+ * You musn't delete a child of the same dir, using iso_node_take() or
+ * iso_node_remove(), while you're using the iterator. You can use
+ * iso_dir_iter_take() or iso_dir_iter_remove() instead.
+ *
+ * You can use the iterator in the way like this
+ *
+ * IsoDirIter *iter;
+ * IsoNode *node;
+ * if ( iso_dir_get_children(dir, &iter) != 1 ) {
+ * // handle error
+ * }
+ * while ( iso_dir_iter_next(iter, &node) == 1 ) {
+ * // do something with the child
+ * }
+ * iso_dir_iter_free(iter);
+ *
+ * An iterator is intended to be used in a single iteration over the
+ * children of a dir. Thus, it should be treated as a temporary object,
+ * and free as soon as possible.
+ *
+ * @return
+ * 1 success, < 0 error
+ * Possible errors:
+ * ISO_NULL_POINTER, if dir or iter are NULL
+ * ISO_OUT_OF_MEM
+ *
+ * @since 0.6.2
+ */
+int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter);
+
+/**
+ * Get the next child.
+ * Take care that the node is owned by its parent, and will be unref() when
+ * the parent is freed. If you want your own ref to it, call iso_node_ref()
+ * on it.
+ *
+ * @return
+ * 1 success, 0 if dir has no more elements, < 0 error
+ * Possible errors:
+ * ISO_NULL_POINTER, if node or iter are NULL
+ * ISO_ERROR, on wrong iter usage, usual caused by modiying the
+ * dir during iteration
+ *
+ * @since 0.6.2
+ */
+int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node);
+
+/**
+ * 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
+ *
+ * @since 0.6.2
+ */
+int iso_dir_iter_has_next(IsoDirIter *iter);
+
+/**
+ * Free a dir iterator.
+ *
+ * @since 0.6.2
+ */
+void iso_dir_iter_free(IsoDirIter *iter);
+
+/**
+ * Removes a child from a directory during an iteration, without freeing it.
+ * It's like iso_node_take(), but to be used during a directory iteration.
+ * The node removed will be the last returned by the iteration.
+ *
+ * The behavior on two call to this function without calling iso_dir_iter_next
+ * between then is undefined, and should never occur. (TODO protect against this?)
+ *
+ * @return
+ * 1 on succes, < 0 error
+ * Possible errors:
+ * ISO_NULL_POINTER, if iter is NULL
+ * ISO_ERROR, on wrong iter usage, for example by call this before
+ * iso_dir_iter_next.
+ *
+ * @since 0.6.2
+ */
+int iso_dir_iter_take(IsoDirIter *iter);
+
+/**
+ * Removes a child from a directory during an iteration and unref() it.
+ * It's like iso_node_remove(), but to be used during a directory iteration.
+ * The node removed will be the last returned by the iteration.
+ *
+ * The behavior on two call to this function without calling iso_tree_iter_next
+ * between then is undefined, and should never occur. (TODO protect against this?)
+ *
+ * @return
+ * 1 on succes, < 0 error
+ * Possible errors:
+ * ISO_NULL_POINTER, if iter is NULL
+ * ISO_ERROR, on wrong iter usage, for example by call this before
+ * iso_dir_iter_next.
+ *
+ * @since 0.6.2
+ */
+int iso_dir_iter_remove(IsoDirIter *iter);
+
+
+/**
+ * @since 0.6.4
+ */
+typedef struct iso_find_condition IsoFindCondition;
+
+/**
+ * Create a new condition that checks if the node name matches the given
+ * wildcard.
+ *
+ * @param wildcard
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_name(const char *wildcard);
+
+/**
+ * Create a new condition that checks the node mode against a mode mask. It
+ * can be used to check both file type and permissions.
+ *
+ * For example:
+ *
+ * iso_new_find_conditions_mode(S_IFREG) : search for regular files
+ * iso_new_find_conditions_mode(S_IFCHR | S_IWUSR) : search for character
+ * devices where owner has write permissions.
+ *
+ * @param mask
+ * Mode mask to AND against node mode.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_mode(mode_t mask);
+
+/**
+ * Create a new condition that checks the node gid.
+ *
+ * @param gid
+ * Desired Group Id.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_gid(gid_t gid);
+
+/**
+ * Create a new condition that checks the node uid.
+ *
+ * @param uid
+ * Desired User Id.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_uid(uid_t uid);
+
+/**
+ * Possible comparison between IsoNode and given conditions.
+ *
+ * @since 0.6.4
+ */
+enum iso_find_comparisons {
+ ISO_FIND_COND_GREATER,
+ ISO_FIND_COND_GREATER_OR_EQUAL,
+ ISO_FIND_COND_EQUAL,
+ ISO_FIND_COND_LESS,
+ ISO_FIND_COND_LESS_OR_EQUAL
+};
+
+/**
+ * Create a new condition that checks the time of last access.
+ *
+ * @param time
+ * Time to compare against IsoNode atime.
+ * @param comparison
+ * Comparison to be done between IsoNode atime and submitted time.
+ * Note that ISO_FIND_COND_GREATER, for example, is true if the node
+ * time is greater than the submitted time.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_atime(time_t time,
+ enum iso_find_comparisons comparison);
+
+/**
+ * Create a new condition that checks the time of last modification.
+ *
+ * @param time
+ * Time to compare against IsoNode mtime.
+ * @param comparison
+ * Comparison to be done between IsoNode mtime and submitted time.
+ * Note that ISO_FIND_COND_GREATER, for example, is true if the node
+ * time is greater than the submitted time.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_mtime(time_t time,
+ enum iso_find_comparisons comparison);
+
+/**
+ * Create a new condition that checks the time of last status change.
+ *
+ * @param time
+ * Time to compare against IsoNode ctime.
+ * @param comparison
+ * Comparison to be done between IsoNode ctime and submitted time.
+ * Note that ISO_FIND_COND_GREATER, for example, is true if the node
+ * time is greater than the submitted time.
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_ctime(time_t time,
+ enum iso_find_comparisons comparison);
+
+/**
+ * Create a new condition that check if the two given conditions are
+ * valid.
+ *
+ * @param a
+ * @param b
+ * IsoFindCondition to compare
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_and(IsoFindCondition *a,
+ IsoFindCondition *b);
+
+/**
+ * Create a new condition that check if at least one the two given conditions
+ * is valid.
+ *
+ * @param a
+ * @param b
+ * IsoFindCondition to compare
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_or(IsoFindCondition *a,
+ IsoFindCondition *b);
+
+/**
+ * Create a new condition that check if the given conditions is false.
+ *
+ * @param negate
+ * @result
+ * The created IsoFindCondition, NULL on error.
+ *
+ * @since 0.6.4
+ */
+IsoFindCondition *iso_new_find_conditions_not(IsoFindCondition *negate);
+
+/**
+ * Find all directory children that match the given condition.
+ *
+ * @param dir
+ * Directory where we will search children.
+ * @param cond
+ * Condition that the children must match in order to be returned.
+ * It will be free together with the iterator. Remember to delete it
+ * if this function return error.
+ * @param iter
+ * Iterator that returns only the children that match condition.
+ * @return
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.4
+ */
+int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond,
+ IsoDirIter **iter);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+const char *iso_symlink_get_dest(const IsoSymlink *link);
+
+/**
+ * Set the destination of a link.
+ *
+ * @param dest
+ * New destination for the link. It must be a non-empty string, otherwise
+ * this function doesn't modify previous destination.
+ * @return
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_symlink_set_dest(IsoSymlink *link, const char *dest);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+void iso_node_set_sort_weight(IsoNode *node, int w);
+
+/**
+ * Get the sort weight of a file.
+ *
+ * @since 0.6.2
+ */
+int iso_file_get_sort_weight(IsoFile *file);
+
+/**
+ * Get the size of the file, in bytes
+ *
+ * @since 0.6.2
+ */
+off_t iso_file_get_size(IsoFile *file);
+
+/**
+ * Get the IsoStream that represents the contents of the given IsoFile.
+ *
+ * If you open() the stream, it should be close() before image generation.
+ *
+ * @return
+ * The IsoStream. No extra ref is added, so the IsoStream belong to the
+ * IsoFile, and it may be freed together with it. Add your own ref with
+ * iso_stream_ref() if you need it.
+ *
+ * @since 0.6.4
+ */
+IsoStream *iso_file_get_stream(IsoFile *file);
+
+/**
+ * Get the block lba of a file node, if it was imported from an old image.
+ *
+ * @param file
+ * The file
+ * @param lba
+ * Will be filled with the kba
+ * @param flag
+ * Reserved for future usage, submit 0
+ * @return
+ * 1 if lba is valid (file comes from old image), 0 if file was newly
+ * added, i.e. it does not come from an old image, < 0 error
+ *
+ * @since 0.6.4
+ */
+int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag);
+
+/*
+ * Like iso_file_get_old_image_lba(), but take an IsoNode.
+ *
+ * @return
+ * 1 if lba is valid (file comes from old image), 0 if file was newly
+ * added, i.e. it does not come from an old image, 2 node type has no
+ * LBA (no regular file), < 0 error
+ *
+ * @since 0.6.4
+ */
+int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag);
+
+/**
+ * Add a new directory to the iso tree. Permissions, owner and hidden atts
+ * are taken from parent, you can modify them later.
+ *
+ * @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 parent if success, < 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
+ * ISO_OUT_OF_MEM
+ *
+ * @since 0.6.2
+ */
+int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir);
+
+/*
+ TODO #00007 expose Stream and this function:
+ int iso_tree_add_new_file(IsoDir *parent, const char *name, stream, file)
+ */
+
+/**
+ * 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 symlink. 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
+ *
+ * @since 0.6.2
+ */
+int iso_tree_add_new_symlink(IsoDir *parent, const char *name,
+ const char *dest, IsoSymlink **link);
+
+/**
+ * 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_WRONG_ARG_VALUE if you select a incorrect mode
+ * ISO_OUT_OF_MEM
+ *
+ * @since 0.6.2
+ */
+int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
+ dev_t dev, IsoSpecial **special);
+
+/**
+ * Set whether to follow or not symbolic links when added a file from a source
+ * to IsoImage. Default behavior is to not follow symlinks.
+ *
+ * @since 0.6.2
+ */
+void iso_tree_set_follow_symlinks(IsoImage *image, int follow);
+
+/**
+ * Get current setting for follow_symlinks.
+ *
+ * @see iso_tree_set_follow_symlinks
+ * @since 0.6.2
+ */
+int iso_tree_get_follow_symlinks(IsoImage *image);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+void iso_tree_set_ignore_hidden(IsoImage *image, int skip);
+
+/**
+ * Get current setting for ignore_hidden.
+ *
+ * @see iso_tree_set_ignore_hidden
+ * @since 0.6.2
+ */
+int iso_tree_get_ignore_hidden(IsoImage *image);
+
+/**
+ * Set the replace mode, that defines the behavior of libisofs when adding
+ * a node whit the same name that an existent one, during a recursive
+ * directory addition.
+ *
+ * @since 0.6.2
+ */
+void iso_tree_set_replace_mode(IsoImage *image, enum iso_replace_mode mode);
+
+/**
+ * Get current setting for replace_mode.
+ *
+ * @see iso_tree_set_replace_mode
+ * @since 0.6.2
+ */
+enum iso_replace_mode iso_tree_get_replace_mode(IsoImage *image);
+
+/**
+ * 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
+ *
+ * @since 0.6.2
+ */
+void iso_tree_set_ignore_special(IsoImage *image, int skip);
+
+/**
+ * Get current setting for ignore_special.
+ *
+ * @see iso_tree_set_ignore_special
+ * @since 0.6.2
+ */
+int iso_tree_get_ignore_special(IsoImage *image);
+
+/**
+ * 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.
+ *
+ * However, if you explicity add a deeper dir, it won't be excluded. i.e.,
+ * in the following example.
+ *
+ * iso_tree_add_exclude(image, "/home/user/data");
+ * iso_tree_add_dir_rec(image, root, "/home/user/data/private");
+ *
+ * the directory /home/user/data/private is added. On the other, side, and
+ * foollowing the the example above,
+ *
+ * iso_tree_add_dir_rec(image, root, "/home/user");
+ *
+ * will exclude the directory "/home/user/data".
+ *
+ * Absolute paths are not mandatory, you can, for example, add a relative
+ * path such as:
+ *
+ * iso_tree_add_exclude(image, "private");
+ * iso_tree_add_exclude(image, "user/data");
+ *
+ * to excluve, respectively, all files or dirs named private, and also all
+ * files or dirs named data that belong to a folder named "user". Not that the
+ * above rule about deeper dirs is still valid. i.e., if you call
+ *
+ * iso_tree_add_dir_rec(image, root, "/home/user/data/music");
+ *
+ * it is included even containing "user/data" string. However, a possible
+ * "/home/user/data/music/user/data" is not added.
+ *
+ * Usual wildcards, such as * or ? are also supported, with the usual meaning
+ * as stated in "man 7 glob". For example
+ *
+ * // to exclude backup text files
+ * iso_tree_add_exclude(image, "*.~");
+ *
+ * @return
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_tree_add_exclude(IsoImage *image, const char *path);
+
+/**
+ * Remove a previously added exclude.
+ *
+ * @see iso_tree_add_exclude
+ * @return
+ * 1 on success, 0 exclude do not exists, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_tree_remove_exclude(IsoImage *image, const char *path);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+void iso_tree_set_report_callback(IsoImage *image,
+ int (*report)(IsoImage*, IsoFileSource*));
+
+/**
+ * Add a new node to the image tree, from an existing file.
+ *
+ * TODO comment Builder and Filesystem related issues when exposing both
+ *
+ * All attributes will be taken from the source file. The appropriate file
+ * type will be created.
+ *
+ * @param image
+ * The image
+ * @param parent
+ * The directory in the image tree where the node will be added.
+ * @param path
+ * The path of the file to add in the filesystem.
+ * @param node
+ * place where to store a pointer to the newly added 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 image, parent or path are NULL
+ * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
+ * ISO_OUT_OF_MEM
+ *
+ * @since 0.6.2
+ */
+int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
+ IsoNode **node);
+
+/**
+ * Add a new node to the image tree, from an existing file, and with the
+ * given name, that must not exist on dir.
+ *
+ * @param image
+ * The image
+ * @param parent
+ * The directory in the image tree where the node will be added.
+ * @param name
+ * The name that the node will have on image.
+ * @param path
+ * The path of the file to add in the filesystem.
+ * @param node
+ * place where to store a pointer to the newly added 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 image, parent or path are NULL
+ * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
+ * ISO_OUT_OF_MEM
+ *
+ * @since 0.6.4
+ */
+int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
+ const char *path, IsoNode **node);
+
+/**
+ * Add the contents of a dir to a given directory of the iso tree.
+ *
+ * There are several options to control what files are added or how they are
+ * managed. Take a look at iso_tree_set_* functions to see diferent options
+ * for recursive directory addition.
+ *
+ * TODO comment Builder and Filesystem related issues when exposing both
+ *
+ * @param image
+ * The image to which the directory belong.
+ * @param parent
+ * Directory on the image tree where to add the contents of the dir
+ * @param dir
+ * Path to a dir in the filesystem
+ * @return
+ * number of nodes in parent if success, < 0 otherwise
+ *
+ * @since 0.6.2
+ */
+int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir);
+
+/**
+ * Locate a node by its path on image.
+ *
+ * @param node
+ * Location for a pointer to the node, it will filled with NULL if the
+ * given path does not exists on image.
+ * The node will be owned by the image 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 path really exists.
+ * @return
+ * 1 found, 0 not found, < 0 error
+ *
+ * @since 0.6.2
+ */
+int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node);
+
+/**
+ * Increments the reference counting of the given IsoDataSource.
+ *
+ * @since 0.6.2
+ */
+void iso_data_source_ref(IsoDataSource *src);
+
+/**
+ * Decrements the reference counting of the given IsoDataSource, freeing it
+ * if refcount reach 0.
+ *
+ * @since 0.6.2
+ */
+void iso_data_source_unref(IsoDataSource *src);
+
+/**
+ * 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.
+ *
+ * @since 0.6.2
+ */
+int iso_data_source_new_from_file(const char *path, IsoDataSource **src);
+
+/**
+ * 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
+ *
+ * @since 0.6.2
+ */
+int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
+ size_t *free_bytes);
+
+#define ISO_MSGS_MESSAGE_LEN 4096
+
+/**
+ * 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
+ *
+ * @since 0.6.2
+ */
+int iso_set_msgs_severities(char *queue_severity, char *print_severity,
+ char *print_id);
+
+/**
+ * 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 at the end of this header
+ * @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
+ *
+ * @since 0.6.2
+ */
+int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
+ char msg_text[], char severity[]);
+
+
+/**
+ * Submit a message to the libisofs queueing system. It will be queued or
+ * printed as if it was generated by libisofs itself.
+ *
+ * @param error_code
+ * The unique error code of your message.
+ * Submit 0 if you do not have reserved error codes within the libburnia
+ * project.
+ * @param msg_text
+ * Not more than ISO_MSGS_MESSAGE_LEN characters of message text.
+ * @param os_errno
+ * Eventual errno related to the message. Submit 0 if the message is not
+ * related to a operating system error.
+ * @param severity
+ * One of "ABORT", "FATAL", "FAILURE", "SORRY", "WARNING", "HINT", "NOTE",
+ * "UPDATE", "DEBUG". Defaults to "FATAL".
+ * @param origin
+ * Submit 0 for now.
+ * @return
+ * 1 if message was delivered, <=0 if failure
+ *
+ * @since 0.6.4
+ */
+int iso_msgs_submit(int error_code, char msg_text[], int os_errno,
+ char severity[], int origin);
+
+
+/**
+ * Convert a severity name into a severity number, which gives the severity
+ * rank of the name.
+ *
+ * @param severity_name
+ * A name as with iso_msgs_submit(), e.g. "SORRY".
+ * @param severity_number
+ * The rank number: the higher, the more severe.
+ * @return
+ * >0 success, <=0 failure
+ *
+ * @since 0.6.4
+ */
+int iso_text_to_sev(char *severity_name, int *severity_number);
+
+
+/**
+ * Convert a severity number into a severity name
+ *
+ * @param severity_number
+ * The rank number: the higher, the more severe.
+ * @param severity_name
+ * A name as with iso_msgs_submit(), e.g. "SORRY".
+ *
+ * @since 0.6.4
+ */
+int iso_sev_to_text(int severity_number, char **severity_name);
+
+
+/**
+ * Get the id of an IsoImage, used for message reporting. This message id,
+ * retrieved with iso_obtain_msgs(), can be used to distinguish what
+ * IsoImage has isssued a given message.
+ *
+ * @since 0.6.2
+ */
+int iso_image_get_msg_id(IsoImage *image);
+
+/**
+ * Get a textual description of a libisofs error.
+ *
+ * @since 0.6.2
+ */
+const char *iso_error_to_msg(int errcode);
+
+/**
+ * Get the severity of a given error code
+ * @return
+ * 0x10000000 -> DEBUG
+ * 0x20000000 -> UPDATE
+ * 0x30000000 -> NOTE
+ * 0x40000000 -> HINT
+ * 0x50000000 -> WARNING
+ * 0x60000000 -> SORRY
+ * 0x64000000 -> MISHAP
+ * 0x68000000 -> FAILURE
+ * 0x70000000 -> FATAL
+ * 0x71000000 -> ABORT
+ *
+ * @since 0.6.2
+ */
+int iso_error_get_severity(int e);
+
+/**
+ * Get the priority of a given error.
+ * @return
+ * 0x00000000 -> ZERO
+ * 0x10000000 -> LOW
+ * 0x20000000 -> MEDIUM
+ * 0x30000000 -> HIGH
+ *
+ * @since 0.6.2
+ */
+int iso_error_get_priority(int e);
+
+/**
+ * Get the message queue code of a libisofs error.
+ */
+int iso_error_get_code(int e);
+
+/**
+ * Set the minimum error severity that causes a libisofs operation to
+ * be aborted as soon as possible.
+ *
+ * @param severity
+ * one of "FAILURE", "MISHAP", "SORRY", "WARNING", "HINT", "NOTE".
+ * Severities greater or equal than FAILURE always cause program to abort.
+ * Severities under NOTE won't never cause function abort.
+ * @return
+ * Previous abort priority on success, < 0 on error.
+ *
+ * @since 0.6.2
+ */
+int iso_set_abort_severity(char *severity);
+
+/**
+ * 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
+ *
+ * @since 0.6.2
+ */
+void *iso_get_messenger();
+
+/**
+ * Take a ref to the given IsoFileSource.
+ *
+ * @since 0.6.2
+ */
+void iso_file_source_ref(IsoFileSource *src);
+
+/**
+ * Drop your ref to the given IsoFileSource, eventually freeing the associated
+ * system resources.
+ *
+ * @since 0.6.2
+ */
+void iso_file_source_unref(IsoFileSource *src);
+
+/*
+ * this are just helpers to invoque methods in class
+ */
+
+/**
+ * Get the path, relative to the filesystem this file source
+ * belongs to.
+ *
+ * @return
+ * the path of the FileSource inside the filesystem, it should be
+ * freed when no more needed.
+ *
+ * @since 0.6.2
+ */
+char* iso_file_source_get_path(IsoFileSource *src);
+
+/**
+ * Get the name of the file, with the dir component of the path.
+ *
+ * @return
+ * the name of the file, it should be freed when no more needed.
+ *
+ * @since 0.6.2
+ */
+char* iso_file_source_get_name(IsoFileSource *src);
+
+/**
+ * Get information about the file.
+ * @return
+ * 1 success, < 0 error
+ * Error codes:
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ *
+ * @since 0.6.2
+ */
+int iso_file_source_lstat(IsoFileSource *src, struct stat *info);
+
+/**
+ * Check if the process has access to read file contents. Note that this
+ * is not necessarily related with (l)stat functions. For example, in a
+ * filesystem implementation to deal with an ISO image, if the user has
+ * read access to the image it will be able to read all files inside it,
+ * despite of the particular permission of each file in the RR tree, that
+ * are what the above functions return.
+ *
+ * @return
+ * 1 if process has read access, < 0 on error
+ * Error codes:
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ *
+ * @since 0.6.2
+ */
+int iso_file_source_access(IsoFileSource *src);
+
+/**
+ * Get information about the file. If the file is a symlink, the info
+ * returned refers to the destination.
+ *
+ * @return
+ * 1 success, < 0 error
+ * Error codes:
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ *
+ * @since 0.6.2
+ */
+int iso_file_source_stat(IsoFileSource *src, struct stat *info);
+
+/**
+ * Opens the source.
+ * @return 1 on success, < 0 on error
+ * Error codes:
+ * ISO_FILE_ALREADY_OPENED
+ * ISO_FILE_ACCESS_DENIED
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ *
+ * @since 0.6.2
+ */
+int iso_file_source_open(IsoFileSource *src);
+
+/**
+ * Close a previuously openned file
+ * @return 1 on success, < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_FILE_NOT_OPENED
+ *
+ * @since 0.6.2
+ */
+int iso_file_source_close(IsoFileSource *src);
+
+/**
+ * Attempts to read up to count bytes from the given source into
+ * the buffer starting at buf.
+ *
+ * The file src must be open() before calling this, and close() when no
+ * more needed. Not valid for dirs. On symlinks it reads the destination
+ * file.
+ *
+ * @param src
+ * The given source
+ * @param buf
+ * Pointer to a buffer of at least count bytes where the read data will be
+ * stored
+ * @param count
+ * Bytes to read
+ * @return
+ * number of bytes read, 0 if EOF, < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_FILE_NOT_OPENED
+ * ISO_WRONG_ARG_VALUE -> if count == 0
+ * ISO_FILE_IS_DIR
+ * ISO_OUT_OF_MEM
+ * ISO_INTERRUPTED
+ *
+ * @since 0.6.2
+ */
+int iso_file_source_read(IsoFileSource *src, void *buf, size_t count);
+
+/**
+ * Read a directory.
+ *
+ * Each call to this function will return a new children, until we reach
+ * the end of file (i.e, no more children), in that case it returns 0.
+ *
+ * The dir must be open() before calling this, and close() when no more
+ * needed. Only valid for dirs.
+ *
+ * Note that "." and ".." children MUST NOT BE returned.
+ *
+ * @param child
+ * pointer to be filled with the given child. Undefined on error or OEF
+ * @return
+ * 1 on success, 0 if EOF (no more children), < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_FILE_NOT_OPENED
+ * ISO_FILE_IS_NOT_DIR
+ * ISO_OUT_OF_MEM
+ *
+ * @since 0.6.2
+ */
+int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child);
+
+/**
+ * Read the destination of a symlink. You don't need to open the file
+ * to call this.
+ *
+ * @param src
+ * An IsoFileSource corresponding to a symbolic link.
+ * @param buf
+ * allocated buffer of at least bufsiz bytes.
+ * The dest. will be copied there, and it will be NULL-terminated
+ * @param bufsiz
+ * characters to be copied. Destination link will be truncated if
+ * it is larger than given size. This include the '\0' character.
+ * @return
+ * 1 on success, < 0 on error
+ * Error codes:
+ * ISO_FILE_ERROR
+ * ISO_NULL_POINTER
+ * ISO_WRONG_ARG_VALUE -> if bufsiz <= 0
+ * ISO_FILE_IS_NOT_SYMLINK
+ * ISO_OUT_OF_MEM
+ * ISO_FILE_BAD_PATH
+ * ISO_FILE_DOESNT_EXIST
+ *
+ * @since 0.6.2
+ */
+int iso_file_source_readlink(IsoFileSource *src, char *buf, size_t bufsiz);
+
+/**
+ * Get the filesystem for this source. No extra ref is added, so you
+ * musn't unref the IsoFilesystem.
+ *
+ * @return
+ * The filesystem, NULL on error
+ *
+ * @since 0.6.2
+ */
+IsoFilesystem* iso_file_source_get_filesystem(IsoFileSource *src);
+
+/**
+ * Take a ref to the given IsoFilesystem
+ *
+ * @since 0.6.2
+ */
+void iso_filesystem_ref(IsoFilesystem *fs);
+
+/**
+ * Drop your ref to the given IsoFilesystem, evetually freeing associated
+ * resources.
+ *
+ * @since 0.6.2
+ */
+void iso_filesystem_unref(IsoFilesystem *fs);
+
+/**
+ * Create a new IsoFilesystem to access a existent ISO image.
+ *
+ * @param src
+ * Data source to access data.
+ * @param opts
+ * Image read options
+ * @param msgid
+ * An image identifer, obtained with iso_image_get_msg_id(), used to
+ * associated messages issued by the filesystem implementation with an
+ * existent image. If you are not using this filesystem in relation with
+ * any image context, just use 0x1fffff as the value for this parameter.
+ * @param fs
+ * Will be filled with a pointer to the filesystem that can be used
+ * to access image contents.
+ * @param
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.2
+ */
+int iso_image_filesystem_new(IsoDataSource *src, IsoReadOpts *opts, int msgid,
+ IsoImageFilesystem **fs);
+
+/**
+ * Get the volset identifier for an existent image. The returned string belong
+ * to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_volset_id(IsoImageFilesystem *fs);
+
+/**
+ * Get the volume identifier for an existent image. The returned string belong
+ * to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_volume_id(IsoImageFilesystem *fs);
+
+/**
+ * Get the publisher identifier for an existent image. The returned string
+ * belong to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_publisher_id(IsoImageFilesystem *fs);
+
+/**
+ * Get the data preparer identifier for an existent image. The returned string
+ * belong to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_data_preparer_id(IsoImageFilesystem *fs);
+
+/**
+ * Get the system identifier for an existent image. The returned string belong
+ * to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_system_id(IsoImageFilesystem *fs);
+
+/**
+ * Get the application identifier for an existent image. The returned string
+ * belong to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_application_id(IsoImageFilesystem *fs);
+
+/**
+ * Get the copyright file identifier for an existent image. The returned string
+ * belong to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_copyright_file_id(IsoImageFilesystem *fs);
+
+/**
+ * Get the abstract file identifier for an existent image. The returned string
+ * belong to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_abstract_file_id(IsoImageFilesystem *fs);
+
+/**
+ * Get the biblio file identifier for an existent image. The returned string
+ * belong to the IsoImageFilesystem and shouldn't be free() nor modified.
+ *
+ * @since 0.6.2
+ */
+const char *iso_image_fs_get_biblio_file_id(IsoImageFilesystem *fs);
+
+/**
+ * Increment reference count of an IsoStream.
+ *
+ * @since 0.6.4
+ */
+void iso_stream_ref(IsoStream *stream);
+
+/**
+ * Decrement reference count of an IsoStream, and eventually free it if
+ * refcount reach 0.
+ *
+ * @since 0.6.4
+ */
+void iso_stream_unref(IsoStream *stream);
+
+/**
+ * Opens the given stream. Remember to close the Stream before writing the
+ * image.
+ *
+ * @return
+ * 1 on success, 2 file greater than expected, 3 file smaller than
+ * expected, < 0 on error
+ *
+ * @since 0.6.4
+ */
+int iso_stream_open(IsoStream *stream);
+
+/**
+ * Close a previously openned IsoStream.
+ *
+ * @return
+ * 1 on success, < 0 on error
+ *
+ * @since 0.6.4
+ */
+int iso_stream_close(IsoStream *stream);
+
+/**
+ * Get the size of a given stream. This function should always return the same
+ * size, even if the underlying source size changes.
+ *
+ * @return
+ * IsoStream size in bytes
+ *
+ * @since 0.6.4
+ */
+off_t iso_stream_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
+ *
+ * @since 0.6.4
+ */
+int iso_stream_read(IsoStream *stream, void *buf, size_t count);
+
+/**
+ * Whether the given IsoStream 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
+ *
+ * @since 0.6.4
+ */
+int iso_stream_is_repeatable(IsoStream *stream);
+
+/**
+ * Get an unique identifier for a given IsoStream.
+ *
+ * @since 0.6.4
+ */
+void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
+ ino_t *ino_id);
+
+/************ Error codes and return values for libisofs ********************/
+
+/** successfully execution */
+#define ISO_SUCCESS 1
+
+/**
+ * special return value, it could be or not an error depending on the
+ * context.
+ */
+#define ISO_NONE 0
+
+/** Operation canceled (FAILURE,HIGH, -1) */
+#define ISO_CANCELED 0xE830FFFF
+
+/** Unknown or unexpected fatal error (FATAL,HIGH, -2) */
+#define ISO_FATAL_ERROR 0xF030FFFE
+
+/** Unknown or unexpected error (FAILURE,HIGH, -3) */
+#define ISO_ERROR 0xE830FFFD
+
+/** Internal programming error. Please report this bug (FATAL,HIGH, -4) */
+#define ISO_ASSERT_FAILURE 0xF030FFFC
+
+/**
+ * NULL pointer as value for an arg. that doesn't allow NULL (FAILURE,HIGH, -5)
+ */
+#define ISO_NULL_POINTER 0xE830FFFB
+
+/** Memory allocation error (FATAL,HIGH, -6) */
+#define ISO_OUT_OF_MEM 0xF030FFFA
+
+/** Interrupted by a signal (FATAL,HIGH, -7) */
+#define ISO_INTERRUPTED 0xF030FFF9
+
+/** Invalid parameter value (FAILURE,HIGH, -8) */
+#define ISO_WRONG_ARG_VALUE 0xE830FFF8
+
+/** Can't create a needed thread (FATAL,HIGH, -9) */
+#define ISO_THREAD_ERROR 0xF030FFF7
+
+/** Write error (FAILURE,HIGH, -10) */
+#define ISO_WRITE_ERROR 0xE830FFF6
+
+/** Buffer read error (FAILURE,HIGH, -11) */
+#define ISO_BUF_READ_ERROR 0xE830FFF5
+
+/** Trying to add to a dir a node already added to a dir (FAILURE,HIGH, -64) */
+#define ISO_NODE_ALREADY_ADDED 0xE830FFC0
+
+/** Node with same name already exists (FAILURE,HIGH, -65) */
+#define ISO_NODE_NAME_NOT_UNIQUE 0xE830FFBF
+
+/** Trying to remove a node that was not added to dir (FAILURE,HIGH, -65) */
+#define ISO_NODE_NOT_ADDED_TO_DIR 0xE830FFBE
+
+/** A requested node does not exist (FAILURE,HIGH, -66) */
+#define ISO_NODE_DOESNT_EXIST 0xE830FFBD
+
+/**
+ * Try to set the boot image of an already bootable image (FAILURE,HIGH, -67)
+ */
+#define ISO_IMAGE_ALREADY_BOOTABLE 0xE830FFBC
+
+/** Trying to use an invalid file as boot image (FAILURE,HIGH, -68) */
+#define ISO_BOOT_IMAGE_NOT_VALID 0xE830FFBB
+
+/**
+ * Error on file operation (FAILURE,HIGH, -128)
+ * (take a look at more specified error codes below)
+ */
+#define ISO_FILE_ERROR 0xE830FF80
+
+/** Trying to open an already openned file (FAILURE,HIGH, -129) */
+#define ISO_FILE_ALREADY_OPENED 0xE830FF7F
+
+/* @deprecated use ISO_FILE_ALREADY_OPENED instead */
+#define ISO_FILE_ALREADY_OPENNED 0xE830FF7F
+
+/** Access to file is not allowed (FAILURE,HIGH, -130) */
+#define ISO_FILE_ACCESS_DENIED 0xE830FF7E
+
+/** Incorrect path to file (FAILURE,HIGH, -131) */
+#define ISO_FILE_BAD_PATH 0xE830FF7D
+
+/** The file does not exist in the filesystem (FAILURE,HIGH, -132) */
+#define ISO_FILE_DOESNT_EXIST 0xE830FF7C
+
+/** Trying to read or close a file not openned (FAILURE,HIGH, -133) */
+#define ISO_FILE_NOT_OPENED 0xE830FF7B
+
+/* @deprecated use ISO_FILE_NOT_OPENED instead */
+#define ISO_FILE_NOT_OPENNED ISO_FILE_NOT_OPENED
+
+/** Directory used where no dir is expected (FAILURE,HIGH, -134) */
+#define ISO_FILE_IS_DIR 0xE830FF7A
+
+/** Read error (FAILURE,HIGH, -135) */
+#define ISO_FILE_READ_ERROR 0xE830FF79
+
+/** Not dir used where a dir is expected (FAILURE,HIGH, -136) */
+#define ISO_FILE_IS_NOT_DIR 0xE830FF78
+
+/** Not symlink used where a symlink is expected (FAILURE,HIGH, -137) */
+#define ISO_FILE_IS_NOT_SYMLINK 0xE830FF77
+
+/** Can't seek to specified location (FAILURE,HIGH, -138) */
+#define ISO_FILE_SEEK_ERROR 0xE830FF76
+
+/** File not supported in ECMA-119 tree and thus ignored (HINT,MEDIUM, -139) */
+#define ISO_FILE_IGNORED 0xC020FF75
+
+/* A file is bigger than supported by used standard (HINT,MEDIUM, -140) */
+#define ISO_FILE_TOO_BIG 0xC020FF74
+
+/* File read error during image creation (MISHAP,HIGH, -141) */
+#define ISO_FILE_CANT_WRITE 0xE430FF73
+
+/* Can't convert filename to requested charset (HINT,MEDIUM, -142) */
+#define ISO_FILENAME_WRONG_CHARSET 0xC020FF72
+
+/* File can't be added to the tree (SORRY,HIGH, -143) */
+#define ISO_FILE_CANT_ADD 0xE030FF71
+
+/**
+ * File path break specification constraints and will be ignored
+ * (HINT,MEDIUM, -141)
+ */
+#define ISO_FILE_IMGPATH_WRONG 0xC020FF70
+
+/** Charset conversion error (FAILURE,HIGH, -256) */
+#define ISO_CHARSET_CONV_ERROR 0xE830FF00
+
+/**
+ * Too much files to mangle, i.e. we cannot guarantee unique file names
+ * (FAILURE,HIGH, -257)
+ */
+#define ISO_MANGLE_TOO_MUCH_FILES 0xE830FEFF
+
+/* image related errors */
+
+/**
+ * Wrong or damaged Primary Volume Descriptor (FAILURE,HIGH, -320)
+ * This could mean that the file is not a valid ISO image.
+ */
+#define ISO_WRONG_PVD 0xE830FEC0
+
+/** Wrong or damaged RR entry (SORRY,HIGH, -321) */
+#define ISO_WRONG_RR 0xE030FEBF
+
+/** Unsupported RR feature (SORRY,HIGH, -322) */
+#define ISO_UNSUPPORTED_RR 0xE030FEBE
+
+/** Wrong or damaged ECMA-119 (FAILURE,HIGH, -323) */
+#define ISO_WRONG_ECMA119 0xE830FEBD
+
+/** Unsupported ECMA-119 feature (FAILURE,HIGH, -324) */
+#define ISO_UNSUPPORTED_ECMA119 0xE830FEBC
+
+/** Wrong or damaged El-Torito catalog (SORRY,HIGH, -325) */
+#define ISO_WRONG_EL_TORITO 0xE030FEBB
+
+/** Unsupported El-Torito feature (SORRY,HIGH, -326) */
+#define ISO_UNSUPPORTED_EL_TORITO 0xE030FEBA
+
+/** Can't patch an isolinux boot image (SORRY,HIGH, -327) */
+#define ISO_ISOLINUX_CANT_PATCH 0xE030FEB9
+
+/** Unsupported SUSP feature (SORRY,HIGH, -328) */
+#define ISO_UNSUPPORTED_SUSP 0xE030FEB8
+
+/** Error on a RR entry that can be ignored (WARNING,HIGH, -329) */
+#define ISO_WRONG_RR_WARN 0xD030FEB7
+
+/** Error on a RR entry that can be ignored (HINT,MEDIUM, -330) */
+#define ISO_SUSP_UNHANDLED 0xC020FEB6
+
+/** Multiple ER SUSP entries found (WARNING,HIGH, -331) */
+#define ISO_SUSP_MULTIPLE_ER 0xD030FEB5
+
+/** Unsupported volume descriptor found (HINT,MEDIUM, -332) */
+#define ISO_UNSUPPORTED_VD 0xC020FEB4
+
+/** El-Torito related warning (WARNING,HIGH, -333) */
+#define ISO_EL_TORITO_WARN 0xD030FEB3
+
+/** Image write cancelled (MISHAP,HIGH, -334) */
+#define ISO_IMAGE_WRITE_CANCELED 0xE430FEB2
+
+/** El-Torito image is hidden (WARNING,HIGH, -335) */
+#define ISO_EL_TORITO_HIDDEN 0xD030FEB1
+
+#endif /*LIBISO_LIBISOFS_H_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/messages.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/messages.c
new file mode 100644
index 00000000..8b55b45e
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/messages.c
@@ -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
+#include
+#include
+#include
+
+#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_OPENED:
+ return "Trying to open an already opened 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_OPENED:
+ return "Trying to read or close a file not opened";
+ 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 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 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);
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/messages.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/messages.h
new file mode 100644
index 00000000..dc8b98c2
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/messages.h
@@ -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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/node.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/node.c
new file mode 100644
index 00000000..95a0095e
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/node.c
@@ -0,0 +1,1171 @@
+/*
+ * 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
+#include
+#include
+#include
+
+struct dir_iter_data
+{
+ /* points to the last visited child, to NULL before start */
+ IsoNode *pos;
+
+ /* Some control flags.
+ * bit 0 -> 1 if next called, 0 reseted at start or on deletion
+ */
+ int flag;
+};
+
+/**
+ * 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;
+}
+
+static
+int iter_next(IsoDirIter *iter, IsoNode **node)
+{
+ struct dir_iter_data *data;
+ if (iter == NULL || node == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = iter->data;
+
+ /* clear next flag */
+ data->flag &= ~0x01;
+
+ if (data->pos == NULL) {
+ /* we are at the beginning */
+ data->pos = iter->dir->children;
+ if (data->pos == NULL) {
+ /* empty dir */
+ *node = NULL;
+ return 0;
+ }
+ } else {
+ if (data->pos->parent != iter->dir) {
+ /* this can happen if the node has been moved to another dir */
+ /* TODO specific error */
+ return ISO_ERROR;
+ }
+ if (data->pos->next == NULL) {
+ /* no more children */
+ *node = NULL;
+ return 0;
+ } else {
+ /* free reference to current position */
+ iso_node_unref(data->pos); /* it is never last ref!! */
+
+ /* advance a position */
+ data->pos = data->pos->next;
+ }
+ }
+
+ /* ok, take a ref to the current position, to prevent internal errors
+ * if deleted somewhere */
+ iso_node_ref(data->pos);
+ data->flag |= 0x01; /* set next flag */
+
+ /* return pointed node */
+ *node = data->pos;
+ 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
+ */
+static
+int iter_has_next(IsoDirIter *iter)
+{
+ struct dir_iter_data *data;
+ if (iter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = iter->data;
+ if (data->pos == NULL) {
+ return iter->dir->children == NULL ? 0 : 1;
+ } else {
+ return data->pos->next == NULL ? 0 : 1;
+ }
+}
+
+static
+void iter_free(IsoDirIter *iter)
+{
+ struct dir_iter_data *data;
+ data = iter->data;
+ if (data->pos != NULL) {
+ iso_node_unref(data->pos);
+ }
+ free(data);
+}
+
+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_ASSERT_FAILURE;
+ }
+
+ /* notify iterators just before remove */
+ iso_notify_dir_iters(node, 0);
+
+ *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 */
+static
+int iter_take(IsoDirIter *iter)
+{
+ struct dir_iter_data *data;
+ if (iter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ data = iter->data;
+
+ if (!(data->flag & 0x01)) {
+ return ISO_ERROR; /* next not called or end of dir */
+ }
+
+ if (data->pos == NULL) {
+ return ISO_ASSERT_FAILURE;
+ }
+
+ /* clear next flag */
+ data->flag &= ~0x01;
+
+ return iso_node_take(data->pos);
+}
+
+static
+int iter_remove(IsoDirIter *iter)
+{
+ int ret;
+ IsoNode *pos;
+ struct dir_iter_data *data;
+
+ if (iter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ data = iter->data;
+ pos = data->pos;
+
+ ret = iter_take(iter);
+ if (ret == ISO_SUCCESS) {
+ /* remove node */
+ iso_node_unref(pos);
+ }
+ return ret;
+}
+
+void iter_notify_child_taken(IsoDirIter *iter, IsoNode *node)
+{
+ IsoNode *pos, *pre;
+ struct dir_iter_data *data;
+ data = iter->data;
+
+ if (data->pos == node) {
+ pos = iter->dir->children;
+ pre = NULL;
+ while (pos != NULL && pos != data->pos) {
+ pre = pos;
+ pos = pos->next;
+ }
+ if (pos == NULL || pos != data->pos) {
+ return;
+ }
+
+ /* dispose iterator reference */
+ iso_node_unref(data->pos);
+
+ if (pre == NULL) {
+ /* node is a first position */
+ iter->dir->children = pos->next;
+ data->pos = NULL;
+ } else {
+ pre->next = pos->next;
+ data->pos = pre;
+ iso_node_ref(pre); /* take iter ref */
+ }
+ }
+}
+
+static
+struct iso_dir_iter_iface iter_class = {
+ iter_next,
+ iter_has_next,
+ iter_free,
+ iter_take,
+ iter_remove,
+ iter_notify_child_taken
+};
+
+int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter)
+{
+ IsoDirIter *it;
+ struct dir_iter_data *data;
+
+ if (dir == NULL || iter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ it = malloc(sizeof(IsoDirIter));
+ if (it == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ data = malloc(sizeof(struct dir_iter_data));
+ if (data == NULL) {
+ free(it);
+ return ISO_OUT_OF_MEM;
+ }
+
+ it->class = &iter_class;
+ it->dir = (IsoDir*)dir;
+ data->pos = NULL;
+ data->flag = 0x00;
+ it->data = data;
+
+ if (iso_dir_iter_register(it) < 0) {
+ free(it);
+ return ISO_OUT_OF_MEM;
+ }
+
+ *iter = it;
+ return ISO_SUCCESS;
+}
+
+int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
+{
+ if (iter == NULL || node == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ return iter->class->next(iter, node);
+}
+
+int iso_dir_iter_has_next(IsoDirIter *iter)
+{
+ if (iter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ return iter->class->has_next(iter);
+}
+
+void iso_dir_iter_free(IsoDirIter *iter)
+{
+ if (iter != NULL) {
+ iso_dir_iter_unregister(iter);
+ iter->class->free(iter);
+ free(iter);
+ }
+}
+
+int iso_dir_iter_take(IsoDirIter *iter)
+{
+ if (iter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ return iter->class->take(iter);
+}
+
+int iso_dir_iter_remove(IsoDirIter *iter)
+{
+ if (iter == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ return iter->class->remove(iter);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * Get the IsoStream that represents the contents of the given IsoFile.
+ *
+ * If you open() the stream, it should be close() before image generation.
+ *
+ * @return
+ * The IsoStream. No extra ref is added, so the IsoStream belong to the
+ * IsoFile, and it may be freed together with it. Add your own ref with
+ * iso_stream_ref() if you need it.
+ *
+ * @since 0.6.4
+ */
+IsoStream *iso_file_get_stream(IsoFile *file)
+{
+ return file->stream;
+}
+
+/**
+ * Get the block lba of a file node, if it was imported from an old image.
+ *
+ * @param file
+ * The file
+ * @param lba
+ * Will be filled with the kba
+ * @param flag
+ * Reserved for future usage, submit 0
+ * @return
+ * 1 if lba is valid (file comes from old image), 0 if file was newly
+ * added, i.e. it does not come from an old image, < 0 error
+ *
+ * @since 0.6.4
+ */
+int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag)
+{
+ if (file == NULL || lba == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (flag != 0) {
+ return ISO_WRONG_ARG_VALUE;
+ }
+ if (file->msblock != 0) {
+ *lba = file->msblock;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Like iso_file_get_old_image_lba(), but take an IsoNode.
+ *
+ * @return
+ * 1 if lba is valid (file comes from old image), 0 if file was newly
+ * added, i.e. it does not come from an old image, 2 node type has no
+ * LBA (no regular file), < 0 error
+ *
+ * @since 0.6.4
+ */
+int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag)
+{
+ if (node == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (ISO_NODE_IS_FILE(node)) {
+ return iso_file_get_old_image_lba((IsoFile*)node, lba, flag);
+ } else {
+ return 2;
+ }
+}
+
+/**
+ * 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;
+}
+
+/* iterators are stored in a linked list */
+struct iter_reg_node {
+ IsoDirIter *iter;
+ struct iter_reg_node *next;
+};
+
+/* list header */
+static
+struct iter_reg_node *iter_reg = NULL;
+
+/**
+ * Add a new iterator to the registry. The iterator register keeps track of
+ * all iterators being used, and are notified when directory structure
+ * changes.
+ */
+int iso_dir_iter_register(IsoDirIter *iter)
+{
+ struct iter_reg_node *new;
+ new = malloc(sizeof(struct iter_reg_node));
+ if (new == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ new->iter = iter;
+ new->next = iter_reg;
+ iter_reg = new;
+ return ISO_SUCCESS;
+}
+
+/**
+ * Unregister a directory iterator.
+ */
+void iso_dir_iter_unregister(IsoDirIter *iter)
+{
+ struct iter_reg_node **pos;
+ pos = &iter_reg;
+ while (*pos != NULL && (*pos)->iter != iter) {
+ pos = &(*pos)->next;
+ }
+ if (*pos) {
+ struct iter_reg_node *tmp = (*pos)->next;
+ free(*pos);
+ *pos = tmp;
+ }
+}
+
+void iso_notify_dir_iters(IsoNode *node, int flag)
+{
+ struct iter_reg_node *pos = iter_reg;
+ while (pos != NULL) {
+ IsoDirIter *iter = pos->iter;
+ if (iter->dir == node->parent) {
+ iter->class->notify_child_taken(iter, node);
+ }
+ pos = pos->next;
+ }
+}
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/node.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/node.h
new file mode 100644
index 00000000..dd13469f
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/node.h
@@ -0,0 +1,344 @@
+/*
+ * 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
+#include
+#include
+#include
+
+/* #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;
+};
+
+struct iso_dir_iter_iface
+{
+
+ int (*next)(IsoDirIter *iter, IsoNode **node);
+
+ int (*has_next)(IsoDirIter *iter);
+
+ void (*free)(IsoDirIter *iter);
+
+ int (*take)(IsoDirIter *iter);
+
+ int (*remove)(IsoDirIter *iter);
+
+ /**
+ * This is called just before remove a node from a directory. The iterator
+ * may want to update its internal state according to this.
+ */
+ void (*notify_child_taken)(IsoDirIter *iter, IsoNode *node);
+};
+
+/**
+ * An iterator for directory children.
+ */
+struct Iso_Dir_Iter
+{
+ struct iso_dir_iter_iface *class;
+
+ /* the directory this iterator iterates over */
+ IsoDir *dir;
+
+ void *data;
+};
+
+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);
+
+/**
+ * Add a new iterator to the registry. The iterator register keeps track of
+ * all iterators being used, and are notified when directory structure
+ * changes.
+ */
+int iso_dir_iter_register(IsoDirIter *iter);
+
+/**
+ * Unregister a directory iterator.
+ */
+void iso_dir_iter_unregister(IsoDirIter *iter);
+
+void iso_notify_dir_iters(IsoNode *node, int flag);
+
+#endif /*LIBISO_NODE_H_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge.c
new file mode 100644
index 00000000..e57ed3d1
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge.c
@@ -0,0 +1,1208 @@
+/*
+ * 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.
+ */
+
+#include "rockridge.h"
+#include "node.h"
+#include "ecma119_tree.h"
+#include "writer.h"
+#include "messages.h"
+#include "image.h"
+
+#include
+
+static
+int susp_append(Ecma119Image *t, struct susp_info *susp, uint8_t *data)
+{
+ susp->n_susp_fields++;
+ susp->susp_fields = realloc(susp->susp_fields, sizeof(void*)
+ * susp->n_susp_fields);
+ if (susp->susp_fields == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ susp->susp_fields[susp->n_susp_fields - 1] = data;
+ susp->suf_len += data[2];
+ return ISO_SUCCESS;
+}
+
+static
+int susp_append_ce(Ecma119Image *t, struct susp_info *susp, uint8_t *data)
+{
+ susp->n_ce_susp_fields++;
+ susp->ce_susp_fields = realloc(susp->ce_susp_fields, sizeof(void*)
+ * susp->n_ce_susp_fields);
+ if (susp->ce_susp_fields == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ susp->ce_susp_fields[susp->n_ce_susp_fields - 1] = data;
+ susp->ce_len += data[2];
+ return ISO_SUCCESS;
+}
+
+static
+uid_t px_get_uid(Ecma119Image *t, Ecma119Node *n)
+{
+ if (t->replace_uid) {
+ return t->uid;
+ } else {
+ return n->node->uid;
+ }
+}
+
+static
+uid_t px_get_gid(Ecma119Image *t, Ecma119Node *n)
+{
+ if (t->replace_gid) {
+ return t->gid;
+ } else {
+ return n->node->gid;
+ }
+}
+
+static
+mode_t px_get_mode(Ecma119Image *t, Ecma119Node *n)
+{
+ if ((n->type == ECMA119_DIR || n->type == ECMA119_PLACEHOLDER)) {
+ if (t->replace_dir_mode) {
+ return (n->node->mode & S_IFMT) | t->dir_mode;
+ }
+ } else {
+ if (t->replace_file_mode) {
+ return (n->node->mode & S_IFMT) | t->file_mode;
+ }
+ }
+ return n->node->mode;
+}
+
+/**
+ * Add a PX System Use Entry. The PX System Use Entry is used to add POSIX
+ * file attributes, such as access permissions or user and group id, to a
+ * ECMA 119 directory record. (RRIP, 4.1.1)
+ */
+static
+int rrip_add_PX(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
+{
+ uint8_t *PX = malloc(44);
+ if (PX == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ PX[0] = 'P';
+ PX[1] = 'X';
+ PX[2] = 44;
+ PX[3] = 1;
+ iso_bb(&PX[4], px_get_mode(t, n), 4);
+ iso_bb(&PX[12], n->nlink, 4);
+ iso_bb(&PX[20], px_get_uid(t, n), 4);
+ iso_bb(&PX[28], px_get_gid(t, n), 4);
+ iso_bb(&PX[36], n->ino, 4);
+
+ return susp_append(t, susp, PX);
+}
+
+/**
+ * Add to the given tree node a TF System Use Entry, used to record some
+ * time stamps related to the file (RRIP, 4.1.6).
+ */
+static
+int rrip_add_TF(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
+{
+ IsoNode *iso;
+ uint8_t *TF = malloc(5 + 3 * 7);
+ if (TF == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ TF[0] = 'T';
+ TF[1] = 'F';
+ TF[2] = 5 + 3 * 7;
+ TF[3] = 1;
+ TF[4] = (1 << 1) | (1 << 2) | (1 << 3);
+
+ iso = n->node;
+ iso_datetime_7(&TF[5], t->replace_timestamps ? t->timestamp : iso->mtime,
+ t->always_gmt);
+ iso_datetime_7(&TF[12], t->replace_timestamps ? t->timestamp : iso->atime,
+ t->always_gmt);
+ iso_datetime_7(&TF[19], t->replace_timestamps ? t->timestamp : iso->ctime,
+ t->always_gmt);
+ return susp_append(t, susp, TF);
+}
+
+/**
+ * Add a PL System Use Entry, used to record the location of the original
+ * parent directory of a directory which has been relocated.
+ *
+ * This is special because it doesn't modify the susp fields of the directory
+ * that gets passed to it; it modifies the susp fields of the ".." entry in
+ * that directory.
+ *
+ * See RRIP, 4.1.5.2 for more details.
+ */
+static
+int rrip_add_PL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
+{
+ uint8_t *PL;
+
+ if (n->type != ECMA119_DIR || n->info.dir->real_parent == NULL) {
+ /* should never occur */
+ return ISO_ASSERT_FAILURE;
+ }
+
+ PL = malloc(12);
+ if (PL == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ PL[0] = 'P';
+ PL[1] = 'L';
+ PL[2] = 12;
+ PL[3] = 1;
+
+ /* write the location of the real parent, already computed */
+ iso_bb(&PL[4], n->info.dir->real_parent->info.dir->block, 4);
+ return susp_append(t, susp, PL);
+}
+
+/**
+ * Add a RE System Use Entry to the given tree node. The purpose of the
+ * this System Use Entry is to indicate to an RRIP-compliant receiving
+ * system that the Directory Record in which an "RE" System Use Entry is
+ * recorded has been relocated from another position in the original
+ * Directory Hierarchy.
+ *
+ * See RRIP, 4.1.5.3 for more details.
+ */
+static
+int rrip_add_RE(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
+{
+ uint8_t *RE = malloc(4);
+ if (RE == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ RE[0] = 'R';
+ RE[1] = 'E';
+ RE[2] = 4;
+ RE[3] = 1;
+ return susp_append(t, susp, RE);
+}
+
+/**
+ * Add a PN System Use Entry to the given tree node.
+ * The PN System Use Entry is used to store the device number, and it's
+ * mandatory if the tree node corresponds to a character or block device.
+ *
+ * See RRIP, 4.1.2 for more details.
+ */
+static
+int rrip_add_PN(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
+{
+ IsoSpecial *node;
+ uint8_t *PN;
+
+ node = (IsoSpecial*)n->node;
+ if (node->node.type != LIBISO_SPECIAL) {
+ /* should never occur */
+ return ISO_ASSERT_FAILURE;
+ }
+
+ PN = malloc(20);
+ if (PN == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ PN[0] = 'P';
+ PN[1] = 'N';
+ PN[2] = 20;
+ PN[3] = 1;
+ iso_bb(&PN[4], node->dev >> 32, 4);
+ iso_bb(&PN[12], node->dev & 0xffffffff, 4);
+ return susp_append(t, susp, PN);
+}
+
+/**
+ * Add to the given tree node a CL System Use Entry, that is used to record
+ * the new location of a directory which has been relocated.
+ *
+ * See RRIP, 4.1.5.1 for more details.
+ */
+static
+int rrip_add_CL(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp)
+{
+ uint8_t *CL;
+ if (n->type != ECMA119_PLACEHOLDER) {
+ /* should never occur */
+ return ISO_ASSERT_FAILURE;
+ }
+ CL = malloc(12);
+ if (CL == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ CL[0] = 'C';
+ CL[1] = 'L';
+ CL[2] = 12;
+ CL[3] = 1;
+ iso_bb(&CL[4], n->info.real_me->info.dir->block, 4);
+ return susp_append(t, susp, CL);
+}
+
+/**
+ * Convert a RR filename to the requested charset. On any conversion error,
+ * the original name will be used.
+ */
+static
+char *get_rr_fname(Ecma119Image *t, const char *str)
+{
+ int ret;
+ char *name;
+
+ if (!strcmp(t->input_charset, t->output_charset)) {
+ /* no conversion needed */
+ return strdup(str);
+ }
+
+ ret = strconv(str, t->input_charset, t->output_charset, &name);
+ if (ret < 0) {
+ /* TODO we should check for possible cancelation */
+ iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
+ "Charset conversion error. Can't convert %s from %s to %s",
+ str, t->input_charset, t->output_charset);
+
+ /* use the original name, it's the best we can do */
+ name = strdup(str);
+ }
+
+ return name;
+}
+
+/**
+ * Add a NM System Use Entry to the given tree node. The purpose of this
+ * System Use Entry is to store the content of an Alternate Name to support
+ * POSIX-style or other names.
+ *
+ * See RRIP, 4.1.4 for more details.
+ *
+ * @param size
+ * Length of the name to be included into the NM
+ * @param flags
+ * @param ce
+ * Whether to add or not to CE
+ */
+static
+int rrip_add_NM(Ecma119Image *t, struct susp_info *susp, char *name, int size,
+ int flags, int ce)
+{
+ uint8_t *NM = malloc(size + 5);
+ if (NM == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ NM[0] = 'N';
+ NM[1] = 'M';
+ NM[2] = size + 5;
+ NM[3] = 1;
+ NM[4] = flags;
+ if (size) {
+ memcpy(&NM[5], name, size);
+ }
+ if (ce) {
+ return susp_append_ce(t, susp, NM);
+ } else {
+ return susp_append(t, susp, NM);
+ }
+}
+
+/**
+ * Add a new SL component (RRIP, 4.1.3.1) to a list of components.
+ *
+ * @param n
+ * Number of components. It will be updated.
+ * @param compos
+ * Pointer to the list of components.
+ * @param s
+ * The component content
+ * @param size
+ * Size of the component content
+ * @param fl
+ * Flags
+ * @return
+ * 1 on success, < 0 on error
+ */
+static
+int rrip_SL_append_comp(size_t *n, uint8_t ***comps, char *s, int size, char fl)
+{
+ uint8_t *comp = malloc(size + 2);
+ if (comp == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ (*n)++;
+ comp[0] = fl;
+ comp[1] = size;
+ *comps = realloc(*comps, (*n) * sizeof(void*));
+ if (*comps == NULL) {
+ free(comp);
+ return ISO_OUT_OF_MEM;
+ }
+ (*comps)[(*n) - 1] = comp;
+
+ if (size) {
+ memcpy(&comp[2], s, size);
+ }
+ return ISO_SUCCESS;
+}
+
+/**
+ * Add a SL System Use Entry to the given tree node. This is used to store
+ * the content of a symbolic link, and is mandatory if the tree node
+ * indicates a symbolic link (RRIP, 4.1.3).
+ *
+ * @param comp
+ * Components of the SL System Use Entry. If they don't fit in a single
+ * SL, more than one SL will be added.
+ * @param n
+ * Number of components in comp
+ * @param ce
+ * Whether to add to a continuation area or system use field.
+ */
+static
+int rrip_add_SL(Ecma119Image *t, struct susp_info *susp, uint8_t **comp,
+ size_t n, int ce)
+{
+ int ret, i, j;
+
+ int total_comp_len = 0;
+ size_t pos, written = 0;
+
+ uint8_t *SL;
+
+ for (i = 0; i < n; i++) {
+
+ total_comp_len += comp[i][1] + 2;
+ if (total_comp_len > 250) {
+ /* we need a new SL entry */
+ total_comp_len -= comp[i][1] + 2;
+ SL = malloc(total_comp_len + 5);
+ if (SL == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ SL[0] = 'S';
+ SL[1] = 'L';
+ SL[2] = total_comp_len + 5;
+ SL[3] = 1;
+ SL[4] = 1; /* CONTINUE */
+ pos = 5;
+ for (j = written; j < i; j++) {
+ memcpy(&SL[pos], comp[j], comp[j][1] + 2);
+ pos += comp[j][1] + 2;
+ }
+
+ /*
+ * In this case we are sure we're writting to CE. Check for
+ * debug purposes
+ */
+ if (ce == 0) {
+ return ISO_ASSERT_FAILURE;
+ }
+ ret = susp_append_ce(t, susp, SL);
+ if (ret < 0) {
+ return ret;
+ }
+ written = i;
+ total_comp_len = comp[i][1] + 2;
+ }
+ }
+
+ SL = malloc(total_comp_len + 5);
+ if (SL == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ SL[0] = 'S';
+ SL[1] = 'L';
+ SL[2] = total_comp_len + 5;
+ SL[3] = 1;
+ SL[4] = 0;
+ pos = 5;
+
+ for (j = written; j < n; j++) {
+ memcpy(&SL[pos], comp[j], comp[j][1] + 2);
+ pos += comp[j][1] + 2;
+ }
+ if (ce) {
+ ret = susp_append_ce(t, susp, SL);
+ } else {
+ ret = susp_append(t, susp, SL);
+ }
+ return ret;
+}
+
+/**
+ * Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification.
+ *
+ * The "ER" System Use Entry is used to uniquely identify a specification
+ * compliant with SUSP. This method adds to the given tree node "." entry
+ * the "ER" corresponding to the RR protocol.
+ *
+ * See SUSP, 5.5 and RRIP, 4.3 for more details.
+ */
+static
+int rrip_add_ER(Ecma119Image *t, struct susp_info *susp)
+{
+ unsigned char *ER = malloc(182);
+ if (ER == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ ER[0] = 'E';
+ ER[1] = 'R';
+ ER[2] = 182;
+ ER[3] = 1;
+ ER[4] = 9;
+ ER[5] = 72;
+ ER[6] = 93;
+ ER[7] = 1;
+ memcpy(&ER[8], "IEEE_1282", 9);
+ memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
+ "FILE SYSTEM SEMANTICS.", 72);
+ memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
+ "PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
+
+ /** This always goes to continuation area */
+ return susp_append_ce(t, susp, ER);
+}
+
+/**
+ * Add a CE System Use Entry to the given tree node. A "CE" is used to add
+ * a continuation area, where additional System Use Entry can be written.
+ * (SUSP, 5.1).
+ */
+static
+int susp_add_CE(Ecma119Image *t, size_t ce_len, struct susp_info *susp)
+{
+ uint8_t *CE = malloc(28);
+ if (CE == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ CE[0] = 'C';
+ CE[1] = 'E';
+ CE[2] = 28;
+ CE[3] = 1;
+ iso_bb(&CE[4], susp->ce_block, 4);
+ iso_bb(&CE[12], susp->ce_len, 4);
+ iso_bb(&CE[20], ce_len, 4);
+
+ return susp_append(t, susp, CE);
+}
+
+/**
+ * Add a SP System Use Entry. The SP provide an identifier that the SUSP is
+ * used within the volume. The SP shall be recorded in the "." entry of the
+ * root directory. See SUSP, 5.3 for more details.
+ */
+static
+int susp_add_SP(Ecma119Image *t, struct susp_info *susp)
+{
+ unsigned char *SP = malloc(7);
+ if (SP == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ SP[0] = 'S';
+ SP[1] = 'P';
+ SP[2] = (char)7;
+ SP[3] = (char)1;
+ SP[4] = 0xbe;
+ SP[5] = 0xef;
+ SP[6] = 0;
+ return susp_append(t, susp, SP);
+}
+
+/**
+ * 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)
+{
+ size_t su_size;
+
+ /* space min is 255 - 33 - 37 = 185
+ * At the same time, it is always an odd number, but we need to pad it
+ * propertly to ensure the length of a directory record is a even number
+ * (ECMA-119, 9.1.13). Thus, in fact the real space is always space - 1
+ */
+ space--;
+ *ce = 0;
+
+ /* PX and TF, we are sure they always fit in SUA */
+ su_size = 44 + 26;
+
+ if (n->type == ECMA119_DIR) {
+ if (n->info.dir->real_parent != NULL) {
+ /* it is a reallocated entry */
+ if (type == 2) {
+ /* we need to add a PL entry */
+ su_size += 12;
+ } else if (type == 0) {
+ /* we need to add a RE entry */
+ su_size += 4;
+ }
+ }
+ } else if (n->type == ECMA119_SPECIAL) {
+ if (S_ISBLK(n->node->mode) || S_ISCHR(n->node->mode)) {
+ /* block or char device, we need a PN entry */
+ su_size += 20;
+ }
+ } else if (n->type == ECMA119_PLACEHOLDER) {
+ /* we need the CL entry */
+ su_size += 12;
+ }
+
+ if (type == 0) {
+ char *name = get_rr_fname(t, n->node->name);
+ size_t namelen = strlen(name);
+ free(name);
+
+ /* NM entry */
+ if (su_size + 5 + namelen <= space) {
+ /* ok, it fits in System Use Area */
+ su_size += 5 + namelen;
+ } else {
+ /* the NM will be divided in a CE */
+ namelen = namelen - (space - su_size - 5 - 28);
+ *ce = 5 + namelen;
+ su_size = space;
+ }
+ if (n->type == ECMA119_SYMLINK) {
+ /*
+ * for symlinks, we also need to write the SL
+ */
+ char *dest, *cur, *prev;
+ size_t sl_len = 5;
+ int cew = (*ce != 0); /* are we writing to CE? */
+
+ dest = get_rr_fname(t, ((IsoSymlink*)n->node)->dest);
+ prev = dest;
+ cur = strchr(prev, '/');
+ while (1) {
+ size_t clen;
+ if (cur) {
+ clen = cur - prev;
+ } else {
+ /* last component */
+ clen = strlen(prev);
+ }
+
+ if (clen == 1 && prev[0] == '.') {
+ clen = 0;
+ } else if (clen == 2 && prev[0] == '.' && prev[1] == '.') {
+ clen = 0;
+ }
+
+ /* flags and len for each component record (RRIP, 4.1.3.1) */
+ clen += 2;
+
+ if (!cew) {
+ /* we are still writing to the SUA */
+ if (su_size + sl_len + clen > space) {
+ /*
+ * ok, we need a Continuation Area anyway
+ * TODO this can be handled better, but for now SL
+ * will be completelly moved into the CA
+ */
+ if (su_size + 28 <= space) {
+ /* the CE entry fills without reducing NM */
+ su_size += 28;
+ } else {
+ /* we need to reduce NM */
+ *ce = (28 - (space - su_size)) + 5;
+ su_size = space;
+ }
+ cew = 1;
+ } else {
+ sl_len += clen;
+ }
+ }
+ if (cew) {
+ if (sl_len + clen > 255) {
+ /* we need an additional SL entry */
+ if (clen > 250) {
+ /*
+ * case 1, component too large to fit in a
+ * single SL entry. Thus, the component need
+ * to be divided anyway.
+ * Note than clen can be up to 255 + 2 = 257.
+ *
+ * First, we check how many bytes fit in current
+ * SL field
+ */
+ int fit = 255 - sl_len - 2;
+ if (clen - 250 <= fit) {
+ /*
+ * the component can be divided between this
+ * and another SL entry
+ */
+ *ce += 255; /* this SL, full */
+ sl_len = 5 + (clen - fit);
+ } else {
+ /*
+ * the component will need a 2rd SL entry in
+ * any case, so we prefer to don't write
+ * anything in this SL
+ */
+ *ce += sl_len + 255;
+ sl_len = 5 + (clen - 250) + 2;
+ }
+ } else {
+ /* case 2, create a new SL entry */
+ *ce += sl_len;
+ sl_len = 5 + clen;
+ }
+ } else {
+ sl_len += clen;
+ }
+ }
+
+ if (!cur || cur[1] == '\0') {
+ /* cur[1] can be \0 if dest ends with '/' */
+ break;
+ }
+ prev = cur + 1;
+ cur = strchr(prev, '/');
+ }
+
+ free(dest);
+
+ /* and finally write the pending SL field */
+ if (!cew) {
+ /* the whole SL fits into the SUA */
+ su_size += sl_len;
+ } else {
+ *ce += sl_len;
+ }
+
+ }
+ } else {
+
+ /* "." or ".." entry */
+ su_size += 5; /* NM field */
+ if (type == 1 && n->parent == NULL) {
+ /*
+ * "." for root directory
+ * we need to write SP and ER entries. The first fits in SUA,
+ * ER needs a Continuation Area, thus we also need a CE entry
+ */
+ su_size += 7 + 28; /* SP + CE */
+ *ce = 182; /* ER */
+ }
+ }
+
+ /*
+ * The System Use field inside the directory record must be padded if
+ * it is an odd number (ECMA-119, 9.1.13)
+ */
+ su_size += (su_size % 2);
+ return su_size;
+}
+
+/**
+ * Free all info in a struct susp_info.
+ */
+static
+void susp_info_free(struct susp_info* susp)
+{
+ size_t i;
+
+ for (i = 0; i < susp->n_susp_fields; ++i) {
+ free(susp->susp_fields[i]);
+ }
+ free(susp->susp_fields);
+
+ for (i = 0; i < susp->n_ce_susp_fields; ++i) {
+ free(susp->ce_susp_fields[i]);
+ }
+ free(susp->ce_susp_fields);
+}
+
+/**
+ * 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)
+{
+ int ret;
+ size_t i;
+ Ecma119Node *node;
+ char *name = NULL;
+ char *dest = NULL;
+
+ if (t == NULL || n == NULL || info == NULL) {
+ return ISO_NULL_POINTER;
+ }
+ if (type < 0 || type > 2 || space < 185) {
+ /* space min is 255 - 33 - 37 = 185 */
+ return ISO_WRONG_ARG_VALUE;
+ }
+
+ if (type == 2 && n->parent != NULL) {
+ node = n->parent;
+ } else {
+ node = n;
+ }
+
+ /* space min is 255 - 33 - 37 = 185
+ * At the same time, it is always an odd number, but we need to pad it
+ * propertly to ensure the length of a directory record is a even number
+ * (ECMA-119, 9.1.13). Thus, in fact the real space is always space - 1
+ */
+ space--;
+
+ /*
+ * SP must be the first entry for the "." record of the root directory
+ * (SUSP, 5.3)
+ */
+ if (type == 1 && n->parent == NULL) {
+ ret = susp_add_SP(t, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+
+ /* PX and TF, we are sure they always fit in SUA */
+ ret = rrip_add_PX(t, node, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ ret = rrip_add_TF(t, node, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+
+ if (n->type == ECMA119_DIR) {
+ if (n->info.dir->real_parent != NULL) {
+ /* it is a reallocated entry */
+ if (type == 2) {
+ /*
+ * we need to add a PL entry
+ * Note that we pass "n" as parameter, not "node"
+ */
+ ret = rrip_add_PL(t, n, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ } else if (type == 0) {
+ /* we need to add a RE entry */
+ ret = rrip_add_RE(t, node, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+ }
+ } else if (n->type == ECMA119_SPECIAL) {
+ if (S_ISBLK(n->node->mode) || S_ISCHR(n->node->mode)) {
+ /* block or char device, we need a PN entry */
+ ret = rrip_add_PN(t, node, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+ } else if (n->type == ECMA119_PLACEHOLDER) {
+ /* we need the CL entry */
+ ret = rrip_add_CL(t, node, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+
+ if (type == 0) {
+ size_t sua_free; /* free space in the SUA */
+ int nm_type = 0; /* 0 whole entry in SUA, 1 part in CE */
+ size_t ce_len = 0; /* len of the CE */
+ size_t namelen;
+
+ /* this two are only defined for symlinks */
+ uint8_t **comps= NULL; /* components of the SL field */
+ size_t n_comp = 0; /* number of components */
+
+ name = get_rr_fname(t, n->node->name);
+ namelen = strlen(name);
+
+ sua_free = space - info->suf_len;
+
+ /* NM entry */
+ if (5 + namelen <= sua_free) {
+ /* ok, it fits in System Use Area */
+ sua_free -= (5 + namelen);
+ nm_type = 0;
+ } else {
+ /* the NM will be divided in a CE */
+ nm_type = 1;
+ namelen = namelen - (sua_free - 5 - 28);
+ ce_len = 5 + namelen;
+ sua_free = 0;
+ }
+ if (n->type == ECMA119_SYMLINK) {
+ /*
+ * for symlinks, we also need to write the SL
+ */
+ char *cur, *prev;
+ size_t sl_len = 5;
+ int cew = (nm_type == 1); /* are we writing to CE? */
+
+ dest = get_rr_fname(t, ((IsoSymlink*)n->node)->dest);
+ prev = dest;
+ cur = strchr(prev, '/');
+ while (1) {
+ size_t clen;
+ char cflag = 0; /* component flag (RRIP, 4.1.3.1) */
+ if (cur) {
+ clen = cur - prev;
+ } else {
+ /* last component */
+ clen = strlen(prev);
+ }
+
+ if (clen == 0) {
+ /* this refers to the roor directory, '/' */
+ cflag = 1 << 3;
+ }
+ if (clen == 1 && prev[0] == '.') {
+ clen = 0;
+ cflag = 1 << 1;
+ } else if (clen == 2 && prev[0] == '.' && prev[1] == '.') {
+ clen = 0;
+ cflag = 1 << 2;
+ }
+
+ /* flags and len for each component record (RRIP, 4.1.3.1) */
+ clen += 2;
+
+ if (!cew) {
+ /* we are still writing to the SUA */
+ if (sl_len + clen > sua_free) {
+ /*
+ * ok, we need a Continuation Area anyway
+ * TODO this can be handled better, but for now SL
+ * will be completelly moved into the CA
+ */
+ if (28 <= sua_free) {
+ /* the CE entry fills without reducing NM */
+ sua_free -= 28;
+ cew = 1;
+ } else {
+ /* we need to reduce NM */
+ nm_type = 1;
+ ce_len = (28 - sua_free) + 5;
+ sua_free = 0;
+ cew = 1;
+ }
+ } else {
+ /* add the component */
+ ret = rrip_SL_append_comp(&n_comp, &comps, prev,
+ clen - 2, cflag);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ sl_len += clen;
+ }
+ }
+ if (cew) {
+ if (sl_len + clen > 255) {
+ /* we need an addition SL entry */
+ if (clen > 250) {
+ /*
+ * case 1, component too large to fit in a
+ * single SL entry. Thus, the component need
+ * to be divided anyway.
+ * Note than clen can be up to 255 + 2 = 257.
+ *
+ * First, we check how many bytes fit in current
+ * SL field
+ */
+ int fit = 255 - sl_len - 2;
+ if (clen - 250 <= fit) {
+ /*
+ * the component can be divided between this
+ * and another SL entry
+ */
+ ret = rrip_SL_append_comp(&n_comp, &comps,
+ prev, fit, 0x01);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ /*
+ * and another component, that will go in
+ * other SL entry
+ */
+ ret = rrip_SL_append_comp(&n_comp, &comps, prev
+ + fit, clen - fit - 2, 0);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ ce_len += 255; /* this SL, full */
+ sl_len = 5 + (clen - fit);
+ } else {
+ /*
+ * the component will need a 2rd SL entry in
+ * any case, so we prefer to don't write
+ * anything in this SL
+ */
+ ret = rrip_SL_append_comp(&n_comp, &comps,
+ prev, 248, 0x01);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ ret = rrip_SL_append_comp(&n_comp, &comps, prev
+ + 248, strlen(prev + 248), 0x00);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ ce_len += sl_len + 255;
+ sl_len = 5 + (clen - 250) + 2;
+ }
+ } else {
+ /* case 2, create a new SL entry */
+ ret = rrip_SL_append_comp(&n_comp, &comps, prev,
+ clen - 2, cflag);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ ce_len += sl_len;
+ sl_len = 5 + clen;
+ }
+ } else {
+ /* the component fit in the SL entry */
+ ret = rrip_SL_append_comp(&n_comp, &comps, prev,
+ clen - 2, cflag);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ sl_len += clen;
+ }
+ }
+
+ if (!cur || cur[1] == '\0') {
+ /* cur[1] can be \0 if dest ends with '/' */
+ break;
+ }
+ prev = cur + 1;
+ cur = strchr(prev, '/');
+ }
+
+ if (cew) {
+ ce_len += sl_len;
+ }
+ }
+
+ /*
+ * We we reach here:
+ * - We know if NM fill in the SUA (nm_type == 0)
+ * - If SL needs an to be written in CE (ce_len > 0)
+ * - The components for SL entry (or entries)
+ */
+
+ if (nm_type == 0) {
+ /* the full NM fills in SUA */
+ ret = rrip_add_NM(t, info, name, strlen(name), 0, 0);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ } else {
+ /*
+ * Write the NM part that fits in SUA... Note that CE
+ * entry and NM in the continuation area is added below
+ */
+ namelen = space - info->suf_len - 28 - 5;
+ ret = rrip_add_NM(t, info, name, namelen, 1, 0);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+
+ if (ce_len > 0) {
+ /* Add the CE entry */
+ ret = susp_add_CE(t, ce_len, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+
+ if (nm_type == 1) {
+ /*
+ * ..and the part that goes to continuation area.
+ */
+ ret = rrip_add_NM(t, info, name + namelen, strlen(name + namelen),
+ 0, 1);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+
+ if (n->type == ECMA119_SYMLINK) {
+
+ /* add the SL entry (or entries) */
+ ret = rrip_add_SL(t, info, comps, n_comp, (ce_len > 0));
+
+ /* free the components */
+ for (i = 0; i < n_comp; i++) {
+ free(comps[i]);
+ }
+ free(comps);
+
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+
+ } else {
+
+ /* "." or ".." entry */
+
+ /* write the NM entry */
+ ret = rrip_add_NM(t, info, NULL, 0, 1 << type, 0);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ if (type == 1 && n->parent == NULL) {
+ /*
+ * "." for root directory
+ * we need to write SP and ER entries. The first fits in SUA,
+ * ER needs a Continuation Area, thus we also need a CE entry.
+ * Note that SP entry was already added above
+ */
+ ret = susp_add_CE(t, 182, info); /* 182 is ER length */
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ ret = rrip_add_ER(t, info);
+ if (ret < 0) {
+ goto add_susp_cleanup;
+ }
+ }
+ }
+
+ /*
+ * The System Use field inside the directory record must be padded if
+ * it is an odd number (ECMA-119, 9.1.13)
+ */
+ info->suf_len += (info->suf_len % 2);
+
+ free(name);
+ free(dest);
+ return ISO_SUCCESS;
+
+ add_susp_cleanup: ;
+ free(name);
+ free(dest);
+ susp_info_free(info);
+ return ret;
+}
+
+/**
+ * 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)
+{
+ size_t i;
+ size_t pos = 0;
+
+ if (info->n_susp_fields == 0) {
+ return;
+ }
+
+ for (i = 0; i < info->n_susp_fields; i++) {
+ memcpy(buf + pos, info->susp_fields[i], info->susp_fields[i][2]);
+ pos += info->susp_fields[i][2];
+ }
+
+ /* free susp_fields */
+ for (i = 0; i < info->n_susp_fields; ++i) {
+ free(info->susp_fields[i]);
+ }
+ free(info->susp_fields);
+ info->susp_fields = NULL;
+ info->n_susp_fields = 0;
+ info->suf_len = 0;
+}
+
+/**
+ * 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)
+{
+ size_t i;
+ uint8_t padding[BLOCK_SIZE];
+ int ret= ISO_SUCCESS;
+
+ if (info->n_ce_susp_fields == 0) {
+ return ret;
+ }
+
+ for (i = 0; i < info->n_ce_susp_fields; i++) {
+ ret = iso_write(t, info->ce_susp_fields[i],
+ info->ce_susp_fields[i][2]);
+ if (ret < 0) {
+ goto write_ce_field_cleanup;
+ }
+ }
+
+ /* pad continuation area until block size */
+ i = BLOCK_SIZE - (info->ce_len % BLOCK_SIZE);
+ if (i > 0 && i < BLOCK_SIZE) {
+ memset(padding, 0, i);
+ ret = iso_write(t, padding, i);
+ }
+
+ write_ce_field_cleanup: ;
+ /* free ce_susp_fields */
+ for (i = 0; i < info->n_ce_susp_fields; ++i) {
+ free(info->ce_susp_fields[i]);
+ }
+ free(info->ce_susp_fields);
+ info->ce_susp_fields = NULL;
+ info->n_ce_susp_fields = 0;
+ info->ce_len = 0;
+ return ret;
+}
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge.h
new file mode 100644
index 00000000..c21a954d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge.h
@@ -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 */
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge_read.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge_read.c
new file mode 100644
index 00000000..02dbc869
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/rockridge_read.c
@@ -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
+#include
+#include
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/stream.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/stream.c
new file mode 100644
index 00000000..6058e894
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/stream.c
@@ -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
+#include
+#include
+
+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
+void fsrc_free(IsoStream *stream)
+{
+ FSrcStreamData *data;
+ data = (FSrcStreamData*)stream->data;
+ iso_file_source_unref(data->src);
+ free(data);
+}
+
+IsoStreamIface fsrc_stream_class = {
+ 0,
+ "fsrc",
+ fsrc_open,
+ fsrc_close,
+ fsrc_get_size,
+ fsrc_read,
+ fsrc_is_repeatable,
+ fsrc_get_id,
+ 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_OPENED;
+ }
+ 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_OPENED;
+ }
+ 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_OPENED;
+ }
+
+ 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
+void mem_free(IsoStream *stream)
+{
+ MemStreamData *data;
+ data = (MemStreamData*)stream->data;
+ free(data->buf);
+ free(data);
+}
+
+IsoStreamIface mem_stream_class = {
+ 0,
+ "mem ",
+ mem_open,
+ mem_close,
+ mem_get_size,
+ mem_read,
+ mem_is_repeatable,
+ mem_get_id,
+ 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);
+}
+
+void iso_stream_get_file_name(IsoStream *stream, char *name)
+{
+ char *type = stream->class->type;
+
+ if (!strncmp(type, "fsrc", 4)) {
+ FSrcStreamData *data = stream->data;
+ char *path = iso_file_source_get_path(data->src);
+ strncpy(name, path, PATH_MAX);
+ } else if (!strncmp(type, "boot", 4)) {
+ strcpy(name, "BOOT CATALOG");
+ } else if (!strncmp(type, "mem ", 4)) {
+ strcpy(name, "MEM SOURCE");
+ } else {
+ strcpy(name, "UNKNOWN SOURCE");
+ }
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/stream.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/stream.h
new file mode 100644
index 00000000..804faf14
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/stream.h
@@ -0,0 +1,45 @@
+/*
+ * 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"
+
+/**
+ * Get an identifier for the file of the source, for debug purposes
+ * @param name
+ * Should provide at least PATH_MAX bytes
+ */
+void iso_stream_get_file_name(IsoStream *stream, char *name);
+
+/**
+ * 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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/tree.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/tree.c
new file mode 100644
index 00000000..420b6113
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/tree.c
@@ -0,0 +1,804 @@
+/*
+ * 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
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * 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;
+}
+
+int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
+ const char *path, IsoNode **node)
+{
+ int result;
+ IsoFilesystem *fs;
+ IsoFileSource *file;
+ IsoNode *new;
+ IsoNode **pos;
+
+ if (image == NULL || parent == NULL || name == NULL || path == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ if (node) {
+ *node = NULL;
+ }
+
+ fs = image->fs;
+ result = fs->get_by_path(fs, path, &file);
+ if (result < 0) {
+ return result;
+ }
+
+ /* find place where to insert */
+ result = iso_dir_exists(parent, name, &pos);
+ if (result) {
+ /* a node with same name already exists */
+ iso_file_source_unref(file);
+ return ISO_NODE_NAME_NOT_UNIQUE;
+ }
+
+ result = image->builder->create_node(image->builder, image, file, &new);
+ if (result < 0) {
+ return result;
+ }
+
+ /* free the file */
+ iso_file_source_unref(file);
+
+ result = iso_node_set_name(new, name);
+ if (result < 0) {
+ iso_node_unref(new);
+ return result;
+ }
+
+ if (node) {
+ *node = new;
+ }
+
+ /* finally, add node to parent */
+ return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER);
+}
+
+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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/tree.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/tree.h
new file mode 100644
index 00000000..9c5347c8
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/tree.h
@@ -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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util.c
new file mode 100644
index 00000000..6317a8ba
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util.c
@@ -0,0 +1,1264 @@
+/*
+ * 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.
+ */
+
+#include "util.h"
+#include "libisofs.h"
+#include "../version.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+/* if we don't have eaccess, we check file access by openning it */
+#ifndef HAVE_EACCESS
+#include
+#include
+#include
+#endif
+
+int int_pow(int base, int power)
+{
+ int result = 1;
+ while (--power >= 0) {
+ result *= base;
+ }
+ return result;
+}
+
+int strconv(const char *str, const char *icharset, const char *ocharset,
+ char **output)
+{
+ size_t inbytes;
+ size_t outbytes;
+ size_t n;
+ iconv_t conv;
+ char *out;
+ char *src;
+ char *ret;
+
+ inbytes = strlen(str);
+ outbytes = (inbytes + 1) * MB_LEN_MAX;
+ out = alloca(outbytes);
+ if (out == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ conv = iconv_open(ocharset, icharset);
+ if (conv == (iconv_t)(-1)) {
+ return ISO_CHARSET_CONV_ERROR;
+ }
+ src = (char *)str;
+ ret = (char *)out;
+
+ n = iconv(conv, &src, &inbytes, &ret, &outbytes);
+ if (n == -1) {
+ /* error */
+ iconv_close(conv);
+ return ISO_CHARSET_CONV_ERROR;
+ }
+ *ret = '\0';
+ iconv_close(conv);
+
+ *output = malloc(ret - out + 1);
+ if (*output == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ memcpy(*output, out, ret - out + 1);
+ return ISO_SUCCESS;
+}
+
+int strnconv(const char *str, const char *icharset, const char *ocharset,
+ size_t len, char **output)
+{
+ size_t inbytes;
+ size_t outbytes;
+ size_t n;
+ iconv_t conv;
+ char *out;
+ char *src;
+ char *ret;
+
+ inbytes = len;
+ outbytes = (inbytes + 1) * MB_LEN_MAX;
+ out = alloca(outbytes);
+ if (out == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ conv = iconv_open(ocharset, icharset);
+ if (conv == (iconv_t)(-1)) {
+ return ISO_CHARSET_CONV_ERROR;
+ }
+ src = (char *)str;
+ ret = (char *)out;
+
+ n = iconv(conv, &src, &inbytes, &ret, &outbytes);
+ if (n == -1) {
+ /* error */
+ iconv_close(conv);
+ return ISO_CHARSET_CONV_ERROR;
+ }
+ *ret = '\0';
+ iconv_close(conv);
+
+ *output = malloc(ret - out + 1);
+ if (*output == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ memcpy(*output, out, ret - out + 1);
+ return ISO_SUCCESS;
+}
+
+/**
+ * Convert a str in a specified codeset to WCHAR_T.
+ * The result must be free() when no more needed
+ *
+ * @return
+ * 1 success, < 0 error
+ */
+static
+int str2wchar(const char *icharset, const char *input, wchar_t **output)
+{
+ iconv_t conv;
+ size_t inbytes;
+ size_t outbytes;
+ char *ret;
+ char *src;
+ wchar_t *wstr;
+ size_t n;
+
+ if (icharset == NULL || input == NULL || output == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ conv = iconv_open("WCHAR_T", icharset);
+ if (conv == (iconv_t)-1) {
+ return ISO_CHARSET_CONV_ERROR;
+ }
+
+ inbytes = strlen(input);
+ outbytes = (inbytes + 1) * sizeof(wchar_t);
+
+ /* we are sure that numchars <= inbytes */
+ wstr = malloc(outbytes);
+ if (wstr == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ ret = (char *)wstr;
+ src = (char *)input;
+
+ n = iconv(conv, &src, &inbytes, &ret, &outbytes);
+ while (n == -1) {
+
+ if (errno == E2BIG) {
+ /* error, should never occur */
+ iconv_close(conv);
+ free(wstr);
+ return ISO_CHARSET_CONV_ERROR;
+ } else {
+ wchar_t *wret;
+
+ /*
+ * Invalid input string charset.
+ * This can happen if input is in fact encoded in a charset
+ * different than icharset.
+ * We can't do anything better than replace by "_" and continue.
+ */
+ inbytes--;
+ src++;
+
+ wret = (wchar_t*) ret;
+ *wret++ = (wchar_t) '_';
+ ret = (char *) wret;
+ outbytes -= sizeof(wchar_t);
+
+ if (!inbytes)
+ break;
+ n = iconv(conv, &src, &inbytes, &ret, &outbytes);
+ }
+ }
+ iconv_close(conv);
+
+ *( (wchar_t *)ret )='\0';
+ *output = wstr;
+ return ISO_SUCCESS;
+}
+
+int str2ascii(const char *icharset, const char *input, char **output)
+{
+ int result;
+ wchar_t *wsrc_;
+ char *ret;
+ char *ret_;
+ char *src;
+ iconv_t conv;
+ size_t numchars;
+ size_t outbytes;
+ size_t inbytes;
+ size_t n;
+
+ if (icharset == NULL || input == NULL || output == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ /* convert the string to a wide character string. Note: outbytes
+ * is in fact the number of characters in the string and doesn't
+ * include the last NULL character.
+ */
+ result = str2wchar(icharset, input, &wsrc_);
+ if (result < 0) {
+ return result;
+ }
+ src = (char *)wsrc_;
+ numchars = wcslen(wsrc_);
+
+ inbytes = numchars * sizeof(wchar_t);
+
+ ret_ = malloc(numchars + 1);
+ if (ret_ == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ outbytes = numchars;
+ ret = ret_;
+
+ /* initialize iconv */
+ conv = iconv_open("ASCII", "WCHAR_T");
+ if (conv == (iconv_t)-1) {
+ free(wsrc_);
+ free(ret_);
+ return ISO_CHARSET_CONV_ERROR;
+ }
+
+ n = iconv(conv, &src, &inbytes, &ret, &outbytes);
+ while (n == -1) {
+ /* The destination buffer is too small. Stops here. */
+ if (errno == E2BIG)
+ break;
+
+ /* An incomplete multi bytes sequence was found. We
+ * can't do anything here. That's quite unlikely. */
+ if (errno == EINVAL)
+ break;
+
+ /* The last possible error is an invalid multi bytes
+ * sequence. Just replace the character with a "_".
+ * Probably the character doesn't exist in ascii like
+ * "é, è, à, ç, ..." in French. */
+ *ret++ = '_';
+ outbytes--;
+
+ if (!outbytes)
+ break;
+
+ /* There was an error with one character but some other remain
+ * to be converted. That's probably a multibyte character.
+ * See above comment. */
+ src += sizeof(wchar_t);
+ inbytes -= sizeof(wchar_t);
+
+ if (!inbytes)
+ break;
+
+ n = iconv(conv, &src, &inbytes, &ret, &outbytes);
+ }
+
+ iconv_close(conv);
+
+ *ret='\0';
+ free(wsrc_);
+
+ *output = ret_;
+ return ISO_SUCCESS;
+}
+
+static
+void set_ucsbe(uint16_t *ucs, char c)
+{
+ char *v = (char*)ucs;
+ v[0] = (char)0;
+ v[1] = c;
+}
+
+/**
+ * @return
+ * -1, 0, 1 if *ucs <, == or > than c
+ */
+static
+int cmp_ucsbe(const uint16_t *ucs, char c)
+{
+ char *v = (char*)ucs;
+ if (v[0] != 0) {
+ return 1;
+ } else if (v[1] == c) {
+ return 0;
+ } else {
+ return (uint8_t)c > (uint8_t)v[1] ? -1 : 1;
+ }
+}
+
+int str2ucs(const char *icharset, const char *input, uint16_t **output)
+{
+ int result;
+ wchar_t *wsrc_;
+ char *src;
+ char *ret;
+ char *ret_;
+ iconv_t conv;
+ size_t numchars;
+ size_t outbytes;
+ size_t inbytes;
+ size_t n;
+
+ if (icharset == NULL || input == NULL || output == NULL) {
+ return ISO_NULL_POINTER;
+ }
+
+ /* convert the string to a wide character string. Note: outbytes
+ * is in fact the number of characters in the string and doesn't
+ * include the last NULL character.
+ */
+ result = str2wchar(icharset, input, &wsrc_);
+ if (result < 0) {
+ return result;
+ }
+ src = (char *)wsrc_;
+ numchars = wcslen(wsrc_);
+
+ inbytes = numchars * sizeof(wchar_t);
+
+ ret_ = malloc((numchars+1) * sizeof(uint16_t));
+ if (ret_ == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+ outbytes = numchars * sizeof(uint16_t);
+ ret = ret_;
+
+ /* initialize iconv */
+ conv = iconv_open("UCS-2BE", "WCHAR_T");
+ if (conv == (iconv_t)-1) {
+ free(wsrc_);
+ free(ret_);
+ return ISO_CHARSET_CONV_ERROR;
+ }
+
+ n = iconv(conv, &src, &inbytes, &ret, &outbytes);
+ while (n == -1) {
+ /* The destination buffer is too small. Stops here. */
+ if (errno == E2BIG)
+ break;
+
+ /* An incomplete multi bytes sequence was found. We
+ * can't do anything here. That's quite unlikely. */
+ if (errno == EINVAL)
+ break;
+
+ /* The last possible error is an invalid multi bytes
+ * sequence. Just replace the character with a "_".
+ * Probably the character doesn't exist in UCS */
+ set_ucsbe((uint16_t*) ret, '_');
+ ret += sizeof(uint16_t);
+ outbytes -= sizeof(uint16_t);
+
+ if (!outbytes)
+ break;
+
+ /* There was an error with one character but some other remain
+ * to be converted. That's probably a multibyte character.
+ * See above comment. */
+ src += sizeof(wchar_t);
+ inbytes -= sizeof(wchar_t);
+
+ if (!inbytes)
+ break;
+
+ n = iconv(conv, &src, &inbytes, &ret, &outbytes);
+ }
+
+ iconv_close(conv);
+
+ /* close the ucs string */
+ set_ucsbe((uint16_t*) ret, '\0');
+ free(wsrc_);
+
+ *output = (uint16_t*)ret_;
+ return ISO_SUCCESS;
+}
+
+static int valid_d_char(char c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
+}
+
+static int valid_a_char(char c)
+{
+ return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') ||
+ (c >= 'A' && c <= 'Z') || (c == '_');
+}
+
+static int valid_j_char(uint16_t c)
+{
+ return cmp_ucsbe(&c, ' ') != -1 && cmp_ucsbe(&c, '*') && cmp_ucsbe(&c, '/')
+ && cmp_ucsbe(&c, ':') && cmp_ucsbe(&c, ';') && cmp_ucsbe(&c, '?')
+ && cmp_ucsbe(&c, '\\');
+}
+
+static
+char *iso_dirid(const char *src, int size)
+{
+ size_t len, i;
+ char name[32];
+
+ len = strlen(src);
+ if (len > size) {
+ len = size;
+ }
+ for (i = 0; i < len; i++) {
+ char c= toupper(src[i]);
+ name[i] = valid_d_char(c) ? c : '_';
+ }
+
+ name[len] = '\0';
+ return strdup(name);
+}
+
+char *iso_1_dirid(const char *src)
+{
+ return iso_dirid(src, 8);
+}
+
+char *iso_2_dirid(const char *src)
+{
+ return iso_dirid(src, 31);
+}
+
+char *iso_1_fileid(const char *src)
+{
+ char *dot; /* Position of the last dot in the filename, will be used
+ * to calculate lname and lext. */
+ int lname, lext, pos, i;
+ char dest[13]; /* 13 = 8 (name) + 1 (.) + 3 (ext) + 1 (\0) */
+
+ if (src == NULL) {
+ return NULL;
+ }
+ dot = strrchr(src, '.');
+
+ lext = dot ? strlen(dot + 1) : 0;
+ lname = strlen(src) - lext - (dot ? 1 : 0);
+
+ /* If we can't build a filename, return NULL. */
+ if (lname == 0 && lext == 0) {
+ return NULL;
+ }
+
+ pos = 0;
+
+ /* Convert up to 8 characters of the filename. */
+ for (i = 0; i < lname && i < 8; i++) {
+ char c= toupper(src[i]);
+
+ dest[pos++] = valid_d_char(c) ? c : '_';
+ }
+
+ /* This dot is mandatory, even if there is no extension. */
+ dest[pos++] = '.';
+
+ /* Convert up to 3 characters of the extension, if any. */
+ for (i = 0; i < lext && i < 3; i++) {
+ char c= toupper(src[lname + 1 + i]);
+
+ dest[pos++] = valid_d_char(c) ? c : '_';
+ }
+
+ dest[pos] = '\0';
+ return strdup(dest);
+}
+
+char *iso_2_fileid(const char *src)
+{
+ char *dot;
+ int lname, lext, lnname, lnext, pos, i;
+ char dest[32]; /* 32 = 30 (name + ext) + 1 (.) + 1 (\0) */
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ dot = strrchr(src, '.');
+
+ /*
+ * Since the maximum length can be divided freely over the name and
+ * extension, we need to calculate their new lengths (lnname and
+ * lnext). If the original filename is too long, we start by trimming
+ * the extension, but keep a minimum extension length of 3.
+ */
+ if (dot == NULL || *(dot + 1) == '\0') {
+ lname = strlen(src);
+ lnname = (lname > 30) ? 30 : lname;
+ lext = lnext = 0;
+ } else {
+ lext = strlen(dot + 1);
+ lname = strlen(src) - lext - 1;
+ lnext = (strlen(src) > 31 && lext > 3) ? (lname < 27 ? 30 - lname : 3)
+ : lext;
+ lnname = (strlen(src) > 31) ? 30 - lnext : lname;
+ }
+
+ if (lnname == 0 && lnext == 0) {
+ return NULL;
+ }
+
+ pos = 0;
+
+ /* Convert up to lnname characters of the filename. */
+ for (i = 0; i < lnname; i++) {
+ char c= toupper(src[i]);
+
+ dest[pos++] = valid_d_char(c) ? c : '_';
+ }
+ dest[pos++] = '.';
+
+ /* Convert up to lnext characters of the extension, if any. */
+ for (i = 0; i < lnext; i++) {
+ char c= toupper(src[lname + 1 + i]);
+
+ dest[pos++] = valid_d_char(c) ? c : '_';
+ }
+ dest[pos] = '\0';
+ return strdup(dest);
+}
+
+/**
+ * Create a dir name suitable for an ISO image with relaxed constraints.
+ *
+ * @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)
+{
+ size_t len, i;
+ char *dest;
+
+ len = strlen(src);
+ if (len > size) {
+ len = size;
+ }
+ dest = malloc(len + 1);
+ for (i = 0; i < len; i++) {
+ char c= src[i];
+ if (relaxed == 2) {
+ /* all chars are allowed */
+ dest[i] = c;
+ } else if (valid_d_char(c)) {
+ /* it is a valid char */
+ dest[i] = c;
+ } else {
+ c= toupper(src[i]);
+ if (valid_d_char(c)) {
+ if (relaxed) {
+ /* lower chars are allowed */
+ dest[i] = src[i];
+ } else {
+ dest[i] = c;
+ }
+ } else {
+ dest[i] = '_';
+ }
+ }
+ }
+
+ dest[len] = '\0';
+ return dest;
+}
+
+/**
+ * Create a file name suitable for an ISO image with relaxed constraints.
+ *
+ * @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)
+{
+ char *dot;
+ int lname, lext, lnname, lnext, pos, i;
+ char *dest = alloca(len + 1 + 1);
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ dot = strrchr(src, '.');
+
+ /*
+ * Since the maximum length can be divided freely over the name and
+ * extension, we need to calculate their new lengths (lnname and
+ * lnext). If the original filename is too long, we start by trimming
+ * the extension, but keep a minimum extension length of 3.
+ */
+ if (dot == NULL || *(dot + 1) == '\0') {
+ lname = strlen(src);
+ lnname = (lname > len) ? len : lname;
+ lext = lnext = 0;
+ } else {
+ lext = strlen(dot + 1);
+ lname = strlen(src) - lext - 1;
+ lnext = (strlen(src) > len + 1 && lext > 3) ?
+ (lname < len - 3 ? len - lname : 3)
+ : lext;
+ lnname = (strlen(src) > len + 1) ? len - lnext : lname;
+ }
+
+ if (lnname == 0 && lnext == 0) {
+ return NULL;
+ }
+
+ pos = 0;
+
+ /* Convert up to lnname characters of the filename. */
+ for (i = 0; i < lnname; i++) {
+ char c= src[i];
+ if (relaxed == 2) {
+ /* all chars are allowed */
+ dest[pos++] = c;
+ } else if (valid_d_char(c)) {
+ /* it is a valid char */
+ dest[pos++] = c;
+ } else {
+ c= toupper(src[i]);
+ if (valid_d_char(c)) {
+ if (relaxed) {
+ /* lower chars are allowed */
+ dest[pos++] = src[i];
+ } else {
+ dest[pos++] = c;
+ }
+ } else {
+ dest[pos++] = '_';
+ }
+ }
+ }
+ if (lnext > 0 || forcedot) {
+ dest[pos++] = '.';
+ }
+
+ /* Convert up to lnext characters of the extension, if any. */
+ for (i = lname + 1; i < lname + 1 + lnext; i++) {
+ char c= src[i];
+ if (relaxed == 2) {
+ /* all chars are allowed */
+ dest[pos++] = c;
+ } else if (valid_d_char(c)) {
+ /* it is a valid char */
+ dest[pos++] = c;
+ } else {
+ c= toupper(src[i]);
+ if (valid_d_char(c)) {
+ if (relaxed) {
+ /* lower chars are allowed */
+ dest[pos++] = src[i];
+ } else {
+ dest[pos++] = c;
+ }
+ } else {
+ dest[pos++] = '_';
+ }
+ }
+ }
+ dest[pos] = '\0';
+ return strdup(dest);
+}
+
+uint16_t *iso_j_file_id(const uint16_t *src)
+{
+ uint16_t *dot;
+ size_t lname, lext, lnname, lnext, pos, i;
+ uint16_t dest[66]; /* 66 = 64 (name + ext) + 1 (.) + 1 (\0) */
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ dot = ucsrchr(src, '.');
+
+ /*
+ * Since the maximum length can be divided freely over the name and
+ * extension, we need to calculate their new lengths (lnname and
+ * lnext). If the original filename is too long, we start by trimming
+ * the extension, but keep a minimum extension length of 3.
+ */
+ if (dot == NULL || cmp_ucsbe(dot + 1, '\0') == 0) {
+ lname = ucslen(src);
+ lnname = (lname > 64) ? 64 : lname;
+ lext = lnext = 0;
+ } else {
+ lext = ucslen(dot + 1);
+ lname = ucslen(src) - lext - 1;
+ lnext = (ucslen(src) > 65 && lext > 3) ? (lname < 61 ? 64 - lname : 3)
+ : lext;
+ lnname = (ucslen(src) > 65) ? 64 - lnext : lname;
+ }
+
+ if (lnname == 0 && lnext == 0) {
+ return NULL;
+ }
+
+ pos = 0;
+
+ /* Convert up to lnname characters of the filename. */
+ for (i = 0; i < lnname; i++) {
+ uint16_t c = src[i];
+ if (valid_j_char(c)) {
+ dest[pos++] = c;
+ } else {
+ set_ucsbe(dest + pos, '_');
+ pos++;
+ }
+ }
+ set_ucsbe(dest + pos, '.');
+ pos++;
+
+ /* Convert up to lnext characters of the extension, if any. */
+ for (i = 0; i < lnext; i++) {
+ uint16_t c = src[lname + 1 + i];
+ if (valid_j_char(c)) {
+ dest[pos++] = c;
+ } else {
+ set_ucsbe(dest + pos, '_');
+ pos++;
+ }
+ }
+ set_ucsbe(dest + pos, '\0');
+ return ucsdup(dest);
+}
+
+uint16_t *iso_j_dir_id(const uint16_t *src)
+{
+ size_t len, i;
+ uint16_t dest[65]; /* 65 = 64 + 1 (\0) */
+
+ if (src == NULL) {
+ return NULL;
+ }
+
+ len = ucslen(src);
+ if (len > 64) {
+ len = 64;
+ }
+ for (i = 0; i < len; i++) {
+ uint16_t c = src[i];
+ if (valid_j_char(c)) {
+ dest[i] = c;
+ } else {
+ set_ucsbe(dest + i, '_');
+ }
+ }
+ set_ucsbe(dest + len, '\0');
+ return ucsdup(dest);
+}
+
+size_t ucslen(const uint16_t *str)
+{
+ size_t i;
+
+ for (i = 0; str[i]; i++)
+ ;
+ return i;
+}
+
+uint16_t *ucsrchr(const uint16_t *str, char c)
+{
+ size_t len = ucslen(str);
+
+ while (len-- > 0) {
+ if (cmp_ucsbe(str + len, c) == 0) {
+ return (uint16_t*)(str + len);
+ }
+ }
+ return NULL;
+}
+
+uint16_t *ucsdup(const uint16_t *str)
+{
+ uint16_t *ret;
+ size_t len = ucslen(str);
+
+ ret = malloc(2 * (len + 1));
+ if (ret != NULL) {
+ memcpy(ret, str, 2 * (len + 1));
+ }
+ return ret;
+}
+
+/**
+ * Although each character is 2 bytes, we actually compare byte-by-byte
+ * (thats what the spec says).
+ */
+int ucscmp(const uint16_t *s1, const uint16_t *s2)
+{
+ const char *s = (const char*)s1;
+ const char *t = (const char*)s2;
+ size_t len1 = ucslen(s1);
+ size_t len2 = ucslen(s2);
+ size_t i, len = MIN(len1, len2) * 2;
+
+ for (i = 0; i < len; i++) {
+ if (s[i] < t[i]) {
+ return -1;
+ } else if (s[i] > t[i]) {
+ return 1;
+ }
+ }
+
+ if (len1 < len2)
+ return -1;
+ else if (len1 > len2)
+ return 1;
+ return 0;
+}
+
+uint16_t *ucscpy(uint16_t *dest, const uint16_t *src)
+{
+ size_t n = ucslen(src) + 1;
+ memcpy(dest, src, n*2);
+ return dest;
+}
+
+uint16_t *ucsncpy(uint16_t *dest, const uint16_t *src, size_t n)
+{
+ n = MIN(n, ucslen(src) + 1);
+ memcpy(dest, src, n*2);
+ return dest;
+}
+
+int str2d_char(const char *icharset, const char *input, char **output)
+{
+ int ret;
+ char *ascii;
+ size_t len, i;
+
+ if (output == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ /** allow NULL input */
+ if (input == NULL) {
+ *output = NULL;
+ return 0;
+ }
+
+ /* this checks for NULL parameters */
+ ret = str2ascii(icharset, input, &ascii);
+ if (ret < 0) {
+ *output = NULL;
+ return ret;
+ }
+
+ len = strlen(ascii);
+
+ for (i = 0; i < len; ++i) {
+ char c= toupper(ascii[i]);
+ ascii[i] = valid_d_char(c) ? c : '_';
+ }
+
+ *output = ascii;
+ return ISO_SUCCESS;
+}
+
+int str2a_char(const char *icharset, const char *input, char **output)
+{
+ int ret;
+ char *ascii;
+ size_t len, i;
+
+ if (output == NULL) {
+ return ISO_OUT_OF_MEM;
+ }
+
+ /** allow NULL input */
+ if (input == NULL) {
+ *output = NULL;
+ return 0;
+ }
+
+ /* this checks for NULL parameters */
+ ret = str2ascii(icharset, input, &ascii);
+ if (ret < 0) {
+ *output = NULL;
+ return ret;
+ }
+
+ len = strlen(ascii);
+
+ for (i = 0; i < len; ++i) {
+ char c= toupper(ascii[i]);
+ ascii[i] = valid_a_char(c) ? c : '_';
+ }
+
+ *output = ascii;
+ return ISO_SUCCESS;
+}
+
+void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
+{
+ int i;
+
+ for (i = 0; i < bytes; ++i)
+ buf[i] = (num >> (8 * i)) & 0xff;
+}
+
+void iso_msb(uint8_t *buf, uint32_t num, int bytes)
+{
+ int i;
+
+ for (i = 0; i < bytes; ++i)
+ buf[bytes - 1 - i] = (num >> (8 * i)) & 0xff;
+}
+
+void iso_bb(uint8_t *buf, uint32_t num, int bytes)
+{
+ iso_lsb(buf, num, bytes);
+ iso_msb(buf+bytes, num, bytes);
+}
+
+uint32_t iso_read_lsb(const uint8_t *buf, int bytes)
+{
+ int i;
+ uint32_t ret = 0;
+
+ for (i=0; i 52 || tzoffset < -48 || always_gmt) {
+ /* absurd timezone offset, represent time in GMT */
+ gmtime_r(&t, &tm);
+ tzoffset = 0;
+ }
+ buf[0] = tm.tm_year;
+ buf[1] = tm.tm_mon + 1;
+ buf[2] = tm.tm_mday;
+ buf[3] = tm.tm_hour;
+ buf[4] = tm.tm_min;
+ buf[5] = tm.tm_sec;
+ buf[6] = tzoffset;
+}
+
+void iso_datetime_17(unsigned char *buf, time_t t, int always_gmt)
+{
+ static int tzsetup = 0;
+ static int tzoffset;
+ struct tm tm;
+
+ if (t == (time_t) - 1) {
+ /* unspecified time */
+ memset(buf, '0', 16);
+ buf[16] = 0;
+ return;
+ }
+
+ if (!tzsetup) {
+ tzset();
+ tzsetup = 1;
+ }
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_isdst = -1; /* some Linuxes change tm_isdst only if it is -1 */
+ localtime_r(&t, &tm);
+
+ localtime_r(&t, &tm);
+
+#ifdef HAVE_TM_GMTOFF
+ tzoffset = tm.tm_gmtoff / 60 / 15;
+#else
+ if (tm.tm_isdst < 0)
+ tm.tm_isdst = 0;
+ tzoffset = ( - timezone / 60 / 15 ) + 4 * tm.tm_isdst;
+#endif
+
+ if (tzoffset > 52 || tzoffset < -48 || always_gmt) {
+ /* absurd timezone offset, represent time in GMT */
+ gmtime_r(&t, &tm);
+ tzoffset = 0;
+ }
+
+ sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
+ sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
+ sprintf((char*)&buf[6], "%02d", tm.tm_mday);
+ sprintf((char*)&buf[8], "%02d", tm.tm_hour);
+ sprintf((char*)&buf[10], "%02d", tm.tm_min);
+ sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
+ memcpy(&buf[14], "00", 2);
+ buf[16] = tzoffset;
+
+}
+
+#ifndef HAVE_TIMEGM
+static
+time_t timegm(struct tm *tm)
+{
+ time_t ret;
+ char *tz;
+
+ tz = getenv("TZ");
+ setenv("TZ", "", 1);
+ tzset();
+ ret = mktime(tm);
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+ return ret;
+}
+#endif
+
+time_t iso_datetime_read_7(const uint8_t *buf)
+{
+ struct tm tm;
+
+ tm.tm_year = buf[0];
+ tm.tm_mon = buf[1] - 1;
+ tm.tm_mday = buf[2];
+ tm.tm_hour = buf[3];
+ tm.tm_min = buf[4];
+ tm.tm_sec = buf[5];
+ return timegm(&tm) - ((int8_t)buf[6]) * 60 * 15;
+}
+
+time_t iso_datetime_read_17(const uint8_t *buf)
+{
+ struct tm tm;
+
+ sscanf((char*)&buf[0], "%4d", &tm.tm_year);
+ sscanf((char*)&buf[4], "%2d", &tm.tm_mon);
+ sscanf((char*)&buf[6], "%2d", &tm.tm_mday);
+ sscanf((char*)&buf[8], "%2d", &tm.tm_hour);
+ sscanf((char*)&buf[10], "%2d", &tm.tm_min);
+ sscanf((char*)&buf[12], "%2d", &tm.tm_sec);
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+
+ return timegm(&tm) - ((int8_t)buf[6]) * 60 * 15;
+}
+
+/**
+ * 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)
+{
+ int access;
+
+ /* use non standard eaccess when available, open() otherwise */
+#ifdef HAVE_EACCESS
+ access = !eaccess(path, R_OK);
+#else
+ int fd = open(path, O_RDONLY);
+ if (fd != -1) {
+ close(fd);
+ access = 1;
+ } else {
+ access = 0;
+ }
+#endif
+
+ if (!access) {
+ 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;
+ }
+ return ISO_SUCCESS;
+}
+
+char *strcopy(const char *buf, size_t len)
+{
+ char *str;
+
+ str = malloc((len + 1) * sizeof(char));
+ if (str == NULL) {
+ return NULL;
+ }
+ strncpy(str, buf, len);
+ str[len] = '\0';
+
+ /* remove trailing spaces */
+ for (len = len-1; str[len] == ' ' && len > 0; --len)
+ str[len] = '\0';
+
+ return str;
+}
+
+/**
+ * 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)
+{
+ size_t len, i;
+
+ if (src != NULL) {
+ len = MIN(strlen(src), max);
+ } else {
+ len = 0;
+ }
+
+ for (i = 0; i < len; ++i)
+ dest[i] = src[i];
+ for (i = len; i < max; ++i)
+ dest[i] = ' ';
+}
+
+char *ucs2str(const char *buf, size_t len)
+{
+ size_t outbytes, inbytes;
+ char *str, *src, *out;
+ iconv_t conv;
+ size_t n;
+
+ inbytes = len;
+
+ outbytes = (inbytes+1) * MB_LEN_MAX;
+
+ /* ensure enought space */
+ out = alloca(outbytes);
+
+ /* convert to local charset */
+ setlocale(LC_CTYPE, "");
+ conv = iconv_open(nl_langinfo(CODESET), "UCS-2BE");
+ if (conv == (iconv_t)(-1)) {
+ return NULL;
+ }
+ src = (char *)buf;
+ str = (char *)out;
+
+ n = iconv(conv, &src, &inbytes, &str, &outbytes);
+ if (n == -1) {
+ /* error */
+ iconv_close(conv);
+ return NULL;
+ }
+ iconv_close(conv);
+ *str = '\0';
+
+ /* remove trailing spaces */
+ for (len = strlen(out) - 1; out[len] == ' ' && len > 0; --len)
+ out[len] = '\0';
+ return strdup(out);
+}
+
+void iso_lib_version(int *major, int *minor, int *micro)
+{
+ *major = LIBISOFS_MAJOR_VERSION;
+ *minor = LIBISOFS_MINOR_VERSION;
+ *micro = LIBISOFS_MICRO_VERSION;
+}
+
+int iso_lib_is_compatible(int major, int minor, int micro)
+{
+ int cmajor, cminor, cmicro;
+
+ /* for now, the rule is that library is compitable if requested
+ * version is lower */
+ iso_lib_version(&cmajor, &cminor, &cmicro);
+
+ return cmajor > major
+ || (cmajor == major
+ && (cminor > minor
+ || (cminor == minor && cmicro >= micro)));
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util.h
new file mode 100644
index 00000000..5a9616c5
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util.h
@@ -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
+#include
+
+#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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util_htable.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util_htable.c
new file mode 100644
index 00000000..684ce6e9
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util_htable.c
@@ -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
+#include
+
+/*
+ * 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;
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util_rbtree.c b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util_rbtree.c
new file mode 100644
index 00000000..7a30fc20
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/util_rbtree.c
@@ -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
+
+/*
+ * 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;
+}
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/writer.h b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/writer.h
new file mode 100644
index 00000000..8d357f8e
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/libisofs/writer.h
@@ -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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/mocked_fsrc.c b/libisofs/tags/ForXorrisoZeroOneTwo/test/mocked_fsrc.c
new file mode 100644
index 00000000..13c6b45d
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/mocked_fsrc.c
@@ -0,0 +1,378 @@
+/*
+ *
+ *
+ */
+
+#include "fsource.h"
+#include "mocked_fsrc.h"
+#include "libisofs.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+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;
+}
+
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/mocked_fsrc.h b/libisofs/tags/ForXorrisoZeroOneTwo/test/mocked_fsrc.h
new file mode 100644
index 00000000..8e92c61c
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/mocked_fsrc.h
@@ -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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/test.c b/libisofs/tags/ForXorrisoZeroOneTwo/test/test.c
new file mode 100644
index 00000000..dd9d0a4f
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/test.c
@@ -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();
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/test.h b/libisofs/tags/ForXorrisoZeroOneTwo/test/test.h
new file mode 100644
index 00000000..6e5e76a5
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/test.h
@@ -0,0 +1,14 @@
+#ifndef TEST_H_
+#define TEST_H_
+
+#include
+#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_*/
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/test_image.c b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_image.c
new file mode 100644
index 00000000..fd0fef6c
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_image.c
@@ -0,0 +1,354 @@
+/*
+ * Unit test for image.h
+ */
+
+
+#include "libisofs.h"
+#include "test.h"
+#include "image.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+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);
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/test_node.c b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_node.c
new file mode 100644
index 00000000..6c2084a5
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_node.c
@@ -0,0 +1,690 @@
+/*
+ * Unit test for node.h
+ */
+
+#include "libisofs.h"
+#include "node.h"
+#include "test.h"
+
+#include
+
+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);
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/test_rockridge.c b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_rockridge.c
new file mode 100644
index 00000000..0a3d411f
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_rockridge.c
@@ -0,0 +1,1395 @@
+/*
+ * Unit test for util.h
+ *
+ * This test utiliy functions
+ */
+#include "test.h"
+#include "ecma119_tree.h"
+#include "rockridge.h"
+#include "node.h"
+
+#include
+
+static void test_rrip_calc_len_file()
+{
+ IsoFile *file;
+ Ecma119Node *node;
+ Ecma119Image t;
+ size_t sua_len = 0, ce_len = 0;
+
+ memset(&t, 0, sizeof(Ecma119Image));
+ t.input_charset = "UTF-8";
+ t.output_charset = "UTF-8";
+
+ file = malloc(sizeof(IsoFile));
+ CU_ASSERT_PTR_NOT_NULL_FATAL(file);
+ file->msblock = 0;
+ file->sort_weight = 0;
+ file->stream = NULL; /* it is not needed here */
+ file->node.type = LIBISO_FILE;
+
+ node = malloc(sizeof(Ecma119Node));
+ CU_ASSERT_PTR_NOT_NULL_FATAL(node);
+ node->node = (IsoNode*)file;
+ node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */
+ node->info.file = NULL; /* it is not needed here */
+ node->type = ECMA119_FILE;
+
+ /* Case 1. Name fit in System Use field */
+ file->node.name = "a small name.txt";
+ node->iso_name = "A_SMALL_.TXT";
+
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 0);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 16) + (5 + 3*7) + 1);
+
+ /* Case 2. Name fits exactly */
+ file->node.name = "a big name, with 133 characters, that it is the max "
+ "that fits in System Use field of the directory record "
+ "PADPADPADADPADPADPADPAD.txt";
+ node->iso_name = "A_BIG_NA.TXT";
+
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 0);
+ /* note that 254 is the max length of a directory record, as it needs to
+ * be an even number */
+ CU_ASSERT_EQUAL(sua_len, 254 - 46);
+
+ /* case 3. A name just 1 character too big to fit in SUA */
+ file->node.name = "a big name, with 133 characters, that it is the max "
+ "that fits in System Use field of the directory record "
+ "PADPADPADADPADPADPADPAD1.txt";
+ node->iso_name = "A_BIG_NA.TXT";
+
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ /* 28 (the chars moved to include the CE entry) + 5 (header of NM in CE) +
+ * 1 (the char that originally didn't fit) */
+ CU_ASSERT_EQUAL(ce_len, 28 + 5 + 1);
+ /* note that 254 is the max length of a directory record, as it needs to
+ * be an even number */
+ CU_ASSERT_EQUAL(sua_len, 254 - 46);
+
+ /* case 4. A 255 characters name */
+ file->node.name = "a big name, with 255 characters, that it is the max "
+ "that a POSIX filename can have. PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
+ "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
+ "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP";
+ node->iso_name = "A_BIG_NA.TXT";
+
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ /* 150 + 5 (header + characters that don't fit in sua) */
+ CU_ASSERT_EQUAL(ce_len, 150 + 5);
+ /* note that 254 is the max length of a directory record, as it needs to
+ * be an even number */
+ CU_ASSERT_EQUAL(sua_len, 254 - 46);
+
+ free(node);
+ free(file);
+}
+
+static void test_rrip_calc_len_symlink()
+{
+ IsoSymlink *link;
+ Ecma119Node *node;
+ Ecma119Image t;
+ size_t sua_len = 0, ce_len = 0;
+
+ memset(&t, 0, sizeof(Ecma119Image));
+ t.input_charset = "UTF-8";
+ t.output_charset = "UTF-8";
+
+ link = malloc(sizeof(IsoSymlink));
+ CU_ASSERT_PTR_NOT_NULL_FATAL(link);
+ link->node.type = LIBISO_SYMLINK;
+
+ node = malloc(sizeof(Ecma119Node));
+ CU_ASSERT_PTR_NOT_NULL_FATAL(node);
+ node->node = (IsoNode*)link;
+ node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */
+ node->type = ECMA119_SYMLINK;
+
+ /* Case 1. Name and dest fit in System Use field */
+ link->node.name = "a small name.txt";
+ link->dest = "/three/components";
+ node->iso_name = "A_SMALL_.TXT";
+
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 0);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 16) + (5 + 3*7) + 1 +
+ (5 + 2 + (2+5) + (2+10)) );
+
+ /* case 2. name + dest fits exactly */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 0);
+ CU_ASSERT_EQUAL(sua_len, 254 - 46);
+
+ /* case 3. name fits, dest is one byte larger to fit */
+ /* 3.a extra byte in dest */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "./and/../a/./big/destination/with/10/componentsk";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 60);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
+
+ /* 3.b extra byte in name */
+ link->node.name = "this name will have 75 characters as it is the max "
+ "that fits in the SUx.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 59);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 75) + (5 + 3*7) + 28);
+
+ /* case 4. name seems to fit, but SL no, and when CE is added NM
+ * doesn't fit too */
+ /* 4.a it just fits */
+ link->node.name = "this name will have 105 characters as it is just the "
+ "max that fits in the SU once we add the CE entry.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 59);
+ CU_ASSERT_EQUAL(sua_len, 254 - 46);
+
+ /* 4.b it just fits, the the component ends in '/' */
+ link->node.name = "this name will have 105 characters as it is just the "
+ "max that fits in the SU once we add the CE entry.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components/";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 59);
+ CU_ASSERT_EQUAL(sua_len, 254 - 46);
+
+ /* 4.c extra char in name, that forces it to be divided */
+ link->node.name = "this name will have 105 characters as it is just the "
+ "max that fits in the SU once we add the CE entryc.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 59 + 6);
+ CU_ASSERT_EQUAL(sua_len, 254 - 46);
+
+ /* 5 max destination length to fit in a single SL entry (250) */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "./and/../a/./very/big/destination/with/10/components/that/"
+ "conforms/the/max/that/fits/in/a/single/SL/as/it/takes/"
+ "just/two/hundred/and/fifty/bytes/bytes/bytes/bytes/bytes"
+ "/bytes/bytes/bytes/bytes/bytes/bytes/../bytes";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 255);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
+
+ /* 6 min destination length to need two SL entries (251) */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "./and/../a/./very/big/destination/with/10/components/that/"
+ "conforms/the/max/that/fits/in/a/single/SL/as/it/takes/"
+ "just/two/hundred/and/fifty/bytes/bytes/bytes/bytes/bytes"
+ "/bytes/bytes/bytes/bytes/bytes/bytes/../bytess";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 261);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
+
+ /* 7 destination with big component that need to be splited
+ * in two SL entries */
+ /* 7.a just fits in one */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "very big component with 248 characters, that is the max that"
+ " fits in a single SL entry. Take care that SL header takes 5 "
+ "bytes, and component header another 2, one for size, another"
+ " for flags. This last characters are just padding to get 248 "
+ "bytes.";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 255);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
+
+ /* 7.b doesn't fits by one character */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "very big component with 249 characters, that is the min that"
+ " doesn't fit in a single SL entry. Take care that SL header "
+ "takes 5 bytes, and component header another 2, one for size,"
+ " another for flags. This last characters are just padding to"
+ " get 249.";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 255 + (5+2+1));
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
+
+ /* 7.c several components before, such as it has just the right len
+ * to fit in the SL entry plus another one */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "the/first/components/take just 245 characters/and thus the "
+ "first SL entry will have/255 - 5 - 245 - 2 (component "
+ "header) = 3/ just the space for another component with a "
+ "single character/This makes that last component fit in exactly 2 "
+ "SLs/very big component with 249 characters, that is the min "
+ "that doesn't fit in a single SL entry. Take care that SL "
+ "header takes 5 bytes, and component header another 2, one "
+ "for size, another for flags. This last characters are just "
+ "padding to get 249.";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 255 + 255);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
+
+ /*
+ * 7.d several components before, and then a big component that doesn't
+ * fit in the 1st SL entry and another one. That case needs a 3rd SL entry,
+ * but instead of divide the component in 2 entries, we put it in 2,
+ * without completelly fill the first one.
+ */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "the/first/components/take just 245 characters/and thus the "
+ "first SL entry will have/255 - 5 - 245 - 2 (component "
+ "header) = 3/ just the space for another component with a "
+ "single character/This makes that last component fit in exactly 2 "
+ "SLs/very big component with 250 characters, that is the min "
+ "that does not fit in a single SL entry. Take care that SL "
+ "header takes 5 bytes, and component header another 2, one "
+ "for size, another for flags. This last characters are just "
+ "padding to get 249.";
+ node->iso_name = "THIS_NAM.TXT";
+ sua_len = rrip_calc_len(&t, node, 0, 255 - 46, &ce_len);
+ CU_ASSERT_EQUAL(ce_len, 252 + 255 + 9);
+ CU_ASSERT_EQUAL(sua_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
+
+ free(link);
+ free(node);
+}
+
+static
+void susp_info_free(struct susp_info *susp)
+{
+ size_t i;
+
+ for (i = 0; i < susp->n_susp_fields; ++i) {
+ free(susp->susp_fields[i]);
+ }
+ free(susp->susp_fields);
+
+ for (i = 0; i < susp->n_ce_susp_fields; ++i) {
+ free(susp->ce_susp_fields[i]);
+ }
+ free(susp->ce_susp_fields);
+}
+
+static
+void test_rrip_get_susp_fields_file()
+{
+ IsoFile *file;
+ Ecma119Node *node;
+ int ret;
+ struct susp_info susp;
+ Ecma119Image t;
+ uint8_t *entry;
+
+ memset(&t, 0, sizeof(Ecma119Image));
+ t.input_charset = "UTF-8";
+ t.output_charset = "UTF-8";
+
+ file = malloc(sizeof(IsoFile));
+ CU_ASSERT_PTR_NOT_NULL_FATAL(file);
+ file->msblock = 0;
+ file->sort_weight = 0;
+ file->stream = NULL; /* it is not needed here */
+ file->node.type = LIBISO_FILE;
+ file->node.mode = S_IFREG | 0555;
+ file->node.uid = 235;
+ file->node.gid = 654;
+ file->node.mtime = 675757578;
+ file->node.atime = 546462546;
+ file->node.ctime = 323245342;
+
+ node = malloc(sizeof(Ecma119Node));
+ CU_ASSERT_PTR_NOT_NULL_FATAL(node);
+ node->node = (IsoNode*)file;
+ node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */
+ node->info.file = NULL; /* it is not needed here */
+ node->type = ECMA119_FILE;
+ node->nlink = 1;
+ node->ino = 0x03447892;
+
+ /* Case 1. Name fit in System Use field */
+ file->node.name = "a small name.txt";
+ node->iso_name = "A_SMALL_.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 0);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0);
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 3); /* PX + TF + NM */
+ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 16) + (5 + 3*7) + 1);
+
+ /* PX is the first entry */
+ entry = susp.susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'P');
+ CU_ASSERT_EQUAL(entry[1], 'X');
+ CU_ASSERT_EQUAL(entry[2], 44);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), S_IFREG | 0555);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), S_IFREG | 0555);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 1);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 235);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 235);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 28, 4), 654);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 32, 4), 654);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 36, 4), 0x03447892);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 40, 4), 0x03447892);
+
+ /* TF is the second entry */
+ entry = susp.susp_fields[1];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'T');
+ CU_ASSERT_EQUAL(entry[1], 'F');
+ CU_ASSERT_EQUAL(entry[2], 5 + 3*7);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0x0E);
+ CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 5), 675757578);
+ CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 12), 546462546);
+ CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 19), 323245342);
+
+ /* NM is the last entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 16);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "a small name.txt", 16);
+
+ susp_info_free(&susp);
+
+ /* Case 2. Name fits exactly */
+ file->node.name = "a big name, with 133 characters, that it is the max "
+ "that fits in System Use field of the directory record "
+ "PADPADPADADPADPADPADPAD.txt";
+ node->iso_name = "A_BIG_NA.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 0);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0);
+ CU_ASSERT_EQUAL(susp.suf_len, 254 - 46);
+
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 3); /* PX + TF + NM */
+
+ /* NM is the last entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 133);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 133 characters, that "
+ "it is the max that fits in System Use field of the "
+ "directory record PADPADPADADPADPADPADPAD.txt", 133);
+
+ susp_info_free(&susp);
+
+ /* case 3. A name just 1 character too big to fit in SUA */
+ file->node.name = "a big name, with 133 characters, that it is the max "
+ "that fits in System Use field of the directory record "
+ "PADPADPADADPADPADPADPAD1.txt";
+ node->iso_name = "A_BIG_NA.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 28 + 5 + 1);
+ CU_ASSERT_EQUAL(susp.suf_len, 254 - 46);
+
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* NM */
+
+ /* test NM entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 105);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 1); /* CONTINUE */
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 133 characters, that "
+ "it is the max that fits in System Use field of the "
+ "directory record", 105);
+
+ /* and CE entry */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'C');
+ CU_ASSERT_EQUAL(entry[1], 'E');
+ CU_ASSERT_EQUAL(entry[2], 28);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 34);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 34);
+
+ /* and check Continuation area */
+ entry = susp.ce_susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 29);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, " PADPADPADADPADPADPADPAD1.txt", 29);
+
+ susp_info_free(&susp);
+
+ /* case 4. A 255 characters name */
+ file->node.name = "a big name, with 255 characters, that it is the max "
+ "that a POSIX filename can have. PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
+ "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
+ "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP";
+ node->iso_name = "A_BIG_NA.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ susp.ce_block = 12;
+ susp.ce_len = 456;
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 150 + 5 + 456);
+ CU_ASSERT_EQUAL(susp.suf_len, 254 - 46);
+
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* NM */
+
+ /* test NM entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 105);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 1); /* CONTINUE */
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "a big name, with 255 characters, that "
+ "it is the max that a POSIX filename can have. PPP"
+ "PPPPPPPPPPPPPPPPPP", 105);
+
+ /* and CE entry */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'C');
+ CU_ASSERT_EQUAL(entry[1], 'E');
+ CU_ASSERT_EQUAL(entry[2], 28);
+ CU_ASSERT_EQUAL(entry[3], 1);
+
+ /* block, offset, size */
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), 12);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), 12);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 456);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 456);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 155);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 155);
+
+ /* and check Continuation area */
+ entry = susp.ce_susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 150);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
+ "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
+ "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP"
+ "PPPPPPPPPPPPPP", 150);
+
+ susp_info_free(&susp);
+
+ free(node);
+ free(file);
+}
+
+static void test_rrip_get_susp_fields_symlink()
+{
+ IsoSymlink *link;
+ Ecma119Node *node;
+ Ecma119Image t;
+ int ret;
+ struct susp_info susp;
+ uint8_t *entry;
+
+ memset(&t, 0, sizeof(Ecma119Image));
+ t.input_charset = "UTF-8";
+ t.output_charset = "UTF-8";
+
+ link = malloc(sizeof(IsoSymlink));
+ CU_ASSERT_PTR_NOT_NULL_FATAL(link);
+ link->node.type = LIBISO_SYMLINK;
+ link->node.mode = S_IFREG | 0555;
+ link->node.uid = 235;
+ link->node.gid = 654;
+ link->node.mtime = 675757578;
+ link->node.atime = 546462546;
+ link->node.ctime = 323245342;
+
+ node = malloc(sizeof(Ecma119Node));
+ CU_ASSERT_PTR_NOT_NULL_FATAL(node);
+ node->node = (IsoNode*)link;
+ node->parent = (Ecma119Node*)0x55555555; /* just to make it not NULL */
+ node->type = ECMA119_SYMLINK;
+ node->nlink = 1;
+ node->ino = 0x03447892;
+
+ /* Case 1. Name and dest fit in System Use field */
+ link->node.name = "a small name.txt";
+ link->dest = "/three/components";
+ node->iso_name = "A_SMALL_.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 0);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0);
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + SL */
+ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 16) + (5 + 3*7) + 1
+ + (5 + 2 + (2 + 5) + (2 + 10)));
+
+ /* PX is the first entry */
+ entry = susp.susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'P');
+ CU_ASSERT_EQUAL(entry[1], 'X');
+ CU_ASSERT_EQUAL(entry[2], 44);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), S_IFREG | 0555);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), S_IFREG | 0555);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 1);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 235);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 235);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 28, 4), 654);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 32, 4), 654);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 36, 4), 0x03447892);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 40, 4), 0x03447892);
+
+ /* TF is the second entry */
+ entry = susp.susp_fields[1];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'T');
+ CU_ASSERT_EQUAL(entry[1], 'F');
+ CU_ASSERT_EQUAL(entry[2], 5 + 3*7);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0x0E);
+ CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 5), 675757578);
+ CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 12), 546462546);
+ CU_ASSERT_EQUAL(iso_datetime_read_7(entry + 19), 323245342);
+
+ /* NM is the 3rd entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 16);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "a small name.txt", 16);
+
+ /* SL is the last entry */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'S');
+ CU_ASSERT_EQUAL(entry[1], 'L');
+ CU_ASSERT_EQUAL(entry[2], 5 + 2 + (2 + 5) + (2 + 10));
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+
+ /* first component */
+ CU_ASSERT_EQUAL(entry[5], 0x8); /* root */
+ CU_ASSERT_EQUAL(entry[6], 0);
+
+ /* 2nd component */
+ CU_ASSERT_EQUAL(entry[7], 0);
+ CU_ASSERT_EQUAL(entry[8], 5);
+ CU_ASSERT_NSTRING_EQUAL(entry + 9, "three", 5);
+
+ /* 3rd component */
+ CU_ASSERT_EQUAL(entry[14], 0);
+ CU_ASSERT_EQUAL(entry[15], 10);
+ CU_ASSERT_NSTRING_EQUAL(entry + 16, "components", 10);
+
+ susp_info_free(&susp);
+
+ /* case 2. name + dest fits exactly */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components";
+ node->iso_name = "THIS_NAM.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 0);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 0);
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + SL */
+ CU_ASSERT_EQUAL(susp.suf_len, 254 - 46);
+
+ /* NM is the 3rd entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 74);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "this name will have 74 characters as "
+ "it is the max that fits in the SU.txt", 74);
+
+ /* SL is the last entry */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'S');
+ CU_ASSERT_EQUAL(entry[1], 'L');
+ CU_ASSERT_EQUAL(entry[2], 5 + 2 + 5 + 2 + 3 + 2 + 5 + 13 + 6 + 4 + 12);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+
+ /* first component */
+ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[6], 0);
+
+ /* 2nd component */
+ CU_ASSERT_EQUAL(entry[7], 0);
+ CU_ASSERT_EQUAL(entry[8], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
+
+ /* 3rd component */
+ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
+ CU_ASSERT_EQUAL(entry[13], 0);
+
+ /* 4th component */
+ CU_ASSERT_EQUAL(entry[14], 0);
+ CU_ASSERT_EQUAL(entry[15], 1);
+ CU_ASSERT_EQUAL(entry[16], 'a');
+
+ /* 5th component */
+ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[18], 0);
+
+ /* 6th component */
+ CU_ASSERT_EQUAL(entry[19], 0);
+ CU_ASSERT_EQUAL(entry[20], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 21, "big", 3);
+
+ /* 7th component */
+ CU_ASSERT_EQUAL(entry[24], 0);
+ CU_ASSERT_EQUAL(entry[25], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 26, "destination", 11);
+
+ /* 8th component */
+ CU_ASSERT_EQUAL(entry[37], 0);
+ CU_ASSERT_EQUAL(entry[38], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 39, "with", 4);
+
+ /* 9th component */
+ CU_ASSERT_EQUAL(entry[43], 0);
+ CU_ASSERT_EQUAL(entry[44], 2);
+ CU_ASSERT_NSTRING_EQUAL(entry + 45, "10", 2);
+
+ /* 10th component */
+ CU_ASSERT_EQUAL(entry[47], 0);
+ CU_ASSERT_EQUAL(entry[48], 10);
+ CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
+
+ susp_info_free(&susp);
+
+ /* case 3. name fits, dest is one byte larger to fit */
+ /* 3.a extra byte in dest */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "./and/../a/./big/destination/with/10/componentsk";
+ node->iso_name = "THIS_NAM.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 60);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* SL */
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
+ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 74) + (5 + 3*7) + 1 + 28);
+
+ /* PX is the first entry */
+ entry = susp.susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'P');
+ CU_ASSERT_EQUAL(entry[1], 'X');
+ CU_ASSERT_EQUAL(entry[2], 44);
+
+ /* TF is the second entry */
+ entry = susp.susp_fields[1];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'T');
+ CU_ASSERT_EQUAL(entry[1], 'F');
+ CU_ASSERT_EQUAL(entry[2], 5 + 3*7);
+
+ /* NM is the 3rd entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 74);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "this name will have 74 characters as "
+ "it is the max that fits in the SU.txt", 74);
+
+ /* and CE entry is last */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'C');
+ CU_ASSERT_EQUAL(entry[1], 'E');
+ CU_ASSERT_EQUAL(entry[2], 28);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 60);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 60);
+
+
+ /* finally, SL is the single entry in CE */
+ entry = susp.ce_susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'S');
+ CU_ASSERT_EQUAL(entry[1], 'L');
+ CU_ASSERT_EQUAL(entry[2], 60);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+
+ /* first component */
+ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[6], 0);
+
+ /* 2nd component */
+ CU_ASSERT_EQUAL(entry[7], 0);
+ CU_ASSERT_EQUAL(entry[8], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
+
+ /* 3rd component */
+ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
+ CU_ASSERT_EQUAL(entry[13], 0);
+
+ /* 4th component */
+ CU_ASSERT_EQUAL(entry[14], 0);
+ CU_ASSERT_EQUAL(entry[15], 1);
+ CU_ASSERT_EQUAL(entry[16], 'a');
+
+ /* 5th component */
+ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[18], 0);
+
+ /* 6th component */
+ CU_ASSERT_EQUAL(entry[19], 0);
+ CU_ASSERT_EQUAL(entry[20], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 21, "big", 3);
+
+ /* 7th component */
+ CU_ASSERT_EQUAL(entry[24], 0);
+ CU_ASSERT_EQUAL(entry[25], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 26, "destination", 11);
+
+ /* 8th component */
+ CU_ASSERT_EQUAL(entry[37], 0);
+ CU_ASSERT_EQUAL(entry[38], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 39, "with", 4);
+
+ /* 9th component */
+ CU_ASSERT_EQUAL(entry[43], 0);
+ CU_ASSERT_EQUAL(entry[44], 2);
+ CU_ASSERT_NSTRING_EQUAL(entry + 45, "10", 2);
+
+ /* 10th component */
+ CU_ASSERT_EQUAL(entry[47], 0);
+ CU_ASSERT_EQUAL(entry[48], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 49, "componentsk", 11);
+
+ susp_info_free(&susp);
+
+ /* 3.b extra byte in name */
+ link->node.name = "this name will have 75 characters as it is the max "
+ "that fits in the SUx.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components";
+ node->iso_name = "THIS_NAM.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 59);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* SL */
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
+ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 75) + (5 + 3*7) + 28);
+
+ /* NM is the 3rd entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 75);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "this name will have 75 characters as it "
+ "is the max that fits in the SUx.txt", 75);
+
+ /* and CE entry is last */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'C');
+ CU_ASSERT_EQUAL(entry[1], 'E');
+ CU_ASSERT_EQUAL(entry[2], 28);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 59);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 59);
+
+
+ /* finally, SL is the single entry in CE */
+ entry = susp.ce_susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'S');
+ CU_ASSERT_EQUAL(entry[1], 'L');
+ CU_ASSERT_EQUAL(entry[2], 59);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+
+ /* first component */
+ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[6], 0);
+
+ /* 2nd component */
+ CU_ASSERT_EQUAL(entry[7], 0);
+ CU_ASSERT_EQUAL(entry[8], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
+
+ /* 3rd component */
+ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
+ CU_ASSERT_EQUAL(entry[13], 0);
+
+ /* 4th component */
+ CU_ASSERT_EQUAL(entry[14], 0);
+ CU_ASSERT_EQUAL(entry[15], 1);
+ CU_ASSERT_EQUAL(entry[16], 'a');
+
+ /* 5th component */
+ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[18], 0);
+
+ /* 6th component */
+ CU_ASSERT_EQUAL(entry[19], 0);
+ CU_ASSERT_EQUAL(entry[20], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 21, "big", 3);
+
+ /* 7th component */
+ CU_ASSERT_EQUAL(entry[24], 0);
+ CU_ASSERT_EQUAL(entry[25], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 26, "destination", 11);
+
+ /* 8th component */
+ CU_ASSERT_EQUAL(entry[37], 0);
+ CU_ASSERT_EQUAL(entry[38], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 39, "with", 4);
+
+ /* 9th component */
+ CU_ASSERT_EQUAL(entry[43], 0);
+ CU_ASSERT_EQUAL(entry[44], 2);
+ CU_ASSERT_NSTRING_EQUAL(entry + 45, "10", 2);
+
+ /* 10th component */
+ CU_ASSERT_EQUAL(entry[47], 0);
+ CU_ASSERT_EQUAL(entry[48], 10);
+ CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
+
+ susp_info_free(&susp);
+
+ /* case 4. name seems to fit, but SL no, and when CE is added NM
+ * doesn't fit too */
+ /* 4.a it just fits */
+ link->node.name = "this name will have 105 characters as it is just the "
+ "max that fits in the SU once we add the CE entry.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components";
+ node->iso_name = "THIS_NAM.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 59);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* SL */
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
+ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 3*7) + (5 + 105) + 28);
+
+ /* NM is the 3rd entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 105);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "this name will have 105 characters as "
+ "it is just the max that fits in the SU once we "
+ "add the CE entry.txt", 105);
+
+ /* and CE entry is last */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'C');
+ CU_ASSERT_EQUAL(entry[1], 'E');
+ CU_ASSERT_EQUAL(entry[2], 28);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 59);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 59);
+
+ /* finally, SL is the single entry in CE */
+ entry = susp.ce_susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'S');
+ CU_ASSERT_EQUAL(entry[1], 'L');
+ CU_ASSERT_EQUAL(entry[2], 59);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+
+ /* first component */
+ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[6], 0);
+
+ /* 2nd component */
+ CU_ASSERT_EQUAL(entry[7], 0);
+ CU_ASSERT_EQUAL(entry[8], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
+
+ /* 3rd component */
+ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
+ CU_ASSERT_EQUAL(entry[13], 0);
+
+ /* 4th component */
+ CU_ASSERT_EQUAL(entry[14], 0);
+ CU_ASSERT_EQUAL(entry[15], 1);
+ CU_ASSERT_EQUAL(entry[16], 'a');
+
+ /* 5th component */
+ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[18], 0);
+
+ /* 6th component */
+ CU_ASSERT_EQUAL(entry[19], 0);
+ CU_ASSERT_EQUAL(entry[20], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 21, "big", 3);
+
+ /* 7th component */
+ CU_ASSERT_EQUAL(entry[24], 0);
+ CU_ASSERT_EQUAL(entry[25], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 26, "destination", 11);
+
+ /* 8th component */
+ CU_ASSERT_EQUAL(entry[37], 0);
+ CU_ASSERT_EQUAL(entry[38], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 39, "with", 4);
+
+ /* 9th component */
+ CU_ASSERT_EQUAL(entry[43], 0);
+ CU_ASSERT_EQUAL(entry[44], 2);
+ CU_ASSERT_NSTRING_EQUAL(entry + 45, "10", 2);
+
+ /* 10th component */
+ CU_ASSERT_EQUAL(entry[47], 0);
+ CU_ASSERT_EQUAL(entry[48], 10);
+ CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
+
+ susp_info_free(&susp);
+
+ /* 4.b it just fits, the the component ends in '/' */
+ link->node.name = "this name will have 105 characters as it is just the "
+ "max that fits in the SU once we add the CE entry.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components/";
+ node->iso_name = "THIS_NAM.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 59);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* SL */
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
+ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 3*7) + (5 + 105) + 28);
+
+ /* NM is the 3rd entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 105);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "this name will have 105 characters as "
+ "it is just the max that fits in the SU once we "
+ "add the CE entry.txt", 105);
+
+ /* and CE entry is last */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'C');
+ CU_ASSERT_EQUAL(entry[1], 'E');
+ CU_ASSERT_EQUAL(entry[2], 28);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 59);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 59);
+
+ /* finally, SL is the single entry in CE */
+ entry = susp.ce_susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'S');
+ CU_ASSERT_EQUAL(entry[1], 'L');
+ CU_ASSERT_EQUAL(entry[2], 59);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+
+ /* first component */
+ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[6], 0);
+
+ /* 2nd component */
+ CU_ASSERT_EQUAL(entry[7], 0);
+ CU_ASSERT_EQUAL(entry[8], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
+
+ /* 3rd component */
+ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
+ CU_ASSERT_EQUAL(entry[13], 0);
+
+ /* 4th component */
+ CU_ASSERT_EQUAL(entry[14], 0);
+ CU_ASSERT_EQUAL(entry[15], 1);
+ CU_ASSERT_EQUAL(entry[16], 'a');
+
+ /* 5th component */
+ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[18], 0);
+
+ /* 6th component */
+ CU_ASSERT_EQUAL(entry[19], 0);
+ CU_ASSERT_EQUAL(entry[20], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 21, "big", 3);
+
+ /* 7th component */
+ CU_ASSERT_EQUAL(entry[24], 0);
+ CU_ASSERT_EQUAL(entry[25], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 26, "destination", 11);
+
+ /* 8th component */
+ CU_ASSERT_EQUAL(entry[37], 0);
+ CU_ASSERT_EQUAL(entry[38], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 39, "with", 4);
+
+ /* 9th component */
+ CU_ASSERT_EQUAL(entry[43], 0);
+ CU_ASSERT_EQUAL(entry[44], 2);
+ CU_ASSERT_NSTRING_EQUAL(entry + 45, "10", 2);
+
+ /* 10th component */
+ CU_ASSERT_EQUAL(entry[47], 0);
+ CU_ASSERT_EQUAL(entry[48], 10);
+ CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
+
+ susp_info_free(&susp);
+
+ /* 4.c extra char in name, that forces it to be divided */
+ link->node.name = "this name will have 106 characters as it is just the "
+ "max that fits in the SU once we add the CE entryc.txt";
+ link->dest = "./and/../a/./big/destination/with/10/components";
+ node->iso_name = "THIS_NAM.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 6 + 59);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 2); /* NM + SL */
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
+ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 3*7) + (5 + 105) + 28);
+
+ /* NM is the 3rd entry */
+ entry = susp.susp_fields[2];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 105);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0x1); /* continue */
+ CU_ASSERT_NSTRING_EQUAL(entry + 5, "this name will have 106 characters as "
+ "it is just the max that fits in the SU once we "
+ "add the CE entryc.tx", 105);
+
+ /* and CE entry is last */
+ entry = susp.susp_fields[3];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'C');
+ CU_ASSERT_EQUAL(entry[1], 'E');
+ CU_ASSERT_EQUAL(entry[2], 28);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 4, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 8, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 12, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 16, 4), 0);
+ CU_ASSERT_EQUAL(iso_read_lsb(entry + 20, 4), 59 + 6);
+ CU_ASSERT_EQUAL(iso_read_msb(entry + 24, 4), 59 + 6);
+
+ /* NM is the 1st entry in CE */
+ entry = susp.ce_susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'N');
+ CU_ASSERT_EQUAL(entry[1], 'M');
+ CU_ASSERT_EQUAL(entry[2], 5 + 1);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+ CU_ASSERT_EQUAL(entry[5], 't');
+
+ /* finally, SL is the single entry in CE */
+ entry = susp.ce_susp_fields[1];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'S');
+ CU_ASSERT_EQUAL(entry[1], 'L');
+ CU_ASSERT_EQUAL(entry[2], 59);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+
+ /* first component */
+ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[6], 0);
+
+ /* 2nd component */
+ CU_ASSERT_EQUAL(entry[7], 0);
+ CU_ASSERT_EQUAL(entry[8], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
+
+ /* 3rd component */
+ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
+ CU_ASSERT_EQUAL(entry[13], 0);
+
+ /* 4th component */
+ CU_ASSERT_EQUAL(entry[14], 0);
+ CU_ASSERT_EQUAL(entry[15], 1);
+ CU_ASSERT_EQUAL(entry[16], 'a');
+
+ /* 5th component */
+ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[18], 0);
+
+ /* 6th component */
+ CU_ASSERT_EQUAL(entry[19], 0);
+ CU_ASSERT_EQUAL(entry[20], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 21, "big", 3);
+
+ /* 7th component */
+ CU_ASSERT_EQUAL(entry[24], 0);
+ CU_ASSERT_EQUAL(entry[25], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 26, "destination", 11);
+
+ /* 8th component */
+ CU_ASSERT_EQUAL(entry[37], 0);
+ CU_ASSERT_EQUAL(entry[38], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 39, "with", 4);
+
+ /* 9th component */
+ CU_ASSERT_EQUAL(entry[43], 0);
+ CU_ASSERT_EQUAL(entry[44], 2);
+ CU_ASSERT_NSTRING_EQUAL(entry + 45, "10", 2);
+
+ /* 10th component */
+ CU_ASSERT_EQUAL(entry[47], 0);
+ CU_ASSERT_EQUAL(entry[48], 10);
+ CU_ASSERT_NSTRING_EQUAL(entry + 49, "components", 10);
+
+ susp_info_free(&susp);
+
+ /* 5 max destination length to fit in a single SL entry (250) */
+ link->node.name = "this name will have 74 characters as it is the max "
+ "that fits in the SU.txt";
+ link->dest = "./and/../a/./very/big/destination/with/10/components/that/"
+ "conforms/the/max/that/fits/in/a single SL/entry as it takes "
+ "just two hundred and/fifty bytes bytes bytes bytes/bytes"
+ " bytes bytes bytes bytes bytes bytes bytes bytes/../bytes";
+ node->iso_name = "THIS_NAM.TXT";
+
+ memset(&susp, 0, sizeof(struct susp_info));
+ ret = rrip_get_susp_fields(&t, node, 0, 255 - 46, &susp);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_EQUAL(susp.ce_len, 255);
+ CU_ASSERT_EQUAL(susp.n_ce_susp_fields, 1); /* SL */
+ CU_ASSERT_EQUAL(susp.n_susp_fields, 4); /* PX + TF + NM + CE */
+ CU_ASSERT_EQUAL(susp.suf_len, 44 + (5 + 3*7) + (5 + 74) + 1 + 28);
+
+ /* just check the SL entry */
+ entry = susp.ce_susp_fields[0];
+ CU_ASSERT_PTR_NOT_NULL(entry);
+ CU_ASSERT_EQUAL(entry[0], 'S');
+ CU_ASSERT_EQUAL(entry[1], 'L');
+ CU_ASSERT_EQUAL(entry[2], 255);
+ CU_ASSERT_EQUAL(entry[3], 1);
+ CU_ASSERT_EQUAL(entry[4], 0);
+
+ /* first component */
+ CU_ASSERT_EQUAL(entry[5], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[6], 0);
+
+ /* 2nd component */
+ CU_ASSERT_EQUAL(entry[7], 0);
+ CU_ASSERT_EQUAL(entry[8], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 9, "and", 3);
+
+ /* 3rd component */
+ CU_ASSERT_EQUAL(entry[12], 0x4); /* parent */
+ CU_ASSERT_EQUAL(entry[13], 0);
+
+ /* 4th component */
+ CU_ASSERT_EQUAL(entry[14], 0);
+ CU_ASSERT_EQUAL(entry[15], 1);
+ CU_ASSERT_EQUAL(entry[16], 'a');
+
+ /* 5th component */
+ CU_ASSERT_EQUAL(entry[17], 0x2); /* current */
+ CU_ASSERT_EQUAL(entry[18], 0);
+
+ /* 6th component */
+ CU_ASSERT_EQUAL(entry[19], 0);
+ CU_ASSERT_EQUAL(entry[20], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 21, "very", 4);
+
+ /* 7th component */
+ CU_ASSERT_EQUAL(entry[25], 0);
+ CU_ASSERT_EQUAL(entry[26], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 27, "big", 3);
+
+ /* 8th component */
+ CU_ASSERT_EQUAL(entry[30], 0);
+ CU_ASSERT_EQUAL(entry[31], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 32, "destination", 11);
+
+ /* 9th component */
+ CU_ASSERT_EQUAL(entry[43], 0);
+ CU_ASSERT_EQUAL(entry[44], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 45, "with", 4);
+
+ /* 10th component */
+ CU_ASSERT_EQUAL(entry[49], 0);
+ CU_ASSERT_EQUAL(entry[50], 2);
+ CU_ASSERT_NSTRING_EQUAL(entry + 51, "10", 2);
+
+ /* 11th component */
+ CU_ASSERT_EQUAL(entry[53], 0);
+ CU_ASSERT_EQUAL(entry[54], 10);
+ CU_ASSERT_NSTRING_EQUAL(entry + 55, "components", 10);
+
+ /* 12th component */
+ CU_ASSERT_EQUAL(entry[65], 0);
+ CU_ASSERT_EQUAL(entry[66], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 67, "that", 4);
+
+ /* 13th component */
+ CU_ASSERT_EQUAL(entry[71], 0);
+ CU_ASSERT_EQUAL(entry[72], 8);
+ CU_ASSERT_NSTRING_EQUAL(entry + 73, "conforms", 8);
+
+ /* 14th component */
+ CU_ASSERT_EQUAL(entry[81], 0);
+ CU_ASSERT_EQUAL(entry[82], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 83, "the", 3);
+
+ /* 15th component */
+ CU_ASSERT_EQUAL(entry[86], 0);
+ CU_ASSERT_EQUAL(entry[87], 3);
+ CU_ASSERT_NSTRING_EQUAL(entry + 88, "max", 3);
+
+ /* 16th component */
+ CU_ASSERT_EQUAL(entry[91], 0);
+ CU_ASSERT_EQUAL(entry[92], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 93, "that", 4);
+
+ /* 17th component */
+ CU_ASSERT_EQUAL(entry[97], 0);
+ CU_ASSERT_EQUAL(entry[98], 4);
+ CU_ASSERT_NSTRING_EQUAL(entry + 99, "fits", 4);
+
+ /* 18th component */
+ CU_ASSERT_EQUAL(entry[103], 0);
+ CU_ASSERT_EQUAL(entry[104], 2);
+ CU_ASSERT_NSTRING_EQUAL(entry + 105, "in", 2);
+
+ /* 19th component */
+ CU_ASSERT_EQUAL(entry[107], 0);
+ CU_ASSERT_EQUAL(entry[108], 11);
+ CU_ASSERT_NSTRING_EQUAL(entry + 109, "a single SL", 11);
+
+ /* 20th component */
+ CU_ASSERT_EQUAL(entry[120], 0);
+ CU_ASSERT_EQUAL(entry[121], 38);
+ CU_ASSERT_NSTRING_EQUAL(entry + 122, "entry as it takes "
+ "just two hundred and", 38);
+
+ /* 21th component */
+ CU_ASSERT_EQUAL(entry[160], 0);
+ CU_ASSERT_EQUAL(entry[161], 29);
+ CU_ASSERT_NSTRING_EQUAL(entry + 162, "fifty bytes bytes bytes bytes", 29);
+
+ /* 22th component */
+ CU_ASSERT_EQUAL(entry[191], 0);
+ CU_ASSERT_EQUAL(entry[192], 53);
+ CU_ASSERT_NSTRING_EQUAL(entry + 193, "bytes bytes bytes bytes bytes bytes"
+ " bytes bytes bytes", 53);
+
+ /* 23th component */
+ CU_ASSERT_EQUAL(entry[246], 0x4); /* parent */
+ CU_ASSERT_EQUAL(entry[247], 0);
+
+ /* 24th component */
+ CU_ASSERT_EQUAL(entry[248], 0);
+ CU_ASSERT_EQUAL(entry[249], 5);
+ CU_ASSERT_NSTRING_EQUAL(entry + 250, "bytes", 5);
+
+ susp_info_free(&susp);
+
+ free(node);
+ free(link);
+}
+
+void add_rockridge_suite()
+{
+ CU_pSuite pSuite = CU_add_suite("RockRidge Suite", NULL, NULL);
+
+ CU_add_test(pSuite, "rrip_calc_len(file)", test_rrip_calc_len_file);
+ CU_add_test(pSuite, "rrip_calc_len(symlink)", test_rrip_calc_len_symlink);
+ CU_add_test(pSuite, "rrip_get_susp_fields(file)", test_rrip_get_susp_fields_file);
+ CU_add_test(pSuite, "rrip_get_susp_fields(symlink)", test_rrip_get_susp_fields_symlink);
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/test_stream.c b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_stream.c
new file mode 100644
index 00000000..35e14666
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_stream.c
@@ -0,0 +1,155 @@
+/*
+ * Unit test for util.h
+ *
+ * This test utiliy functions
+ */
+#include "test.h"
+#include "stream.h"
+
+#include
+
+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);
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/test_tree.c b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_tree.c
new file mode 100644
index 00000000..8379439c
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_tree.c
@@ -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
+
+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);
+
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/test/test_util.c b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_util.c
new file mode 100644
index 00000000..0852e926
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/test/test_util.c
@@ -0,0 +1,1072 @@
+/*
+ * Unit test for util.h
+ *
+ * This test utiliy functions
+ */
+#include "test.h"
+#include "util.h"
+
+#include
+#include
+#include
+
+static void test_int_pow()
+{
+ CU_ASSERT_EQUAL(int_pow(1, 2), 1);
+ CU_ASSERT_EQUAL(int_pow(2, 2), 4);
+ CU_ASSERT_EQUAL(int_pow(0, 2), 0);
+ CU_ASSERT_EQUAL(int_pow(-1, 2), 1);
+ CU_ASSERT_EQUAL(int_pow(-1, 3), -1);
+ CU_ASSERT_EQUAL(int_pow(3, 2), 9);
+ CU_ASSERT_EQUAL(int_pow(3, 10), 59049);
+}
+
+static void test_strconv()
+{
+ int ret;
+ char *out;
+
+ /* Prova de cadeia com codificação ISO-8859-15 */
+ unsigned char in1[45] =
+ {0x50, 0x72, 0x6f, 0x76, 0x61, 0x20, 0x64, 0x65, 0x20, 0x63, 0x61,
+ 0x64, 0x65, 0x69, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x20, 0x63, 0x6f,
+ 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0xe7, 0xe3, 0x6f, 0x20, 0x49,
+ 0x53, 0x4f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, 0x31, 0x35, 0x0a,
+ 0x00}; /* encoded in ISO-8859-15 */
+ unsigned char out1[47] =
+ {0x50, 0x72, 0x6f, 0x76, 0x61, 0x20, 0x64, 0x65, 0x20, 0x63, 0x61,
+ 0x64, 0x65, 0x69, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x20, 0x63, 0x6f,
+ 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0xc3, 0xa7, 0xc3, 0xa3, 0x6f,
+ 0x20, 0x49, 0x53, 0x4f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, 0x31,
+ 0x35, 0x0a, 0x00}; /* encoded in UTF-8 */
+ unsigned char in2[45] =
+ {0x50, 0x72, 0x6f, 0x76, 0x61, 0x20, 0x64, 0x65, 0x20, 0x63, 0x61,
+ 0x64, 0x65, 0x69, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x20, 0x63, 0x6f,
+ 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0xe7, 0xe3, 0x6f, 0x20, 0x49,
+ 0x53, 0x4f, 0x2d, 0x38, 0x38, 0xff, 0xff, 0x2d, 0x31, 0x35, 0x0a,
+ 0x00}; /* incorrect encoding */
+
+ /* ISO-8859-15 to UTF-8 */
+ ret = strconv((char*)in1, "ISO-8859-15", "UTF-8", &out);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_STRING_EQUAL(out, (char*)out1);
+ free(out);
+
+ /* UTF-8 to ISO-8859-15 */
+ ret = strconv((char*)out1, "UTF-8", "ISO-8859-15", &out);
+ CU_ASSERT_EQUAL(ret, 1);
+ CU_ASSERT_STRING_EQUAL(out, (char*)in1);
+ free(out);
+
+ /* try with an incorrect input */
+ ret = strconv((char*)in2, "UTF-8", "ISO-8859-15", &out);
+ CU_ASSERT_EQUAL(ret, ISO_CHARSET_CONV_ERROR);
+}
+
+static void test_div_up()
+{
+ CU_ASSERT_EQUAL( DIV_UP(1, 2), 1 );
+ CU_ASSERT_EQUAL( DIV_UP(2, 2), 1 );
+ CU_ASSERT_EQUAL( DIV_UP(0, 2), 0 );
+ CU_ASSERT_EQUAL( DIV_UP(-1, 2), 0 );
+ CU_ASSERT_EQUAL( DIV_UP(3, 2), 2 );
+}
+
+static void test_round_up()
+{
+ CU_ASSERT_EQUAL( ROUND_UP(1, 2), 2 );
+ CU_ASSERT_EQUAL( ROUND_UP(2, 2), 2 );
+ CU_ASSERT_EQUAL( ROUND_UP(0, 2), 0 );
+ CU_ASSERT_EQUAL( ROUND_UP(-1, 2), 0 );
+ CU_ASSERT_EQUAL( ROUND_UP(3, 2), 4 );
+ CU_ASSERT_EQUAL( ROUND_UP(15, 7), 21 );
+ CU_ASSERT_EQUAL( ROUND_UP(13, 7), 14 );
+ CU_ASSERT_EQUAL( ROUND_UP(14, 7), 14 );
+}
+
+static void test_iso_lsb_msb()
+{
+ uint8_t buf[4];
+ uint32_t num;
+
+ num = 0x01020304;
+ iso_lsb(buf, num, 4);
+ CU_ASSERT_EQUAL( buf[0], 0x04 );
+ CU_ASSERT_EQUAL( buf[1], 0x03 );
+ CU_ASSERT_EQUAL( buf[2], 0x02 );
+ CU_ASSERT_EQUAL( buf[3], 0x01 );
+
+ iso_msb(buf, num, 4);
+ CU_ASSERT_EQUAL( buf[0], 0x01 );
+ CU_ASSERT_EQUAL( buf[1], 0x02 );
+ CU_ASSERT_EQUAL( buf[2], 0x03 );
+ CU_ASSERT_EQUAL( buf[3], 0x04 );
+
+ iso_lsb(buf, num, 2);
+ CU_ASSERT_EQUAL( buf[0], 0x04 );
+ CU_ASSERT_EQUAL( buf[1], 0x03 );
+
+ iso_msb(buf, num, 2);
+ CU_ASSERT_EQUAL( buf[0], 0x03 );
+ CU_ASSERT_EQUAL( buf[1], 0x04 );
+}
+
+static void test_iso_read_lsb_msb()
+{
+ uint8_t buf[4];
+ uint32_t num;
+
+ buf[0] = 0x04;
+ buf[1] = 0x03;
+ buf[2] = 0x02;
+ buf[3] = 0x01;
+
+ num = iso_read_lsb(buf, 4);
+ CU_ASSERT_EQUAL(num, 0x01020304);
+
+ num = iso_read_msb(buf, 4);
+ CU_ASSERT_EQUAL(num, 0x04030201);
+
+ num = iso_read_lsb(buf, 2);
+ CU_ASSERT_EQUAL(num, 0x0304);
+
+ num = iso_read_msb(buf, 2);
+ CU_ASSERT_EQUAL(num, 0x0403);
+}
+
+static void test_iso_bb()
+{
+ uint8_t buf[8];
+ uint32_t num;
+
+ num = 0x01020304;
+ iso_bb(buf, num, 4);
+ CU_ASSERT_EQUAL( buf[0], 0x04 );
+ CU_ASSERT_EQUAL( buf[1], 0x03 );
+ CU_ASSERT_EQUAL( buf[2], 0x02 );
+ CU_ASSERT_EQUAL( buf[3], 0x01 );
+ CU_ASSERT_EQUAL( buf[4], 0x01 );
+ CU_ASSERT_EQUAL( buf[5], 0x02 );
+ CU_ASSERT_EQUAL( buf[6], 0x03 );
+ CU_ASSERT_EQUAL( buf[7], 0x04 );
+
+ iso_bb(buf, num, 2);
+ CU_ASSERT_EQUAL( buf[0], 0x04 );
+ CU_ASSERT_EQUAL( buf[1], 0x03 );
+ CU_ASSERT_EQUAL( buf[2], 0x03 );
+ CU_ASSERT_EQUAL( buf[3], 0x04 );
+}
+
+static void test_iso_datetime_7()
+{
+ uint8_t buf[7];
+ time_t t1, t2, tr;
+ char *tz;
+ struct tm tp;
+
+ tz = getenv("TZ");
+
+ setenv("TZ", "", 1);
+ tzset();
+
+ strptime("01-03-1976 13:27:45", "%d-%m-%Y %T", &tp);
+ t1 = mktime(&tp); /* t1 in GMT */
+
+ strptime("01-07-2007 13:27:45", "%d-%m-%Y %T", &tp);
+ t2 = mktime(&tp); /* t1 in GMT (summer time) */
+
+ /* ----------------- European Timezones ----------------------*/
+ setenv("TZ", "Europe/Madrid", 1);
+ tzset();
+
+ iso_datetime_7(buf, t1, 0);
+ CU_ASSERT_EQUAL(buf[0], 76); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 3); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 14); /* hour (GMT+1) */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 4); /* GMT+1 hour for CET */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ iso_datetime_7(buf, t2, 0);
+ CU_ASSERT_EQUAL(buf[0], 107); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 7); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 15); /* hour (GMT+2, summer time) */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 8); /* GMT+2 hour for CEST */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Europe/London", 1);
+ tzset();
+
+ iso_datetime_7(buf, t1, 0);
+ CU_ASSERT_EQUAL(buf[0], 76); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 3); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 13); /* hour (GMT+0) */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 0); /* GMT+0 */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ iso_datetime_7(buf, t2, 0);
+ CU_ASSERT_EQUAL(buf[0], 107); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 7); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 14); /* hour (GMT+1, summer time) */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 4); /* GMT+1 */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ /* ----------------- American Timezones ----------------------*/
+ setenv("TZ", "America/New_York", 1);
+ tzset();
+
+ iso_datetime_7(buf, t1, 0);
+ CU_ASSERT_EQUAL(buf[0], 76); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 3); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 8); /* hour */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], -5*4); /* GMT-5 for EST */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ /* ----------------- Asia Timezones ----------------------*/
+ setenv("TZ", "Asia/Hong_Kong", 1);
+ tzset();
+
+ iso_datetime_7(buf, t1, 0);
+ CU_ASSERT_EQUAL(buf[0], 76); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 3); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 21); /* hour */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 8*4); /* GMT+8 */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ /* read from another timestamp */
+ setenv("TZ", "Europe/Madrid", 1);
+ tzset();
+
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ /* ----------------- Africa Timezones ----------------------*/
+
+ /* Africa country without Daylight saving time */
+ setenv("TZ", "Africa/Luanda", 1);
+ tzset();
+
+ iso_datetime_7(buf, t1, 0);
+ CU_ASSERT_EQUAL(buf[0], 76); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 3); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 14); /* hour (GMT+1) */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 4); /* GMT+1 hour */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ iso_datetime_7(buf, t2, 0);
+ CU_ASSERT_EQUAL(buf[0], 107); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 7); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 14); /* hour (GMT+1, no summer time) */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 4); /* GMT+1 hour */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ /* ----------------- Australia Timezones ----------------------*/
+
+ /* this is GMT+9:30 (note that in South summer is winter in North) */
+ setenv("TZ", "Australia/Broken_Hill", 1);
+ tzset();
+
+ iso_datetime_7(buf, t1, 0);
+ CU_ASSERT_EQUAL(buf[0], 76); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 3); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 23); /* hour GMT+9+1 (summer time!!) */
+ CU_ASSERT_EQUAL(buf[4], 57); /* minute + 30 */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 42); /* GMT+9:30 hour + 1 (summer time) */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ iso_datetime_7(buf, t2, 0);
+ CU_ASSERT_EQUAL(buf[0], 107); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 7); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 22); /* hour (GMT+9) */
+ CU_ASSERT_EQUAL(buf[4], 57); /* minute +30 */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 38); /* GMT+9:30 */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ /* ----------------- Pacific Timezones ----------------------*/
+
+ /* this is GMT+13, the max supported */
+ setenv("TZ", "Pacific/Tongatapu", 1);
+ tzset();
+
+ iso_datetime_7(buf, t1, 0);
+ CU_ASSERT_EQUAL(buf[0], 76); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 3); /* month */
+ CU_ASSERT_EQUAL(buf[2], 2); /* day */
+ CU_ASSERT_EQUAL(buf[3], 2); /* hour (GMT+13) */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], 52); /* GMT+13 hour */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ /* this is GMT-11, I can't found a -12 timezone */
+ setenv("TZ", "Pacific/Pago_Pago", 1);
+ tzset();
+
+ iso_datetime_7(buf, t1, 0);
+ CU_ASSERT_EQUAL(buf[0], 76); /* year since 1900 */
+ CU_ASSERT_EQUAL(buf[1], 3); /* month */
+ CU_ASSERT_EQUAL(buf[2], 1); /* day */
+ CU_ASSERT_EQUAL(buf[3], 2); /* hour (GMT-11) */
+ CU_ASSERT_EQUAL(buf[4], 27); /* minute */
+ CU_ASSERT_EQUAL(buf[5], 45); /* second */
+ CU_ASSERT_EQUAL((int8_t)buf[6], -44); /* GMT-11 hour */
+
+ /* check that reading returns the same time */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+
+ /* --- and now test from several zones, just for write/read compatibilty */
+ setenv("TZ", "Pacific/Kiritimati", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 1); /* this needs GMT */
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "America/Argentina/La_Rioja", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "America/Argentina/La_Rioja", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "America/Caracas", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Asia/Bangkok", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Asia/Tehran", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Pacific/Pitcairn", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Antarctica/McMurdo", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "EET", 1); /* Eastern European Time */
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Europe/Moscow", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Asia/Novosibirsk", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Asia/Vladivostok", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Asia/Anadyr", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Atlantic/Canary", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "Indian/Mauritius", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ iso_datetime_7(buf, t1, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t1);
+ iso_datetime_7(buf, t2, 0);
+ tr = iso_datetime_read_7(buf);
+ CU_ASSERT_EQUAL(tr, t2);
+
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+}
+
+static void test_iso_1_dirid()
+{
+ char *dir;
+ dir = iso_1_dirid("dir1");
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+ dir = iso_1_dirid("dIR1");
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+ dir = iso_1_dirid("DIR1");
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+ dir = iso_1_dirid("dirwithbigname");
+ CU_ASSERT_STRING_EQUAL(dir, "DIRWITHB");
+ free(dir);
+ dir = iso_1_dirid("dirwith8");
+ CU_ASSERT_STRING_EQUAL(dir, "DIRWITH8");
+ free(dir);
+ dir = iso_1_dirid("dir.1");
+ CU_ASSERT_STRING_EQUAL(dir, "DIR_1");
+ free(dir);
+ dir = iso_1_dirid("4f<0KmM::xcvf");
+ CU_ASSERT_STRING_EQUAL(dir, "4F_0KMM_");
+ free(dir);
+}
+
+static void test_iso_2_dirid()
+{
+ char *dir;
+ dir = iso_2_dirid("dir1");
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+ dir = iso_2_dirid("dIR1");
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+ dir = iso_2_dirid("DIR1");
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+ dir = iso_2_dirid("dirwithbigname");
+ CU_ASSERT_STRING_EQUAL(dir, "DIRWITHBIGNAME");
+ free(dir);
+ dir = iso_2_dirid("dirwith8");
+ CU_ASSERT_STRING_EQUAL(dir, "DIRWITH8");
+ free(dir);
+ dir = iso_2_dirid("dir.1");
+ CU_ASSERT_STRING_EQUAL(dir, "DIR_1");
+ free(dir);
+ dir = iso_2_dirid("4f<0KmM::xcvf");
+ CU_ASSERT_STRING_EQUAL(dir, "4F_0KMM__XCVF");
+ free(dir);
+ dir = iso_2_dirid("directory with 31 characters ok");
+ CU_ASSERT_STRING_EQUAL(dir, "DIRECTORY_WITH_31_CHARACTERS_OK");
+ free(dir);
+ dir = iso_2_dirid("directory with more than 31 characters");
+ CU_ASSERT_STRING_EQUAL(dir, "DIRECTORY_WITH_MORE_THAN_31_CHA");
+ free(dir);
+}
+
+static void test_iso_1_fileid()
+{
+ char *file;
+ file = iso_1_fileid("file1");
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+ file = iso_1_fileid("fILe1");
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+ file = iso_1_fileid("FILE1");
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+ file = iso_1_fileid(".EXT");
+ CU_ASSERT_STRING_EQUAL(file, ".EXT");
+ free(file);
+ file = iso_1_fileid("file.ext");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_1_fileid("fiLE.ext");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_1_fileid("file.EXt");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_1_fileid("FILE.EXT");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_1_fileid("bigfilename");
+ CU_ASSERT_STRING_EQUAL(file, "BIGFILEN.");
+ free(file);
+ file = iso_1_fileid("bigfilename.ext");
+ CU_ASSERT_STRING_EQUAL(file, "BIGFILEN.EXT");
+ free(file);
+ file = iso_1_fileid("bigfilename.e");
+ CU_ASSERT_STRING_EQUAL(file, "BIGFILEN.E");
+ free(file);
+ file = iso_1_fileid("file.bigext");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.BIG");
+ free(file);
+ file = iso_1_fileid(".bigext");
+ CU_ASSERT_STRING_EQUAL(file, ".BIG");
+ free(file);
+ file = iso_1_fileid("bigfilename.bigext");
+ CU_ASSERT_STRING_EQUAL(file, "BIGFILEN.BIG");
+ free(file);
+ file = iso_1_fileid("file<:a.ext");
+ CU_ASSERT_STRING_EQUAL(file, "FILE__A.EXT");
+ free(file);
+ file = iso_1_fileid("file.<:a");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.__A");
+ free(file);
+ file = iso_1_fileid("file<:a.--a");
+ CU_ASSERT_STRING_EQUAL(file, "FILE__A.__A");
+ free(file);
+ file = iso_1_fileid("file.ex1.ex2");
+ CU_ASSERT_STRING_EQUAL(file, "FILE_EX1.EX2");
+ free(file);
+ file = iso_1_fileid("file.ex1.ex2.ex3");
+ CU_ASSERT_STRING_EQUAL(file, "FILE_EX1.EX3");
+ free(file);
+ file = iso_1_fileid("fil.ex1.ex2.ex3");
+ CU_ASSERT_STRING_EQUAL(file, "FIL_EX1_.EX3");
+ free(file);
+}
+
+static void test_iso_2_fileid()
+{
+ char *file;
+ file = iso_2_fileid("file1");
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+ file = iso_2_fileid("fILe1");
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+ file = iso_2_fileid("FILE1");
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+ file = iso_2_fileid(".EXT");
+ CU_ASSERT_STRING_EQUAL(file, ".EXT");
+ free(file);
+ file = iso_2_fileid("file.ext");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_2_fileid("fiLE.ext");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_2_fileid("file.EXt");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_2_fileid("FILE.EXT");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_2_fileid("bigfilename");
+ CU_ASSERT_STRING_EQUAL(file, "BIGFILENAME.");
+ free(file);
+ file = iso_2_fileid("bigfilename.ext");
+ CU_ASSERT_STRING_EQUAL(file, "BIGFILENAME.EXT");
+ free(file);
+ file = iso_2_fileid("bigfilename.e");
+ CU_ASSERT_STRING_EQUAL(file, "BIGFILENAME.E");
+ free(file);
+ file = iso_2_fileid("31 characters filename.extensio");
+ CU_ASSERT_STRING_EQUAL(file, "31_CHARACTERS_FILENAME.EXTENSIO");
+ free(file);
+ file = iso_2_fileid("32 characters filename.extension");
+ CU_ASSERT_STRING_EQUAL(file, "32_CHARACTERS_FILENAME.EXTENSIO");
+ free(file);
+ file = iso_2_fileid("more than 30 characters filename.extension");
+ CU_ASSERT_STRING_EQUAL(file, "MORE_THAN_30_CHARACTERS_FIL.EXT");
+ free(file);
+ file = iso_2_fileid("file.bigext");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.BIGEXT");
+ free(file);
+ file = iso_2_fileid(".bigext");
+ CU_ASSERT_STRING_EQUAL(file, ".BIGEXT");
+ free(file);
+ file = iso_2_fileid("bigfilename.bigext");
+ CU_ASSERT_STRING_EQUAL(file, "BIGFILENAME.BIGEXT");
+ free(file);
+ file = iso_2_fileid("file<:a.ext");
+ CU_ASSERT_STRING_EQUAL(file, "FILE__A.EXT");
+ free(file);
+ file = iso_2_fileid("file.<:a");
+ CU_ASSERT_STRING_EQUAL(file, "FILE.__A");
+ free(file);
+ file = iso_2_fileid("file<:a.--a");
+ CU_ASSERT_STRING_EQUAL(file, "FILE__A.__A");
+ free(file);
+ file = iso_2_fileid("file.ex1.ex2");
+ CU_ASSERT_STRING_EQUAL(file, "FILE_EX1.EX2");
+ free(file);
+ file = iso_2_fileid("file.ex1.ex2.ex3");
+ CU_ASSERT_STRING_EQUAL(file, "FILE_EX1_EX2.EX3");
+ free(file);
+ file = iso_2_fileid("fil.ex1.ex2.ex3");
+ CU_ASSERT_STRING_EQUAL(file, "FIL_EX1_EX2.EX3");
+ free(file);
+ file = iso_2_fileid(".file.bigext");
+ CU_ASSERT_STRING_EQUAL(file, "_FILE.BIGEXT");
+ free(file);
+}
+
+static void test_iso_r_dirid()
+{
+ char *dir;
+
+ dir = iso_r_dirid("dir1", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+
+ dir = iso_r_dirid("dIR1", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+
+ /* allow lowercase */
+ dir = iso_r_dirid("dIR1", 31, 1);
+ CU_ASSERT_STRING_EQUAL(dir, "dIR1");
+ free(dir);
+ dir = iso_r_dirid("dIR1", 31, 2);
+ CU_ASSERT_STRING_EQUAL(dir, "dIR1");
+ free(dir);
+
+ dir = iso_r_dirid("DIR1", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIR1");
+ free(dir);
+ dir = iso_r_dirid("dirwithbigname", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIRWITHBIGNAME");
+ free(dir);
+ dir = iso_r_dirid("dirwith8", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIRWITH8");
+ free(dir);
+
+ /* dot is not allowed */
+ dir = iso_r_dirid("dir.1", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIR_1");
+ free(dir);
+ dir = iso_r_dirid("dir.1", 31, 1);
+ CU_ASSERT_STRING_EQUAL(dir, "dir_1");
+ free(dir);
+ dir = iso_r_dirid("dir.1", 31, 2);
+ CU_ASSERT_STRING_EQUAL(dir, "dir.1");
+ free(dir);
+
+ dir = iso_r_dirid("4f<0KmM::xcvf", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "4F_0KMM__XCVF");
+ free(dir);
+ dir = iso_r_dirid("4f<0KmM::xcvf", 31, 1);
+ CU_ASSERT_STRING_EQUAL(dir, "4f_0KmM__xcvf");
+ free(dir);
+ dir = iso_r_dirid("4f<0KmM::xcvf", 31, 2);
+ CU_ASSERT_STRING_EQUAL(dir, "4f<0KmM::xcvf");
+ free(dir);
+
+ dir = iso_r_dirid("directory with 31 characters ok", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIRECTORY_WITH_31_CHARACTERS_OK");
+ free(dir);
+ dir = iso_r_dirid("directory with more than 31 characters", 31, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIRECTORY_WITH_MORE_THAN_31_CHA");
+ free(dir);
+ dir = iso_r_dirid("directory with more than 31 characters", 35, 0);
+ CU_ASSERT_STRING_EQUAL(dir, "DIRECTORY_WITH_MORE_THAN_31_CHARACT");
+ free(dir);
+}
+
+static void test_iso_r_fileid()
+{
+ char *file;
+
+ /* force dot */
+ file = iso_r_fileid("file1", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+
+ /* and not */
+ file = iso_r_fileid("file1", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "FILE1");
+ free(file);
+
+ /* allow lowercase */
+ file = iso_r_fileid("file1", 30, 1, 0);
+ CU_ASSERT_STRING_EQUAL(file, "file1");
+ free(file);
+ file = iso_r_fileid("file1", 30, 2, 0);
+ CU_ASSERT_STRING_EQUAL(file, "file1");
+ free(file);
+
+ /* force d-char and dot */
+ file = iso_r_fileid("fILe1", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+ /* force d-char but not dot */
+ file = iso_r_fileid("fILe1", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "FILE1");
+ free(file);
+ /* allow lower case but force dot */
+ file = iso_r_fileid("fILe1", 30, 1, 1);
+ CU_ASSERT_STRING_EQUAL(file, "fILe1.");
+ free(file);
+
+ file = iso_r_fileid("FILE1", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, "FILE1.");
+ free(file);
+ file = iso_r_fileid(".EXT", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, ".EXT");
+ free(file);
+ file = iso_r_fileid(".EXT", 30, 1, 0);
+ CU_ASSERT_STRING_EQUAL(file, ".EXT");
+ free(file);
+
+ file = iso_r_fileid("file.ext", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+
+ /* not force dot is the same in this case */
+ file = iso_r_fileid("fiLE.ext", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_r_fileid("fiLE.ext", 30, 2, 0);
+ CU_ASSERT_STRING_EQUAL(file, "fiLE.ext");
+ free(file);
+
+ file = iso_r_fileid("file.EXt", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+ file = iso_r_fileid("FILE.EXT", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, "FILE.EXT");
+ free(file);
+
+ file = iso_r_fileid("31 characters filename.extensio", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, "31_CHARACTERS_FILENAME.EXTENSIO");
+ free(file);
+ file = iso_r_fileid("32 characters filename.extension", 30, 0, 1);
+ CU_ASSERT_STRING_EQUAL(file, "32_CHARACTERS_FILENAME.EXTENSIO");
+ free(file);
+
+ /* allow lowercase */
+ file = iso_r_fileid("31 characters filename.extensio", 30, 1, 1);
+ CU_ASSERT_STRING_EQUAL(file, "31_characters_filename.extensio");
+ free(file);
+
+ /* and all characters */
+ file = iso_r_fileid("31 characters filename.extensio", 30, 2, 1);
+ CU_ASSERT_STRING_EQUAL(file, "31 characters filename.extensio");
+ free(file);
+
+ file = iso_r_fileid("more than 30 characters filename.extension", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "MORE_THAN_30_CHARACTERS_FIL.EXT");
+ free(file);
+
+ /* incrementing the size... */
+ file = iso_r_fileid("more than 30 characters filename.extension", 35, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "MORE_THAN_30_CHARACTERS_FILENAME.EXT");
+ free(file);
+
+ file = iso_r_fileid("more than 30 characters filename.extension", 36, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "MORE_THAN_30_CHARACTERS_FILENAME.EXTE");
+ free(file);
+
+ file = iso_r_fileid("file.bigext", 30, 1, 0);
+ CU_ASSERT_STRING_EQUAL(file, "file.bigext");
+ free(file);
+
+ file = iso_r_fileid(".bigext", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, ".BIGEXT");
+ free(file);
+
+ /* "strange" characters */
+ file = iso_r_fileid("file<:a.ext", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "FILE__A.EXT");
+ free(file);
+ file = iso_r_fileid("file<:a.ext", 30, 1, 0);
+ CU_ASSERT_STRING_EQUAL(file, "file__a.ext");
+ free(file);
+ file = iso_r_fileid("file<:a.ext", 30, 2, 0);
+ CU_ASSERT_STRING_EQUAL(file, "file<:a.ext");
+ free(file);
+
+ /* multiple dots */
+ file = iso_r_fileid("fi.le.a.ext", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "FI_LE_A.EXT");
+ free(file);
+ file = iso_r_fileid("fi.le.a.ext", 30, 1, 0);
+ CU_ASSERT_STRING_EQUAL(file, "fi_le_a.ext");
+ free(file);
+ file = iso_r_fileid("fi.le.a.ext", 30, 2, 0);
+ CU_ASSERT_STRING_EQUAL(file, "fi.le.a.ext");
+ free(file);
+
+ file = iso_r_fileid("file.<:a", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "FILE.__A");
+ free(file);
+ file = iso_r_fileid("file<:a.--a", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "FILE__A.__A");
+ free(file);
+
+ file = iso_r_fileid(".file.bigext", 30, 0, 0);
+ CU_ASSERT_STRING_EQUAL(file, "_FILE.BIGEXT");
+ free(file);
+
+ file = iso_r_fileid(".file.bigext", 30, 2, 0);
+ CU_ASSERT_STRING_EQUAL(file, ".file.bigext");
+ free(file);
+}
+
+static void test_iso_rbtree_insert()
+{
+ int res;
+ IsoRBTree *tree;
+ char *str1, *str2, *str3, *str4, *str5;
+ void *str;
+
+ res = iso_rbtree_new((compare_function_t)strcmp, &tree);
+ CU_ASSERT_EQUAL(res, 1);
+
+ /* ok, insert one str */
+ str1 = "first str";
+ res = iso_rbtree_insert(tree, str1, &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str1);
+
+ str2 = "second str";
+ res = iso_rbtree_insert(tree, str2, &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str2);
+
+ /* an already inserted string */
+ str3 = "second str";
+ res = iso_rbtree_insert(tree, str3, &str);
+ CU_ASSERT_EQUAL(res, 0);
+ CU_ASSERT_PTR_EQUAL(str, str2);
+
+ /* an already inserted string */
+ str3 = "first str";
+ res = iso_rbtree_insert(tree, str3, &str);
+ CU_ASSERT_EQUAL(res, 0);
+ CU_ASSERT_PTR_EQUAL(str, str1);
+
+ str4 = "a string to be inserted first";
+ res = iso_rbtree_insert(tree, str4, &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str4);
+
+ str5 = "this to be inserted last";
+ res = iso_rbtree_insert(tree, str5, &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str5);
+
+ /*
+ * TODO write a really good test to check all possible estrange
+ * behaviors of a red-black tree
+ */
+
+ iso_rbtree_destroy(tree, NULL);
+}
+
+void test_iso_htable_put_get()
+{
+ int res;
+ IsoHTable *table;
+ char *str1, *str2, *str3, *str4, *str5;
+ void *str;
+
+ res = iso_htable_create(4, iso_str_hash, (compare_function_t)strcmp, &table);
+ CU_ASSERT_EQUAL(res, 1);
+
+ /* try to get str from empty table */
+ res = iso_htable_get(table, "first str", &str);
+ CU_ASSERT_EQUAL(res, 0);
+
+ /* ok, insert one str */
+ str1 = "first str";
+ res = iso_htable_put(table, str1, str1);
+ CU_ASSERT_EQUAL(res, 1);
+
+ /* and now get str from table */
+ res = iso_htable_get(table, "first str", &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str1);
+ res = iso_htable_get(table, "second str", &str);
+ CU_ASSERT_EQUAL(res, 0);
+
+ str2 = "second str";
+ res = iso_htable_put(table, str2, str2);
+ CU_ASSERT_EQUAL(res, 1);
+
+ str = NULL;
+ res = iso_htable_get(table, "first str", &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str1);
+ res = iso_htable_get(table, "second str", &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str2);
+
+ /* insert again, with same key but other data */
+ res = iso_htable_put(table, str2, str1);
+ CU_ASSERT_EQUAL(res, 0);
+
+ res = iso_htable_get(table, "second str", &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str2);
+
+ str3 = "third str";
+ res = iso_htable_put(table, str3, str3);
+ CU_ASSERT_EQUAL(res, 1);
+
+ str4 = "four str";
+ res = iso_htable_put(table, str4, str4);
+ CU_ASSERT_EQUAL(res, 1);
+
+ str5 = "fifth str";
+ res = iso_htable_put(table, str5, str5);
+ CU_ASSERT_EQUAL(res, 1);
+
+ /* some searches */
+ res = iso_htable_get(table, "sixth str", &str);
+ CU_ASSERT_EQUAL(res, 0);
+
+ res = iso_htable_get(table, "fifth str", &str);
+ CU_ASSERT_EQUAL(res, 1);
+ CU_ASSERT_PTR_EQUAL(str, str5);
+
+ iso_htable_destroy(table, NULL);
+}
+
+void add_util_suite()
+{
+ CU_pSuite pSuite = CU_add_suite("UtilSuite", NULL, NULL);
+
+ CU_add_test(pSuite, "strconv()", test_strconv);
+ CU_add_test(pSuite, "int_pow()", test_int_pow);
+ CU_add_test(pSuite, "DIV_UP()", test_div_up);
+ CU_add_test(pSuite, "ROUND_UP()", test_round_up);
+ CU_add_test(pSuite, "iso_bb()", test_iso_bb);
+ CU_add_test(pSuite, "iso_lsb/msb()", test_iso_lsb_msb);
+ CU_add_test(pSuite, "iso_read_lsb/msb()", test_iso_read_lsb_msb);
+ CU_add_test(pSuite, "iso_datetime_7()", test_iso_datetime_7);
+ CU_add_test(pSuite, "iso_1_dirid()", test_iso_1_dirid);
+ CU_add_test(pSuite, "iso_2_dirid()", test_iso_2_dirid);
+ CU_add_test(pSuite, "iso_1_fileid()", test_iso_1_fileid);
+ CU_add_test(pSuite, "iso_2_fileid()", test_iso_2_fileid);
+ CU_add_test(pSuite, "iso_r_dirid()", test_iso_r_dirid);
+ CU_add_test(pSuite, "iso_r_fileid()", test_iso_r_fileid);
+ CU_add_test(pSuite, "iso_rbtree_insert()", test_iso_rbtree_insert);
+ CU_add_test(pSuite, "iso_htable_put/get()", test_iso_htable_put_get);
+}
diff --git a/libisofs/tags/ForXorrisoZeroOneTwo/version.h.in b/libisofs/tags/ForXorrisoZeroOneTwo/version.h.in
new file mode 100644
index 00000000..f903ff0a
--- /dev/null
+++ b/libisofs/tags/ForXorrisoZeroOneTwo/version.h.in
@@ -0,0 +1,3 @@
+#define LIBISOFS_MAJOR_VERSION @LIBISOFS_MAJOR_VERSION@
+#define LIBISOFS_MINOR_VERSION @LIBISOFS_MINOR_VERSION@
+#define LIBISOFS_MICRO_VERSION @LIBISOFS_MICRO_VERSION@