Compare commits

...

No commits in common. "master" and "thomas@3055" have entirely different histories.

138 changed files with 36062 additions and 13374 deletions

View File

@ -1,2 +1,3 @@
Vreixo Formoso
Mario Danic Mario Danic
Thomas Schmitt

View File

@ -1,4 +0,0 @@
Joe Neeman
Philippe Rouquier
Suriyan Laohaprapanon
Vreixo Formoso Lopes

View File

@ -1,7 +1,7 @@
Derek Foreman <derek@signalmarketing.com> and Ben Jansens <xor@orodu.net> Vreixo Formoso <metalpain2002@yahoo.es>,
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens Mario Danic <mario.danic@gmail.com>,
Mario Danic <mario.danic@gmail.com>, Thomas Schmitt <scdbackup@gmx.net> Thomas Schmitt <scdbackup@gmx.net>
Copyright (C) 2006 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 This program is free software; you can redistribute it and/or modify

View File

@ -1,13 +1 @@
Development
===========
- Support for reading of plain iso images.
- Support for reading RR extensions
Version 0.2.8
=============
TODO

View File

@ -10,74 +10,121 @@ lib_LTLIBRARIES = libisofs/libisofs.la
libisofs_libisofs_la_LDFLAGS = \ libisofs_libisofs_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
libisofs_libisofs_la_SOURCES = \ libisofs_libisofs_la_SOURCES = \
libisofs/builder.h \
libisofs/builder.c \
libisofs/node.h \
libisofs/node.c \
libisofs/tree.h \ libisofs/tree.h \
libisofs/tree.c \ libisofs/tree.c \
libisofs/volume.h \ libisofs/find.c \
libisofs/volume.c \ libisofs/image.h \
libisofs/util.h \ libisofs/image.c \
libisofs/util.c \ libisofs/fsource.h \
libisofs/ecma119.c \ libisofs/fsource.c \
libisofs/ecma119.h \ libisofs/fs_local.c \
libisofs/ecma119_tree.c \ libisofs/fs_image.c \
libisofs/ecma119_tree.h \ libisofs/messages.h \
libisofs/susp.h \ libisofs/messages.c \
libisofs/susp.c \
libisofs/rockridge.h \
libisofs/rockridge.c \
libisofs/joliet.c \
libisofs/joliet.h \
libisofs/exclude.c \
libisofs/exclude.h \
libisofs/hash.h \
libisofs/hash.c \
libisofs/file.h \
libisofs/file.c \
libisofs/file_src.h \
libisofs/file_src.c \
libisofs/eltorito.h \
libisofs/eltorito.c \
libisofs/data_source.c \
libisofs/ecma119_read.h \
libisofs/ecma119_read.c \
libisofs/ecma119_read_rr.h \
libisofs/ecma119_read_rr.c \
libisofs/libiso_msgs.h \ libisofs/libiso_msgs.h \
libisofs/libiso_msgs.c \ libisofs/libiso_msgs.c \
libisofs/messages.h \ libisofs/stream.h \
libisofs/messages.c 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 = \ libinclude_HEADERS = \
libisofs/libisofs.h libisofs/libisofs.h
## ========================================================================= ## ## ========================================================================= ##
## Build test applications ## Build demo applications
noinst_PROGRAMS = \ noinst_PROGRAMS = \
test/iso \ demo/lsl \
test/isoread \ demo/cat \
test/isoms \ demo/catbuffer \
test/isoadd \ demo/tree \
test/isogrow demo/find \
demo/ecma119tree \
demo/iso \
demo/isoread \
demo/isocat \
demo/isomodify \
demo/isoms \
demo/isogrow
test_iso_CPPFLAGS = -Ilibisofs demo_lsl_CPPFLAGS = -Ilibisofs
test_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_lsl_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_iso_SOURCES = test/iso.c demo_lsl_SOURCES = demo/lsl.c
test_isoread_CPPFLAGS = -Ilibisofs demo_cat_CPPFLAGS = -Ilibisofs
test_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_cat_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoread_SOURCES = test/iso_read.c demo_cat_SOURCES = demo/cat.c
test_isoms_CPPFLAGS = -Ilibisofs demo_catbuffer_CPPFLAGS = -Ilibisofs
test_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_catbuffer_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoms_SOURCES = test/iso_ms.c demo_catbuffer_SOURCES = demo/cat_buffer.c
test_isoadd_CPPFLAGS = -Ilibisofs demo_tree_CPPFLAGS = -Ilibisofs
test_isoadd_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoadd_SOURCES = test/iso_add.c 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
test_isogrow_CPPFLAGS = -Ilibisofs -Ilibburn
test_isogrow_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lburn
test_isogrow_SOURCES = test/iso_grow.c
## Build unit test ## Build unit test
@ -89,38 +136,31 @@ test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lcunit
test_test_LDFLAGS = -L.. -lm test_test_LDFLAGS = -L.. -lm
test_test_SOURCES = \ test_test_SOURCES = \
test/test_exclude.c \ test/test.h \
test/test.c \
test/test_node.c \
test/test_image.c \
test/test_tree.c \ test/test_tree.c \
test/test_ecma119_tree.c \
test/test_file_hashtable.c \
test/test_util.c \ test/test_util.c \
test/test_volume.c \ test/test_rockridge.c \
test/test_data_source.c \ test/test_stream.c \
test/test_read.c \ test/mocked_fsrc.h \
test/test.c test/mocked_fsrc.c
## ========================================================================= ## ## ========================================================================= ##
## Build documentation (You need Doxygen for this to work) ## Build documentation (You need Doxygen for this to work)
webhost = http://libburn-api.pykix.org
webpath = /
docdir = $(DESTDIR)$(prefix)/share/doc/$(PACKAGE)-$(VERSION) docdir = $(DESTDIR)$(prefix)/share/doc/$(PACKAGE)-$(VERSION)
doc: doc/html doc: doc/html
doc/html: doc/doxygen.conf doc/html: doc/doxygen.conf
if [ -f ./doc/doc.lock ]; then \ $(RM) -r doc/html; \
$(RM) -r doc/html; \ doxygen doc/doxygen.conf;
doxygen doc/doxygen.conf; \
fi
doc-upload: doc/html
scp -r $</* $(webhost):$(webpath)
all: doc
install-data-local: install-data-local:
if [ -f ./doc/doc.lock ]; then \ if [ -d doc/html ]; then \
$(mkinstalldirs) $(docdir)/html; \ $(mkinstalldirs) $(docdir)/html; \
$(INSTALL_DATA) doc/html/* $(docdir)/html; \ $(INSTALL_DATA) doc/html/* $(docdir)/html; \
fi fi
@ -130,38 +170,22 @@ uninstall-local:
## ========================================================================= ## ## ========================================================================= ##
# Indent source files
indent_files = \
$(libisofs_libisofs_la_SOURCES) \
$(test_iso_SOURCES)
indent: $(indent_files)
indent -bad -bap -nbbb -nbbo -nbc -bli0 -br -bls \
-cdw -ce -cli0 -ncs -nbfda -i8 -l79 -lc79 \
-lp -saf -sai -nprs -npsl -saw -sob -ss -ut \
-sbi0 -nsc -ts8 -npcs -ncdb -fca \
$^
.PHONY: indent
## ========================================================================= ##
# Extra things # Extra things
nodist_pkgconfig_DATA = \ nodist_pkgconfig_DATA = \
libisofs-5.pc libisofs-1.pc
EXTRA_DIST = \ EXTRA_DIST = \
libisofs-5.pc.in \ libisofs-1.pc.in \
version.h.in \ version.h.in \
doc/comments \
doc/doxygen.conf.in \ doc/doxygen.conf.in \
doc/Tutorial \
README \ README \
AUTHORS \ AUTHORS \
CONTRIBUTORS \
COPYRIGHT \ COPYRIGHT \
COPYING \ COPYING \
NEWS \ NEWS \
INSTALL \ INSTALL \
ChangeLog TODO \
ChangeLog \
Roadmap

21
NEWS
View File

@ -1 +1,20 @@
nothing here now == 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

155
README
View File

@ -1,56 +1,130 @@
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
libburnia-project.org libisofs
------------------------------------------------------------------------------
This all is under GPL.
(See GPL reference, our clarification and commitment at the end of this text)
------------------------------------------------------------------------------
libburnia-project.org
By Mario Danic <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
Copyright (C) 2006-2007 Mario Danic, Thomas Schmitt
Still containing parts of
Libburn. By Derek Foreman <derek@signalmarketing.com> and
Ben Jansens <xor@orodu.net>
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
These parts are to be replaced by own code of above libburnia-project.org
copyright holders and then libburnia-project.org is to be their sole copyright.
This is done to achieve the right to issue the clarification and the
commitment as written at the end of this text.
The rights and merits of the Libburn-copyright holders Derek Foreman and
Ben Jansens will be duely respected.
This libburnia-project.org toplevel README (C) 2006-2007 Thomas Schmitt
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Build and Installation Released under GPL (see COPYING file for details).
Our build system is based on autotools. For preparing the build of a SVN Copyright (C) 2008 Vreixo Formoso, Mario Danic, Thomas Schmitt
snapshot you will need autotools of at least version 1.7.
Check out from SVN by libisofs is part of the libburnia project (libburnia-project.org)
svn co http://svn.libburnia-project.org/libburn/trunk libburn ------------------------------------------------------------------------------
go into directory libburn and apply autotools by
./bootstrap 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 Alternatively you may unpack a release tarball for which you do not need
autotools installed. autotools installed.
To build a libburnia-project.org subproject it should be sufficient to go To build libisofs it should be sufficient to go into its toplevel directory
into its toplevel directory (here: "libburn") and execute and execute
./configure --prefix=/usr ./configure --prefix=/usr
make make
To make the libraries accessible for running resp. developing applications To make the libraries accessible for running resp. developing applications
make install make install
See INSTALL file for further details.
The other half of the project, libisofs, is hosted in the libburnia SVN, too:
svn co http://svn.libburnia-project.org/libisofs/trunk libisofs
See README file there.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Overview of libburnia-project.org Overview of libburnia-project.org
libburnia-project.org is an open-source software project for reading, mastering libburnia-project.org is an open-source software project for reading, mastering
@ -204,6 +278,17 @@ Project history as far as known to me:
We look back on improved stability, a substantially extended list of media We look back on improved stability, a substantially extended list of media
and write modes, and better protection against typical user mishaps. 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.
------------------------------------------------------------------------------ ------------------------------------------------------------------------------

33
Roadmap Normal file
View File

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

87
TODO
View File

@ -1,64 +1,35 @@
GENERAL
=======
Improve documentation
Build system improvements
Clarify licencing (GPL2 only (!) with exception)
FEATURES FEATURES
======== ========
El-Torito
Support for multiple images
HFS/HFS+
CD reading
[ok] plain iso
[ok] Rock Ridge
[ok] Joliet
Merge RR and Joliet trees
[ok] User options to customize reading
[ok] Read El-Torito info
[ok] Multisession
[ok] DVD+RW image growing
El-Torito images from previous session
Add new el-torito image from prev. session file
Path for isolinux from prev. session
UDF
[ok] ISO relaxed contraints
ISO 9660:1998
Support for special files (only dirs, reg. files and symlinks are supported).
Modification of timestamps attribs on nodes
TESTS TODO
=====
[several done]
Test all util.h functions, especially date-related ones
Test for RR read functions
For all
IMPLEMENTATION
==============
a way to return NULL sources meaning a failure!!
[ok] Error message queue
Better charset support
[ok] default input charset to locale one, no always UTF-8
add charset management on image reading
use iso-8859-1 instead of UTF-8 on RR?
[ok] Improve date handling
for DVD+RW, the VD to be written at the beginning of disc must be
returned as 32KB block
Sources to write file contents
encyrption/compression of files
auto cut of files to 2gb limit
BUGS
==== ====
Joliet names need ";1" at the end #00001 (node.h) -> consider adding new timestamps to IsoTreeNode
RR Continuation Areas can't be in Directory Record block #00004 (libisofs.h) -> Add a get_mime_type() function.
[ok] Fix mangle names when iso relaxed constraints #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
=====

View File

@ -1,4 +1,4 @@
AC_INIT([libisofs], [0.2.9], [http://libburnia-project.org]) AC_INIT([libisofs], [0.6.3], [http://libburnia-project.org])
AC_PREREQ([2.50]) AC_PREREQ([2.50])
dnl AC_CONFIG_HEADER([config.h]) dnl AC_CONFIG_HEADER([config.h])
@ -13,35 +13,51 @@ dnl one must include some config.h and this was a pitfall.
dnl So why dig the pit at all ? dnl So why dig the pit at all ?
dnl AM_CONFIG_HEADER(config.h) dnl AM_CONFIG_HEADER(config.h)
dnl Making releases:
dnl BURN_MICRO_VERSION += 1;
dnl BURN_INTERFACE_AGE += 1;
dnl BURN_BINARY_AGE += 1;
dnl if any functions have been added, set BURN_INTERFACE_AGE to 0.
dnl if backwards compatibility has been broken,
dnl set BURN_BINARY_AGE and BURN_INTERFACE_AGE to 0.
dnl dnl
dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
dnl dnl
BURN_MAJOR_VERSION=0 dnl CURRENT and AGE describe the binary compatibility interval of a
BURN_MINOR_VERSION=2 dnl dynamic library.
BURN_MICRO_VERSION=4 dnl See also http://www.gnu.org/software/libtool/manual.html#Interfaces
BURN_INTERFACE_AGE=0 dnl
BURN_BINARY_AGE=0 dnl The name of the library will be libisofs.so.$CURRENT-$AGE.$AGE.$REV
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION 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(BURN_MAJOR_VERSION) AC_SUBST(LIBISOFS_MAJOR_VERSION)
AC_SUBST(BURN_MINOR_VERSION) AC_SUBST(LIBISOFS_MINOR_VERSION)
AC_SUBST(BURN_MICRO_VERSION) AC_SUBST(LIBISOFS_MICRO_VERSION)
AC_SUBST(BURN_INTERFACE_AGE) AC_SUBST(LIBISOFS_VERSION)
AC_SUBST(BURN_BINARY_AGE)
AC_SUBST(BURN_VERSION)
dnl Libtool versioning dnl Libtool versioning
LT_RELEASE=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION LT_RELEASE=$LIBISOFS_MAJOR_VERSION.$LIBISOFS_MINOR_VERSION
LT_CURRENT=`expr $BURN_MICRO_VERSION - $BURN_INTERFACE_AGE` # SONAME = 6 - 0 = 6 . Library name = libisofs.6.0.0
LT_REVISION=$BURN_INTERFACE_AGE LT_CURRENT=6
LT_AGE=`expr $BURN_BINARY_AGE - $BURN_INTERFACE_AGE` LT_REVISION=0
LT_AGE=0
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE` LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
AC_SUBST(LT_RELEASE) AC_SUBST(LT_RELEASE)
@ -65,7 +81,7 @@ AC_SYS_LARGEFILE
AC_FUNC_FSEEKO AC_FUNC_FSEEKO
AC_CHECK_FUNC([fseeko]) AC_CHECK_FUNC([fseeko])
if test ! $ac_cv_func_fseeko; then if test ! $ac_cv_func_fseeko; then
AC_ERROR([Libisofs requires largefile support.]) AC_MSG_ERROR([Libisofs requires largefile support.])
fi fi
AC_PROG_LIBTOOL AC_PROG_LIBTOOL
@ -76,12 +92,28 @@ AC_PROG_INSTALL
AC_CHECK_HEADERS() 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_CHECK_MEMBER([struct tm.tm_gmtoff],
[AC_DEFINE(HAVE_TM_GMTOFF, 1, [AC_DEFINE(HAVE_TM_GMTOFF, 1,
[Define this if tm structure includes a tm_gmtoff entry.])], [Define this if tm structure includes a tm_gmtoff entry.])],
, ,
[#include <time.h>]) [#include <time.h>])
dnl Check if non standard timegm() function is available
AC_CHECK_DECL([timegm],
[AC_DEFINE(HAVE_TIMEGM, 1, [Define this if timegm function is available])],
,
[#include <time.h>])
dnl Check if non standard eaccess() function is available
AC_CHECK_DECL([eaccess],
[AC_DEFINE(HAVE_EACCESS, 1, [Define this if eaccess function is available])],
,
[#include <unistd.h>])
THREAD_LIBS=-lpthread THREAD_LIBS=-lpthread
AC_SUBST(THREAD_LIBS) AC_SUBST(THREAD_LIBS)
@ -108,10 +140,16 @@ else
CFLAGS="$CFLAGS -DDEBUG" CFLAGS="$CFLAGS -DDEBUG"
fi 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([ AC_CONFIG_FILES([
Makefile Makefile
doc/doxygen.conf doc/doxygen.conf
version.h version.h
libisofs-5.pc libisofs-1.pc
]) ])
AC_OUTPUT AC_OUTPUT

74
demo/cat.c Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "libisofs.h"
#include "fsource.h"
#include <stdio.h>
#include <stdlib.h>
/*
* Little test program to test filesystem implementations.
* Outputs file contents to stdout!
*/
int main(int argc, char **argv)
{
int res;
IsoFilesystem *fs;
IsoFileSource *file;
struct stat info;
if (argc != 2) {
fprintf(stderr, "Usage: cat /path/to/file\n");
return 1;
}
/* create filesystem object */
res = iso_local_filesystem_new(&fs);
if (res < 0) {
fprintf(stderr, "Can't get local fs object, err = %d\n", res);
return 1;
}
res = fs->get_by_path(fs, argv[1], &file);
if (res < 0) {
fprintf(stderr, "Can't get file, err = %d\n", res);
return 1;
}
res = iso_file_source_lstat(file, &info);
if (res < 0) {
fprintf(stderr, "Can't stat file, err = %d\n", res);
return 1;
}
if (S_ISDIR(info.st_mode)) {
fprintf(stderr, "Path refers to a directory!!\n");
return 1;
} else {
char buf[1024];
res = iso_file_source_open(file);
if (res < 0) {
fprintf(stderr, "Can't open file, err = %d\n", res);
return 1;
}
while ((res = iso_file_source_read(file, buf, 1024)) > 0) {
fwrite(buf, 1, res, stdout);
}
if (res < 0) {
fprintf(stderr, "Error reading, err = %d\n", res);
return 1;
}
iso_file_source_close(file);
}
iso_file_source_unref(file);
iso_filesystem_unref(fs);
return 0;
}

127
demo/cat_buffer.c Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "libisofs.h"
#include "buffer.h"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/*
* Little test program that reads a file and outputs it to stdout, using
* the libisofs ring buffer as intermediate memory
*/
struct th_data
{
IsoRingBuffer *rbuf;
char *path;
};
#define WRITE_CHUNK 2048
#define READ_CHUNK 2048
static
void *write_function(void *arg)
{
ssize_t bytes;
int res;
unsigned char tmp[WRITE_CHUNK];
struct th_data *data = (struct th_data *) arg;
int fd = open(data->path, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "Writer thread error: Can't open file");
iso_ring_buffer_writer_close(data->rbuf, 1);
pthread_exit(NULL);
}
res = 1;
while ( (bytes = read(fd, tmp, WRITE_CHUNK)) > 0) {
res = iso_ring_buffer_write(data->rbuf, tmp, bytes);
if (res <= 0) {
break;
}
/* To test premature reader exit >>>>>>>>>>>
iso_ring_buffer_writer_close(data->rbuf);
pthread_exit(NULL);
<<<<<<<<<<<<<<<<<<<<<<<<< */
// if (rand() > 2000000000) {
// fprintf(stderr, "Writer sleeping\n");
// sleep(1);
// }
}
fprintf(stderr, "Writer finish: %d\n", res);
close(fd);
iso_ring_buffer_writer_close(data->rbuf, 0);
pthread_exit(NULL);
}
static
void *read_function(void *arg)
{
unsigned char tmp[READ_CHUNK];
int res = 1;
struct th_data *data = (struct th_data *) arg;
while ( (res = iso_ring_buffer_read(data->rbuf, tmp, READ_CHUNK)) > 0) {
write(1, tmp, READ_CHUNK);
/* To test premature reader exit >>>>>>>>>>>
iso_ring_buffer_reader_close(data->rbuf);
pthread_exit(NULL);
<<<<<<<<<<<<<<<<<<<<<<<<< */
// if (rand() > 2000000000) {
// fprintf(stderr, "Reader sleeping\n");
// sleep(1);
// }
}
fprintf(stderr, "Reader finish: %d\n", res);
iso_ring_buffer_reader_close(data->rbuf, 0);
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int res;
struct th_data data;
pthread_t reader;
pthread_t writer;
if (argc != 2) {
fprintf(stderr, "Usage: catbuffer /path/to/file\n");
return 1;
}
res = iso_ring_buffer_new(1024, &data.rbuf);
if (res < 0) {
fprintf(stderr, "Can't create buffer\n");
return 1;
}
data.path = argv[1];
res = pthread_create(&writer, NULL, write_function, (void *) &data);
res = pthread_create(&reader, NULL, read_function, (void *) &data);
pthread_join(writer, NULL);
pthread_join(reader, NULL);
fprintf(stderr, "Buffer was %d times full and %d times empty.\n",
iso_ring_buffer_get_times_full(data.rbuf),
iso_ring_buffer_get_times_empty(data.rbuf));
free(data.rbuf);
return 0;
}

136
demo/ecma119_tree.c Normal file
View File

@ -0,0 +1,136 @@
/*
* Little program that imports a directory to iso image, generates the
* ecma119 low level tree and prints it.
* Note that this is not an API example, but a little program for test
* purposes.
*/
#include "libisofs.h"
#include "ecma119.h"
#include "ecma119_tree.h"
#include "util.h"
#include "filesrc.h"
#include "node.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
static void
print_permissions(mode_t mode)
{
char perm[10];
//TODO suid, sticky...
perm[9] = '\0';
perm[8] = mode & S_IXOTH ? 'x' : '-';
perm[7] = mode & S_IWOTH ? 'w' : '-';
perm[6] = mode & S_IROTH ? 'r' : '-';
perm[5] = mode & S_IXGRP ? 'x' : '-';
perm[4] = mode & S_IWGRP ? 'w' : '-';
perm[3] = mode & S_IRGRP ? 'r' : '-';
perm[2] = mode & S_IXUSR ? 'x' : '-';
perm[1] = mode & S_IWUSR ? 'w' : '-';
perm[0] = mode & S_IRUSR ? 'r' : '-';
printf("[%s]",perm);
}
static void
print_dir(Ecma119Node *dir, int level)
{
int i;
char *sp = alloca(level * 2 + 1);
for (i = 0; i < level * 2; i += 2) {
sp[i] = '|';
sp[i+1] = ' ';
}
sp[level * 2-1] = '-';
sp[level * 2] = '\0';
for (i = 0; i < dir->info.dir->nchildren; i++) {
Ecma119Node *child = dir->info.dir->children[i];
if (child->type == ECMA119_DIR) {
printf("%s+[D] ", sp);
print_permissions(iso_node_get_permissions(child->node));
printf(" %s\n", child->iso_name);
print_dir(child, level+1);
} else if (child->type == ECMA119_FILE) {
printf("%s-[F] ", sp);
print_permissions(iso_node_get_permissions(child->node));
printf(" %s {%p}\n", child->iso_name, (void*)child->info.file);
} else if (child->type == ECMA119_SYMLINK) {
printf("%s-[L] ", sp);
print_permissions(iso_node_get_permissions(child->node));
printf(" %s -> %s\n", child->iso_name,
((IsoSymlink*)child->node)->dest);
} else if (child->type == ECMA119_SPECIAL) {
printf("%s-[S] ", sp);
print_permissions(iso_node_get_permissions(child->node));
printf(" %s\n", child->iso_name);
} else if (child->type == ECMA119_PLACEHOLDER) {
printf("%s-[RD] ", sp);
print_permissions(iso_node_get_permissions(child->node));
printf(" %s\n", child->iso_name);
} else {
printf("%s-[????] ", sp);
}
}
}
int main(int argc, char **argv)
{
int result;
IsoImage *image;
Ecma119Image *ecma119;
if (argc != 2) {
printf ("You need to specify a valid path\n");
return 1;
}
iso_init();
iso_set_msgs_severities("NEVER", "ALL", "");
result = iso_image_new("volume_id", &image);
if (result < 0) {
printf ("Error creating image\n");
return 1;
}
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]);
if (result < 0) {
printf ("Error adding directory %d\n", result);
return 1;
}
ecma119 = calloc(1, sizeof(Ecma119Image));
iso_rbtree_new(iso_file_src_cmp, &(ecma119->files));
ecma119->iso_level = 1;
ecma119->rockridge = 1;
ecma119->image = image;
ecma119->input_charset = strdup("UTF-8");
/* create low level tree */
result = ecma119_tree_create(ecma119);
if (result < 0) {
printf ("Error creating ecma-119 tree: %d\n", result);
return 1;
}
printf("================= ECMA-119 TREE =================\n");
print_dir(ecma119->root, 0);
printf("\n\n");
ecma119_node_free(ecma119->root);
iso_rbtree_destroy(ecma119->files, iso_file_src_free);
free(ecma119->input_charset);
free(ecma119);
iso_image_unref(image);
iso_finish();
return 0;
}

176
demo/iso.c Normal file
View File

@ -0,0 +1,176 @@
/*
* Little program to show how to create an iso image from a local
* directory.
*/
#include "libisofs.h"
#include "libburn/libburn.h"
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
const char * const optstring = "JRIL:b:hV:";
extern char *optarg;
extern int optind;
void usage(char **argv)
{
printf("%s [OPTIONS] DIRECTORY OUTPUT\n", argv[0]);
}
void help()
{
printf(
"Options:\n"
" -J Add Joliet support\n"
" -R Add Rock Ridge support\n"
" -I Add ISO 9660:1999 support\n"
" -V label Volume Label\n"
" -L <num> Set the ISO level (1 or 2)\n"
" -b file Specifies a boot image to add to image\n"
" -h Print this message\n"
);
}
int callback(IsoFileSource *src)
{
char *path = iso_file_source_get_path(src);
printf("CALLBACK: %s\n", path);
free(path);
return 1;
}
int main(int argc, char **argv)
{
int result;
int c;
IsoImage *image;
struct burn_source *burn_src;
unsigned char buf[2048];
FILE *fd;
IsoWriteOpts *opts;
char *volid = "VOLID";
char *boot_img = NULL;
int rr = 0, j = 0, iso1999 = 0, level = 1;
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
case 'h':
usage(argv);
help();
exit(0);
break;
case 'J':
j = 1;
break;
case 'R':
rr = 1;
break;
case 'I':
iso1999 = 1;
break;
case 'L':
level = atoi(optarg);
break;
case 'b':
boot_img = optarg;
break;
case 'V':
volid = optarg;
break;
case '?':
usage(argv);
exit(1);
break;
}
}
if (argc < 2) {
printf ("Please pass directory from which to build ISO\n");
usage(argv);
return 1;
}
if (argc < 3) {
printf ("Please supply output file\n");
usage(argv);
return 1;
}
fd = fopen(argv[optind+1], "w");
if (!fd) {
err(1, "error opening output file");
}
result = iso_init();
if (result < 0) {
printf ("Can't initialize libisofs\n");
return 1;
}
iso_set_msgs_severities("NEVER", "ALL", "");
result = iso_image_new(volid, &image);
if (result < 0) {
printf ("Error creating image\n");
return 1;
}
iso_tree_set_follow_symlinks(image, 0);
iso_tree_set_ignore_hidden(image, 0);
iso_tree_set_ignore_special(image, 0);
iso_set_abort_severity("SORRY");
/*iso_tree_set_report_callback(image, callback);*/
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[optind]);
if (result < 0) {
printf ("Error adding directory %d\n", result);
return 1;
}
if (boot_img) {
/* adds El-Torito boot info. Tunned for isolinux */
ElToritoBootImage *bootimg;
result = iso_image_set_boot_image(image, boot_img, ELTORITO_NO_EMUL,
"/isolinux/boot.cat", &bootimg);
if (result < 0) {
printf ("Error adding boot image %d\n", result);
return 1;
}
el_torito_set_load_size(bootimg, 4);
el_torito_patch_isolinux_image(bootimg);
}
result = iso_write_opts_new(&opts, 0);
if (result < 0) {
printf ("Cant create write opts, error %d\n", result);
return 1;
}
iso_write_opts_set_iso_level(opts, level);
iso_write_opts_set_rockridge(opts, rr);
iso_write_opts_set_joliet(opts, j);
iso_write_opts_set_iso1999(opts, iso1999);
result = iso_image_create_burn_source(image, opts, &burn_src);
if (result < 0) {
printf ("Cant create image, error %d\n", result);
return 1;
}
iso_write_opts_free(opts);
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
fwrite(buf, 1, 2048, fd);
}
fclose(fd);
burn_src->free_data(burn_src);
free(burn_src);
iso_image_unref(image);
iso_finish();
return 0;
}

95
demo/iso_cat.c Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include "libisofs.h"
/*
* Little test program that extracts a file form a given ISO image.
* Outputs file contents to stdout!
*/
int main(int argc, char **argv)
{
int res;
IsoFilesystem *fs;
IsoFileSource *file;
struct stat info;
IsoDataSource *src;
IsoReadOpts *opts;
if (argc != 3) {
fprintf(stderr, "Usage: isocat /path/to/image /path/to/file\n");
return 1;
}
res = iso_init();
if (res < 0) {
fprintf(stderr, "Can't init libisofs\n");
return 1;
}
res = iso_data_source_new_from_file(argv[1], &src);
if (res < 0) {
fprintf(stderr, "Error creating data source\n");
return 1;
}
res = iso_read_opts_new(&opts, 0);
if (res < 0) {
fprintf(stderr, "Error creating read options\n");
return 1;
}
res = iso_image_filesystem_new(src, opts, 1, &fs);
if (res < 0) {
fprintf(stderr, "Error creating filesystem\n");
return 1;
}
iso_read_opts_free(opts);
res = fs->get_by_path(fs, argv[2], &file);
if (res < 0) {
fprintf(stderr, "Can't get file, err = %d\n", res);
return 1;
}
res = iso_file_source_lstat(file, &info);
if (res < 0) {
fprintf(stderr, "Can't stat file, err = %d\n", res);
return 1;
}
if (S_ISDIR(info.st_mode)) {
fprintf(stderr, "Path refers to a directory!!\n");
return 1;
} else {
char buf[1024];
res = iso_file_source_open(file);
if (res < 0) {
fprintf(stderr, "Can't open file, err = %d\n", res);
return 1;
}
while ((res = iso_file_source_read(file, buf, 1024)) > 0) {
fwrite(buf, 1, res, stdout);
}
if (res < 0) {
fprintf(stderr, "Error reading, err = %d\n", res);
return 1;
}
iso_file_source_close(file);
}
iso_file_source_unref(file);
iso_filesystem_unref(fs);
iso_data_source_unref(src);
iso_finish();
return 0;
}

257
demo/iso_grow.c Normal file
View File

@ -0,0 +1,257 @@
/*
* Very simple program to show how to grow an iso image.
*/
#include "libisofs.h"
#include "libburn/libburn.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
static IsoDataSource *libburn_data_source_new(struct burn_drive *d);
void usage(char **argv)
{
printf("%s DISC DIRECTORY\n", argv[0]);
}
int main(int argc, char **argv)
{
int result;
IsoImage *image;
IsoDataSource *src;
struct burn_source *burn_src;
struct burn_drive_info *drives;
struct burn_drive *drive;
unsigned char buf[32 * 2048];
IsoWriteOpts *opts;
int ret = 0;
IsoReadImageFeatures *features;
uint32_t ms_block;
IsoReadOpts *ropts;
if (argc < 3) {
usage(argv);
return 1;
}
iso_init();
iso_set_msgs_severities("NEVER", "ALL", "");
/* create the image context */
result = iso_image_new("volume_id", &image);
if (result < 0) {
printf ("Error creating image\n");
return 1;
}
iso_tree_set_follow_symlinks(image, 0);
iso_tree_set_ignore_hidden(image, 0);
if (!burn_initialize()) {
err(1, "Can't init libburn");
}
burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
if (burn_drive_scan_and_grab(&drives, argv[1], 0) != 1) {
err(1, "Can't open device. Are you sure it is a valid drive?\n");
}
drive = drives[0].drive;
#ifdef ISO_GROW_CHECK_MEDIA
{
/* some check before going on */
enum burn_disc_status state;
int pno;
char name[80];
state = burn_disc_get_status(drive);
burn_disc_get_profile(drive, &pno, name);
/*
* my drives report BURN_DISC_BLANK on a DVD+RW with data.
* is that correct?
*/
if ( (pno != 0x1a) /*|| (state != BURN_DISC_FULL)*/ ) {
printf("You need to insert a DVD+RW with some data.\n");
printf("Profile: %x, state: %d.\n", pno, state);
ret = 1;
goto exit_cleanup;
}
}
#endif
/* create the data source to accesss previous image */
src = libburn_data_source_new(drive);
if (src == NULL) {
printf("Can't create data source.\n");
ret = 1;
goto exit_cleanup;
}
/* import previous image */
ret = iso_read_opts_new(&ropts, 0);
if (ret < 0) {
fprintf(stderr, "Error creating read options\n");
return 1;
}
result = iso_image_import(image, src, ropts, &features);
iso_data_source_unref(src);
if (result < 0) {
printf ("Error importing previous session %d\n", result);
return 1;
}
iso_read_opts_free(ropts);
iso_tree_set_replace_mode(image, ISO_REPLACE_IF_NEWER);
/* add new dir */
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[2]);
if (result < 0) {
printf ("Error adding directory %d\n", result);
return 1;
}
/* generate a multisession image with new contents */
result = iso_write_opts_new(&opts, 1);
if (result < 0) {
printf("Cant create write opts, error %d\n", result);
return 1;
}
/* round up to 32kb aligment = 16 block */
ms_block = ((iso_read_image_features_get_size(features) + 15) / 16 ) * 16;
iso_write_opts_set_ms_block(opts, ms_block);
iso_write_opts_set_appendable(opts, 1);
iso_write_opts_set_overwrite_buf(opts, buf);
iso_read_image_features_destroy(features);
result = iso_image_create_burn_source(image, opts, &burn_src);
if (result < 0) {
printf("Cant create image, error %d\n", result);
return 1;
}
iso_write_opts_free(opts);
/* a. write the new image */
printf("Adding new data...\n");
{
struct burn_disc *target_disc;
struct burn_session *session;
struct burn_write_opts *burn_options;
struct burn_track *track;
struct burn_progress progress;
char reasons[BURN_REASONS_LEN];
target_disc = burn_disc_create();
session = burn_session_create();
burn_disc_add_session(target_disc, session, BURN_POS_END);
track = burn_track_create();
burn_track_set_source(track, burn_src);
burn_session_add_track(session, track, BURN_POS_END);
burn_options = burn_write_opts_new(drive);
burn_drive_set_speed(drive, 0, 0);
burn_write_opts_set_underrun_proof(burn_options, 1);
/* mmm, check for 32K alignment? */
burn_write_opts_set_start_byte(burn_options, ms_block * 2048);
if (burn_write_opts_auto_write_type(burn_options, target_disc,
reasons, 0) == BURN_WRITE_NONE) {
printf("Failed to find a suitable write mode:\n%s\n", reasons);
ret = 1;
goto exit_cleanup;
}
/* ok, write the new track */
burn_disc_write(burn_options, target_disc);
burn_write_opts_free(burn_options);
while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
usleep(1002);
while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
printf("Writing: sector %d of %d\n", progress.sector, progress.sectors);
sleep(1);
}
}
/* b. write the new vol desc */
printf("Writing the new vol desc...\n");
ret = burn_random_access_write(drive, 0, (char*)buf, 32*2048, 0);
if (ret != 1) {
printf("Ups, new vol desc write failed\n");
}
iso_image_unref(image);
exit_cleanup:;
burn_drive_release(drives[0].drive, 0);
burn_finish();
iso_finish();
exit(ret);
}
static int
libburn_ds_read_block(IsoDataSource *src, uint32_t lba, uint8_t *buffer)
{
struct burn_drive *d;
off_t data_count;
d = (struct burn_drive*)src->data;
if ( burn_read_data(d, (off_t) lba * (off_t) 2048, (char*)buffer,
2048, &data_count, 0) < 0 ) {
return -1; /* error */
}
return 1;
}
static
int libburn_ds_open(IsoDataSource *src)
{
/* nothing to do, device is always opened */
return 1;
}
static
int libburn_ds_close(IsoDataSource *src)
{
/* nothing to do, device is always opened */
return 1;
}
static void
libburn_ds_free_data(IsoDataSource *src)
{
/* nothing to do */
}
static IsoDataSource *
libburn_data_source_new(struct burn_drive *d)
{
IsoDataSource *ret;
ret = malloc(sizeof(IsoDataSource));
ret->version = 0;
ret->refcount = 1;
ret->read_block = libburn_ds_read_block;
ret->open = libburn_ds_open;
ret->close = libburn_ds_close;
ret->free_data = libburn_ds_free_data;
ret->data = d;
return ret;
}

109
demo/iso_modify.c Normal file
View File

@ -0,0 +1,109 @@
/*
* Little program to show how to modify an iso image.
*/
#include "libisofs.h"
#include "libburn/libburn.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
void usage(char **argv)
{
printf("%s [OPTIONS] IMAGE DIRECTORY OUTPUT\n", argv[0]);
}
int main(int argc, char **argv)
{
int result;
IsoImage *image;
IsoDataSource *src;
struct burn_source *burn_src;
unsigned char buf[2048];
FILE *fd;
IsoWriteOpts *opts;
IsoReadOpts *ropts;
if (argc < 4) {
usage(argv);
return 1;
}
fd = fopen(argv[3], "w");
if (!fd) {
err(1, "error opening output file");
}
iso_init();
iso_set_msgs_severities("NEVER", "ALL", "");
/* create the data source to accesss previous image */
result = iso_data_source_new_from_file(argv[1], &src);
if (result < 0) {
printf ("Error creating data source\n");
return 1;
}
/* create the image context */
result = iso_image_new("volume_id", &image);
if (result < 0) {
printf ("Error creating image\n");
return 1;
}
iso_tree_set_follow_symlinks(image, 0);
iso_tree_set_ignore_hidden(image, 0);
/* import previous image */
result = iso_read_opts_new(&ropts, 0);
if (result < 0) {
fprintf(stderr, "Error creating read options\n");
return 1;
}
result = iso_image_import(image, src, ropts, NULL);
iso_read_opts_free(ropts);
iso_data_source_unref(src);
if (result < 0) {
printf ("Error importing previous session %d\n", result);
return 1;
}
/* add new dir */
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[2]);
if (result < 0) {
printf ("Error adding directory %d\n", result);
return 1;
}
/* generate a new image with both previous and added contents */
result = iso_write_opts_new(&opts, 1);
if (result < 0) {
printf("Cant create write opts, error %d\n", result);
return 1;
}
/* for isolinux: iso_write_opts_set_allow_full_ascii(opts, 1); */
result = iso_image_create_burn_source(image, opts, &burn_src);
if (result < 0) {
printf ("Cant create image, error %d\n", result);
return 1;
}
iso_write_opts_free(opts);
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
fwrite(buf, 1, 2048, fd);
}
fclose(fd);
burn_src->free_data(burn_src);
free(burn_src);
iso_image_unref(image);
iso_finish();
return 0;
}

114
demo/iso_ms.c Normal file
View File

@ -0,0 +1,114 @@
/*
* Little program to show how to create a multisession iso image.
*/
#include "libisofs.h"
#include "libburn/libburn.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
void usage(char **argv)
{
printf("%s LSS NWA DISC DIRECTORY OUTPUT\n", argv[0]);
}
int main(int argc, char **argv)
{
int result;
IsoImage *image;
IsoDataSource *src;
struct burn_source *burn_src;
unsigned char buf[2048];
FILE *fd;
IsoWriteOpts *opts;
IsoReadOpts *ropts;
uint32_t ms_block;
if (argc < 6) {
usage(argv);
return 1;
}
fd = fopen(argv[5], "w");
if (!fd) {
err(1, "error opening output file");
}
iso_init();
iso_set_msgs_severities("NEVER", "ALL", "");
/* create the data source to accesss previous image */
result = iso_data_source_new_from_file(argv[3], &src);
if (result < 0) {
printf ("Error creating data source\n");
return 1;
}
/* create the image context */
result = iso_image_new("volume_id", &image);
if (result < 0) {
printf ("Error creating image\n");
return 1;
}
iso_tree_set_follow_symlinks(image, 0);
iso_tree_set_ignore_hidden(image, 0);
/* import previous image */
result = iso_read_opts_new(&ropts, 0);
if (result < 0) {
fprintf(stderr, "Error creating read options\n");
return 1;
}
iso_read_opts_set_start_block(ropts, atoi(argv[1]));
result = iso_image_import(image, src, ropts, NULL);
iso_read_opts_free(ropts);
iso_data_source_unref(src);
if (result < 0) {
printf ("Error importing previous session %d\n", result);
return 1;
}
/* add new dir */
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[4]);
if (result < 0) {
printf ("Error adding directory %d\n", result);
return 1;
}
/* generate a multisession image with new contents */
result = iso_write_opts_new(&opts, 1);
if (result < 0) {
printf("Cant create write opts, error %d\n", result);
return 1;
}
/* round up to 32kb aligment = 16 block */
ms_block = atoi(argv[2]);
iso_write_opts_set_ms_block(opts, ms_block);
iso_write_opts_set_appendable(opts, 1);
result = iso_image_create_burn_source(image, opts, &burn_src);
if (result < 0) {
printf ("Cant create image, error %d\n", result);
return 1;
}
iso_write_opts_free(opts);
while (burn_src->read_xt(burn_src, buf, 2048) == 2048) {
fwrite(buf, 1, 2048, fd);
}
fclose(fd);
burn_src->free_data(burn_src);
free(burn_src);
iso_image_unref(image);
iso_finish();
return 0;
}

167
demo/iso_read.c Normal file
View File

@ -0,0 +1,167 @@
/*
* Little program to output the contents of an iso image.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "libisofs.h"
static void
print_permissions(mode_t mode)
{
char perm[10];
//TODO suid, sticky...
perm[9] = '\0';
perm[8] = mode & S_IXOTH ? 'x' : '-';
perm[7] = mode & S_IWOTH ? 'w' : '-';
perm[6] = mode & S_IROTH ? 'r' : '-';
perm[5] = mode & S_IXGRP ? 'x' : '-';
perm[4] = mode & S_IWGRP ? 'w' : '-';
perm[3] = mode & S_IRGRP ? 'r' : '-';
perm[2] = mode & S_IXUSR ? 'x' : '-';
perm[1] = mode & S_IWUSR ? 'w' : '-';
perm[0] = mode & S_IRUSR ? 'r' : '-';
printf(" %s ",perm);
}
static void
print_type(mode_t mode)
{
switch(mode & S_IFMT) {
case S_IFSOCK: printf("[S] "); break;
case S_IFLNK: printf("[L] "); break;
case S_IFREG: printf("[R] "); break;
case S_IFBLK: printf("[B] "); break;
case S_IFDIR: printf("[D] "); break;
case S_IFIFO: printf("[F] "); break;
}
}
static void
print_file_src(IsoFileSource *file)
{
struct stat info;
char *name;
iso_file_source_lstat(file, &info);
print_type(info.st_mode);
print_permissions(info.st_mode);
//printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino);
name = iso_file_source_get_name(file);
printf(" %s", name);
free(name);
if (S_ISLNK(info.st_mode)) {
char buf[PATH_MAX];
iso_file_source_readlink(file, buf, PATH_MAX);
printf(" -> %s\n", buf);
}
printf("\n");
}
static void
print_dir(IsoFileSource *dir, int level)
{
int ret, i;
IsoFileSource *file;
struct stat info;
char *sp = alloca(level * 2 + 1);
for (i = 0; i < level * 2; i += 2) {
sp[i] = '|';
sp[i+1] = ' ';
}
sp[level * 2-1] = '-';
sp[level * 2] = '\0';
ret = iso_file_source_open(dir);
if (ret < 0) {
printf ("Can't open dir %d\n", ret);
}
while ((ret = iso_file_source_readdir(dir, &file)) == 1) {
printf("%s", sp);
print_file_src(file);
ret = iso_file_source_lstat(file, &info);
if (ret < 0) {
break;
}
if (S_ISDIR(info.st_mode)) {
print_dir(file, level + 1);
}
iso_file_source_unref(file);
}
iso_file_source_close(dir);
if (ret < 0) {
printf ("Can't print dir\n");
}
}
int main(int argc, char **argv)
{
int result;
IsoImageFilesystem *fs;
IsoDataSource *src;
IsoFileSource *root;
IsoReadOpts *ropts;
if (argc != 2) {
printf ("You need to specify a valid path\n");
return 1;
}
iso_init();
iso_set_msgs_severities("NEVER", "ALL", "");
result = iso_data_source_new_from_file(argv[1], &src);
if (result < 0) {
printf ("Error creating data source\n");
return 1;
}
result = iso_read_opts_new(&ropts, 0);
if (result < 0) {
fprintf(stderr, "Error creating read options\n");
return 1;
}
result = iso_image_filesystem_new(src, ropts, 1, &fs);
iso_read_opts_free(ropts);
if (result < 0) {
printf ("Error creating filesystem\n");
return 1;
}
printf("\nVOLUME INFORMATION\n");
printf("==================\n\n");
printf("Vol. id: %s\n", iso_image_fs_get_volume_id(fs));
printf("Publisher: %s\n", iso_image_fs_get_publisher_id(fs));
printf("Data preparer: %s\n", iso_image_fs_get_data_preparer_id(fs));
printf("System: %s\n", iso_image_fs_get_system_id(fs));
printf("Application: %s\n", iso_image_fs_get_application_id(fs));
printf("Copyright: %s\n", iso_image_fs_get_copyright_file_id(fs));
printf("Abstract: %s\n", iso_image_fs_get_abstract_file_id(fs));
printf("Biblio: %s\n", iso_image_fs_get_biblio_file_id(fs));
printf("\nDIRECTORY TREE\n");
printf("==============\n");
result = fs->get_root(fs, &root);
if (result < 0) {
printf ("Can't get root %d\n", result);
return 1;
}
//print_file_src(root);
print_dir(root, 0);
iso_file_source_unref(root);
fs->close(fs);
iso_filesystem_unref((IsoFilesystem*)fs);
iso_data_source_unref(src);
iso_finish();
return 0;
}

130
demo/lsl.c Normal file
View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "libisofs.h"
#include "fsource.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
/*
* Little test program to test filesystem implementations.
*
*/
static void
print_permissions(mode_t mode)
{
char perm[10];
//TODO suid, sticky...
perm[9] = '\0';
perm[8] = mode & S_IXOTH ? 'x' : '-';
perm[7] = mode & S_IWOTH ? 'w' : '-';
perm[6] = mode & S_IROTH ? 'r' : '-';
perm[5] = mode & S_IXGRP ? 'x' : '-';
perm[4] = mode & S_IWGRP ? 'w' : '-';
perm[3] = mode & S_IRGRP ? 'r' : '-';
perm[2] = mode & S_IXUSR ? 'x' : '-';
perm[1] = mode & S_IWUSR ? 'w' : '-';
perm[0] = mode & S_IRUSR ? 'r' : '-';
printf(" %s ",perm);
}
static void
print_type(mode_t mode)
{
switch(mode & S_IFMT) {
case S_IFSOCK: printf("[S] "); break;
case S_IFLNK: printf("[L] "); break;
case S_IFREG: printf("[R] "); break;
case S_IFBLK: printf("[B] "); break;
case S_IFDIR: printf("[D] "); break;
case S_IFIFO: printf("[F] "); break;
}
}
static void
print_file_src(IsoFileSource *file)
{
struct stat info;
char *name;
iso_file_source_lstat(file, &info);
print_type(info.st_mode);
print_permissions(info.st_mode);
printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino);
name = iso_file_source_get_name(file);
printf(" %s", name);
free(name);
if (S_ISLNK(info.st_mode)) {
char buf[PATH_MAX];
iso_file_source_readlink(file, buf, PATH_MAX);
printf(" -> %s\n", buf);
}
printf("\n");
}
int main(int argc, char **argv)
{
int res;
IsoFilesystem *fs;
IsoFileSource *dir;
IsoFileSource *file;
struct stat info;
if (argc != 2) {
fprintf(stderr, "Usage: lsl /path/to/file\n");
return 1;
}
/* create filesystem object */
res = iso_local_filesystem_new(&fs);
if (res < 0) {
fprintf(stderr, "Can't get local fs object, err = %d\n", res);
return 1;
}
res = fs->get_by_path(fs, argv[1], &dir);
if (res < 0) {
fprintf(stderr, "Can't get file, err = %d\n", res);
return 1;
}
res = iso_file_source_lstat(dir, &info);
if (res < 0) {
fprintf(stderr, "Can't stat file, err = %d\n", res);
return 1;
}
if (S_ISDIR(info.st_mode)) {
res = iso_file_source_open(dir);
if (res < 0) {
fprintf(stderr, "Can't open file, err = %d\n", res);
return 1;
}
while (iso_file_source_readdir(dir, &file) == 1) {
print_file_src(file);
iso_file_source_unref(file);
}
res = iso_file_source_close(dir);
if (res < 0) {
fprintf(stderr, "Can't close file, err = %d\n", res);
return 1;
}
} else {
print_file_src(dir);
}
iso_file_source_unref(dir);
iso_filesystem_unref(fs);
return 0;
}

107
demo/tree.c Normal file
View File

@ -0,0 +1,107 @@
/*
* Little program that import a directory and prints the resulting iso tree.
*/
#include "libisofs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
static void
print_permissions(mode_t mode)
{
char perm[10];
//TODO suid, sticky...
perm[9] = '\0';
perm[8] = mode & S_IXOTH ? 'x' : '-';
perm[7] = mode & S_IWOTH ? 'w' : '-';
perm[6] = mode & S_IROTH ? 'r' : '-';
perm[5] = mode & S_IXGRP ? 'x' : '-';
perm[4] = mode & S_IWGRP ? 'w' : '-';
perm[3] = mode & S_IRGRP ? 'r' : '-';
perm[2] = mode & S_IXUSR ? 'x' : '-';
perm[1] = mode & S_IWUSR ? 'w' : '-';
perm[0] = mode & S_IRUSR ? 'r' : '-';
printf("[%s]",perm);
}
static void
print_dir(IsoDir *dir, int level)
{
int i;
IsoDirIter *iter;
IsoNode *node;
char *sp = alloca(level * 2 + 1);
for (i = 0; i < level * 2; i += 2) {
sp[i] = '|';
sp[i+1] = ' ';
}
sp[level * 2-1] = '-';
sp[level * 2] = '\0';
iso_dir_get_children(dir, &iter);
while (iso_dir_iter_next(iter, &node) == 1) {
if (ISO_NODE_IS_DIR(node)) {
printf("%s+[D] ", sp);
print_permissions(iso_node_get_permissions(node));
printf(" %s\n", iso_node_get_name(node));
print_dir(ISO_DIR(node), level+1);
} else if (ISO_NODE_IS_FILE(node)) {
printf("%s-[F] ", sp);
print_permissions(iso_node_get_permissions(node));
printf(" %s\n", iso_node_get_name(node) );
} else if (ISO_NODE_IS_SYMLINK(node)) {
printf("%s-[L] ", sp);
print_permissions(iso_node_get_permissions(node));
printf(" %s -> %s \n", iso_node_get_name(node),
iso_symlink_get_dest(ISO_SYMLINK(node)) );
} else {
printf("%s-[C] ", sp);
print_permissions(iso_node_get_permissions(node));
printf(" %s\n", iso_node_get_name(node) );
}
}
iso_dir_iter_free(iter);
}
int main(int argc, char **argv)
{
int result;
IsoImage *image;
if (argc != 2) {
printf ("You need to specify a valid path\n");
return 1;
}
iso_init();
iso_set_msgs_severities("NEVER", "ALL", "");
result = iso_image_new("volume_id", &image);
if (result < 0) {
printf ("Error creating image\n");
return 1;
}
result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]);
if (result < 0) {
printf ("Error adding directory %d\n", result);
return 1;
}
printf("================= IMAGE =================\n");
print_dir(iso_image_get_root(image), 0);
printf("\n\n");
iso_image_unref(image);
iso_finish();
return 0;
}

View File

@ -1,4 +0,0 @@
all clean:
$(MAKE) -C .. -$(MAKEFLAGS) $@
.PHONY: all clean

506
doc/Tutorial Executable file
View File

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

32
doc/Wiki Executable file
View File

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

View File

@ -1,123 +0,0 @@
/**
@author Mario Danic, Thomas Schmitt
@mainpage Libburn Documentation Index
@section intro Introduction
Libburn is an open-source library for reading, mastering and writing
optical discs. For now this means only CD-R and CD-RW.
The project comprises of several more or less interdependent parts which
together strive to be a usable foundation for application development.
These are libraries, language bindings, and middleware binaries which emulate
classical (and valuable) Linux tools.
Our scope is currently Linux 2.4 and 2.6 only. For ports to other systems
we would need : login on a development machine resp. a live OS on CD or DVD,
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
volunteers for testing of realistic use cases.
We do have a workable code base for burning data CDs, though. The burn API is
quite comprehensively documented and can be used to build a presentable
application.
We do have a functional binary which emulates parts of cdrecord in order to
prove that usability, and in order to allow you to explore libburn's scope
by help of existing cdrecord frontends.
@subsection components The project components (list subject to growth, hopefully):
- libburn is the library by which preformatted data get onto optical media.
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
/dev/hdX (e.g. on kernel 2.6).
libburn is the foundation of our cdrecord emulation.
- libisofs is the library to pack up hard disk files and directories into a
ISO 9660 disk image. This may then be brought to CD via libburn.
libisofs is to be the foundation of our upcoming mkisofs emulation.
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
cdrecord is a powerful GPL'ed burn program included in Joerg
Schilling's cdrtools. cdrskin strives to be a second source for
the services traditionally provided by cdrecord.
cdrskin does not contain any bytes copied from cdrecord's sources.
Many bytes have been copied from the message output of cdrecord
runs, though.
See cdrskin/README for more.
- "test" is a collection of application gestures and examples given by the
authors of the library features. The main API example of libburn
is named test/libburner.c .
Explore these examples if you look for inspiration.
We plan to be a responsive upstream. Bear with us.
@section using Using the libraries
Our build system is based on autotools.
User experience tells us that you will need at least autotools version 1.7.
To build libburn and its subprojects it should be sufficient to go into
its toplevel directory and execute
- ./bootstrap (needed if you downloaded from SVN)
- ./configure
- make
To make the libraries accessible for running resp. developing applications
- make install
Both libraries are written in C language and get built by autotools.
Thus we expect them to be useable by a wide range of Linux-implemented
languages and development tools.
@section libburner Libburner
libburner is a minimal demo application for the library libburn
(see: libburn/libburn.h) as provided on http://libburn.pykix.org .
It can list the available devices, can blank a CD-RW and
can burn to CD-R or CD-RW.
It's main purpose, nevertheless, is to show you how to use libburn and also
to serve the libburn team as reference application. libburner does indeed
define the standard way how above three gestures can be implemented and
stay upward compatible for a good while.
@subsection libburner-help Libburner --help
<pre>
Usage: test/libburner
[--drive <address>|<driveno>|"-"]
[--blank_fast|--blank_full] [--audio]
[--try_to_simulate] [--stdin_size <bytes>]
[<one or more imagefiles>|"-"]
Examples
A bus scan (needs rw-permissions to see a drive):
test/libburner --drive -
Burn a file to drive chosen by number:
test/libburner --drive 0 my_image_file
Burn a file to drive chosen by persistent address:
test/libburner --drive /dev/hdc my_image_file
Blank a used CD-RW (is combinable with burning in one run):
test/libburner --drive /dev/hdc --blank_fast
Burn two audio tracks
lame --decode -t /path/to/track1.mp3 track1.cd
test/dewav /path/to/track2.wav -o track2.cd
test/libburner --drive /dev/hdc --audio track1.cd track2.cd
Burn a compressed afio archive on-the-fly, pad up to 700 MB:
( cd my_directory ; find . -print | afio -oZ - ) | \
test/libburner --drive /dev/hdc --stdin_size 734003200 -
To be read from *not mounted* CD via: afio -tvZ /dev/hdc
Program tar would need a clean EOF which our padded CD cannot deliver.
</pre>
@subsection libburner-source Sourceode of libburner
Click on blue names of functions, structures, variables, etc in oder to
get to the according specs of libburn API or libburner sourcecode.
*/

View File

@ -1,121 +0,0 @@
/**
@author Mario Danic, Thomas Schmitt
@mainpage Libburn Documentation Index
@section intro Introduction
Libburn is an open-source library for reading, mastering and writing
optical discs. For now this means only CD-R and CD-RW.
The project comprises of several more or less interdependent parts which
together strive to be a usable foundation for application development.
These are libraries, language bindings, and middleware binaries which emulate
classical (and valuable) Linux tools.
Our scope is currently Linux 2.4 and 2.6 and we will have a hard time to widen
this for now, because of our history. The project could need advise from or
membership of skilled kernel people and people who know how to talk CD/DVD
drives into doing things.
We do have a workable code base for burning data CDs, though. The burn API is
quite comprehensively documented and can be used to build a presentable
application.
We do have a functional binary which emulates parts of cdrecord in order to
prove that usability, and in order to allow you to explore libburn's scope
by help of existing cdrecord frontends.
@subsection components The project components (list subject to growth, hopefully):
- libburn is the library by which preformatted data get onto optical media.
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
/dev/hdX (e.g. on kernel 2.6).
libburn is the foundation of our cdrecord emulation.
- libisofs is the library to pack up hard disk files and directories into a
ISO 9660 disk image. This may then be brought to CD via libburn.
libisofs is to be the foundation of our upcoming mkisofs emulation.
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
cdrecord is a powerful GPL'ed burn program included in Joerg
Schilling's cdrtools. cdrskin strives to be a second source for
the services traditionally provided by cdrecord.
cdrskin does not contain any bytes copied from cdrecord's sources.
Many bytes have been copied from the message output of cdrecord
runs, though.
See cdrskin/README for more.
- "test" is a collection of application gestures and examples given by the
authors of the library features. The main API example of libburn
is named test/libburner.c .
Explore these examples if you look for inspiration.
We plan to be a responsive upstream. Bear with us.
@section using Using the libraries
Our build system is based on autotools.
User experience tells us that you will need at least autotools version 1.7.
To build libburn and its subprojects it should be sufficient to go into
its toplevel directory and execute
- ./bootstrap (needed if you downloaded from SVN)
- ./configure
- make
To make the libraries accessible for running resp. developing applications
- make install
Both libraries are written in C language and get built by autotools.
Thus we expect them to be useable by a wide range of Linux-implemented
languages and development tools.
@section libburner Libburner
libburner is a minimal demo application for the library libburn
(see: libburn/libburn.h) as provided on http://libburn.pykix.org .
It can list the available devices, can blank a CD-RW and
can burn to CD-R or CD-RW.
It's main purpose, nevertheless, is to show you how to use libburn and also
to serve the libburn team as reference application. libburner does indeed
define the standard way how above three gestures can be implemented and
stay upward compatible for a good while.
@subsection libburner-help Libburner --help
<pre>
Usage: test/libburner
[--drive <address>|<driveno>|"-"]
[--verbose <level>] [--blank_fast|--blank_full]
[--burn_for_real|--try_to_simulate] [--stdin_size <bytes>]
[<imagefile>|"-"]
Examples
A bus scan (needs rw-permissions to see a drive):
test/libburner --drive -
Burn a file to drive chosen by number:
test/libburner --drive 0 --burn_for_real my_image_file
Burn a file to drive chosen by persistent address:
test/libburner --drive /dev/hdc --burn_for_real my_image_file
Blank a used CD-RW (is combinable with burning in one run):
test/libburner --drive 0 --blank_fast
Burn a compressed afio archive on-the-fly, pad up to 700 MB:
( cd my_directory ; find . -print | afio -oZ - ) | \
test/libburner --drive /dev/hdc --burn_for_real --stdin_size 734003200 -
To be read from *not mounted* CD via:
afio -tvZ /dev/hdc
Program tar would need a clean EOF which our padded CD cannot deliver.
</pre>
@subsection libburner-source Sourceode of libburner
Click on blue names of functions, structures, variables, etc in oder to
get to the according specs of libburn API or libburner sourcecode.
@include libburner.c
*/

0
doc/devel/1. Overview Normal file
View File

193
doc/devel/2. Features Normal file
View File

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

193
doc/devel/3. Use Cases Normal file
View File

@ -0,0 +1,193 @@
USE CASES FOR NG LIBISOFS
=========================
3.1 General Operations
======================
3.1.1 Creation of a new image
-----------------------------
Desc: Creation of a new ISO image from files on the local filesystem
Phases:
- User creates a new image context
- User get the root (empty) of the image
- User adds files to the image root (see 3.2.)
- User sets the options for the the new image (extension to use...)
- User gets a burn_source to write the image.
- The burn_source can be used by libburn to write the new image.
3.1.2 Image growing (multisession)
----------------------------------
Desc: An existing image can be grown with new files. New content is added
incrementally. Suitable for multisession. Growing support for
overwritteable media.
Phases:
- Uses reads an existing image to get the image context.
- User get the root of the image
- User modifies the image tree (see 3.2.)
- User sets the options for the the new image (extension to use...)
A required option will be the nwa for the image.
Optionally it can pass a pointer to a 64K buffer, that will be filled
with suitable volume descriptors to be used with overwrieable media.
- User gets a burn_source to write the image.
- The burn_source can be used by libburn to write an image that should be
appended to the previous image.
3.1.3 Image modification
------------------------
Desc: Creation of a new image from the contents of a previous image.
Phases:
- Uses reads an existing image to get the image context.
- User get the root of the image
- User modifies the image tree (see 3.2.)
- User sets the options for the the new image (extension to use...)
- User gets a burn_source to write the image.
- The burn_source can be used by libburn to write the image to another
device or file.
3.2 Tree operations
===================
3.2.1 Addition of contents
--------------------------
All addition operations take a parent dir. The functions check that the
node name is unique among all children. Image context options determine
what to do if a file with such name already exist.
3.2.1.1 Directories
--------------------
- Creation of new directories in image, given a parent dir. and a name.
Attributes are initialized to default values
- Addition of a dir from the filesystem, given a parent.
Dir contents are not added. Name and other attributes taken from
the dir on filesystem
- Recursive addition of a dir, given a parent. Directory contents are
recursivelly added to image.
3.2.1.2 Regular files
----------------------
- Addition of a local filesystem file. Name, attributes and contents to
be written taken from the filesystem file.
- Addition of files from the previous image. Files are automatically
added to the tree when the image is read. Name and attrbs taken from
previous image. When the image has no RR extensions, unavailable atts
are initialized to default values. The contents are only written to
img if we choose image modification.
- Addition of filtered files. Name and atts taken from the local
filesystem. A filter (see 3.3) is applied to the file contents before
written to image.
- Addition of splitted files. Like local filesystem files, but the file
is splitted in several files on a given size. Suitable for big (> 2GB)
files. Name of the splitted files automatically generated.
3.2.1.3 Symbolic links
----------------------
Simbolic links are only written to image if RR extensions are enabled.
- Addition of a simbolic link from local filesystem. Name, atts and
dest of a path are taken from the simbolic link.
- Addition of new link on image to a path. Name and dest specified,
the destination is specified as a path. Attributes initialized to
default values.
- Addition of new link on image to another node. Name and dest
specified, the dest is set to a node previously added to image.
When written, the destination path is computed as the relative path
from the link to the destination node. Attributes initialized to
default values.
3.2.1.4 Special files (block devices, fifos...)
-----------------------------------------------
Special files are only written to image if RR extensions are enabled.
- Addition of special files from filesystem.
- Creation of new special files on image.
3.2.2 Modification of contents
------------------------------
3.2.2.1 Deletion of nodes
-------------------------
- Any node can be deleted. When a dir is remove, all its contents
are also removed.
3.2.2.2 Move
------------
- Any node can be move to another dir..
3.2.2.3 Rename
--------------
- You can change the name of any node
3.2.2.4 Change of POSIX attributes
----------------------------------
- Following POSIX atts can be changed: owner (uid/gid), permissions,
timestamps.
3.2.3 Bootable information
--------------------------
- Addition of a boot image to a volume.
- In most cases, the catalog and the boot image itself is added to the
iso tree.
- Alternatively, user can select to add a hidden images, i.e., images
that don't appear in the iso tree.
- Modification of boot image attributes:
- bootable flag
- load segment
- load size
- Automatic patching of isolinux images. User needs to set whether to apply
this.
- Reading of El-Torito info from multisession images. Modification of its
attributes.
- Removing of El-Torito images
3.2.4 Other operations
----------------------
3.2.4.1 Set file sort weight
-----------------------------
- Any file can have a sort weight, that will determine the order in
which the files are written to image
3.2.4.2 Hidding of nodes
------------------------
- Files can be hidden in the RR or Joliet tree
3.3 Filters
===========
[TODO]
Support for:
- compression filter
- encryption filter
- external process filter

0
doc/devel/4. Design Normal file
View File

View File

7
doc/devel/README Normal file
View File

@ -0,0 +1,7 @@
Index
=====
1. Overview
2. Features
3. Design
4. Implementation

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,821 @@
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0" class="java.beans.XMLDecoder">
<object class="com.horstmann.violet.SequenceDiagramGraph">
<void method="addNode">
<object id="LifelineNode0" class="com.horstmann.violet.ImplicitParameterNode">
<void property="name">
<void property="text">
<string>fs:Filesystem</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>160.0</double>
<double>73.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ActivationBarNode0" class="com.horstmann.violet.CallNode">
<void method="addChild">
<object id="LifelineNode1" class="com.horstmann.violet.ImplicitParameterNode">
<void property="name">
<void property="text">
<string>file:FileSource</string>
</void>
</void>
</object>
</void>
<void property="implicitParameter">
<object idref="LifelineNode0"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>192.0</double>
<double>209.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="LifelineNode1"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>274.0</double>
<double>202.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="LifelineNode2" class="com.horstmann.violet.ImplicitParameterNode">
<void property="name">
<void property="text">
<string>User</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>34.86475730998367</double>
<double>0.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ActivationBarNode1" class="com.horstmann.violet.CallNode">
<void method="addChild">
<object idref="LifelineNode0"/>
</void>
<void method="addChild">
<object id="LifelineNode3" class="com.horstmann.violet.ImplicitParameterNode">
<void property="name">
<void property="text">
<string>b:TNBuilder</string>
</void>
</void>
</object>
</void>
<void method="addChild">
<object idref="ActivationBarNode0"/>
</void>
<void method="addChild">
<object id="ActivationBarNode2" class="com.horstmann.violet.CallNode">
<void method="addChild">
<object id="ActivationBarNode3" class="com.horstmann.violet.CallNode">
<void method="addChild">
<object id="ActivationBarNode4" class="com.horstmann.violet.CallNode">
<void property="implicitParameter">
<object idref="LifelineNode1"/>
</void>
</object>
</void>
<void method="addChild">
<object id="LifelineNode4" class="com.horstmann.violet.ImplicitParameterNode">
<void property="name">
<void property="text">
<string>ftn:FileTN</string>
</void>
</void>
</object>
</void>
<void method="addChild">
<object id="ActivationBarNode5" class="com.horstmann.violet.CallNode">
<void property="implicitParameter">
<object idref="LifelineNode4"/>
</void>
</object>
</void>
<void method="addChild">
<object id="LifelineNode5" class="com.horstmann.violet.ImplicitParameterNode">
<void property="name">
<void property="text">
<string>fs:FileStream</string>
</void>
</void>
</object>
</void>
<void method="addChild">
<object id="ActivationBarNode6" class="com.horstmann.violet.CallNode">
<void property="implicitParameter">
<object idref="LifelineNode4"/>
</void>
</object>
</void>
<void property="implicitParameter">
<object idref="LifelineNode3"/>
</void>
</object>
</void>
<void property="implicitParameter">
<object id="LifelineNode6" class="com.horstmann.violet.ImplicitParameterNode">
<void property="name">
<void property="text">
<string>d:DirTreeNode</string>
</void>
</void>
</object>
</void>
</object>
</void>
<void method="addChild">
<object id="ActivationBarNode7" class="com.horstmann.violet.CallNode">
<void property="implicitParameter">
<object idref="LifelineNode4"/>
</void>
</object>
</void>
<void property="implicitParameter">
<object idref="LifelineNode2"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>66.86475730998367</double>
<double>80.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="LifelineNode3"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>539.756828460011</double>
<double>126.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="LifelineNode6"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>651.0</double>
<double>0.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ActivationBarNode2"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>683.0</double>
<double>305.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ActivationBarNode3"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>571.756828460011</double>
<double>328.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ActivationBarNode4"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>306.0</double>
<double>351.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="LifelineNode4"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>331.97135964975513</double>
<double>374.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ActivationBarNode5"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>363.97135964975513</double>
<double>457.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="LifelineNode5"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>418.8259109283281</double>
<double>480.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ActivationBarNode6"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>363.97135964975513</double>
<double>563.0</double>
</void>
</object>
</void>
<void method="addNode">
<object class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>1. User wants to add a file to a dir in the iso node</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>143.89406091532933</double>
<double>16.868736840587744</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>2. It creates the source filesystem and the
custom builder</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>317.51829970572646</double>
<double>74.92004824517142</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode0" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double0" property="bounds">
<void method="setRect">
<double>570.819415201306</double>
<double>142.7048538003265</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double0"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>570.819415201306</double>
<double>142.7048538003265</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode1" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double1" property="bounds">
<void method="setRect">
<double>218.81410916050066</double>
<double>114.16388304026121</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double1"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>218.81410916050066</double>
<double>114.16388304026121</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>3. It gets the file from the filesystem
and add it to parent dir</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>379.1320632384976</double>
<double>217.4323774110454</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode2" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double2" property="bounds">
<void method="setRect">
<double>327.03195662574825</double>
<double>218.46075295682857</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double2"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>327.03195662574825</double>
<double>218.46075295682857</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>4. The dir delegates in the builder.
5. The builder stat&apos;s the source file. In
this example it&apos;s a reg. file</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>767.038589176755</double>
<double>206.92203801047344</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode3" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double3" property="bounds">
<void method="setRect">
<double>694.4969551615891</double>
<double>312.7614712457156</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double3"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>694.4969551615891</double>
<double>312.7614712457156</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode4" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double4" property="bounds">
<void method="setRect">
<double>314.9148790283507</double>
<double>359.23720542189034</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double4"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>314.9148790283507</double>
<double>359.23720542189034</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>6. The conversion is not needed, so
the builder just creates a FileTreeNode</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>762.2817607167442</double>
<double>335.3564064307673</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode5" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double5" property="bounds">
<void method="setRect">
<double>522.2869299335649</double>
<double>399.9594286575042</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double5"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>522.2869299335649</double>
<double>399.9594286575042</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode4" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>7. Sets the attributes from source</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>774.1738318667714</double>
<double>413.8440760209469</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode5" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>8 ...and a FileStream to read contents
from the FileSource</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>762.2817607167442</double>
<double>478.0612602310938</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode6" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double6" property="bounds">
<void method="setRect">
<double>534.9181953038541</double>
<double>453.1845675071054</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double6"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>534.9181953038541</double>
<double>453.1845675071054</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode7" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double7" property="bounds">
<void method="setRect">
<double>482.368075796364</double>
<double>524.8261757327898</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double7"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>482.368075796364</double>
<double>524.8261757327898</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode6" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>9. Finally, the FileTreeNode is added to
the parent dir, and returned to the user</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>757.5249322567332</double>
<double>556.5489298212734</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode8" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double8" property="bounds">
<void method="setRect">
<double>689.7401267015781</double>
<double>614.8200784564067</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double8"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>689.7401267015781</double>
<double>614.8200784564067</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ActivationBarNode7"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>363.97135964975513</double>
<double>656.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode7" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>10. The user can change any attribute
on the FileTreeNode</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>735.3910524340093</double>
<double>659.0235200658623</double>
</void>
</object>
</void>
<void method="addNode">
<object id="PointNode9" class="com.horstmann.violet.PointNode">
<void id="Rectangle2D$Double9" property="bounds">
<void method="setRect">
<double>373.3523804664971</double>
<double>666.0945878777277</double>
<double>0.0</double>
<double>0.0</double>
</void>
</void>
<void property="bounds">
<object idref="Rectangle2D$Double9"/>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>373.3523804664971</double>
<double>666.0945878777277</double>
</void>
</object>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>«create»</string>
</void>
</object>
<object idref="ActivationBarNode0"/>
<object idref="LifelineNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>«create»</string>
</void>
</object>
<object idref="ActivationBarNode1"/>
<object idref="LifelineNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ReturnEdge">
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="SOLID"/>
</void>
<void property="middleLabel">
<string>file</string>
</void>
</object>
<object idref="ActivationBarNode0"/>
<object idref="ActivationBarNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>add_file(file,b)</string>
</void>
</object>
<object idref="ActivationBarNode1"/>
<object idref="ActivationBarNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>create_file(file)</string>
</void>
</object>
<object idref="ActivationBarNode2"/>
<object idref="ActivationBarNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>lstat()</string>
</void>
</object>
<object idref="ActivationBarNode3"/>
<object idref="ActivationBarNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ReturnEdge">
<void property="middleLabel">
<string>S_IFREG</string>
</void>
</object>
<object idref="ActivationBarNode4"/>
<object idref="ActivationBarNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>«create»</string>
</void>
</object>
<object idref="ActivationBarNode3"/>
<object idref="LifelineNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>set attributes</string>
</void>
</object>
<object idref="ActivationBarNode3"/>
<object idref="ActivationBarNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ReturnEdge"/>
<object idref="ActivationBarNode5"/>
<object idref="ActivationBarNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ReturnEdge">
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="SOLID"/>
</void>
<void property="middleLabel">
<string>ftn</string>
</void>
</object>
<object idref="ActivationBarNode3"/>
<object idref="ActivationBarNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>«create»</string>
</void>
</object>
<object idref="ActivationBarNode3"/>
<object idref="LifelineNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>set stream (fs)</string>
</void>
</object>
<object idref="ActivationBarNode3"/>
<object idref="ActivationBarNode6"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ReturnEdge"/>
<object idref="ActivationBarNode6"/>
<object idref="ActivationBarNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ReturnEdge">
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="SOLID"/>
</void>
<void property="middleLabel">
<string>ftn</string>
</void>
</object>
<object idref="ActivationBarNode2"/>
<object idref="ActivationBarNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>«create»</string>
</void>
</object>
<object idref="ActivationBarNode1"/>
<object idref="LifelineNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>get(path)</string>
</void>
</object>
<object idref="ActivationBarNode1"/>
<object idref="ActivationBarNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode0"/>
<object idref="PointNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode0"/>
<object idref="PointNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode1"/>
<object idref="PointNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode2"/>
<object idref="PointNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode2"/>
<object idref="PointNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode3"/>
<object idref="PointNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode4"/>
<object idref="PointNode6"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode5"/>
<object idref="PointNode7"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode6"/>
<object idref="PointNode8"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.CallEdge">
<void property="middleLabel">
<string>set_permission()</string>
</void>
</object>
<object idref="ActivationBarNode1"/>
<object idref="ActivationBarNode7"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ReturnEdge"/>
<object idref="ActivationBarNode7"/>
<object idref="ActivationBarNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="NoteNode7"/>
<object idref="PointNode9"/>
</void>
</object>
</java>

View File

@ -0,0 +1,884 @@
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0" class="java.beans.XMLDecoder">
<object class="com.horstmann.violet.ClassDiagramGraph">
<void method="addNode">
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
<void property="methods">
<void property="text">
<string>get_root()
get_from_path(char *)</string>
</void>
</void>
<void property="name">
<void property="text">
<string>«interface»
Filesystem</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>159.04005306497305</double>
<double>489.4913761627291</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>MountedFilesytem</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>56.38849919058573</double>
<double>630.9884605487425</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>IsoImage</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>258.8562868808994</double>
<double>766.3563832139356</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode1" class="com.horstmann.violet.InterfaceNode">
<void property="methods">
<void property="text">
<string>lstat()
read()
close()
open()
readdir()</string>
</void>
</void>
<void property="name">
<void property="text">
<string>«interface»
SourceFile</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>481.55979910778467</double>
<double>464.84194569982117</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>TarFile</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>176.58261638364775</double>
<double>701.0593878047844</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode2" class="com.horstmann.violet.InterfaceNode">
<void property="methods">
<void property="text">
<string>read()
size()
open()
close()</string>
</void>
</void>
<void property="name">
<void property="text">
<string>«interface»
Stream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>779.894860994415</double>
<double>340.36024540554786</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FdStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>907.9433913981195</double>
<double>505.6600343909271</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FileStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>646.2536512193697</double>
<double>514.5953286599063</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>TransformStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>774.6238447615127</double>
<double>513.9203093177954</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode3" class="com.horstmann.violet.InterfaceNode">
<void property="methods">
<void property="text">
<string>create_file()
create_symlink()
create_dir()</string>
</void>
</void>
<void property="name">
<void property="text">
<string>«interface»
TreeNodeBuilder</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>469.51180397870456</double>
<double>119.92057094444797</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>TreeNode</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>777.5164467644091</double>
<double>137.7586776694888</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>File</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>776.3272396494064</double>
<double>235.11044131455145</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode8" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Dir</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>899.7797731623193</double>
<double>242.40651557378732</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode9" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Symlink</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>658.5957352641371</double>
<double>237.4888555445569</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode4" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
FileBuilder</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>68.74900622278733</double>
<double>236.29964842955417</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode5" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
DirBuilder</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>190.04813195306485</double>
<double>236.2996484295542</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode6" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
SymlinkBuilder</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>304.21201499332614</double>
<double>236.29964842955417</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>POSIX inspired interface to files on different filesystems.
open/close act as a opendir/closedir if the file is a dir,
I think we don&apos;t need different function to open a dir.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>154.8805850420814</double>
<double>333.9382491299707</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>&quot;Sources&quot; for file contents</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>587.0127806828101</double>
<double>358.755499461917</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode10" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>CutOutStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>845.6997102991108</double>
<double>605.2834046956852</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode11" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FilterStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>721.2489168102784</double>
<double>605.2834046956852</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode7" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
Filter</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>715.5920625607861</double>
<double>705.6925676241749</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>Used for arbitray streams, not related to
filesystem high-level idea. Also used for
files like fifos, that can&apos;t be added directly as
regulat files via de Builder, because its size is
unknown. The need to be added as new_files
on image</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>906.5108934811542</double>
<double>328.0975464705584</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>Create the user-specified TreeNode from the
user-specified source. If the source type differs the
TreeNode type the use wants to create, it makes
the needed conversion, if possible. Each builder
implementation can do different conversions.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>654.7808793787427</double>
<double>20.610173055266337</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode4" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>Together with the SourceFile encapsulates the
access to a given filesystem and abstracts it to
a POSIX interface.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>20.610173055266422</double>
<double>403.050865276332</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode5" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>The TreeNodeBuilder can be created with
the combination of different interfaces for
each factory method</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>149.90663761154804</double>
<double>57.982756057296896</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode12" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>MountedSrc</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>373.3523804664971</double>
<double>634.9818895055197</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode13" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>TarSrc</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>479.4183976444791</double>
<double>695.7930726875627</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode14" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>IsoSrc</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>578.4133470105959</double>
<double>773.574818618083</double>
</void>
</object>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="InterfaceNode0"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode4"/>
<object idref="InterfaceNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode3"/>
<object idref="InterfaceNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode0"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode2"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode1"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode4"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
<void property="middleLabel">
<string>{{create}}</string>
</void>
</object>
<object idref="InterfaceNode3"/>
<object idref="ClassNode6"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode9"/>
<object idref="ClassNode6"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode7"/>
<object idref="ClassNode6"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode8"/>
<object idref="ClassNode6"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode7"/>
<object idref="InterfaceNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="InterfaceNode3"/>
<object idref="InterfaceNode6"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="InterfaceNode3"/>
<object idref="InterfaceNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="InterfaceNode3"/>
<object idref="InterfaceNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="InterfaceNode3"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode1"/>
<object idref="NoteNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode2"/>
<object idref="NoteNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode11"/>
<object idref="ClassNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode10"/>
<object idref="ClassNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode11"/>
<object idref="InterfaceNode7"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode3"/>
<object idref="NoteNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode3"/>
<object idref="NoteNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode0"/>
<object idref="NoteNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode4"/>
<object idref="NoteNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode5"/>
<object idref="NoteNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode6"/>
<object idref="NoteNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode5"/>
<object idref="InterfaceNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode12"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode13"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode14"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode12"/>
<object idref="ClassNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode13"/>
<object idref="ClassNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode14"/>
<object idref="ClassNode1"/>
</void>
</object>
</java>

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,634 @@
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0" class="java.beans.XMLDecoder">
<object class="com.horstmann.violet.ClassDiagramGraph">
<void method="addNode">
<object class="com.horstmann.violet.PackageNode">
<void method="addChild">
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
BurnSource</string>
</void>
</void>
</object>
</void>
<void property="name">
<string>libburn</string>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>600.0</double>
<double>50.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="InterfaceNode0"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>612.4370214406964</double>
<double>81.3237865499184</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Ecma119Source</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>604.1172144213822</double>
<double>242.59825146055505</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>WriterState</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>861.1034292438676</double>
<double>244.31119796826698</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FilesWriterSt</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>984.2531292100068</double>
<double>359.95094883087904</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>VolDescWriterSt</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>717.2457054234224</double>
<double>357.4185959653686</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>DirInfoWriterSt</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>854.6043620021998</double>
<double>355.85097462036043</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Ecma119Image</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>392.3294860655768</double>
<double>240.39714472372754</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>The context data for image burn sources, contains
references to the tree, creation options...</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>261.45257180386454</double>
<double>85.80450046553075</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Ecma119Node</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>291.8219414851778</double>
<double>612.806815288254</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode1" class="com.horstmann.violet.InterfaceNode">
<void property="methods">
<void property="text">
<string>init()
write_voldesc()
write_dir_info()</string>
</void>
</void>
<void property="name">
<void property="text">
<string>«interface»
ImageWriter</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>401.9520048709197</double>
<double>344.8700633507891</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>JolietNode</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>409.0872475609359</double>
<double>614.8200784564067</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode8" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FileRegistry</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>718.2810974616434</double>
<double>459.0339463910502</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode9" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Ecma119Writer</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>273.51763645062584</double>
<double>489.95333138112096</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode10" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>JolietWriter</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>404.3304191009253</double>
<double>485.1965029211101</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode11" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>ElToritoWriter</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>512.5482665661723</double>
<double>485.19650292111</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode12" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>size : off_t
block : uint32_t</string>
</void>
</void>
<void property="name">
<void property="text">
<string>IsoFile</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>720.659511691649</double>
<double>568.4410009713001</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode2" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
Stream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>909.7434429770816</double>
<double>580.3330721213274</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>ImageWriter goal is to encapsulate the output
of image blocks related to one &quot;specification&quot;,
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&apos;t be
avoided, as Ecma119Image has to be responsible of the
instantation in the correct order and following the user
needs.
</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>2.3784142300054896</double>
<double>160.54296052536733</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>The files are registered into the file registry, that will take care
about the written of content.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>286.59891471565567</double>
<double>708.7674405416217</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>Each state will invoque property method in each of
the ImageWriters. Some writers can return without
outputting anything. It is possible that when dealing
with UDF or other specification we would need new
states and methods in ImageWriter</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>765.8493820617523</double>
<double>132.001989765302</double>
</void>
</object>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode0"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode3"/>
<object idref="ClassNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode4"/>
<object idref="ClassNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode2"/>
<object idref="ClassNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="DIAMOND"/>
</void>
</object>
<object idref="ClassNode0"/>
<object idref="ClassNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode5"/>
<object idref="NoteNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode0"/>
<object idref="ClassNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode10"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode9"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode11"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>*</string>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="ClassNode5"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode9"/>
<object idref="ClassNode6"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode10"/>
<object idref="ClassNode7"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>*</string>
</void>
</object>
<object idref="ClassNode8"/>
<object idref="ClassNode12"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode12"/>
<object idref="InterfaceNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode5"/>
<object idref="ClassNode8"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode2"/>
<object idref="ClassNode8"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="InterfaceNode1"/>
<object idref="ClassNode8"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode1"/>
<object idref="NoteNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode6"/>
<object idref="NoteNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode7"/>
<object idref="NoteNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode8"/>
<object idref="NoteNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode1"/>
<object idref="NoteNode3"/>
</void>
</object>
</java>

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -0,0 +1,552 @@
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0" class="java.beans.XMLDecoder">
<object class="com.horstmann.violet.ClassDiagramGraph">
<void method="addNode">
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Volume</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>479.2699858975891</double>
<double>226.94112549695433</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>block : uint32_t</string>
</void>
</void>
<void property="name">
<void property="text">
<string>ElToritoCatalog</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>472.58578643762684</double>
<double>344.73506473629425</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>bootable : bool
type : enum
partition_type : enum
load_seg : uint16
load_size : uint16
patch_isolinux : bool
block: uint32_t</string>
</void>
</void>
<void property="name">
<void property="text">
<string>BootImage</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>470.4142135623731</double>
<double>487.3919189857866</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>In a future we can support several boot
images</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>251.63542622468316</double>
<double>429.69343417595167</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>img : boolean</string>
</void>
</void>
<void property="name">
<void property="text">
<string>BootNode</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>193.07106781186545</double>
<double>334.49242404917493</double>
</void>
</object>
</void>
<void method="addNode">
<object class="com.horstmann.violet.PackageNode">
<void method="addChild">
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>TreeNode</string>
</void>
</void>
</object>
</void>
<void property="name">
<string>iso_tree</string>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>180.0</double>
<double>40.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ClassNode4"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>193.0</double>
<double>69.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>The img field is an implementation detail, used
to distinguish between the catalog node and the image
node. This is needed when the image is written.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>57.81118318204312</double>
<double>584.0458146424488</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>The support for growing or modify El-Torito images
is really hard to implement. The reason: when the
image is hidden, we don&apos;t know its size, so the best we
can do is just refer to the old image. When modify, all
we can do may be wrong.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>748.978906441031</double>
<double>574.8973495522459</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>The block in both Catalog and BootImage is needed
for multissession images</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>629.3242465083424</double>
<double>441.1316647878586</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>File</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>188.09040379562163</double>
<double>172.5340546095176</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>CatalogStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>851.105100475371</double>
<double>283.5127233261827</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FileStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>743.4055403867466</double>
<double>284.4253525880894</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode8" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>TransformStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>958.5987801403015</double>
<double>279.8322618091961</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
Stream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>847.6728065449973</double>
<double>157.05765855361264</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode9" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>IsoLinuxPatch</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>968.73629022557</double>
<double>384.6660889654818</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode4" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>Generates the content of the catalog on-the-fly</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>517.6021638285529</double>
<double>107.48023074035522</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode5" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>To apply the needed patch to isolinux
images</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>923.4814562296309</double>
<double>509.1168824543143</double>
</void>
</object>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>1 image</string>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="ClassNode1"/>
<object idref="ClassNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode1"/>
<object idref="NoteNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>0..1 boot_cat</string>
</void>
</object>
<object idref="ClassNode0"/>
<object idref="ClassNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>0..1 node</string>
</void>
</object>
<object idref="ClassNode1"/>
<object idref="ClassNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode3"/>
<object idref="NoteNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>0..1 node</string>
</void>
</object>
<object idref="ClassNode2"/>
<object idref="ClassNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode3"/>
<object idref="ClassNode5"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode5"/>
<object idref="ClassNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode8"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode7"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>1</string>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="ClassNode8"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode6"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode1"/>
<object idref="NoteNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode2"/>
<object idref="NoteNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode2"/>
<object idref="NoteNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode5"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode9"/>
<object idref="ClassNode8"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode1"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode2"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode6"/>
<object idref="ClassNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode6"/>
<object idref="NoteNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode9"/>
<object idref="NoteNode5"/>
</void>
</object>
</java>

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,748 @@
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0" class="java.beans.XMLDecoder">
<object class="com.horstmann.violet.ClassDiagramGraph">
<void method="addNode">
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>volume_id : char*
publisher_id : char*
data_preparer_id : char*
system_id : char*
application_id : char*
copyright_file_id : char*
abstract_file_id : char*
biblio_file_id : char*</string>
</void>
</void>
<void property="name">
<void property="text">
<string>Volume</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>1160.4799402311673</double>
<double>240.649943764645</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>sort_weight : int
block : uint32_t</string>
</void>
</void>
<void property="name">
<void property="text">
<string>File</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>687.5479565719912</double>
<double>269.2931470368318</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>name : char *
attribs : struct stat
hidden : enum</string>
</void>
</void>
<void property="name">
<void property="text">
<string>TreeNode</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>706.83671056434</double>
<double>108.4726745515399</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
<void property="methods">
<void property="text">
<string>add(XXX)
remove(Node)
children()</string>
</void>
</void>
<void property="name">
<void property="text">
<string>Directory</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>986.1687535943008</double>
<double>267.29314703683184</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>dest : char*</string>
</void>
</void>
<void property="name">
<void property="text">
<string>Symlink</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>571.9364350336367</double>
<double>273.31078127658077</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Special</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>813.0651280884073</double>
<double>272.20749521231266</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>name : char*</string>
</void>
</void>
<void property="methods">
<void property="text">
<string>&lt;&lt;static&gt;&gt;new(id)
&lt;&lt;static&gt;&gt;read(src, opts)
create()
grow()</string>
</void>
</void>
<void property="name">
<void property="text">
<string>Image</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>1149.1980515339465</double>
<double>455.5218613006981</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>In addition to the dest as a path, it could
be a good idea to have a ref to tree node.
That way we can compute the dest on creation
time, and thus links to files on image are also valid
after moving or renaming those files</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>322.02220861890066</double>
<double>362.2044136147912</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>Image is a context for the creation of images. Its &quot;static&quot;
methods, new() and read() are used to create a new
image context, either from scratch or from an existing
image (for example, a ms disc). The methods create() and
grow() return an BurnSource suitable for libburn.
create() writes a full image, grow() only add to the image
the new files, thus it is suitable for a new session
</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>1212.7956394939486</double>
<double>697.0920982847697</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>Ecma119Source</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>1423.5617211564486</double>
<double>483.61244144432396</double>
</void>
</object>
</void>
<void method="addNode">
<object class="com.horstmann.violet.PackageNode">
<void method="addChild">
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
BurnSource</string>
</void>
</void>
</object>
</void>
<void property="name">
<string>Libburn</string>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>1420.0</double>
<double>280.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="InterfaceNode0"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>1431.4906533445824</double>
<double>311.35760744838467</double>
</void>
</object>
</void>
<void method="addNode">
<object class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>Class diagram for the public tree. Note that getters and setters are not shown,
to improve readability. Note also that not all the attributes will have public getters
or/and setters.
El-Torito related information is shown in another diagram.
We don&apos;t show the several functions in Dir to manage the tree.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>290.59037712396525</double>
<double>9.859316379054544</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode1" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
DataSource</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>1192.781692587207</double>
<double>608.8954677283948</double>
</void>
</object>
</void>
<void method="addNode">
<object class="com.horstmann.violet.PackageNode">
<void method="addChild">
<object id="InterfaceNode2" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
Filters</string>
</void>
</void>
</object>
</void>
<void property="name">
<string>filters</string>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>260.0</double>
<double>710.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="InterfaceNode2"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>265.45434264405947</double>
<double>743.9994422711634</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode8" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>TransformStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>486.9335577265969</double>
<double>640.636302316303</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode9" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>CutOutStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>555.9916340674516</double>
<double>750.220757440409</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode3" class="com.horstmann.violet.InterfaceNode">
<void property="methods">
<void property="text">
<string>get_size()
read()
open()
close()
is_repeatable()</string>
</void>
</void>
<void property="name">
<void property="text">
<string>«interface»
Stream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>688.5487814157467</double>
<double>437.25152600545294</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode10" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FdStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>680.6673668471356</double>
<double>637.245696021424</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode11" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FileStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>828.9404615480411</double>
<double>642.40096597045</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode12" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FilteredStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>428.449880813367</double>
<double>747.5389646099015</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode4" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
SourceFile</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>1000.6667341519202</double>
<double>639.0812755928229</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>For files, we need to know whethe they come
from a previous session. That&apos;s the purpose of
the block field</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>818.829652614022</double>
<double>414.36457377531684</double>
</void>
</object>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>1 volume</string>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="ClassNode6"/>
<object idref="ClassNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode4"/>
<object idref="NoteNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode6"/>
<object idref="NoteNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode7"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
<void property="middleLabel">
<string>{create}</string>
</void>
</object>
<object idref="ClassNode6"/>
<object idref="ClassNode7"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>0..1</string>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode6"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>* children</string>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="ClassNode3"/>
<object idref="ClassNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>1 root</string>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="ClassNode0"/>
<object idref="ClassNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode4"/>
<object idref="ClassNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode1"/>
<object idref="ClassNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode5"/>
<object idref="ClassNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode3"/>
<object idref="ClassNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>1 parent</string>
</void>
</object>
<object idref="ClassNode2"/>
<object idref="ClassNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode8"/>
<object idref="InterfaceNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode11"/>
<object idref="InterfaceNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>1</string>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="ClassNode8"/>
<object idref="InterfaceNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode10"/>
<object idref="InterfaceNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode9"/>
<object idref="ClassNode8"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode12"/>
<object idref="ClassNode8"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode12"/>
<object idref="InterfaceNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode11"/>
<object idref="InterfaceNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>1 src</string>
</void>
</object>
<object idref="ClassNode1"/>
<object idref="InterfaceNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode1"/>
<object idref="NoteNode2"/>
</void>
</object>
</java>

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

File diff suppressed because it is too large Load Diff

492
doc/devel/UML/stream.violet Normal file
View File

@ -0,0 +1,492 @@
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0" class="java.beans.XMLDecoder">
<object class="com.horstmann.violet.ClassDiagramGraph">
<void method="addNode">
<object id="ClassNode0" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>TransformStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>374.71280028618764</double>
<double>246.7337520453866</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode0" class="com.horstmann.violet.InterfaceNode">
<void property="methods">
<void property="text">
<string>get_size()
read()
open()
close()
is_repeatable()</string>
</void>
</void>
<void property="name">
<void property="text">
<string>«interface»
Stream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>576.3280239753375</double>
<double>43.34897573453627</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode1" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FileStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>741.9465965652432</double>
<double>246.8166228690261</double>
</void>
</object>
</void>
<void method="addNode">
<object class="com.horstmann.violet.PackageNode">
<void method="addChild">
<object id="ClassNode2" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>CompressionFilter</string>
</void>
</void>
</object>
</void>
<void method="addChild">
<object id="ClassNode3" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>EncryptionFilter</string>
</void>
</void>
</object>
</void>
<void method="addChild">
<object id="ClassNode4" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>ExtAppFilter</string>
</void>
</void>
</object>
</void>
<void method="addChild">
<object id="InterfaceNode1" class="com.horstmann.violet.InterfaceNode">
<void property="methods">
<void property="text">
<string>filter(in, out)</string>
</void>
</void>
<void property="name">
<void property="text">
<string>«interface»
Filter</string>
</void>
</void>
</object>
</void>
<void property="name">
<string>Filters</string>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>270.0</double>
<double>480.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode0" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>A Stream to read data from an abstract
file represented by a SourceFile</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>781.6101730552666</double>
<double>137.2161620284267</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode1" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>A stream to get data from an arbitrary file
descritor. size must be know in advance.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>580.8730162779191</double>
<double>392.3137084989848</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode5" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>fd : int
size : off_t</string>
</void>
</void>
<void property="name">
<void property="text">
<string>FdStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>565.61818228198</double>
<double>253.24264068711926</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ClassNode2"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>281.2426406871193</double>
<double>620.6274169979695</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ClassNode3"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>429.51546936508925</double>
<double>624.9910026589843</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="ClassNode4"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>568.2426406871186</double>
<double>624.6274169979695</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode2" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>A Filter do a tranformation on a stream of data.
The main difference with TransformSources is that
a Filter can be applied to several sources.
NOTES:
- filter() method still to define
- A filter_changes_size() method can be useful
</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>724.6274169979696</double>
<double>510.3015151901651</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode6" class="com.horstmann.violet.ClassNode">
<void property="name">
<void property="text">
<string>FilteredStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>439.0</double>
<double>357.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="ClassNode7" class="com.horstmann.violet.ClassNode">
<void property="attributes">
<void property="text">
<string>size : off_t
lba: off_t</string>
</void>
</void>
<void property="name">
<void property="text">
<string>CutOutStream</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>321.0</double>
<double>358.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode3" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>This can be implemented as a Filter, but
it has no sense to have the same cut out
filter to several sources, so this is a better
place.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>67.0</double>
<double>276.0</double>
</void>
</object>
</void>
<void method="addNode">
<object id="NoteNode4" class="com.horstmann.violet.NoteNode">
<void property="text">
<void property="text">
<string>A stream that applies some transformation
to the contents of another stream.</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>122.0</double>
<double>183.0</double>
</void>
</object>
</void>
<void method="addNode">
<object idref="InterfaceNode1"/>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>437.57046683437824</double>
<double>509.23933115391503</double>
</void>
</object>
</void>
<void method="addNode">
<object id="InterfaceNode2" class="com.horstmann.violet.InterfaceNode">
<void property="name">
<void property="text">
<string>«interface»
SourceFile</string>
</void>
</void>
</object>
<object class="java.awt.geom.Point2D$Double">
<void method="setLocation">
<double>920.6530291048848</double>
<double>248.90158697766475</double>
</void>
</object>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode0"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode1"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
<void property="endLabel">
<string>1</string>
</void>
<void property="startArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="BLACK_DIAMOND"/>
</void>
</object>
<object idref="ClassNode0"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode5"/>
<object idref="InterfaceNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode5"/>
<object idref="NoteNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode7"/>
<object idref="ClassNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
</object>
<object idref="ClassNode6"/>
<object idref="ClassNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode7"/>
<object idref="NoteNode3"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode0"/>
<object idref="NoteNode4"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode2"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode3"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="VHV"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="TRIANGLE"/>
</void>
<void property="lineStyle">
<object class="com.horstmann.violet.LineStyle" field="DOTTED"/>
</void>
</object>
<object idref="ClassNode4"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode6"/>
<object idref="InterfaceNode1"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="InterfaceNode1"/>
<object idref="NoteNode2"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.NoteEdge"/>
<object idref="ClassNode1"/>
<object idref="NoteNode0"/>
</void>
<void method="connect">
<object class="com.horstmann.violet.ClassRelationshipEdge">
<void property="bentStyle">
<object class="com.horstmann.violet.BentStyle" field="HVH"/>
</void>
<void property="endArrowHead">
<object class="com.horstmann.violet.ArrowHead" field="V"/>
</void>
</object>
<object idref="ClassNode1"/>
<object idref="InterfaceNode2"/>
</void>
</object>
</java>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

91
doc/devel/codestyle.xml Normal file
View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="1">
<profile kind="CodeFormatterProfile" name="nglibisofs" version="1">
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.lineSplit" value="80"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression" value="16"/>
<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block_in_case" value="next_line_shifted"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation" value="18"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration" value="18"/>
<setting id="org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration" value="end_of_line"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.cdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
</profile>
</profiles>

View File

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

View File

@ -17,8 +17,8 @@
# This tag specifies the encoding used for all characters in the config file that # 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 # 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 # 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 # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list
# possible encodings. # of possible encodings.
DOXYFILE_ENCODING = UTF-8 DOXYFILE_ENCODING = UTF-8

View File

@ -1,4 +0,0 @@
all clean:
$(MAKE) -C .. -$(MAKEFLAGS) $@
.PHONY: all clean

328
libisofs/buffer.c Normal file
View File

@ -0,0 +1,328 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/*
* Synchronized ring buffer, works with a writer thread and a read thread.
*
* TODO #00010 : optimize ring buffer
* - write/read at the end of buffer requires a second mutex_lock, even if
* there's enought space/data at the beginning
* - pre-buffer for writes < BLOCK_SIZE
*
*/
#include "buffer.h"
#include "libburn/libburn.h"
#include "ecma119.h"
#include <pthread.h>
#include <string.h>
#ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
struct iso_ring_buffer
{
uint8_t *buf;
/*
* Max number of bytes in buffer
*/
size_t cap;
/*
* Number of bytes available.
*/
size_t size;
/* position for reading and writing, offset from buf */
size_t rpos;
size_t wpos;
/*
* flags to report if read or writer threads ends execution
* 0 not finished, 1 finished ok, 2 finish with error
*/
unsigned int rend :2;
unsigned int wend :2;
/* just for statistical purposes */
unsigned int times_full;
unsigned int times_empty;
pthread_mutex_t mutex;
pthread_cond_t empty;
pthread_cond_t full;
};
/**
* Create a new buffer.
*
* The created buffer should be freed with iso_ring_buffer_free()
*
* @param size
* Number of blocks in buffer. You should supply a number >= 32, otherwise
* size will be ignored and 32 will be used by default, which leads to a
* 64 KiB buffer.
* @return
* 1 success, < 0 error
*/
int iso_ring_buffer_new(size_t size, IsoRingBuffer **rbuf)
{
IsoRingBuffer *buffer;
if (rbuf == NULL) {
return ISO_NULL_POINTER;
}
buffer = malloc(sizeof(IsoRingBuffer));
if (buffer == NULL) {
return ISO_OUT_OF_MEM;
}
buffer->cap = (size > 32 ? size : 32) * BLOCK_SIZE;
buffer->buf = malloc(buffer->cap);
if (buffer->buf == NULL) {
free(buffer);
return ISO_OUT_OF_MEM;
}
buffer->size = 0;
buffer->wpos = 0;
buffer->rpos = 0;
buffer->times_full = 0;
buffer->times_empty = 0;
buffer->rend = buffer->wend = 0;
/* init mutex and waiting queues */
pthread_mutex_init(&buffer->mutex, NULL);
pthread_cond_init(&buffer->empty, NULL);
pthread_cond_init(&buffer->full, NULL);
*rbuf = buffer;
return ISO_SUCCESS;
}
void iso_ring_buffer_free(IsoRingBuffer *buf)
{
if (buf == NULL) {
return;
}
free(buf->buf);
pthread_mutex_destroy(&buf->mutex);
pthread_cond_destroy(&buf->empty);
pthread_cond_destroy(&buf->full);
free(buf);
}
/**
* Write count bytes into buffer. It blocks until all bytes where written or
* reader close the buffer.
*
* @param buf
* the buffer
* @param data
* pointer to a memory region of at least coun bytes, from which data
* will be read.
* @param
* Number of bytes to write
* @return
* 1 succes, 0 read finished, < 0 error
*/
int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count)
{
size_t len;
int bytes_write = 0;
if (buf == NULL || data == NULL) {
return ISO_NULL_POINTER;
}
while (bytes_write < count) {
pthread_mutex_lock(&buf->mutex);
while (buf->size == buf->cap) {
/*
* Note. There's only a writer, so we have no race conditions.
* Thus, the while(buf->size == buf->cap) is used here
* only to propertly detect the reader has been cancelled
*/
if (buf->rend) {
/* the read procces has been finished */
pthread_mutex_unlock(&buf->mutex);
return 0;
}
buf->times_full++;
/* wait until space available */
pthread_cond_wait(&buf->full, &buf->mutex);
}
len = MIN(count - bytes_write, buf->cap - buf->size);
if (buf->wpos + len > buf->cap) {
len = buf->cap - buf->wpos;
}
memcpy(buf->buf + buf->wpos, data + bytes_write, len);
buf->wpos = (buf->wpos + len) % (buf->cap);
bytes_write += len;
buf->size += len;
/* wake up reader */
pthread_cond_signal(&buf->empty);
pthread_mutex_unlock(&buf->mutex);
}
return ISO_SUCCESS;
}
/**
* Read count bytes from the buffer into dest. It blocks until the desired
* bytes has been read. If the writer finishes before outputting enought
* bytes, 0 (EOF) is returned, the number of bytes already read remains
* unknown.
*
* @return
* 1 success, 0 EOF, < 0 error
*/
int iso_ring_buffer_read(IsoRingBuffer *buf, uint8_t *dest, size_t count)
{
size_t len;
int bytes_read = 0;
if (buf == NULL || dest == NULL) {
return ISO_NULL_POINTER;
}
while (bytes_read < count) {
pthread_mutex_lock(&buf->mutex);
while (buf->size == 0) {
/*
* Note. There's only a reader, so we have no race conditions.
* Thus, the while(buf->size == 0) is used here just to ensure
* a reader detects the EOF propertly if the writer has been
* canceled while the reader was waiting
*/
if (buf->wend) {
/* the writer procces has been finished */
pthread_mutex_unlock(&buf->mutex);
return 0; /* EOF */
}
buf->times_empty++;
/* wait until data available */
pthread_cond_wait(&buf->empty, &buf->mutex);
}
len = MIN(count - bytes_read, buf->size);
if (buf->rpos + len > buf->cap) {
len = buf->cap - buf->rpos;
}
memcpy(dest + bytes_read, buf->buf + buf->rpos, len);
buf->rpos = (buf->rpos + len) % (buf->cap);
bytes_read += len;
buf->size -= len;
/* wake up the writer */
pthread_cond_signal(&buf->full);
pthread_mutex_unlock(&buf->mutex);
}
return ISO_SUCCESS;
}
void iso_ring_buffer_writer_close(IsoRingBuffer *buf, int error)
{
pthread_mutex_lock(&buf->mutex);
buf->wend = error ? 2 : 1;
/* ensure no reader is waiting */
pthread_cond_signal(&buf->empty);
pthread_mutex_unlock(&buf->mutex);
}
void iso_ring_buffer_reader_close(IsoRingBuffer *buf, int error)
{
pthread_mutex_lock(&buf->mutex);
if (buf->rend) {
/* reader already closed */
pthread_mutex_unlock(&buf->mutex);
return;
}
buf->rend = error ? 2 : 1;
/* ensure no writer is waiting */
pthread_cond_signal(&buf->full);
pthread_mutex_unlock(&buf->mutex);
}
/**
* Get the times the buffer was full.
*/
unsigned int iso_ring_buffer_get_times_full(IsoRingBuffer *buf)
{
return buf->times_full;
}
/**
* Get the times the buffer was empty.
*/
unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf)
{
return buf->times_empty;
}
/**
* Get the status of the buffer used by a burn_source.
*
* @param b
* A burn_source previously obtained with
* iso_image_create_burn_source().
* @param size
* Will be filled with the total size of the buffer, in bytes
* @param free_bytes
* Will be filled with the bytes currently available in buffer
* @return
* < 0 error, > 0 state:
* 1="active" : input and consumption are active
* 2="ending" : input has ended without error
* 3="failing" : input had error and ended,
* 5="abandoned" : consumption has ended prematurely
* 6="ended" : consumption has ended without input error
* 7="aborted" : consumption has ended after input error
*/
int iso_ring_buffer_get_status(struct burn_source *b, size_t *size,
size_t *free_bytes)
{
int ret;
IsoRingBuffer *buf;
if (b == NULL) {
return ISO_NULL_POINTER;
}
buf = ((Ecma119Image*)(b->data))->buffer;
/* get mutex */
pthread_mutex_lock(&buf->mutex);
if (size) {
*size = buf->cap;
}
if (free_bytes) {
*free_bytes = buf->cap - buf->size;
}
ret = (buf->rend ? 4 : 0) + (buf->wend + 1);
pthread_mutex_unlock(&buf->mutex);
return ret;
}

95
libisofs/buffer.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#ifndef LIBISO_BUFFER_H_
#define LIBISO_BUFFER_H_
#include <stdlib.h>
#include <stdint.h>
#define BLOCK_SIZE 2048
typedef struct iso_ring_buffer IsoRingBuffer;
/**
* Create a new buffer.
*
* The created buffer should be freed with iso_ring_buffer_free()
*
* @param size
* Number of blocks in buffer. You should supply a number >= 32, otherwise
* size will be ignored and 32 will be used by default, which leads to a
* 64 KiB buffer.
* @return
* 1 success, < 0 error
*/
int iso_ring_buffer_new(size_t size, IsoRingBuffer **rbuf);
/**
* Free a given buffer
*/
void iso_ring_buffer_free(IsoRingBuffer *buf);
/**
* Write count bytes into buffer. It blocks until all bytes where written or
* reader close the buffer.
*
* @param buf
* the buffer
* @param data
* pointer to a memory region of at least coun bytes, from which data
* will be read.
* @param
* Number of bytes to write
* @return
* 1 succes, 0 read finished, < 0 error
*/
int iso_ring_buffer_write(IsoRingBuffer *buf, uint8_t *data, size_t count);
/**
* Read count bytes from the buffer into dest. It blocks until the desired
* bytes has been read. If the writer finishes before outputting enought
* bytes, 0 (EOF) is returned, the number of bytes already read remains
* unknown.
*
* @return
* 1 success, 0 EOF, < 0 error
*/
int iso_ring_buffer_read(IsoRingBuffer *buf, uint8_t *dest, size_t count);
/**
* Close the buffer (to be called by the writer).
* You have to explicity close the buffer when you don't have more data to
* write, otherwise reader will be waiting forever.
*
* @param error
* Writer has finished prematurely due to an error
*/
void iso_ring_buffer_writer_close(IsoRingBuffer *buf, int error);
/**
* Close the buffer (to be called by the reader).
* If for any reason you don't want to read more data, you need to call this
* to let the writer thread finish.
*
* @param error
* Reader has finished prematurely due to an error
*/
void iso_ring_buffer_reader_close(IsoRingBuffer *buf, int error);
/**
* Get the times the buffer was full.
*/
unsigned int iso_ring_buffer_get_times_full(IsoRingBuffer *buf);
/**
* Get the times the buffer was empty.
*/
unsigned int iso_ring_buffer_get_times_empty(IsoRingBuffer *buf);
#endif /*LIBISO_BUFFER_H_*/

209
libisofs/builder.c Normal file
View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "builder.h"
#include "node.h"
#include "fsource.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
void iso_node_builder_ref(IsoNodeBuilder *builder)
{
++builder->refcount;
}
void iso_node_builder_unref(IsoNodeBuilder *builder)
{
if (--builder->refcount == 0) {
/* free private data */
builder->free(builder);
free(builder);
}
}
static
int default_create_file(IsoNodeBuilder *builder, IsoImage *image,
IsoFileSource *src, IsoFile **file)
{
int ret;
struct stat info;
IsoStream *stream;
IsoFile *node;
char *name;
if (builder == NULL || src == NULL || file == NULL) {
return ISO_NULL_POINTER;
}
ret = iso_file_source_stat(src, &info);
if (ret < 0) {
return ret;
}
/* this will fail if src is a dir, is not accessible... */
ret = iso_file_source_stream_new(src, &stream);
if (ret < 0) {
return ret;
}
/* take a ref to the src, as stream has taken our ref */
iso_file_source_ref(src);
name = iso_file_source_get_name(src);
ret = iso_node_new_file(name, stream, &node);
if (ret < 0) {
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;
}

80
libisofs/builder.h Normal file
View File

@ -0,0 +1,80 @@
/*
* 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.
*
* Note that the src is never unref, so you need to free 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_*/

View File

@ -1,107 +1,195 @@
/* /*
* Contains a simple implementation of a data source that reads from a * Copyright (c) 2007 Vreixo Formoso
* given file. *
* 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 <assert.h> #include "libisofs.h"
#include "util.h"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "libisofs.h" /**
* Private data for File IsoDataSource
#define BLOCK_SIZE 2048 */
struct file_data_src
#define BLOCK_OUT_OF_FILE -1; {
#define READ_ERROR -2; char *path;
#define SEEK_ERROR -3; int fd;
struct file_data_src {
int fd;
int nblocks;
}; };
static int /**
ds_read_block(struct data_source *src, int lba, unsigned char *buffer) * Increments the reference counting of the given IsoDataSource.
*/
void iso_data_source_ref(IsoDataSource *src)
{ {
struct file_data_src *data; src->refcount++;
assert(src && buffer);
data = (struct file_data_src*)src->data;
/* For block devices size is always 0, so this can't be used.
* if (lba >= data->nblocks)
* return BLOCK_OUT_OF_FILE;
*/
/* goes to requested block */
if ( lseek(data->fd, (off_t)lba * (off_t)BLOCK_SIZE, SEEK_SET) == (off_t) -1 )
return SEEK_ERROR;
if ( read(data->fd, buffer, BLOCK_SIZE) != BLOCK_SIZE )
return READ_ERROR;
return 0;
} }
static int ds_get_size(struct data_source *src)
{
struct file_data_src *data;
assert(src);
data = (struct file_data_src*)src->data;
return data->nblocks;
}
static void ds_free_data(struct data_source *src)
{
struct file_data_src *data;
assert(src);
data = (struct file_data_src*)src->data;
/* close the file */
close(data->fd);
free(data);
}
struct data_source *data_source_from_file(const char *path)
{
int fd;
struct stat info;
struct file_data_src *data;
struct data_source *ret;
assert(path);
fd = open(path, O_RDONLY);
if (fd == -1)
return NULL;
fstat(fd, &info);
data = malloc(sizeof(struct file_data_src));
data->fd = fd;
data->nblocks = info.st_size / BLOCK_SIZE;
ret = malloc(sizeof(struct data_source));
ret->refcount = 1;
ret->read_block = ds_read_block;
ret->get_size = ds_get_size;
ret->free_data = ds_free_data;
ret->data = data;
return ret;
}
void data_source_free(struct data_source *src) /**
* 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) { if (--src->refcount == 0) {
src->free_data(src); src->free_data(src);
free(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;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,320 +1,476 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /*
/* vim: set noet ts=8 sts=8 sw=8 : */ * Copyright (c) 2007 Vreixo Formoso
*
/** * This file is part of the libisofs project; you can redistribute it and/or
* \file ecma119.h * 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 and definitions used for writing an emca119 (ISO9660) compatible
* volume.
*/ */
#ifndef LIBISO_ECMA119_H #ifndef LIBISO_ECMA119_H_
#define LIBISO_ECMA119_H #define LIBISO_ECMA119_H_
#include "libisofs.h"
#include "util.h"
#include "buffer.h"
#include <sys/time.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> /* for FILE */ #include <pthread.h>
#include <sys/types.h>
#include "susp.h"
struct ecma119_tree_node; #define BLOCK_SIZE 2048
struct joliet_tree_node;
/** /**
* The possible states that the ecma119 writer can be in. * Holds the options for the image generation.
*/ */
enum ecma119_write_state struct iso_write_opts {
{
ECMA119_WRITE_BEFORE,
ECMA119_WRITE_SYSTEM_AREA, int level; /**< ISO level to write at. (ECMA-119, 10) */
ECMA119_WRITE_PRI_VOL_DESC,
ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC,
ECMA119_WRITE_SUP_VOL_DESC_JOLIET,
ECMA119_WRITE_VOL_DESC_TERMINATOR,
ECMA119_WRITE_L_PATH_TABLE,
ECMA119_WRITE_M_PATH_TABLE,
ECMA119_WRITE_L_PATH_TABLE_JOLIET,
ECMA119_WRITE_M_PATH_TABLE_JOLIET,
ECMA119_WRITE_DIR_RECORDS,
ECMA119_WRITE_DIR_RECORDS_JOLIET,
ECMA119_WRITE_ELTORITO_CATALOG,
ECMA119_WRITE_FILES,
ECMA119_WRITE_DONE /** 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;
* Data describing the state of the ecma119 writer. Everything here should be typedef struct ecma119_node Ecma119Node;
* considered private! typedef struct joliet_node JolietNode;
*/ typedef struct iso1999_node Iso1999Node;
struct ecma119_write_target typedef struct Iso_File_Src IsoFileSrc;
typedef struct Iso_Image_Writer IsoImageWriter;
struct ecma119_image
{ {
struct ecma119_tree_node *root; IsoImage *image;
struct joliet_tree_node *joliet_root; Ecma119Node *root;
struct iso_volset *volset;
int volnum;
time_t now; /**< Time at which writing began. */ unsigned int iso_level :2;
off_t total_size; /**< Total size of the output. This only
* includes the current volume. */
uint32_t vol_space_size;
unsigned int rockridge:1; /* extensions */
unsigned int joliet:1; unsigned int rockridge :1;
unsigned int iso_level:2; unsigned int joliet :1;
unsigned int eltorito:1; unsigned int eltorito :1;
unsigned int iso1999 :1;
unsigned int write_eltorito:1;
/**<
* In multisession discs, select whether to copy el-torito catalog
* and boot image. Copy is needed for isolinux images, that need to
* be patched. However, it can lead to problems when the image is
* not present in the iso filesystem, because we can't figure out
* its size. In those cases, we only copy 1 block of data.
* When modifying images, we always need to copy data. Thus, this is
* always 1 for both new and modified images.
*/
struct el_torito_boot_catalog *catalog;
uint32_t catblock; /**< location of the boot catalog in the new image */
uint32_t imgblock; /**< location of the boot image in the new image */
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
int replace_mode; /**< Replace ownership and modes of files
*
* 0. filesystem values
* 1. useful values
* bits 1-4 bitmask:
* 2 - replace dir
* 3 - replace file
* 4 - replace gid
* 5 - replace uid
*/
mode_t dir_mode;
mode_t file_mode;
gid_t gid;
uid_t uid;
char *input_charset;
char *ouput_charset;
int cache_inodes;
int sort_files; /**< if sort files or not. Sorting is based of
* the weight of each file */
/**
* In the CD, each file must have an unique inode number. So each
* time we add a new file, this is incremented.
*/
ino_t ino;
uint32_t ms_block; /**< if != 0, nwa for multisession */ /* allways write timestamps in GMT */
struct data_source* src; unsigned int always_gmt :1;
int curblock;
uint16_t block_size;
uint32_t path_table_size;
uint32_t path_table_size_joliet;
uint32_t l_path_table_pos;
uint32_t m_path_table_pos;
uint32_t l_path_table_pos_joliet;
uint32_t m_path_table_pos_joliet;
uint32_t total_dir_size;
uint32_t total_dir_size_joliet;
struct ecma119_tree_node **dirlist; /* relaxed constraints */
/**< A pre-order list of directories unsigned int omit_version_numbers :1;
* (this is the order in which we write unsigned int allow_deep_paths :1;
* out directory records). unsigned int allow_longer_paths :1;
*/ unsigned int max_37_char_filenames :1;
struct ecma119_tree_node **pathlist; unsigned int no_force_dots :1;
/**< A breadth-first list of unsigned int allow_lowercase :1;
* directories. This is used for unsigned int allow_full_ascii :1;
* writing out the path tables.
*/ unsigned int relaxed_vol_atts : 1;
size_t dirlist_len; /**< The length of the previous 2 lists.
*/ /** Allow paths on Joliet tree to be larger than 240 bytes */
unsigned int joliet_longer_paths :1;
/*
struct iso_file_table *file_table; * Mode replace. If one of these flags is set, the correspodent values are
/**< * replaced with values below.
* A hash table with info about all files */
*/ 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;
struct iso_file **filelist; /**< A pre-order list of files.*/ uid_t uid;
size_t filelist_len; /* Length of the previous list. */ gid_t gid;
mode_t file_mode;
mode_t dir_mode;
time_t timestamp;
int curfile; /**< Used as a helper field for writing /**
out filelist and dirlist */ * if sort files or not. Sorting is based of the weight of each file
*/
int sort_files;
/* Joliet versions of the above lists. Since Joliet doesn't require /**
* directory relocation, the order of these lists might be different * In the CD, each file must have an unique inode number. So each
* from the lists above (but they will be the same length). * time we add a new file, this is incremented.
*/ */
struct joliet_tree_node **dirlist_joliet; ino_t ino;
struct joliet_tree_node **pathlist_joliet;
size_t dirlist_len_joliet;
enum ecma119_write_state state; /* The current state of the writer. */ char *input_charset;
char *output_charset;
/* Most writers work by unsigned int appendable : 1;
* 1) making sure state_data is big enough for their data uint32_t ms_block; /**< start block for a ms image */
* 2) writing _all_ their data into state_data time_t now; /**< Time at which writing began. */
* 3) relying on write_data_chunk to write the data block
* by block.
*/
uint8_t *state_data;
off_t state_data_size;
off_t state_data_off;
int state_data_valid;
/* for writing out files */ /** Total size of the output. This only includes the current volume. */
struct state_files { off_t total_size;
struct iso_file_src *src; /* source for reading from the file */ uint32_t vol_space_size;
int file; /* The index in filelist that we are
* currently writing (or about to write). */
} state_files;
/* temp buffer for read functions */ /* Bytes already written, just for progress notification */
uint8_t buffer[2048]; off_t bytes_written;
int bytes_read; 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] #define BP(a,b) [(b) - (a) + 1]
/* ECMA-119, 8.4 */
struct ecma119_pri_vol_desc struct ecma119_pri_vol_desc
{ {
uint8_t vol_desc_type BP(1, 1); uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6); uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7); uint8_t vol_desc_version BP(7, 7);
uint8_t unused1 BP(8, 8); uint8_t unused1 BP(8, 8);
uint8_t system_id BP(9, 40); uint8_t system_id BP(9, 40);
uint8_t volume_id BP(41, 72); uint8_t volume_id BP(41, 72);
uint8_t unused2 BP(73, 80); uint8_t unused2 BP(73, 80);
uint8_t vol_space_size BP(81, 88); uint8_t vol_space_size BP(81, 88);
uint8_t unused3 BP(89, 120); uint8_t unused3 BP(89, 120);
uint8_t vol_set_size BP(121, 124); uint8_t vol_set_size BP(121, 124);
uint8_t vol_seq_number BP(125, 128); uint8_t vol_seq_number BP(125, 128);
uint8_t block_size BP(129, 132); uint8_t block_size BP(129, 132);
uint8_t path_table_size BP(133, 140); uint8_t path_table_size BP(133, 140);
uint8_t l_path_table_pos BP(141, 144); uint8_t l_path_table_pos BP(141, 144);
uint8_t opt_l_path_table_pos BP(145, 148); uint8_t opt_l_path_table_pos BP(145, 148);
uint8_t m_path_table_pos BP(149, 152); uint8_t m_path_table_pos BP(149, 152);
uint8_t opt_m_path_table_pos BP(153, 156); uint8_t opt_m_path_table_pos BP(153, 156);
uint8_t root_dir_record BP(157, 190); uint8_t root_dir_record BP(157, 190);
uint8_t vol_set_id BP(191, 318); uint8_t vol_set_id BP(191, 318);
uint8_t publisher_id BP(319, 446); uint8_t publisher_id BP(319, 446);
uint8_t data_prep_id BP(447, 574); uint8_t data_prep_id BP(447, 574);
uint8_t application_id BP(575, 702); uint8_t application_id BP(575, 702);
uint8_t copyright_file_id BP(703, 739); uint8_t copyright_file_id BP(703, 739);
uint8_t abstract_file_id BP(740, 776); uint8_t abstract_file_id BP(740, 776);
uint8_t bibliographic_file_id BP(777, 813); uint8_t bibliographic_file_id BP(777, 813);
uint8_t vol_creation_time BP(814, 830); uint8_t vol_creation_time BP(814, 830);
uint8_t vol_modification_time BP(831, 847); uint8_t vol_modification_time BP(831, 847);
uint8_t vol_expiration_time BP(848, 864); uint8_t vol_expiration_time BP(848, 864);
uint8_t vol_effective_time BP(865, 881); uint8_t vol_effective_time BP(865, 881);
uint8_t file_structure_version BP(882, 882); uint8_t file_structure_version BP(882, 882);
uint8_t reserved1 BP(883, 883); uint8_t reserved1 BP(883, 883);
uint8_t app_use BP(884, 1395); uint8_t app_use BP(884, 1395);
uint8_t reserved2 BP(1396, 2048); uint8_t reserved2 BP(1396, 2048);
}; };
/* ECMA-119, 8.5 */
struct ecma119_sup_vol_desc struct ecma119_sup_vol_desc
{ {
uint8_t vol_desc_type BP(1, 1); uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6); uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7); uint8_t vol_desc_version BP(7, 7);
uint8_t vol_flags BP(8, 8); uint8_t vol_flags BP(8, 8);
uint8_t system_id BP(9, 40); uint8_t system_id BP(9, 40);
uint8_t volume_id BP(41, 72); uint8_t volume_id BP(41, 72);
uint8_t unused2 BP(73, 80); uint8_t unused2 BP(73, 80);
uint8_t vol_space_size BP(81, 88); uint8_t vol_space_size BP(81, 88);
uint8_t esc_sequences BP(89, 120); uint8_t esc_sequences BP(89, 120);
uint8_t vol_set_size BP(121, 124); uint8_t vol_set_size BP(121, 124);
uint8_t vol_seq_number BP(125, 128); uint8_t vol_seq_number BP(125, 128);
uint8_t block_size BP(129, 132); uint8_t block_size BP(129, 132);
uint8_t path_table_size BP(133, 140); uint8_t path_table_size BP(133, 140);
uint8_t l_path_table_pos BP(141, 144); uint8_t l_path_table_pos BP(141, 144);
uint8_t opt_l_path_table_pos BP(145, 148); uint8_t opt_l_path_table_pos BP(145, 148);
uint8_t m_path_table_pos BP(149, 152); uint8_t m_path_table_pos BP(149, 152);
uint8_t opt_m_path_table_pos BP(153, 156); uint8_t opt_m_path_table_pos BP(153, 156);
uint8_t root_dir_record BP(157, 190); uint8_t root_dir_record BP(157, 190);
uint8_t vol_set_id BP(191, 318); uint8_t vol_set_id BP(191, 318);
uint8_t publisher_id BP(319, 446); uint8_t publisher_id BP(319, 446);
uint8_t data_prep_id BP(447, 574); uint8_t data_prep_id BP(447, 574);
uint8_t application_id BP(575, 702); uint8_t application_id BP(575, 702);
uint8_t copyright_file_id BP(703, 739); uint8_t copyright_file_id BP(703, 739);
uint8_t abstract_file_id BP(740, 776); uint8_t abstract_file_id BP(740, 776);
uint8_t bibliographic_file_id BP(777, 813); uint8_t bibliographic_file_id BP(777, 813);
uint8_t vol_creation_time BP(814, 830); uint8_t vol_creation_time BP(814, 830);
uint8_t vol_modification_time BP(831, 847); uint8_t vol_modification_time BP(831, 847);
uint8_t vol_expiration_time BP(848, 864); uint8_t vol_expiration_time BP(848, 864);
uint8_t vol_effective_time BP(865, 881); uint8_t vol_effective_time BP(865, 881);
uint8_t file_structure_version BP(882, 882); uint8_t file_structure_version BP(882, 882);
uint8_t reserved1 BP(883, 883); uint8_t reserved1 BP(883, 883);
uint8_t app_use BP(884, 1395); uint8_t app_use BP(884, 1395);
uint8_t reserved2 BP(1396, 2048); uint8_t reserved2 BP(1396, 2048);
}; };
/* ECMA-119, 8.2 */
struct ecma119_boot_rec_vol_desc struct ecma119_boot_rec_vol_desc
{ {
uint8_t vol_desc_type BP(1, 1); uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6); uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7); uint8_t vol_desc_version BP(7, 7);
uint8_t boot_sys_id BP(8, 39); uint8_t boot_sys_id BP(8, 39);
uint8_t boot_id BP(40, 71); uint8_t boot_id BP(40, 71);
uint8_t boot_catalog BP(72, 75); uint8_t boot_catalog BP(72, 75);
uint8_t unused BP(76, 2048); uint8_t unused BP(76, 2048);
};
struct ecma119_vol_desc_terminator
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t reserved BP(8, 2048);
}; };
/* ECMA-119, 9.1 */
struct ecma119_dir_record struct ecma119_dir_record
{ {
uint8_t len_dr BP(1, 1); uint8_t len_dr BP(1, 1);
uint8_t len_xa BP(2, 2); uint8_t len_xa BP(2, 2);
uint8_t block BP(3, 10); uint8_t block BP(3, 10);
uint8_t length BP(11, 18); uint8_t length BP(11, 18);
uint8_t recording_time BP(19, 25); uint8_t recording_time BP(19, 25);
uint8_t flags BP(26, 26); uint8_t flags BP(26, 26);
uint8_t file_unit_size BP(27, 27); uint8_t file_unit_size BP(27, 27);
uint8_t interleave_gap_size BP(28, 28); uint8_t interleave_gap_size BP(28, 28);
uint8_t vol_seq_number BP(29, 32); uint8_t vol_seq_number BP(29, 32);
uint8_t len_fi BP(33, 33); uint8_t len_fi BP(33, 33);
uint8_t file_id BP(34, 34); /* 34 to 33+len_fi */ uint8_t file_id BP(34, 34); /* 34 to 33+len_fi */
/* padding field (if len_fi is even) */ /* padding field (if len_fi is even) */
/* system use (len_dr - len_su + 1 to len_dr) */ /* system use (len_dr - len_su + 1 to len_dr) */
}; };
/* ECMA-119, 9.4 */
struct ecma119_path_table_record struct ecma119_path_table_record
{ {
uint8_t len_di BP(1, 1); uint8_t len_di BP(1, 1);
uint8_t len_xa BP(2, 2); uint8_t len_xa BP(2, 2);
uint8_t block BP(3, 6); uint8_t block BP(3, 6);
uint8_t parent BP(7, 8); uint8_t parent BP(7, 8);
uint8_t dir_id BP(9, 9); /* 9 to 8+len_di */ uint8_t dir_id BP(9, 9); /* 9 to 8+len_di */
/* padding field (if len_di is odd) */ /* padding field (if len_di is odd) */
}; };
/** /* ECMA-119, 8.3 */
* A utility function for writers that want to write their data all at once struct ecma119_vol_desc_terminator
* rather than block-by-block. This creates a buffer of size \p size, passes {
* it to the given writer, then hands out block-sized chunks. uint8_t vol_desc_type BP(1, 1);
*/ uint8_t std_identifier BP(2, 6);
void uint8_t vol_desc_version BP(7, 7);
ecma119_start_chunking(struct ecma119_write_target *t, uint8_t reserved BP(8, 2048);
void (*)(struct ecma119_write_target*, uint8_t*), };
off_t size,
uint8_t *buf);
#endif /* LIBISO_ECMA119_H */ #endif /*LIBISO_ECMA119_H_*/

View File

@ -1,888 +0,0 @@
/*
* Functions to read an ISO image.
*/
/*
* TODO
* we need some kind of force option, to continue reading image on
* minor errors, such as incorrect time stamps....
*
* TODO
* need to check the ZF linux-especific extension for transparent decompresion
* TODO
* what the RR entry is?
*/
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "ecma119_read.h"
#include "ecma119_read_rr.h"
#include "ecma119.h"
#include "util.h"
#include "volume.h"
#include "tree.h"
#include "messages.h"
#include "eltorito.h"
#define BLOCK_SIZE 2048
static int
iso_read_dir(struct iso_read_info *info, struct iso_tree_node_dir *parent,
uint32_t block);
static struct el_torito_boot_catalog *
read_el_torito_boot_catalog(struct iso_read_info *info, uint32_t block)
{
struct el_torito_validation_entry *ve;
struct el_torito_default_entry *entry;
struct el_torito_boot_catalog *catalog;
struct el_torito_boot_image *image;
unsigned char buffer[BLOCK_SIZE];
if ( info->src->read_block(info->src, block, buffer) < 0 ) {
info->error = LIBISOFS_READ_FAILURE;
return NULL;
}
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) ) {
iso_msg_sorry(LIBISO_EL_TORITO_WRONG, "Wrong or damaged El-Torito "
"Catalog.\n El-Torito info will be ignored.");
return NULL;
}
/* check for a valid platform */
if (ve->platform_id[0] != 0) {
iso_msg_hint(LIBISO_EL_TORITO_UNHANLED, "Unsupported El-Torito platform.\n"
"Only 80x86 si supported. El-Torito info will be ignored.");
}
/* ok, once we are here we assume it is a valid catalog */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
image = calloc(1, sizeof(struct el_torito_boot_image));
catalog->image = image;
catalog->proc = LIBISO_PREVIMG;
{
/*
* Create the placeholder.
* Note that this could be modified later if we find a directory entry
* for the catalog in the iso tree.
*/
struct iso_tree_node_boot *boot;
boot = calloc(1, sizeof(struct iso_tree_node_boot));
boot->node.refcount = 1;
boot->node.attrib.st_mode = S_IFREG | 0777;
boot->node.attrib.st_atime = boot->node.attrib.st_mtime
= boot->node.attrib.st_ctime = time(NULL);
boot->node.attrib.st_size = 2048;
boot->node.type = LIBISO_NODE_BOOT;
boot->node.procedence = LIBISO_PREVIMG;
boot->node.name = NULL;
boot->loc.block = block;
catalog->node = boot;
}
/* parse the default entry */
entry = (struct el_torito_default_entry *)(buffer + 32);
image->bootable = entry->boot_indicator[0] ? 1 : 0;
//FIXME we need a way to handle patch_isolinux in ms images!!!
image->isolinux = 0;
image->type = entry->boot_media_type[0];
image->partition_type = entry->system_type[0];
image->load_seg = iso_read_lsb(entry->load_seg, 2);
image->load_size = iso_read_lsb(entry->sec_count, 2);
{
/*
* Create the placeholder.
* Note that this could be modified later if we find a directory entry
* for the image in the iso tree.
*/
struct iso_tree_node_boot *boot;
boot = calloc(1, sizeof(struct iso_tree_node_boot));
boot->node.refcount = 1;
boot->node.attrib.st_mode = S_IFREG | 0777;
boot->node.attrib.st_atime = boot->node.attrib.st_mtime
= boot->node.attrib.st_ctime = time(NULL);
boot->node.attrib.st_size = 2048;
boot->node.type = LIBISO_NODE_BOOT;
boot->node.procedence = LIBISO_PREVIMG;
boot->node.name = NULL;
boot->img = 1;
boot->loc.block = iso_read_lsb(entry->block, 4);
image->node = boot;
}
//TODO how can we check if there are more entries?
return catalog;
}
static struct el_torito_boot_catalog *
read_el_torito_vol_desc(struct iso_read_info *info, unsigned char *buf)
{
struct ecma119_boot_rec_vol_desc *vol;
vol = (struct ecma119_boot_rec_vol_desc*)buf;
/* 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)) {
iso_msg_hint(LIBISO_BOOT_VD_UNHANLED, "Unsupported Boot Vol. Desc.\n"
"Only El-Torito Specification, Version 1.0 Volume "
"Descriptors are supported. Ignoring boot info");
return NULL;
}
return read_el_torito_boot_catalog(info, iso_read_lsb(vol->boot_catalog, 4));
}
/**
* This reads the "." directory entry, and set the properties of the
* given directory propertly.
*/
static int
iso_read_dot_record(struct iso_read_info *info,
struct iso_tree_node_dir *dir,
struct ecma119_dir_record *record)
{
struct susp_sys_user_entry *sue;
struct susp_iterator *iter;
assert( info && dir && record );
iter = susp_iter_new(info, record);
while ( (sue = susp_iter_next(iter)) ) {
/* ignore entries from different version */
if (sue->version[0] != 1)
continue;
/* we don't care about any RR entry but PX and TF */
if (SUSP_SIG(sue, 'P', 'X')) {
if (read_rr_PX(info, sue, &dir->node.attrib))
break;
} else if (SUSP_SIG(sue, 'T', 'F')) {
if (read_rr_TF(info, sue, &dir->node.attrib))
break;
}
}
susp_iter_free(iter);
if (info->error)
return -1;
return 0;
}
/**
* Creates a suitable iso_tree_node from a directory record, and adds
* it to parent dir. If the directory record refers to a dir, it calls
* recursively iso_read_dir.
* On success, return 0.
* If file is not supported, return 0 but a new tree node is not added
* to parent.
* On serious error, returns -1
*/
static int
iso_read_single_directory_record(struct iso_read_info *info,
struct iso_tree_node_dir *parent,
struct ecma119_dir_record *record)
{
struct iso_tree_node *node;
struct stat atts;
time_t recorded;
char *name = NULL;
char *linkdest = NULL;
uint32_t relocated_dir = 0;
assert(info && record && parent);
memset(&atts, 0, sizeof(atts));
/*
* 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 (info->rr) {
struct susp_sys_user_entry *sue;
struct susp_iterator *iter;
iter = susp_iter_new(info, record);
while ( (sue = susp_iter_next(iter)) ) {
/* ignore entries from different version */
if (sue->version[0] != 1)
continue;
if (SUSP_SIG(sue, 'P', 'X')) {
if (read_rr_PX(info, sue, &atts))
break;
} else if (SUSP_SIG(sue, 'T', 'F')) {
if (read_rr_TF(info, sue, &atts))
break;
} else if (SUSP_SIG(sue, 'N', 'M')) {
name = read_rr_NM(sue, name);
if (!name) {
info->error = LIBISOFS_WRONG_RR;
break;
}
} else if (SUSP_SIG(sue, 'S', 'L')) {
linkdest = read_rr_SL(sue, linkdest);
if (!linkdest) {
info->error = LIBISOFS_WRONG_RR;
break;
}
} 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; /* is 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);
} else if (SUSP_SIG(sue, 'S', 'F')) {
iso_msg_sorry(LIBISO_RR_UNSUPPORTED, "Sparse files not supported.");
info->error = LIBISOFS_UNSUPPORTED_IMAGE;
break;
} else if (SUSP_SIG(sue, 'R', 'R')) {
/* TODO I've seen this RR on mkisofs images. what's this? */
continue;
} else {
char msg[28];
sprintf(msg, "Unhandled SUSP entry %c%c.", sue->sig[0], sue->sig[1]);
iso_msg_hint(LIBISO_SUSP_UNHANLED, msg);
}
}
if ( !info->error && !relocated_dir && atts.st_mode == (mode_t) 0 ) {
iso_msg_sorry(LIBISO_RR_ERROR, "Mandatory Rock Ridge PX entry is "
"not present or it contains invalid values.");
info->error = LIBISOFS_WRONG_RR;
}
susp_iter_free(iter);
if (info->error)
return -1;
//TODO convert name to needed charset!!
} else {
/* RR extensions are not read / used */
atts.st_mode = info->mode;
atts.st_gid = info->gid;
atts.st_uid = info->uid;
if (record->flags[0] & 0x02)
atts.st_mode |= S_IFDIR;
else
atts.st_mode |= S_IFREG;
atts.st_ino = ++info->ino;
}
/*
* if we haven't RR extensions, or no NM entry is present,
* we use the name in directory record
*/
if (!name) {
size_t len;
name = info->get_name((char*)record->file_id, record->len_fi[0]);
/* remove trailing version number */
len = strlen(name);
if (len > 2 && name[len-2] == ';' && name[len-1] == '1') {
name[len-2] = '\0';
}
}
/*
* 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);
if (relocated_dir) {
/*
* Ensure that a placeholder for a relocated dir appears as
* a directory (mode & S_IFDIR).
* This is need because the placeholder is really a file, and
* in theory PX entry must be ignored.
* However, to make code clearer, we don't ignore it, because
* anyway it will be replaced by "." entry when recursing.
*/
atts.st_mode = S_IFDIR | (atts.st_mode & ~S_IFMT);
}
//TODO sanity checks!!
switch(atts.st_mode & S_IFMT) {
case S_IFDIR:
{
node = calloc(1, sizeof(struct iso_tree_node_dir));
node->type = LIBISO_NODE_DIR;
}
break;
case S_IFREG:
{
uint32_t block;
block = iso_read_bb(record->block, 4, NULL);
if (info->bootcat && block == info->bootcat->node->loc.block) {
/* it is the boot catalog */
node = (struct iso_tree_node*)info->bootcat->node;
} else if (info->bootcat && block == info->bootcat->image->node->loc.block) {
/* it is the boot image */
node = (struct iso_tree_node*)info->bootcat->image->node;
} else {
/* it is a file */
node = calloc(1, sizeof(struct iso_tree_node_file));
node->type = LIBISO_NODE_FILE;
/* set block with extend */
((struct iso_tree_node_file*)node)->loc.block = block;
}
}
break;
case S_IFLNK:
{
node = calloc(1, sizeof(struct iso_tree_node_symlink));
node->type = LIBISO_NODE_SYMLINK;
/* set the link dest */
((struct iso_tree_node_symlink*)node)->dest = linkdest;
}
break;
default:
iso_msg_sorry(LIBISO_RR_UNSUPPORTED, "File type not supported.");
return -1;
}
node->name = name;
node->attrib = atts;
node->refcount++; /* 1 for news, 2 for boot nodes */
node->procedence = LIBISO_PREVIMG;
iso_tree_add_child(parent, node);
if (node->type == LIBISO_NODE_DIR) {
uint32_t block;
if (relocated_dir)
block = relocated_dir;
else
block = iso_read_bb(record->block, 4, NULL);
/* add all children */
return iso_read_dir(info, (struct iso_tree_node_dir*)node, block);
} else
return 0;
}
/**
* Read all directory records in a directory, and creates a node for each
* of them, adding them to \p dir.
*/
static int
iso_read_dir(struct iso_read_info *info, struct iso_tree_node_dir *dir,
uint32_t block)
{
unsigned char buffer[2048];
struct ecma119_dir_record *record;
uint32_t size;
uint32_t pos = 0;
uint32_t tlen = 0;
if ( info->src->read_block(info->src, block, buffer) < 0 ) {
info->error = LIBISOFS_READ_FAILURE;
return -1;
}
/* Attributes of dir are set in the "." entry */
record = (struct ecma119_dir_record *)(buffer + pos);
size = iso_read_bb(record->length, 4, NULL);
if (info->rr)
iso_read_dot_record(info, dir, record);
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
*/
if ( info->src->read_block(info->src, ++block, buffer) < 0 ) {
info->error = LIBISOFS_READ_FAILURE;
return -1;
}
tlen += 2048 - pos;
pos = 0;
/* next block must begin with a non-0 directory record */
assert(buffer[0] != 0);
continue;
}
/*
* What about ignoring files with existence flag?
* if (record->flags[0] & 0x01)
* continue;
*/
/*
* TODO
* 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.
* We can do that here, but I think it's a better option doing it
* on an app. using the library, such as genisofs.
*
* if ( record->len_fi[0] == 8 &&
* !strncmp(record->file_id,"RR_MOVED", 8) ) {
* continue;
* }
*/
/* check for unsupported multiextend */
if (record->flags[0] & 0x80) {
iso_msg_fatal(LIBISO_IMG_UNSUPPORTED, "Unsupported image.\n"
"This image makes use of Multi-Extend features, that "
"are not supported at this time.\n"
"If you need support for that, please request us this feature.\n"
"Thank you in advance\n");
info->error = LIBISOFS_UNSUPPORTED_IMAGE;
return -1;
}
/* check for unsupported interleaved mode */
if ( record->file_unit_size[0] || record->interleave_gap_size[0] ) {
iso_msg_fatal(LIBISO_IMG_UNSUPPORTED, "Unsupported image.\n"
"This image has at least one file recorded in "
"interleaved mode.\n"
"We don't support this mode, as we think it's not used.\n"
"If you're reading this, then we're wrong :)\n"
"Please contact libisofs developers, so we can fix this.\n"
"Thank you in advance\n");
info->error = LIBISOFS_UNSUPPORTED_IMAGE;
return -1;
}
//TODO check for unsupported extended attribs?
//TODO check for other flags?
if ( iso_read_single_directory_record(info, dir, record) )
return -1;
tlen += record->len_dr[0];
pos += record->len_dr[0];
}
return 0;
}
/**
* Read the SUSP system user entries of the "." entry of the root directory,
* indentifying when Rock Ridge extensions are being used.
*/
static int
read_root_susp_entries(struct iso_read_info *info,
struct iso_tree_node_dir *root,
uint32_t block)
{
unsigned char buffer[2048];
struct ecma119_dir_record *record;
struct susp_sys_user_entry *sue;
struct susp_iterator *iter;
if ( info->src->read_block(info->src, block, buffer) < 0 ) {
info->error = LIBISOFS_READ_FAILURE;
return -1;
}
/* record will be the "." directory entry for the root record */
record = (struct ecma119_dir_record *)buffer;
/*
* TODO
* 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(info, record);
/* first entry must be an SP system use entry */
sue = susp_iter_next(iter);
if (!sue && info->error) {
susp_iter_free(iter);
return -1;
} else if (!sue || !SUSP_SIG(sue, 'S', 'P') ) {
iso_msg_debug("SUSP/RR is not being used.");
susp_iter_free(iter);
return 0;
}
/* it is a SP system use entry */
if ( sue->version[0] != 1 || sue->data.SP.be[0] != 0xBE
|| sue->data.SP.ef[0] != 0xEF) {
iso_msg_sorry(LIBISO_SUSP_WRONG, "SUSP SP system use entry seems to "
"be wrong. Ignoring Rock Ridge Extensions.");
susp_iter_free(iter);
return 0;
}
iso_msg_debug("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
* features is easy...
*/
info->len_skp = sue->data.SP.len_skp[0];
/*
* Ok, now search for ER entry.
* Just notice that the attributes for root dir are read in
* iso_read_dir
*
* TODO 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 ( (sue = susp_iter_next(iter)) ) {
/* ignore entries from different version */
if (sue->version[0] != 1)
continue;
if (SUSP_SIG(sue, 'E', 'R')) {
if (info->rr) {
iso_msg_warn(LIBISO_SUSP_MULTIPLE_ER,
"More than one ER has found. This is not supported.\n"
"It will be ignored, but can cause problems. "
"Please notify us about this.\n");
}
/*
* 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("Suitable Rock Ridge ER found. Version 1.10.");
info->rr = 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("Suitable Rock Ridge ER found. Version 1.12.");
info->rr = RR_EXT_112;
//TODO check also version?
} else {
iso_msg_warn(LIBISO_SUSP_MULTIPLE_ER,
"Not Rock Ridge ER found.\n"
"That will be ignored, but can cause problems in "
"image reading. Please notify us about this");
}
}
}
susp_iter_free(iter);
if (info->error)
return -1;
return 0;
}
static struct iso_volset *
read_pvm(struct iso_read_info *info, uint32_t block)
{
struct ecma119_pri_vol_desc *pvm;
struct iso_volume *volume;
struct iso_volset *volset;
struct ecma119_dir_record *rootdr;
char* volset_id;
unsigned char buffer[BLOCK_SIZE];
if ( info->src->read_block(info->src, block, buffer) < 0 ) {
info->error = LIBISOFS_READ_FAILURE;
return NULL;
}
pvm = (struct ecma119_pri_vol_desc *)buffer;
/* sanity checks */
if ( pvm->vol_desc_type[0] != 1
|| strncmp((char*)pvm->std_identifier, "CD001", 5)
|| pvm->vol_desc_version[0] != 1
|| pvm->file_structure_version[0] != 1 ) {
iso_msg_fatal(LIBISO_WRONG_IMG, "Wrong PVM. Maybe this is a damaged "
"image, or it's not an ISO-9660 image.\n");
info->error = LIBISOFS_WRONG_PVM;
return NULL;
}
volume = iso_volume_new(NULL, NULL, NULL);
/* fill strings */
volume->volume_id = strcopy((char*)pvm->volume_id, 32);
volume->publisher_id = strcopy((char*)pvm->publisher_id, 128);
volume->data_preparer_id = strcopy((char*)pvm->data_prep_id, 128);
volume->system_id = strcopy((char*)pvm->system_id, 32);
volume->application_id = strcopy((char*)pvm->application_id, 128);
volume->copyright_file_id = strcopy((char*)pvm->copyright_file_id, 37);
volume->abstract_file_id = strcopy((char*)pvm->abstract_file_id, 37);
volume->biblio_file_id = strcopy((char*)pvm->bibliographic_file_id, 37);
volset_id = strcopy((char*)pvm->vol_set_id, 128);
*(info->size) = iso_read_bb(pvm->vol_space_size, 4, NULL);
volset = iso_volset_new(volume, volset_id);
free(volset_id);
/*
* TODO
* I don't like the way the differences volset - volume are hanled now.
* While theorically right (a volset can contain several volumes), in
* practice it seems that this never happen. Current implementation, with
* the volume array in volset, make things innecessarily harder. I think
* we can refactor that in a single way.
*/
//volset->volset_size = pvm->vol_set_size[0];
rootdr = (struct ecma119_dir_record *)pvm->root_dir_record;
/*
* check if RR is being used. Note that this functions returns
* != 0 on error. Info about if RR is being used is stored in info
*/
if ( read_root_susp_entries(info, volume->root,
iso_read_bb(rootdr->block, 4, NULL)) ) {
/* error, cleanup and return */
iso_volset_free(volset);
return NULL;
}
/* are RR ext present */
info->hasRR = info->rr ? 1 : 0;
info->iso_root_block = iso_read_bb(rootdr->block, 4, NULL);
/*
* PVM has things that can be interested, but don't have a member in
* volume struct, such as creation date. In a multisession disc, we could
* keep the creation date and update the modification date, for example.
*/
return volset;
}
struct iso_volset *
iso_volset_read(struct data_source *src, struct ecma119_read_opts *opts)
{
struct iso_read_info info;
struct iso_volset *volset;
uint32_t block, root_dir_block;
unsigned char buffer[BLOCK_SIZE];
assert(src && opts);
/* fill info with suitable values */
info.error = LIBISOFS_READ_OK;
info.src = src;
info.rr = RR_EXT_NO;
info.len_skp = 0;
info.ino = 0;
info.norock = opts->norock;
info.uid = opts->uid;
info.gid = opts->gid;
info.mode = opts->mode & ~S_IFMT;
info.size = &opts->size;
info.bootcat = NULL;
root_dir_block = 0;
/* read primary volume description */
volset = read_pvm(&info, opts->block + 16);
if (volset == NULL) {
opts->error = info.error;
return NULL;
}
block = opts->block + 17;
do {
if ( info.src->read_block(info.src, block, buffer) < 0 ) {
info.error = LIBISOFS_READ_FAILURE;
/* cleanup and exit */
goto read_cleanup;
}
switch (buffer[0]) {
case 0:
/*
* This is a boot record
* Here we handle el-torito
*/
info.bootcat = read_el_torito_vol_desc(&info, buffer);
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. */
info.hasJoliet = 1;
root = (struct ecma119_dir_record*)sup->root_dir_record;
root_dir_block = iso_read_bb(root->block, 4, NULL);
//TODO maybe we can set the volume attribs from this
//descriptor
} else {
iso_msg_hint(LIBISO_UNSUPPORTED_VD,
"Not supported Sup. Vol. Desc found.");
}
}
break;
case 255:
/*
* volume set terminator
* ignore, as it's checked in loop end condition
*/
break;
default:
{
char msg[32];
sprintf(msg, "Ignoring Volume descriptor %d.", buffer[0]);
iso_msg_hint(LIBISO_UNSUPPORTED_VD, msg);
}
break;
}
block++;
} while (buffer[0] != 255);
opts->hasRR = info.hasRR;
opts->hasJoliet = info.hasJoliet;
/* user doesn't want to read RR extensions */
if (info.norock)
info.rr = RR_EXT_NO;
/* select what tree to read */
if (info.rr) {
/* RR extensions are available */
if (opts->preferjoliet && info.hasJoliet) {
/* if user prefers joliet, that is used */
iso_msg_debug("Reading Joliet extensions.");
info.get_name = ucs2str;
info.rr = RR_EXT_NO;
/* root_dir_block already contains root for joliet */
} else {
/* RR will be used */
iso_msg_debug("Reading Rock Ridge extensions.");
root_dir_block = info.iso_root_block;
info.get_name = strcopy;
}
} else {
/* RR extensions are not available */
if (info.hasJoliet && !opts->nojoliet) {
/* joliet will be used */
iso_msg_debug("Reading Joliet extensions.");
info.get_name = ucs2str;
/* root_dir_block already contains root for joliet */
} else {
/* default to plain iso */
iso_msg_debug("Reading plain ISO-9660 tree.");
root_dir_block = info.iso_root_block;
info.get_name = strcopy;
}
}
/* Read the ISO/RR or Joliet tree */
if ( iso_read_dir(&info, volset->volume[0]->root, root_dir_block) ) {
/* error, cleanup and return */
goto read_cleanup;
}
// TODO merge tree info
/* Add El-Torito info to the volume */
if (info.bootcat) {
/* ok, add the bootcat to the volume */
iso_msg_debug("Found El-Torito bootable volume");
volset->volume[0]->bootcat = info.bootcat;
}
return volset;
read_cleanup:;
if (info.bootcat) {
el_torito_boot_catalog_free(info.bootcat);
}
iso_volset_free(volset);
return NULL;
}

View File

@ -1,76 +0,0 @@
/*
* ecma119_read.h
*
* Defines structures for reading from a iso image.
*/
#ifndef ECMA119_READ_H_
#define ECMA119_READ_H_
#include <stdint.h>
#include "libisofs.h"
enum read_error {
LIBISOFS_READ_OK = 0,
LIBISOFS_READ_FAILURE, /**< Truncated image or read error */
LIBISOFS_WRONG_PVM, /**< Incorrect PVM */
LIBISOFS_UNSUPPORTED_IMAGE, /**< Format not supported (interleaved...) */
LIBISOFS_WRONG_RR /**< Wrong RR/SUSP extension format */
};
/**
* Should the RR extensions be read?
*/
enum read_rr_ext {
RR_EXT_NO = 0, /*< Do not use RR extensions */
RR_EXT_110, /*< RR extensions conforming version 1.10 */
RR_EXT_112 /*< RR extensions conforming version 1.12 */
};
/**
* Structure that keeps info needed in the read process.
*/
struct iso_read_info {
struct data_source *src;
enum read_error error;
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) */
uint32_t iso_root_block; /**< Will be filled with the block lba of the
* extend for the root directory, as read from
* the PVM
*/
enum read_rr_ext rr; /*< If we need to read RR extensions. i.e., if the image
* contains RR extensions, and the user wants to read them. */
char *(*get_name)(const char *, size_t);
/**<
* The function used to read the name from a directoy record. For
* ISO, the name is in US-ASCII. For Joliet, in UCS-2BE. Thus, we
* need different functions for both.
*/
ino_t ino; /*< Joliet and RR version 1.10 does not have file serial numbers,
* we need to generate it. */
uint8_t len_skp; /*< 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. */
unsigned int norock:1; /*< Do not read Rock Ridge extensions */
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 ext are present,
to 0 if not. */
uint32_t *size;
/* place for el-torito boot catalog */
struct el_torito_boot_catalog *bootcat;
};
#endif /*ECMA119_READ_H_*/

View File

@ -1,316 +0,0 @@
/*
* This file contains functions related to the reading of SUSP and
* Rock Ridge extensions on an ECMA-119 image.
*/
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ecma119.h"
#include "ecma119_read.h"
#include "ecma119_read_rr.h"
#include "util.h"
#include "messages.h"
#define BLOCK_SIZE 2048
/**
* Fills a struct stat with the values of a Rock Ridge PX entry
* On error, info->error is set propertly and the function returns != 0
*/
int
read_rr_PX(struct iso_read_info *info, struct susp_sys_user_entry *px,
struct stat *st)
{
assert( info && px && st);
assert( px->sig[0] == 'P' && px->sig[1] == 'X');
if ( info->rr == RR_EXT_112 && px->len_sue[0] != 44 ) {
iso_msg_sorry(LIBISO_RR_ERROR, "Invalid PX entry for RR version 1.12");
info->error = LIBISOFS_WRONG_RR;
return -1;
} else if ( info->rr == RR_EXT_110 && px->len_sue[0] != 36 ) {
iso_msg_sorry(LIBISO_RR_ERROR, "Invalid PX entry for RR version 1.10");
info->error = LIBISOFS_WRONG_RR;
return -1;
}
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 (info->rr == RR_EXT_112) {
st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
} else {
st->st_ino = ++info->ino;
}
return 0;
}
/**
* Fills a struct stat with the values of a Rock Ridge TF entry
* On error, info->error is set propertly and the function returns != 0
*/
int
read_rr_TF(struct iso_read_info *info, struct susp_sys_user_entry *tf,
struct stat *st)
{
time_t time;
int s;
int nts = 0;
assert( info && tf && st);
assert( tf->sig[0] == 'T' && tf->sig[1] == 'F');
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) {
iso_msg_sorry(LIBISO_RR_ERROR, "RR TF entry too short.");
info->error = LIBISOFS_WRONG_RR;
return -1;
}
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) {
iso_msg_sorry(LIBISO_RR_ERROR, "RR TF entry too short.");
info->error = LIBISOFS_WRONG_RR;
return -1;
}
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) {
iso_msg_sorry(LIBISO_RR_ERROR, "RR TF entry too short.");
info->error = LIBISOFS_WRONG_RR;
return -1;
}
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 0;
}
char *
read_rr_NM(struct susp_sys_user_entry *nm, char *name)
{
assert(nm);
assert( nm->sig[0] == 'N' && nm->sig[1] == 'M');
/* concatenate the results */
if (name) {
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);
}
return name;
}
char *
read_rr_SL(struct susp_sys_user_entry *sl, char *dest)
{
int pos;
assert(sl);
assert( sl->sig[0] == 'S' && sl->sig[1] == 'L');
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) {
char msg[38];
sprintf(msg, "SL component flag %x not supported.", flags);
iso_msg_sorry(LIBISO_RR_ERROR, msg);
return NULL;
} else {
len = sl->data.SL.comps[pos + 1];
comp = (char*)&sl->data.SL.comps[pos + 2];
}
if (dest) {
int size = strlen(dest);
dest = realloc(dest, strlen(dest) + len + 2);
if ( dest[size-1] != '/' ) {
dest[size] = '/';
dest[size+1] = '\0';
}
strncat(dest, comp, len);
} else {
dest = strcopy(comp, len);
}
}
return dest;
}
struct susp_iterator {
uint8_t* base;
int pos;
int size;
struct iso_read_info *info;
uint32_t ce_block;
uint32_t ce_off;
uint32_t ce_len; /*< Length of the next continuation area, 0 if
no more CA are specified */
uint8_t *buffer; /*< If there are continuation areas */
};
struct susp_iterator *
susp_iter_new(struct iso_read_info *info, struct ecma119_dir_record *record)
{
struct susp_iterator *iter = malloc(sizeof(struct susp_iterator));
int pad = (record->len_fi[0] + 1) % 2;
iter->base = record->file_id + record->len_fi[0] + pad;
iter->pos = info->len_skp; /* 0 in most cases */
iter->size = record->len_dr[0] - record->len_fi[0] - 33 -pad;
iter->info = info;
iter->ce_len = 0;
iter->buffer = NULL;
return iter;
}
struct susp_sys_user_entry *
susp_iter_next(struct susp_iterator* iter)
{
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 block needed to cache the full CE */
for (block = 0; block < nblocks; ++block) {
if (iter->info->src->read_block(iter->info->src,
iter->ce_block + block,
iter->buffer + block * BLOCK_SIZE)) {
iter->info->error = LIBISOFS_READ_FAILURE;
return NULL;
}
}
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 NULL;
}
}
if (entry->len_sue[0] == 0) {
/* a wrong image with this lead us to a infinity loop */
iso_msg_sorry(LIBISO_RR_ERROR, "Damaged RR/SUSP information.");
iter->info->error = LIBISOFS_WRONG_RR;
return NULL;
}
iter->pos += entry->len_sue[0];
if ( SUSP_SIG(entry, 'C', 'E') ) {
/* Continuation entry */
if (iter->ce_len) {
iso_msg_sorry(LIBISO_RR_ERROR, "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.\n"
"Ignoring last CE. Maybe the image is damaged.\n");
} 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);
} else if ( SUSP_SIG(entry, 'P', 'D') ) {
/* skip padding */
return susp_iter_next(iter);
}
return entry;
}
void
susp_iter_free(struct susp_iterator* iter)
{
free(iter->buffer);
free(iter);
}

View File

@ -1,144 +0,0 @@
/*
* This file contains functions related to the reading of SUSP and
* Rock Ridge extensions on an ECMA-119 image.
*/
#ifndef ECMA119_READ_RR_H_
#define ECMA119_READ_RR_H_
#include "libisofs.h"
#include "ecma119.h"
#include "ecma119_read.h"
#define SUSP_SIG(entry, a, b) ( (entry->sig[0] == a) && (entry->sig[1] == b) )
/**
* 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.
*/
struct susp_iterator;
struct susp_iterator *susp_iter_new(struct iso_read_info *info,
struct ecma119_dir_record *record);
/**
* Get the next SUSP System User Entry using given iterator.
* The returned pointer refers directly 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.
*
* It return NULL when no more entries are available. Also, it will return
* NULL on error. You must check info->error to distinguish between both
* situations.
*/
struct susp_sys_user_entry *susp_iter_next(struct susp_iterator* iter);
/**
* Free a given susp iterator.
*/
void susp_iter_free(struct susp_iterator* iter);
struct susp_CE {
uint8_t block[8];
uint8_t offset[8];
uint8_t len[8];
};
struct susp_SP {
uint8_t be[1];
uint8_t ef[1];
uint8_t len_skp[1];
};
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. */
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. */
struct rr_TF {
uint8_t flags[1];
uint8_t t_stamps[1];
};
/** Alternate name. */
struct rr_NM {
uint8_t flags[1];
uint8_t name[1];
};
/** Link for a relocated directory. */
struct rr_CL {
uint8_t child_loc[8];
};
/** Sim link. */
struct rr_SL {
uint8_t flags[1];
uint8_t comps[1];
};
/**
* Struct for a SUSP System User Entry
*/
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_NM NM;
struct rr_CL CL;
struct rr_SL SL;
} data; /* 5 to 4+len_sue */
};
/**
* Fills a struct stat with the values of a Rock Ridge PX entry
* On error, info->error is set propertly and the function returns != 0
*/
int read_rr_PX(struct iso_read_info *info, struct susp_sys_user_entry *px,
struct stat *st);
/**
* Fills a struct stat with the values of a Rock Ridge TF entry
* On error, info->error is set propertly and the function returns != 0
*/
int read_rr_TF(struct iso_read_info *info, struct susp_sys_user_entry *tf,
struct stat *st);
/**
* Apends the content of given Rock Ridge NM entry to \p name
* On error, returns NULL
*/
char *read_rr_NM(struct susp_sys_user_entry *nm, char *name);
/**
* Apends the components in specified SL entry to \p dest, adding
* needed '/'.
* On error, returns NULL
*/
char *read_rr_SL(struct susp_sys_user_entry *sl, char *dest);
#endif /*ECMA119_READ_RR_H_*/

File diff suppressed because it is too large Load Diff

View File

@ -1,103 +1,90 @@
/* vim: set noet ts=8 sts=8 sw=8 : */ /*
* Copyright (c) 2007 Vreixo Formoso
/** *
* \file ecma119_tree.h * 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
* Declarations for creating, modifying and printing filesystem trees that * published by the Free Software Foundation. See COPYING file for details.
* are compatible with ecma119.
*/ */
#ifndef LIBISO_ECMA119_TREE_H #ifndef LIBISO_ECMA119_TREE_H_
#define LIBISO_ECMA119_TREE_H #define LIBISO_ECMA119_TREE_H_
#include <sys/stat.h> #include "libisofs.h"
#include "ecma119.h"
#include "file.h"
struct ecma119_write_target;
struct iso_tree_node;
enum ecma119_node_type { enum ecma119_node_type {
ECMA119_FILE, ECMA119_FILE,
ECMA119_SYMLINK, ECMA119_DIR,
ECMA119_DIR, ECMA119_SYMLINK,
ECMA119_PLACEHOLDER, /**< placeholder for a relocated dir. */ ECMA119_SPECIAL,
ECMA119_BOOT ECMA119_PLACEHOLDER
}; };
struct ecma119_dir_info { /**
struct susp_info self_susp; /**< susp entries for "." */ * Struct with info about a node representing a directory
struct susp_info parent_susp; /**< susp entries for ".." */ */
struct ecma119_dir_info
{
/* Block where the directory entries will be written on image */
size_t block;
size_t len; /**< sum of the lengths of children's size_t nchildren;
* Directory Records (including SU) */ Ecma119Node **children;
size_t CE_len; /**< sum of the lengths of children's
* SUSP CE areas */
size_t block;
int depth; /*
size_t path_len; /**< The length of a path up to, and * Size of the dir, i.e., sum of the lengths of all directory records.
* including, this directory. This * It is computed by calc_dir_size() [ecma119.c].
* cannot exceed 255. */ * Note that this don't include the length of any SUSP Continuation
size_t nchildren; * Area needed by the dir, but it includes the size of the SUSP entries
struct ecma119_tree_node **children; * than fit in the directory records System Use Field.
*/
size_t len;
struct ecma119_tree_node *real_parent; /**
/**< The parent before relocation */ * 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 * A node for a tree containing all the information necessary for writing
* an ISO9660 volume. * an ISO9660 volume.
*/ */
struct ecma119_tree_node struct ecma119_node
{ {
char *iso_name; /**< in ASCII, conforming to the /**
* current ISO level. */ * Name in ASCII, conforming to selected ISO level.
char *full_name; /**< full name, in current locale */ * Version number is not include, it is added on the fly
size_t dirent_len; /**< Length of the directory record, */
* not including SU. */ char *iso_name;
struct ecma119_tree_node *parent; Ecma119Node *parent;
struct ecma119_write_target *target;
struct stat attrib; IsoNode *node; /*< reference to the iso node */
struct susp_info susp; /* TODO #00009 : add true support for harlinks and inode numbers */
ino_t ino;
nlink_t nlink;
enum ecma119_node_type type; /**< file, symlink, directory or placeholder */ /**< file, symlink, special, directory or placeholder */
union { enum ecma119_node_type type;
struct iso_file *file; union
char *dest; {
struct ecma119_dir_info dir; IsoFileSrc *file;
struct ecma119_tree_node *real_me; /**< this field points to struct ecma119_dir_info *dir;
* the relocated directory. /** this field points to the relocated directory. */
*/ Ecma119Node *real_me;
unsigned int boot_img:1; /** For boot nodes, it identifies if this } info;
* corresponds to image(1) or catalog(0).
* The block is stored in ecma119_write_target
*/
} info;
}; };
/** /**
* Create a new ecma119_tree that corresponds to the tree represented by *
* \p iso_root.
*/ */
struct ecma119_tree_node* int ecma119_tree_create(Ecma119Image *img);
ecma119_tree_create(struct ecma119_write_target *target,
struct iso_tree_node *iso_root);
/** /**
* Free an ecma119 tree. * Free an Ecma119Node, and its children if node is a dir
*/ */
void void ecma119_node_free(Ecma119Node *node);
ecma119_tree_free(struct ecma119_tree_node *root);
/** #endif /*LIBISO_ECMA119_TREE_H_*/
* Print an ecma119 tree.
*/
void
ecma119_tree_print(struct ecma119_tree_node *root, int spaces);
#endif /* LIBISO_ECMA119_TREE_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,83 +1,103 @@
#ifndef ELTORITO_H_ /*
#define ELTORITO_H_ * 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 "tree.h"
#include "file.h"
#include "ecma119.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 { struct el_torito_boot_catalog {
struct iso_tree_node_boot *node; /* node of the catalog */ IsoBoot *node; /* node of the catalog */
struct el_torito_boot_image *image; /* default boot image */ struct el_torito_boot_image *image; /* default boot image */
enum tree_node_from proc; /* whether the catalog is new or read from a
* prev session/image */
}; };
struct el_torito_boot_image { struct el_torito_boot_image {
struct iso_tree_node_boot *node; IsoFile *image;
unsigned int bootable:1; /**< If the entry is bootable. */ unsigned int bootable:1; /**< If the entry is bootable. */
unsigned int isolinux:1; /**< If the image will be patched */ unsigned int isolinux:1; /**< If the image will be patched */
unsigned char type; /**< The type of image */ unsigned char type; /**< The type of image */
unsigned char partition_type; /**< type of partition for HD-emul images */ unsigned char partition_type; /**< type of partition for HD-emul images */
short load_seg; /**< Load segment for the initial boot image. */ short load_seg; /**< Load segment for the initial boot image. */
short load_size; /**< Number of sector to load. */ short load_size; /**< Number of sectors to load. */
}; };
/** El-Torito, 2.1 */
struct el_torito_validation_entry { struct el_torito_validation_entry {
uint8_t header_id BP(1, 1); uint8_t header_id BP(1, 1);
uint8_t platform_id BP(2, 2); uint8_t platform_id BP(2, 2);
uint8_t reserved BP(3, 4); uint8_t reserved BP(3, 4);
uint8_t id_string BP(5, 28); uint8_t id_string BP(5, 28);
uint8_t checksum BP(29, 30); uint8_t checksum BP(29, 30);
uint8_t key_byte1 BP(31, 31); uint8_t key_byte1 BP(31, 31);
uint8_t key_byte2 BP(32, 32); uint8_t key_byte2 BP(32, 32);
}; };
/** El-Torito, 2.2 */
struct el_torito_default_entry { struct el_torito_default_entry {
uint8_t boot_indicator BP(1, 1); uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2); uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4); uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5); uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6); uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8); uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12); uint8_t block BP(9, 12);
uint8_t unused2 BP(13, 32); uint8_t unused2 BP(13, 32);
}; };
struct el_torito_section_header_entry { /** El-Torito, 2.3 */
uint8_t header_indicator BP(1, 1); struct el_torito_section_header {
uint8_t platform_id BP(2, 2); uint8_t header_indicator BP(1, 1);
uint8_t number BP(3, 4); uint8_t platform_id BP(2, 2);
uint8_t character BP(5, 32); uint8_t number BP(3, 4);
uint8_t character BP(5, 32);
}; };
/** El-Torito, 2.4 */
struct el_torito_section_entry { struct el_torito_section_entry {
uint8_t boot_indicator BP(1, 1); uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2); uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4); uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5); uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6); uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8); uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12); uint8_t block BP(9, 12);
uint8_t selec_criteria BP(13, 13); uint8_t selec_criteria BP(13, 13);
uint8_t vendor_sc BP(14, 32); uint8_t vendor_sc BP(14, 32);
}; };
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat); void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat);
/** /**
* Write the Boot Record Volume Descriptor * 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.
*/ */
void int el_torito_catalog_file_src_create(Ecma119Image *target, IsoFileSrc **src);
el_torito_write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
void
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
/** /**
* Write catalog + image * Create a writer for el-torito information.
*/ */
void int eltorito_writer_create(Ecma119Image *target);
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf);
#endif /*ELTORITO_H_*/ #endif /* LIBISO_ELTORITO_H */

View File

@ -1,29 +0,0 @@
#include "exclude.h"
void
iso_exclude_add_path(struct iso_hash_table *table, const char *path)
{
if (!path)
return;
table->num += iso_hash_insert(table->table, path);
}
void
iso_exclude_empty(struct iso_hash_table *table)
{
if (!table->num)
return;
iso_hash_empty(table->table);
table->num=0;
}
int
iso_exclude_lookup(struct iso_hash_table *table, const char *path)
{
if (!table->num || !path)
return 0;
return iso_hash_lookup(table->table, path);
}

View File

@ -1,30 +0,0 @@
#ifndef ISO_EXCLUDE_H
#define ISO_EXCLUDE_H
#include "hash.h"
struct iso_hash_table {
struct iso_hash_node *table[HASH_NODES];
int num;
};
/**
* Add a path to ignore when adding a directory recursively.
*
* \param path The path, on the local filesystem, of the file.
*/
int iso_exclude_lookup(struct iso_hash_table *table, const char *path);
/**
* Add the path of a file or directory to ignore when adding a directory recursively.
*
* \param path The path, on the local filesystem, of the file.
*/
void iso_exclude_add_path(struct iso_hash_table *table, const char *path);
/**
* Remove all paths that were set to be ignored when adding a directory recusively.
*/
void iso_exclude_empty(struct iso_hash_table *table);
#endif /* ISO_EXCLUDE */

View File

@ -1,254 +0,0 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include "file.h"
#include "tree.h"
#include "file_src.h"
#include "messages.h"
#include "ecma119.h"
//TODO: refactor both hash and this hash table into a single one??
struct iso_file *
iso_file_new(struct ecma119_write_target *t, struct iso_tree_node_file *f)
{
struct iso_file *file = calloc(1, sizeof(struct iso_file));
if (!file)
return NULL;
if (f->node.procedence == LIBISO_NEW) {
file->path = f->loc.path; /*TODO strdup? it needs to be free on clear then */
file->real_dev = f->node.attrib.st_dev;
file->real_ino = f->node.attrib.st_ino;
file->src = iso_file_src_from_path(file->path);
} else {
file->block = f->loc.block;
file->prev_img = 1;
file->real_dev = 0; /* we use 0 as dev for prev. session files */
/* don't take care about inode number read from RR TX, block
* number is good enouht for this. Moreover, when we are modifying
* an image, we will modify file->block with the block where the
* file needs to be written in the new image. So, we store the block
* in original image here */
file->real_ino = f->loc.block;
file->src = iso_file_src_from_prev_img(t->src, f->loc.block,
f->node.attrib.st_size);
}
if (!file->src)
goto creation_error;
file->size = file->src->get_size(file->src);
if (file->size != f->node.attrib.st_size) {
char msg[PATH_MAX + 32];
/* can only happen on path files */
assert(f->node.procedence == LIBISO_NEW);
sprintf(msg, "Size of file %s has changed\n", file->path);
iso_msg_sorry(LIBISO_CANT_READ_FILE, msg);
}
file->nlink = 1;
file->sort_weight = f->sort_weight;
return file;
creation_error:;
free(file);
return NULL;
}
static unsigned int
iso_file_table_hash(const char *path)
{
unsigned int hash_num=0;
const char *c;
c=path;
while(*c)
hash_num = (hash_num << 15) + (hash_num << 3) + (hash_num >> 3) + *c++;
return hash_num % FILE_HASH_NODES;
}
static inline unsigned int
iso_file_table_hash_inode(dev_t dev, ino_t ino)
{
return (dev ^ ino) % FILE_HASH_NODES;
}
struct iso_file_table*
iso_file_table_new(int cache_inodes)
{
struct iso_file_table *table = calloc(1, sizeof(struct iso_file_table));
table->cache_inodes = cache_inodes;
return table;
}
static struct iso_file_hash_node *
iso_file_table_node_new(struct iso_file *file)
{
struct iso_file_hash_node *node;
node = calloc(1, sizeof(struct iso_file_hash_node) );
node->file = file;
return node;
}
static void
iso_file_table_node_free(struct iso_file_hash_node *node)
{
iso_file_src_free(node->file->src);
free(node->file);
free(node);
}
void
iso_file_table_clear(struct iso_file_table *ft)
{
int i;
for (i=0; i < FILE_HASH_NODES; i++) {
struct iso_file_hash_node *node;
node=ft->table[i];
if (!node)
continue;
ft->table[i] = NULL;
do {
struct iso_file_hash_node *next;
next = node->next;
iso_file_table_node_free(node);
node = next;
} while (node);
}
ft->count = 0;
}
/**
* return 0 if equal, != 0 if not
*/
static int
iso_table_compare_files(struct iso_file_table *ft,
struct iso_file *f1, struct iso_file *f2)
{
assert(ft && f1 && f2);
if (f1->prev_img || f2->prev_img) {
if (f1->prev_img && f2->prev_img)
return f1->real_ino != f2->real_ino;
else
return 1;
}
if (ft->cache_inodes) {
return (f1->real_dev != f2->real_dev) || (f1->real_ino != f2->real_ino);
} else {
return strcmp(f1->path, f2->path);
}
}
int
iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f)
{
struct iso_file_hash_node *node;
unsigned int hash_num;
assert(ft && f);
/* find the hash number */
if (f->prev_img)
hash_num = f->real_ino % FILE_HASH_NODES;
else if (ft->cache_inodes)
hash_num = iso_file_table_hash_inode(f->real_dev, f->real_ino);
else
hash_num = iso_file_table_hash(f->path);
/* insert it */
node = ft->table[hash_num];
/* unfortunately, we can't safely consider that a file
* won't be twice in the hash table so make sure it
* doesn't already exists */
if (!node) {
ft->table[hash_num]=iso_file_table_node_new(f);
ft->count++;
return 1;
}
/* if it's already in, we don't do anything */
if (!iso_table_compare_files(ft, f, node->file))
return 0;
while (node->next) {
node = node->next;
/* if it's already in, we don't do anything */
if (!iso_table_compare_files(ft, f, node->file))
return 0;
}
node->next = iso_file_table_node_new(f);
ft->count++;
return 1;
}
/** 0 on equal, != 0 otherwise */
static int
iso_table_compare_node_file(struct iso_file_table *ft,
struct iso_tree_node_file *f1, struct iso_file *f2)
{
assert(ft && f1 && f2);
if (f1->node.procedence || f2->prev_img) {
if (f1->node.procedence && f2->prev_img)
return f1->loc.block != f2->real_ino;
else
return 1;
}
if (ft->cache_inodes) {
return (f1->node.attrib.st_dev != f2->real_dev)
|| (f1->node.attrib.st_ino != f2->real_ino);
} else {
return strcmp(f1->loc.path, f2->path);
}
}
struct iso_file *
iso_file_table_lookup(struct iso_file_table *ft, struct iso_tree_node_file *f)
{
struct iso_file_hash_node *node;
unsigned int hash_num;
int equal;
assert(ft && f);
/* find the hash number */
if (f->node.procedence == LIBISO_PREVIMG)
hash_num = f->loc.block % FILE_HASH_NODES;
else if ( ft->cache_inodes )
hash_num = iso_file_table_hash_inode(f->node.attrib.st_dev,
f->node.attrib.st_ino);
else
hash_num = iso_file_table_hash(f->loc.path);
node = ft->table[hash_num];
if (!node)
return NULL;
equal = !iso_table_compare_node_file(ft, f, node->file);
if (equal)
return node->file;
while (node->next) {
node = node->next;
equal = !iso_table_compare_node_file(ft, f, node->file);
if (equal)
return node->file;
}
return NULL;
}

View File

@ -1,74 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* \file file.h
*
* Declare the structs to keep track of the files to be written into image.
* These files are stored in a hash table. Two modes of operation are supported:
* when cache inodes is enabled, the files are indexed into the table by the
* device and inode id in the local filesystem. This way, two different files
* with same inode and device id are treated as if they were a single file.
* This is usually the correct behavior, as a different file with same inode
* and device used to be a hard link.
* When cache inode is disabled, indexing is done by path on local filesystem.
*/
#ifndef FILE_H_
#define FILE_H_
#include <stdint.h>
#define FILE_HASH_NODES 2048
struct iso_file {
unsigned int prev_img:1; /**< if the file comes from a previous image */
char *path; /**< Path of the file on local filesystem */
off_t size; /**< size of this file */
ino_t ino; /**< This will be the inode number on CD of the file (RR) */
nlink_t nlink; /**< Number of hard links of the file on CD (RR) */
uint32_t block; /**< Block where this file is to be written on image */
dev_t real_dev;
ino_t real_ino; /**< for lookup by inode caching */
int sort_weight;
struct iso_file_src *src;
};
struct iso_file_hash_node {
struct iso_file_hash_node *next;
struct iso_file *file;
};
struct iso_file_table {
struct iso_file_hash_node *table[FILE_HASH_NODES];
size_t count;
int cache_inodes; /**< 1 to index by inode number */
};
struct iso_tree_node_file;
struct ecma119_write_target;
/**
* Create a struct that represents the specified iso_tree_node_file,
* suitable to be stored into the table,
*/
struct iso_file *iso_file_new(struct ecma119_write_target *t,
struct iso_tree_node_file*);
struct iso_file_table *iso_file_table_new(int cache_inodes);
/**
* Clear a hash table. All iso_file structs stored will also be freed,
* but not the path of each iso_file
*/
void iso_file_table_clear(struct iso_file_table *ft);
/**
* Add a new file to the table.
* \return 1 if the file is added, 0 if the file already exist on table
*/
int iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f);
struct iso_file *iso_file_table_lookup(struct iso_file_table *ft,
struct iso_tree_node_file *f);
#endif /*FILE_H_*/

View File

@ -1,306 +0,0 @@
/*
* Implementation of iso_file_src for:
*
* a) read from local filesystem files
* b) read from previous session / image files
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <limits.h>
#include "file_src.h"
#include "messages.h"
#include "libisofs.h"
#include "util.h"
#define BLOCK_SIZE 2048
void iso_file_src_free(struct iso_file_src *src)
{
src->free_data(src);
free(src);
}
/*
* ==========================================================================
* A) FILE SRC FOR LOCAL FILESYSTEM FILES
* ==========================================================================
*/
struct local_file_data {
int fd; /* the file descriptor, once the file is opened */
off_t size; /* file size */
off_t bytes_read; /* bytes already read from file */
int error;
char *path; /* path of the file on local filesystem */
};
static
int lf_open(struct iso_file_src *src)
{
struct local_file_data *data;
assert(src);
data = (struct local_file_data*) src->data;
assert(data->fd == -1);
data->fd = open(data->path, O_RDONLY);
data->bytes_read = (off_t) 0;
data->error = 0;
return (data->fd != -1 ? 1 : 0);
}
static
void lf_close(struct iso_file_src *src)
{
struct local_file_data *data;
assert(src);
data = (struct local_file_data*) src->data;
assert(data->fd != -1);
close(data->fd);
data->fd = -1;
}
static
int lf_read_block(struct iso_file_src *src, unsigned char *buffer)
{
ssize_t bytes;
struct local_file_data *data;
assert(src);
assert(buffer);
data = (struct local_file_data*) src->data;
assert(data->fd != -1);
if (data->bytes_read >= data->size) {
return 0;
}
if (data->error) {
memset(buffer, 0, BLOCK_SIZE);
data->bytes_read += BLOCK_SIZE;
return -2;
}
bytes = 0;
do {
ssize_t result;
result = read(data->fd, buffer + bytes, BLOCK_SIZE - bytes);
if (result < 0) {
char msg[PATH_MAX + 32];
sprintf(msg, "Problem reading from %s", data->path);
iso_msg_sorry(LIBISO_CANT_READ_FILE, msg);
/* fill buffer with 0s and return */
memset(buffer + bytes, 0, BLOCK_SIZE - bytes);
data->bytes_read += BLOCK_SIZE;
return -1;
}
if (!result)
break;
bytes += result;
} while (bytes < BLOCK_SIZE);
if (bytes < BLOCK_SIZE) {
/* eof */
memset(buffer + bytes, 0, BLOCK_SIZE - bytes);
}
data->bytes_read += (off_t) bytes;
if (data->bytes_read >= data->size) {
return 0;
} else {
return 1;
}
}
static
off_t lf_get_size(struct iso_file_src *src)
{
struct local_file_data *data;
assert(src);
data = (struct local_file_data*) src->data;
return data->size;
}
static
void lf_free_data(struct iso_file_src *src)
{
struct local_file_data *data;
data = (struct local_file_data*) src->data;
free(data->path);
free(data);
}
struct iso_file_src*
iso_file_src_from_path(const char *path)
{
struct stat info;
struct iso_file_src *src;
struct local_file_data *data;
assert(path);
if (lstat(path, &info) < 0) {
iso_msg_fatal(LIBISO_FILE_DOESNT_EXIST, "File doesn't exist");
return NULL;
}
if (access(path, R_OK) < 0) {
iso_msg_fatal(LIBISO_FILE_NO_READ_ACCESS, "No read access");
return NULL;
}
data = malloc(sizeof(struct local_file_data));
if (!data)
return NULL;
src = malloc(sizeof(struct iso_file_src));
if (!src) {
free(data);
return NULL;
}
data->fd = -1;
data->path = strdup(path);
data->size = info.st_size;
src->open = lf_open;
src->close = lf_close;
src->read_block = lf_read_block;
src->get_size = lf_get_size;
src->free_data = lf_free_data;
src->data = data;
return src;
}
/*
* ==========================================================================
* B) FILE SRC FOR PREVIOUS IMAGE FILES
* ==========================================================================
*/
struct prev_img_file_data {
int block; /* block where image begins */
off_t size; /* file size */
int nblocks; /* file size in blocks */
int current; /* last block read from file */
int error;
struct data_source *src; /* source for reading from previous image */
};
static
int pi_open(struct iso_file_src *src)
{
struct prev_img_file_data *data;
assert(src);
data = (struct prev_img_file_data*) src->data;
data->current = data->block;
data->error = 0;
return 1;
}
static
void pi_close(struct iso_file_src *src)
{
/* nothing needed */
return;
}
static
int pi_read_block(struct iso_file_src *src, unsigned char *buffer)
{
int res;
struct prev_img_file_data *data;
assert(src);
assert(buffer);
data = (struct prev_img_file_data*) src->data;
if (data->current >= data->block + data->nblocks) {
return 0;
}
if (data->error) {
memset(buffer, 0, BLOCK_SIZE);
data->current++;
return -2;
}
res = data->src->read_block(data->src, data->current++, buffer);
if (res < 0) {
iso_msg_sorry(LIBISO_CANT_READ_IMG,
"Problem reading file from previous image");
/* fill buffer with 0s and return */
memset(buffer, 0, BLOCK_SIZE);
return -1;
}
if (data->current >= data->block + data->nblocks) {
return 0;
} else {
return 1;
}
}
static
off_t pi_get_size(struct iso_file_src *src)
{
struct prev_img_file_data *data;
assert(src);
data = (struct prev_img_file_data*) src->data;
return data->size;
}
static
void pi_free_data(struct iso_file_src *src)
{
free(src->data);
}
struct iso_file_src*
iso_file_src_from_prev_img(struct data_source* data_src, int block, off_t size)
{
struct iso_file_src *src;
struct prev_img_file_data *data;
data = malloc(sizeof(struct prev_img_file_data));
if (!data)
return NULL;
src = malloc(sizeof(struct iso_file_src));
if (!src) {
free(data);
return NULL;
}
data->block = block;
data->size = size;
data->nblocks = div_up(size, BLOCK_SIZE);
data->src = data_src;
src->open = pi_open;
src->close = pi_close;
src->read_block = pi_read_block;
src->get_size = pi_get_size;
src->free_data = pi_free_data;
src->data = data;
return src;
}

View File

@ -1,94 +0,0 @@
/*
* Class for reading data from files, with base implementations
* for reading local filesystem files and previous session files.
*
* TODO this is kept private for now, it can be useful to make that
* public later.
*/
#ifndef FILE_SRC_H_
#define FILE_SRC_H_
#include <sys/types.h>
struct data_source;
struct iso_file_src {
/**
* Opens the file.
* This should be called before any call to read_block().
* @return 1 on success, <= 0 on error
*/
int (*open)(struct iso_file_src *src);
/**
* Close the file.
* This should be called when the iso_file_src is no more needed.
*/
void (*close)(struct iso_file_src *src);
/**
* Read data from the file in 2048 bytes chunks.
*
* A pointer to the contents of the file will be updated, in such a way
* that each time this function is called, new data is read to the buffer.
* It behaves in the same way as usual read(2) call this way.
*
* This always reads 2048 bytes, unless an EOF is found, or we reach the
* size previously returned by get_size(). In this case, the buffer is
* completed with 0s.
*
* @param buffer Buffer where the data will be written. Its size must
* be at least 2048 bytes.
* @return
* 1 if file contains more data. If we reach EOF before the expected
* size, this keeps returning 1, and next blocks are filled with 0s.
* 0 when we reach the expected size, that in normal usage is also EOF
* on file.
* < 0 on error. If such case, next calls to read_block will keep
* returning < 0 until we reach the expected size, filling blocks with
* 0s.
*/
int (*read_block)(struct iso_file_src *src, unsigned char *buffer);
/**
* Get the size in bytes of the file.
*
* This is set when the iso_file_src is created, and should not change. If
* the actual file size changes, it will be truncated or padding with 0s
* when the block is read
*/
off_t (*get_size)(struct iso_file_src *);
/** Clean up the source specific data */
void (*free_data)(struct iso_file_src *);
/** Source specific data */
void *data;
};
/**
* Get a iso_file_src() for reading from a local filesystem file.
*/
struct iso_file_src* iso_file_src_from_path(const char *path);
/**
* Get a iso_file_src() for reading from a previous image file.
* @param src data_source to read from previous image. It is not freed,
* so you need to free it when no more needed.
* @param block block on image where file begins
* @param nblocks number of block of the file
*/
struct iso_file_src*
iso_file_src_from_prev_img(struct data_source* src, int block, off_t size);
/**
* free a iso_file_src
*/
void iso_file_src_free(struct iso_file_src *src);
#endif /*FILE_SRC_H_*/

387
libisofs/filesrc.c Normal file
View File

@ -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 <stdlib.h>
#include <string.h>
#include <limits.h>
int iso_file_src_cmp(const void *n1, const void *n2)
{
const IsoFileSrc *f1, *f2;
unsigned int fs_id1, fs_id2;
dev_t dev_id1, dev_id2;
ino_t ino_id1, ino_id2;
f1 = (const IsoFileSrc *)n1;
f2 = (const IsoFileSrc *)n2;
iso_stream_get_id(f1->stream, &fs_id1, &dev_id1, &ino_id1);
iso_stream_get_id(f2->stream, &fs_id2, &dev_id2, &ino_id2);
if (fs_id1 < fs_id2) {
return -1;
} else if (fs_id1 > fs_id2) {
return 1;
} else {
/* files belong to the same fs */
if (dev_id1 > dev_id2) {
return -1;
} else if (dev_id1 < dev_id2) {
return 1;
} else {
/* files belong to same device in same fs */
return (ino_id1 < ino_id2) ? -1 : (ino_id1 > ino_id2) ? 1 : 0;
}
}
}
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
{
int ret;
IsoFileSrc *fsrc;
unsigned int fs_id;
dev_t dev_id;
ino_t ino_id;
if (img == NULL || file == NULL || src == NULL) {
return ISO_NULL_POINTER;
}
iso_stream_get_id(file->stream, &fs_id, &dev_id, &ino_id);
fsrc = malloc(sizeof(IsoFileSrc));
if (fsrc == NULL) {
return ISO_OUT_OF_MEM;
}
/* fill key and other atts */
fsrc->prev_img = file->msblock ? 1 : 0;
fsrc->block = file->msblock;
fsrc->sort_weight = file->sort_weight;
fsrc->stream = file->stream;
/* insert the filesrc in the tree */
ret = iso_rbtree_insert(img->files, fsrc, (void**)src);
if (ret <= 0) {
free(fsrc);
return ret;
}
iso_stream_ref(fsrc->stream);
return ISO_SUCCESS;
}
/**
* Add a given IsoFileSrc to the given image target.
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
* being written several times to image. If you call again this function
* with a node that refers to the same source file, the previously
* created one will be returned.
*
* @param img
* The image where this file is to be written
* @param new
* The IsoFileSrc to add
* @param src
* Will be filled with a pointer to the IsoFileSrc really present in
* the tree. It could be different than new if the same file already
* exists in the tree.
* @return
* 1 on success, 0 if file already exists on tree, < 0 error
*/
int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src)
{
int ret;
if (img == NULL || new == NULL || src == NULL) {
return ISO_NULL_POINTER;
}
/* insert the filesrc in the tree */
ret = iso_rbtree_insert(img->files, new, (void**)src);
return ret;
}
void iso_file_src_free(void *node)
{
iso_stream_unref(((IsoFileSrc*)node)->stream);
free(node);
}
off_t iso_file_src_get_size(IsoFileSrc *file)
{
return iso_stream_get_size(file->stream);
}
static int cmp_by_weight(const void *f1, const void *f2)
{
IsoFileSrc *f = *((IsoFileSrc**)f1);
IsoFileSrc *g = *((IsoFileSrc**)f2);
/* higher weighted first */
return g->sort_weight - f->sort_weight;
}
static
int is_ms_file(void *arg)
{
IsoFileSrc *f = (IsoFileSrc *)arg;
return f->prev_img ? 0 : 1;
}
static
int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
{
size_t i, size;
Ecma119Image *t;
IsoFileSrc **filelist;
int (*inc_item)(void *);
if (writer == NULL) {
return ISO_ASSERT_FAILURE;
}
t = writer->target;
/* on appendable images, ms files shouldn't be included */
if (t->appendable) {
inc_item = is_ms_file;
} else {
inc_item = NULL;
}
/* store the filesrcs in a array */
filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files, inc_item, &size);
if (filelist == NULL) {
return ISO_OUT_OF_MEM;
}
/* sort files by weight, if needed */
if (t->sort_files) {
qsort(filelist, size, sizeof(void*), cmp_by_weight);
}
/* fill block value */
for (i = 0; i < size; ++i) {
IsoFileSrc *file = filelist[i];
file->block = t->curblock;
t->curblock += DIV_UP(iso_file_src_get_size(file), BLOCK_SIZE);
}
/* the list is only needed by this writer, store locally */
writer->data = filelist;
return ISO_SUCCESS;
}
static
int filesrc_writer_write_vol_desc(IsoImageWriter *writer)
{
/* nothing needed */
return ISO_SUCCESS;
}
/* open a file, i.e., its Stream */
static inline
int filesrc_open(IsoFileSrc *file)
{
return iso_stream_open(file->stream);
}
static inline
int filesrc_close(IsoFileSrc *file)
{
return iso_stream_close(file->stream);
}
/**
* @return
* 1 ok, 0 EOF, < 0 error
*/
static
int filesrc_read(IsoFileSrc *file, char *buf, size_t count)
{
size_t bytes = 0;
/* loop to ensure the full buffer is filled */
do {
ssize_t result;
result = iso_stream_read(file->stream, buf + bytes, count - bytes);
if (result < 0) {
/* fill buffer with 0s and return */
memset(buf + bytes, 0, count - bytes);
return result;
}
if (result == 0)
break;
bytes += result;
} while (bytes < count);
if (bytes < count) {
/* eof */
memset(buf + bytes, 0, count - bytes);
return 0;
} else {
return 1;
}
}
static
int filesrc_writer_write_data(IsoImageWriter *writer)
{
int res;
size_t i, b;
Ecma119Image *t;
IsoFileSrc *file;
IsoFileSrc **filelist;
char name[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;
}

84
libisofs/filesrc.h Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#ifndef LIBISO_FILESRC_H_
#define LIBISO_FILESRC_H_
#include "libisofs.h"
#include "stream.h"
#include "ecma119.h"
#include <stdint.h>
struct Iso_File_Src
{
unsigned int prev_img :1; /**< if the file comes from a previous image */
uint32_t block; /**< Block where this file will be written on image */
int sort_weight;
IsoStream *stream;
};
int iso_file_src_cmp(const void *n1, const void *n2);
/**
* Create a new IsoFileSrc to get data from a specific IsoFile.
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
* being written several times to image. If you call again this function
* with a node that refers to the same source file, the previously
* created one will be returned. No new IsoFileSrc is created in that case.
*
* @param img
* The image where this file is to be written
* @param file
* The IsoNode we want to write
* @param src
* Will be filled with a pointer to the IsoFileSrc
* @return
* 1 on success, < 0 on error
*/
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src);
/**
* Add a given IsoFileSrc to the given image target.
*
* The IsoFileSrc will be cached in a tree to prevent the same file for
* being written several times to image. If you call again this function
* with a node that refers to the same source file, the previously
* created one will be returned.
*
* @param img
* The image where this file is to be written
* @param new
* The IsoFileSrc to add
* @param src
* Will be filled with a pointer to the IsoFileSrc really present in
* the tree. It could be different than new if the same file already
* exists in the tree.
* @return
* 1 on success, 0 if file already exists on tree, < 0 error
*/
int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src);
/**
* Free the IsoFileSrc especific data
*/
void iso_file_src_free(void *node);
/**
* Get the size of the file this IsoFileSrc represents
*/
off_t iso_file_src_get_size(IsoFileSrc *file);
/**
* Create a Writer for file contents.
*
* It takes care of written the files in the correct order.
*/
int iso_file_src_writer_create(Ecma119Image *target);
#endif /*LIBISO_FILESRC_H_*/

49
libisofs/filter.c Normal file
View File

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

62
libisofs/filter.h Normal file
View File

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

View File

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

629
libisofs/find.c Normal file
View File

@ -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 <fnmatch.h>
#include <string.h>
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;
}

2697
libisofs/fs_image.c Normal file

File diff suppressed because it is too large Load Diff

692
libisofs/fs_local.c Normal file
View File

@ -0,0 +1,692 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/*
* Filesystem/FileSource implementation to access the local filesystem.
*/
#include "fsource.h"
#include "util.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <libgen.h>
#include <string.h>
static
int iso_file_source_new_lfs(IsoFileSource *parent, const char *name,
IsoFileSource **src);
/*
* We can share a local filesystem object, as it has no private atts.
*/
IsoFilesystem *lfs= NULL;
typedef struct
{
/** reference to the parent (if root it points to itself) */
IsoFileSource *parent;
char *name;
unsigned int openned :2; /* 0: not openned, 1: file, 2:dir */
union
{
int fd;
DIR *dir;
} info;
} _LocalFsFileSource;
static
char* lfs_get_path(IsoFileSource *src)
{
_LocalFsFileSource *data;
data = src->data;
if (data->parent == src) {
return strdup("/");
} else {
char *path = lfs_get_path(data->parent);
int pathlen = strlen(path);
path = realloc(path, pathlen + strlen(data->name) + 2);
if (pathlen != 1) {
/* pathlen can only be 1 for root */
path[pathlen] = '/';
path[pathlen + 1] = '\0';
}
return strcat(path, data->name);
}
}
static
char* lfs_get_name(IsoFileSource *src)
{
_LocalFsFileSource *data;
data = src->data;
return strdup(data->name);
}
static
int lfs_lstat(IsoFileSource *src, struct stat *info)
{
_LocalFsFileSource *data;
char *path;
if (src == NULL || info == NULL) {
return ISO_NULL_POINTER;
}
data = src->data;
path = lfs_get_path(src);
if (lstat(path, info) != 0) {
int err;
/* error, choose an appropriate return code */
switch (errno) {
case EACCES:
err = ISO_FILE_ACCESS_DENIED;
break;
case ENOTDIR:
case ENAMETOOLONG:
case ELOOP:
err = ISO_FILE_BAD_PATH;
break;
case ENOENT:
err = ISO_FILE_DOESNT_EXIST;
break;
case EFAULT:
case ENOMEM:
err = ISO_OUT_OF_MEM;
break;
default:
err = ISO_FILE_ERROR;
break;
}
return err;
}
free(path);
return ISO_SUCCESS;
}
static
int lfs_stat(IsoFileSource *src, struct stat *info)
{
_LocalFsFileSource *data;
char *path;
if (src == NULL || info == NULL) {
return ISO_NULL_POINTER;
}
data = src->data;
path = lfs_get_path(src);
if (stat(path, info) != 0) {
int err;
/* error, choose an appropriate return code */
switch (errno) {
case EACCES:
err = ISO_FILE_ACCESS_DENIED;
break;
case ENOTDIR:
case ENAMETOOLONG:
case ELOOP:
err = ISO_FILE_BAD_PATH;
break;
case ENOENT:
err = ISO_FILE_DOESNT_EXIST;
break;
case EFAULT:
case ENOMEM:
err = ISO_OUT_OF_MEM;
break;
default:
err = ISO_FILE_ERROR;
break;
}
return err;
}
free(path);
return ISO_SUCCESS;
}
static
int lfs_access(IsoFileSource *src)
{
int ret;
_LocalFsFileSource *data;
char *path;
if (src == NULL) {
return ISO_NULL_POINTER;
}
data = src->data;
path = lfs_get_path(src);
ret = iso_eaccess(path);
free(path);
return ret;
}
static
int lfs_open(IsoFileSource *src)
{
int err;
struct stat info;
_LocalFsFileSource *data;
char *path;
if (src == NULL) {
return ISO_NULL_POINTER;
}
data = src->data;
if (data->openned) {
return ISO_FILE_ALREADY_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
off_t lfs_lseek(IsoFileSource *src, off_t offset, int flag)
{
_LocalFsFileSource *data;
int whence;
if (src == NULL) {
return (off_t)ISO_NULL_POINTER;
}
switch (flag) {
case 0:
whence = SEEK_SET; break;
case 1:
whence = SEEK_CUR; break;
case 2:
whence = SEEK_END; break;
default:
return (off_t)ISO_WRONG_ARG_VALUE;
}
data = src->data;
switch (data->openned) {
case 1: /* not dir */
{
off_t ret;
ret = lseek(data->info.fd, offset, whence);
if (ret < 0) {
/* error on read */
switch (errno) {
case ESPIPE:
ret = (off_t)ISO_FILE_ERROR;
break;
default:
ret = (off_t)ISO_ERROR;
break;
}
}
return ret;
}
case 2: /* directory */
return (off_t)ISO_FILE_IS_DIR;
default:
return (off_t)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,
lfs_lseek
};
/**
*
* @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;
}

117
libisofs/fsource.c Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "fsource.h"
#include <stdlib.h>
/**
* Values belong 1000 are reserved for libisofs usage
*/
unsigned int iso_fs_global_id = 1000;
void iso_file_source_ref(IsoFileSource *src)
{
++src->refcount;
}
void iso_file_source_unref(IsoFileSource *src)
{
if (--src->refcount == 0) {
src->class->free(src);
free(src);
}
}
void iso_filesystem_ref(IsoFilesystem *fs)
{
++fs->refcount;
}
void iso_filesystem_unref(IsoFilesystem *fs)
{
if (--fs->refcount == 0) {
fs->free(fs);
free(fs);
}
}
/*
* this are just helpers to invoque methods in class
*/
inline
char* iso_file_source_get_path(IsoFileSource *src)
{
return src->class->get_path(src);
}
inline
char* iso_file_source_get_name(IsoFileSource *src)
{
return src->class->get_name(src);
}
inline
int iso_file_source_lstat(IsoFileSource *src, struct stat *info)
{
return src->class->lstat(src, info);
}
inline
int iso_file_source_access(IsoFileSource *src)
{
return src->class->access(src);
}
inline
int iso_file_source_stat(IsoFileSource *src, struct stat *info)
{
return src->class->stat(src, info);
}
inline
int iso_file_source_open(IsoFileSource *src)
{
return src->class->open(src);
}
inline
int iso_file_source_close(IsoFileSource *src)
{
return src->class->close(src);
}
inline
int iso_file_source_read(IsoFileSource *src, void *buf, size_t count)
{
return src->class->read(src, buf, count);
}
inline
off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag)
{
return src->class->lseek(src, offset, flag);
}
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);
}

33
libisofs/fsource.h Normal file
View File

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

View File

@ -1,158 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "hash.h"
static unsigned int
iso_hash_path(const char *path)
{
unsigned int hash_num=0;
const char *c;
c=path;
while(*c)
hash_num = (hash_num << 15) + (hash_num << 3) + (hash_num >> 3) + *c++;
return hash_num % HASH_NODES;
}
int
iso_hash_lookup(struct iso_hash_node **table, const char *path)
{
struct iso_hash_node *node;
unsigned int hash_num;
hash_num = iso_hash_path(path);
node=table[hash_num];
if (!node)
return 0;
if (!strcmp(path, node->path))
return 1;
while (node->next) {
node=node->next;
if (!strcmp(path, node->path))
return 1;
}
return 0;
}
static struct iso_hash_node*
iso_hash_node_new (const char *path)
{
struct iso_hash_node *node;
/*create an element to be inserted in the hash table */
node=malloc(sizeof(struct iso_hash_node));
node->path=strdup(path);
node->next=NULL;
return node;
}
int
iso_hash_insert(struct iso_hash_node **table, const char *path)
{
struct iso_hash_node *node;
unsigned int hash_num;
/* find the hash number */
hash_num = iso_hash_path(path);
/* insert it */
node = table[hash_num];
/* unfortunately, we can't safely consider that a path
* won't be twice in the hash table so make sure it
* doesn't already exists */
if (!node) {
table[hash_num]=iso_hash_node_new(path);
return 1;
}
/* if it's already in, we don't do anything */
if (!strcmp(path, node->path))
return 0;
while (node->next) {
node = node->next;
/* if it's already in, we don't do anything */
if (!strcmp (path, node->path))
return 0;
}
node->next = iso_hash_node_new(path);
return 1;
}
static void
iso_hash_node_free(struct iso_hash_node *node)
{
free(node->path);
free(node);
}
int
iso_hash_remove(struct iso_hash_node **table, const char *path)
{
unsigned int hash_num;
struct iso_hash_node *node;
hash_num = iso_hash_path(path);
node=table[hash_num];
if (!node)
return 0;
if (!strcmp(path, node->path)) {
table[hash_num]=node->next;
iso_hash_node_free(node);
return 1;
}
while (node->next) {
struct iso_hash_node *prev;
prev = node;
node = node->next;
if (!strcmp (path, node->path)) {
prev->next=node->next;
iso_hash_node_free(node);
return 1;
}
}
return 0;
}
void
iso_hash_empty(struct iso_hash_node **table)
{
int i;
for (i=0; i < HASH_NODES; i++) {
struct iso_hash_node *node;
node=table[i];
if (!node)
continue;
table[i]=NULL;
do {
struct iso_hash_node *next;
next=node->next;
iso_hash_node_free(node);
node=next;
} while (node);
}
}

View File

@ -1,46 +0,0 @@
#ifndef ISO_HASH_H
#define ISO_HASH_H
struct iso_hash_node {
struct iso_hash_node *next;
char *path;
};
#define HASH_NODES 128
/**
* Searches in the hash table if the path exists.
*
* \param table The hash table.
* \param path The path of the file to look for.
*
* \return 1 if the path exists in the hash table, 0 otherwise.
*/
int iso_hash_lookup(struct iso_hash_node **table, const char *path);
/**
* Insert a new path in the hash table.
*
* \param table The hash table.
* \param path The path of a file to add to the hash table.
*
* \return 1 if the file wasn't already in the hash table, 0 otherwise.
*/
int iso_hash_insert(struct iso_hash_node **table, const char *path);
/**
* Remove a path from the hash table.
*
* \param table The hash table.
* \param path The path of a file to remove from the hash table.
*
* \return 1 if the file was found and removed, 0 otherwise.
*/
int iso_hash_remove(struct iso_hash_node **table, const char *path);
/**
* Empty the hash table.
*/
void iso_hash_empty(struct iso_hash_node **table);
#endif /* ISO_HASH_H */

277
libisofs/image.c Normal file
View File

@ -0,0 +1,277 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "libisofs.h"
#include "image.h"
#include "node.h"
#include "messages.h"
#include "eltorito.h"
#include <stdlib.h>
#include <string.h>
/**
* Create a new image, empty.
*
* The image will be owned by you and should be unref() when no more needed.
*
* @param name
* Name of the image. This will be used as volset_id and volume_id.
* @param image
* Location where the image pointer will be stored.
* @return
* 1 sucess, < 0 error
*/
int iso_image_new(const char *name, IsoImage **image)
{
int res;
IsoImage *img;
if (image == NULL) {
return ISO_NULL_POINTER;
}
img = calloc(1, sizeof(IsoImage));
if (img == NULL) {
return ISO_OUT_OF_MEM;
}
/* local filesystem will be used by default */
res = iso_local_filesystem_new(&(img->fs));
if (res < 0) {
free(img);
return ISO_OUT_OF_MEM;
}
/* use basic builder as default */
res = iso_node_basic_builder_new(&(img->builder));
if (res < 0) {
iso_filesystem_unref(img->fs);
free(img);
return ISO_OUT_OF_MEM;
}
/* fill image fields */
res = iso_node_new_root(&img->root);
if (res < 0) {
iso_node_builder_unref(img->builder);
iso_filesystem_unref(img->fs);
free(img);
return res;
}
img->refcount = 1;
img->id = iso_message_id++;
if (name != NULL) {
img->volset_id = strdup(name);
img->volume_id = strdup(name);
}
*image = img;
return ISO_SUCCESS;
}
/**
* Increments the reference counting of the given image.
*/
void iso_image_ref(IsoImage *image)
{
++image->refcount;
}
/**
* Decrements the reference couting of the given image.
* If it reaches 0, the image is free, together with its tree nodes (whether
* their refcount reach 0 too, of course).
*/
void iso_image_unref(IsoImage *image)
{
if (--image->refcount == 0) {
int nexcl;
/* we need to free the image */
if (image->user_data_free != NULL) {
/* free attached data */
image->user_data_free(image->user_data);
}
for (nexcl = 0; nexcl < image->nexcludes; ++nexcl) {
free(image->excludes[nexcl]);
}
free(image->excludes);
iso_node_unref((IsoNode*)image->root);
iso_node_builder_unref(image->builder);
iso_filesystem_unref(image->fs);
el_torito_boot_catalog_free(image->bootcat);
free(image->volset_id);
free(image->volume_id);
free(image->publisher_id);
free(image->data_preparer_id);
free(image->system_id);
free(image->application_id);
free(image->copyright_file_id);
free(image->abstract_file_id);
free(image->biblio_file_id);
free(image);
}
}
/**
* Attach user defined data to the image. Use this if your application needs
* to store addition info together with the IsoImage. If the image already
* has data attached, the old data will be freed.
*
* @param data
* Pointer to application defined data that will be attached to the
* image. You can pass NULL to remove any already attached data.
* @param give_up
* Function that will be called when the image does not need the data
* any more. It receives the data pointer as an argumente, and eventually
* causes data to be free. It can be NULL if you don't need it.
*/
int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*))
{
if (image == NULL || (data != NULL && free == NULL)) {
return ISO_NULL_POINTER;
}
if (image->user_data != NULL) {
/* free previously attached data */
if (image->user_data_free) {
image->user_data_free(image->user_data);
}
image->user_data = NULL;
image->user_data_free = NULL;
}
if (data != NULL) {
image->user_data = data;
image->user_data_free = give_up;
}
return ISO_SUCCESS;
}
/**
* The the data previously attached with iso_image_attach_data()
*/
void *iso_image_get_attached_data(IsoImage *image)
{
return image->user_data;
}
IsoDir *iso_image_get_root(const IsoImage *image)
{
return image->root;
}
void iso_image_set_volset_id(IsoImage *image, const char *volset_id)
{
free(image->volset_id);
image->volset_id = strdup(volset_id);
}
const char *iso_image_get_volset_id(const IsoImage *image)
{
return image->volset_id;
}
void iso_image_set_volume_id(IsoImage *image, const char *volume_id)
{
free(image->volume_id);
image->volume_id = strdup(volume_id);
}
const char *iso_image_get_volume_id(const IsoImage *image)
{
return image->volume_id;
}
void iso_image_set_publisher_id(IsoImage *image, const char *publisher_id)
{
free(image->publisher_id);
image->publisher_id = strdup(publisher_id);
}
const char *iso_image_get_publisher_id(const IsoImage *image)
{
return image->publisher_id;
}
void iso_image_set_data_preparer_id(IsoImage *image,
const char *data_preparer_id)
{
free(image->data_preparer_id);
image->data_preparer_id = strdup(data_preparer_id);
}
const char *iso_image_get_data_preparer_id(const IsoImage *image)
{
return image->data_preparer_id;
}
void iso_image_set_system_id(IsoImage *image, const char *system_id)
{
free(image->system_id);
image->system_id = strdup(system_id);
}
const char *iso_image_get_system_id(const IsoImage *image)
{
return image->system_id;
}
void iso_image_set_application_id(IsoImage *image, const char *application_id)
{
free(image->application_id);
image->application_id = strdup(application_id);
}
const char *iso_image_get_application_id(const IsoImage *image)
{
return image->application_id;
}
void iso_image_set_copyright_file_id(IsoImage *image,
const char *copyright_file_id)
{
free(image->copyright_file_id);
image->copyright_file_id = strdup(copyright_file_id);
}
const char *iso_image_get_copyright_file_id(const IsoImage *image)
{
return image->copyright_file_id;
}
void iso_image_set_abstract_file_id(IsoImage *image,
const char *abstract_file_id)
{
free(image->abstract_file_id);
image->abstract_file_id = strdup(abstract_file_id);
}
const char *iso_image_get_abstract_file_id(const IsoImage *image)
{
return image->abstract_file_id;
}
void iso_image_set_biblio_file_id(IsoImage *image, const char *biblio_file_id)
{
free(image->biblio_file_id);
image->biblio_file_id = strdup(biblio_file_id);
}
const char *iso_image_get_biblio_file_id(const IsoImage *image)
{
return image->biblio_file_id;
}
int iso_image_get_msg_id(IsoImage *image)
{
return image->id;
}

112
libisofs/image.h Normal file
View File

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

1016
libisofs/iso1999.c Normal file

File diff suppressed because it is too large Load Diff

59
libisofs/iso1999.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/**
* Structures related to ISO/IEC 9660:1999, that is version 2 of ISO-9660
* "See doc/devel/cookbook/ISO 9660-1999" and
* ISO/IEC DIS 9660:1999(E) "Information processing. Volume and file structure
* of CD­-ROM for Information Interchange"
* for further details.
*/
#ifndef LIBISO_ISO1999_H
#define LIBISO_ISO1999_H
#include "libisofs.h"
#include "ecma119.h"
enum iso1999_node_type {
ISO1999_FILE,
ISO1999_DIR
};
struct iso1999_dir_info {
Iso1999Node **children;
size_t nchildren;
size_t len;
size_t block;
};
struct iso1999_node
{
char *name; /**< Name chosen output charset. */
Iso1999Node *parent;
IsoNode *node; /*< reference to the iso node */
enum iso1999_node_type type;
union {
IsoFileSrc *file;
struct iso1999_dir_info *dir;
} info;
};
/**
* Create a IsoWriter to deal with ISO 9660:1999 estructures, and add it to
* the given target.
*
* @return
* 1 on success, < 0 on error
*/
int iso1999_writer_create(Ecma119Image *target);
#endif /* LIBISO_ISO1999_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,97 +1,56 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /*
/* vim: set noet ts=8 sts=8 sw=8 : */ * 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.
*/
/** /**
* \file joliet.h * Declare Joliet related structures.
*
* Declare the filesystems trees that are Joliet-compatible and the public
* functions for tying them into an ecma119 volume.
*/ */
#ifndef LIBISO_JOLIET_H #ifndef LIBISO_JOLIET_H
#define LIBISO_JOLIET_H #define LIBISO_JOLIET_H
#include <stdint.h> #include "libisofs.h"
#include <stdlib.h> #include "ecma119.h"
struct ecma119_write_target;
struct iso_tree_node;
enum joliet_node_type { enum joliet_node_type {
JOLIET_FILE, JOLIET_FILE,
JOLIET_DIR, JOLIET_DIR
JOLIET_BOOT
}; };
struct joliet_dir_info { struct joliet_dir_info {
struct joliet_tree_node **children; JolietNode **children;
size_t nchildren; size_t nchildren;
size_t len; size_t len;
size_t block; size_t block;
}; };
struct joliet_tree_node struct joliet_node
{ {
uint16_t *name; /**< In UCS-2BE. */ uint16_t *name; /**< Name in UCS-2BE. */
size_t dirent_len;
JolietNode *parent;
IsoNode *node; /*< reference to the iso node */
struct joliet_tree_node *parent;
struct ecma119_write_target *target;
enum joliet_node_type type; enum joliet_node_type type;
union { union {
struct iso_file *file; IsoFileSrc *file;
struct joliet_dir_info dir; struct joliet_dir_info *dir;
unsigned int boot_img:1; /** For boot nodes, it identifies if this
* corresponds to image(1) or catalog(0).
* The block is stored in ecma119_write_target
*/
} info; } info;
}; };
/** /**
* Create a new joliet_tree that corresponds to the tree represented by * Create a IsoWriter to deal with Joliet estructures, and add it to the given
* \p iso_root. * target.
*
* @return
* 1 on success, < 0 on error
*/ */
struct joliet_tree_node* int joliet_writer_create(Ecma119Image *target);
joliet_tree_create(struct ecma119_write_target *target,
struct iso_tree_node *iso_root);
/**
* Calculate the size of each directory in the joliet heirarchy.
*/
void
joliet_calc_dir_size(struct ecma119_write_target *t, struct joliet_tree_node*);
/**
* Calculate the position of each directory in the joliet heirarchy.
*/
void
joliet_calc_dir_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
/**
* Calculate the size of the joliet path table and fill in the list of
* directories.
*/
void
joliet_prepare_path_tables(struct ecma119_write_target *t);
void
joliet_tree_free(struct joliet_tree_node *root);
void
joliet_write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
void
joliet_wr_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf);
void
joliet_wr_l_path_table(struct ecma119_write_target *t, uint8_t *buf);
void
joliet_wr_m_path_table(struct ecma119_write_target *t, uint8_t *buf);
void
joliet_wr_dir_records(struct ecma119_write_target *t, uint8_t *buf);
#endif /* LIBISO_JOLIET_H */ #endif /* LIBISO_JOLIET_H */

View File

@ -1,7 +1,8 @@
/* libiso_msgs /* libiso_msgs (generated from libdax_msgs : Fri Feb 22 19:42:52 CET 2008)
Message handling facility of libiso. Message handling facility of libisofs.
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL Copyright (C) 2006 - 2008 Thomas Schmitt <scdbackup@gmx.net>,
provided under GPL version 2
*/ */
#include <stdio.h> #include <stdio.h>
@ -39,7 +40,7 @@ static int libiso_msgs_item_new(struct libiso_msgs_item **item,
if(ret==0) if(ret==0)
o->timestamp= tv.tv_sec+0.000001*tv.tv_usec; o->timestamp= tv.tv_sec+0.000001*tv.tv_usec;
o->process_id= getpid(); o->process_id= getpid();
o->driveno= -1; o->origin= -1;
o->severity= LIBISO_MSGS_SEV_ALL; o->severity= LIBISO_MSGS_SEV_ALL;
o->priority= LIBISO_MSGS_PRIO_ZERO; o->priority= LIBISO_MSGS_PRIO_ZERO;
o->error_code= 0; o->error_code= 0;
@ -108,12 +109,12 @@ int libiso_msgs_item_get_msg(struct libiso_msgs_item *item,
int libiso_msgs_item_get_origin(struct libiso_msgs_item *item, int libiso_msgs_item_get_origin(struct libiso_msgs_item *item,
double *timestamp, pid_t *process_id, int *driveno, double *timestamp, pid_t *process_id, int *origin,
int flag) int flag)
{ {
*timestamp= item->timestamp; *timestamp= item->timestamp;
*process_id= item->process_id; *process_id= item->process_id;
*driveno= item->driveno; *origin= item->origin;
return(1); return(1);
} }
@ -137,6 +138,7 @@ int libiso_msgs_new(struct libiso_msgs **m, int flag)
(*m)= o= (struct libiso_msgs *) malloc(sizeof(struct libiso_msgs)); (*m)= o= (struct libiso_msgs *) malloc(sizeof(struct libiso_msgs));
if(o==NULL) if(o==NULL)
return(-1); return(-1);
o->refcount= 1;
o->oldest= NULL; o->oldest= NULL;
o->youngest= NULL; o->youngest= NULL;
o->count= 0; o->count= 0;
@ -152,43 +154,6 @@ int libiso_msgs_new(struct libiso_msgs **m, int flag)
} }
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);
#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_set_severities(struct libiso_msgs *m, int queue_severity,
int print_severity, char *print_id, int flag)
{
m->queue_severity= queue_severity;
m->print_severity= print_severity;
strncpy(m->print_id,print_id,80);
m->print_id[80]= 0;
return(1);
}
static int libiso_msgs_lock(struct libiso_msgs *m, int flag) static int libiso_msgs_lock(struct libiso_msgs *m, int flag)
{ {
@ -219,6 +184,65 @@ static int libiso_msgs_unlock(struct libiso_msgs *m, int flag)
} }
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 libiso_msgs__text_to_sev(char *severity_name, int *severity,
int flag) int flag)
{ {
@ -228,6 +252,10 @@ int libiso_msgs__text_to_sev(char *severity_name, int *severity,
*severity= LIBISO_MSGS_SEV_ABORT; *severity= LIBISO_MSGS_SEV_ABORT;
else if(strncmp(severity_name,"FATAL",5)==0) else if(strncmp(severity_name,"FATAL",5)==0)
*severity= LIBISO_MSGS_SEV_FATAL; *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) else if(strncmp(severity_name,"SORRY",5)==0)
*severity= LIBISO_MSGS_SEV_SORRY; *severity= LIBISO_MSGS_SEV_SORRY;
else if(strncmp(severity_name,"WARNING",7)==0) else if(strncmp(severity_name,"WARNING",7)==0)
@ -240,10 +268,12 @@ int libiso_msgs__text_to_sev(char *severity_name, int *severity,
*severity= LIBISO_MSGS_SEV_UPDATE; *severity= LIBISO_MSGS_SEV_UPDATE;
else if(strncmp(severity_name,"DEBUG",5)==0) else if(strncmp(severity_name,"DEBUG",5)==0)
*severity= LIBISO_MSGS_SEV_DEBUG; *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) else if(strncmp(severity_name,"ALL",3)==0)
*severity= LIBISO_MSGS_SEV_ALL; *severity= LIBISO_MSGS_SEV_ALL;
else { else {
*severity= LIBISO_MSGS_SEV_NEVER; *severity= LIBISO_MSGS_SEV_ALL;
return(0); return(0);
} }
return(1); return(1);
@ -254,8 +284,7 @@ int libiso_msgs__sev_to_text(int severity, char **severity_name,
int flag) int flag)
{ {
if(flag&1) { if(flag&1) {
*severity_name= *severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nMISHAP\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL";
"NEVER\nABORT\nFATAL\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
return(1); return(1);
} }
*severity_name= ""; *severity_name= "";
@ -265,6 +294,10 @@ int libiso_msgs__sev_to_text(int severity, char **severity_name,
*severity_name= "ABORT"; *severity_name= "ABORT";
else if(severity>=LIBISO_MSGS_SEV_FATAL) else if(severity>=LIBISO_MSGS_SEV_FATAL)
*severity_name= "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) else if(severity>=LIBISO_MSGS_SEV_SORRY)
*severity_name= "SORRY"; *severity_name= "SORRY";
else if(severity>=LIBISO_MSGS_SEV_WARNING) else if(severity>=LIBISO_MSGS_SEV_WARNING)
@ -277,6 +310,8 @@ int libiso_msgs__sev_to_text(int severity, char **severity_name,
*severity_name= "UPDATE"; *severity_name= "UPDATE";
else if(severity>=LIBISO_MSGS_SEV_DEBUG) else if(severity>=LIBISO_MSGS_SEV_DEBUG)
*severity_name= "DEBUG"; *severity_name= "DEBUG";
else if(severity>=LIBISO_MSGS_SEV_ERRFILE)
*severity_name= "ERRFILE";
else if(severity>=LIBISO_MSGS_SEV_ALL) else if(severity>=LIBISO_MSGS_SEV_ALL)
*severity_name= "ALL"; *severity_name= "ALL";
else { else {
@ -287,7 +322,7 @@ int libiso_msgs__sev_to_text(int severity, char **severity_name,
} }
int libiso_msgs_submit(struct libiso_msgs *m, int driveno, int error_code, int libiso_msgs_submit(struct libiso_msgs *m, int origin, int error_code,
int severity, int priority, char *msg_text, int severity, int priority, char *msg_text,
int os_errno, int flag) int os_errno, int flag)
{ {
@ -325,7 +360,7 @@ int libiso_msgs_submit(struct libiso_msgs *m, int driveno, int error_code,
ret= libiso_msgs_item_new(&item,m->youngest,0); ret= libiso_msgs_item_new(&item,m->youngest,0);
if(ret<=0) if(ret<=0)
goto failed; goto failed;
item->driveno= driveno; item->origin= origin;
item->error_code= error_code; item->error_code= error_code;
item->severity= severity; item->severity= severity;
item->priority= priority; item->priority= priority;

View File

@ -1,8 +1,8 @@
/* libiso_msgs /* libiso_msgs (generated from libdax_msgs : Fri Feb 22 19:42:52 CET 2008)
Message handling facility of libisofs. Message handling facility of libisofs.
Copyright (C) 2006-2007 Thomas Schmitt <scdbackup@gmx.net>, Copyright (C) 2006-2008 Thomas Schmitt <scdbackup@gmx.net>,
provided under GPL provided under GPL version 2
*/ */
@ -23,7 +23,7 @@ struct libiso_msgs_item {
double timestamp; double timestamp;
pid_t process_id; pid_t process_id;
int driveno; int origin;
int severity; int severity;
int priority; int priority;
@ -43,6 +43,8 @@ struct libiso_msgs_item {
struct libiso_msgs { struct libiso_msgs {
int refcount;
struct libiso_msgs_item *oldest; struct libiso_msgs_item *oldest;
struct libiso_msgs_item *youngest; struct libiso_msgs_item *youngest;
int count; int count;
@ -68,6 +70,31 @@ struct libiso_msgs {
#ifndef LIBISO_MSGS_H_INTERNAL #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 */ /* Public Opaque Handles */
/** A pointer to this is a opaque handle to a message handling facility */ /** A pointer to this is a opaque handle to a message handling facility */
@ -86,13 +113,26 @@ struct libiso_msgs_item;
/* It is well advisable to let applications select severities via strings and /* It is well advisable to let applications select severities via strings and
forwarded functions libiso_msgs__text_to_sev(), libiso_msgs__sev_to_text(). forwarded functions libiso_msgs__text_to_sev(), libiso_msgs__sev_to_text().
These macros are for use by libdax/libburn only. These macros are for use by the owner of libiso_msgs.
*/ */
/** Use this to get messages of any severity. Do not use for submitting. /** Use this to get messages of any severity. Do not use for submitting.
*/ */
#define LIBISO_MSGS_SEV_ALL 0x00000000 #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 /** Debugging messages not to be visible to normal users by default
*/ */
#define LIBISO_MSGS_SEV_DEBUG 0x10000000 #define LIBISO_MSGS_SEV_DEBUG 0x10000000
@ -113,15 +153,70 @@ struct libiso_msgs_item;
*/ */
#define LIBISO_MSGS_SEV_WARNING 0x50000000 #define LIBISO_MSGS_SEV_WARNING 0x50000000
/** Non-fatal error messages indicating that parts of the action failed
but processing will/should go on /** 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 #define LIBISO_MSGS_SEV_SORRY 0x60000000
/** An error message which puts the whole operation of libdax in question
/** 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 #define LIBISO_MSGS_SEV_FATAL 0x70000000
/** A message from an abort handler which will finally finish libburn /** A message from an abort handler which will finally finish libburn
*/ */
#define LIBISO_MSGS_SEV_ABORT 0x71000000 #define LIBISO_MSGS_SEV_ABORT 0x71000000
@ -134,7 +229,7 @@ struct libiso_msgs_item;
/* Registered Priorities */ /* Registered Priorities */
/* Priorities are to be used by libburn/libdax only. */ /* Priorities are to be selected by the programmers and not by the user. */
#define LIBISO_MSGS_PRIO_ZERO 0x00000000 #define LIBISO_MSGS_PRIO_ZERO 0x00000000
#define LIBISO_MSGS_PRIO_LOW 0x10000000 #define LIBISO_MSGS_PRIO_LOW 0x10000000
@ -146,12 +241,23 @@ struct libiso_msgs_item;
#define LIBISO_MSGS_PRIO_NEVER 0x7fffffff #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 */ /* Public Functions */
/* Calls initiated from inside libdax/libburn */ /* Calls initiated from inside the direct owner (e.g. from libburn) */
/** Create new empty message handling facility with queue. /** 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) @param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success, <=0 failure @return >0 success, <=0 failure
*/ */
@ -160,18 +266,37 @@ int libiso_msgs_new(struct libiso_msgs **m, int flag);
/** Destroy a message handling facility and all its eventual messages. /** Destroy a message handling facility and all its eventual messages.
The submitted pointer gets set to NULL. 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) @param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 for success, 0 for pointer to NULL @return 1 for success, 0 for pointer to NULL, -1 for fatal error
*/ */
int libiso_msgs_destroy(struct libiso_msgs **m, int flag); 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. /** Submit a message to a message handling facility.
@param driveno libdax drive number. Use -1 if no number is known. @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. @param error_code Unique error code. Use only registered codes. See below.
The same unique error_code may be issued at different The same unique error_code may be issued at different
occasions but those should be equivalent out of the view occasions but those should be equivalent out of the view
of a libdax application. (E.g. "cannot open ATA drive" of a libiso_msgs application. (E.g. "cannot open ATA drive"
versus "cannot open SCSI drive" would be equivalent.) versus "cannot open SCSI drive" would be equivalent.)
@param severity The LIBISO_MSGS_SEV_* of the event. @param severity The LIBISO_MSGS_SEV_* of the event.
@param priority The LIBISO_MSGS_PRIO_* number of the event. @param priority The LIBISO_MSGS_PRIO_* number of the event.
@ -180,12 +305,13 @@ int libiso_msgs_destroy(struct libiso_msgs **m, int flag);
@param flag Bitfield for control purposes (unused yet, submit 0) @param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on rejection, <0 for severe errors @return 1 on success, 0 on rejection, <0 for severe errors
*/ */
int libiso_msgs_submit(struct libiso_msgs *m, int driveno, int error_code, int libiso_msgs_submit(struct libiso_msgs *m, int origin, int error_code,
int severity, int priority, char *msg_text, int severity, int priority, char *msg_text,
int os_errno, int flag); int os_errno, int flag);
/* Calls from applications (to be forwarded by libdax/libburn) */
/* Calls from applications (to be forwarded by direct owner) */
/** Convert a registered severity number into a severity name /** Convert a registered severity number into a severity name
@ -209,7 +335,7 @@ int libiso_msgs__text_to_sev(char *severity_name, int *severity,
LIBISO_MSGS_SEV_ALL) and for messages to be printed directly to stderr LIBISO_MSGS_SEV_ALL) and for messages to be printed directly to stderr
(default LIBISO_MSGS_SEV_NEVER). (default LIBISO_MSGS_SEV_NEVER).
@param print_id A text of at most 80 characters to be printed before @param print_id A text of at most 80 characters to be printed before
any eventually printed message (default is "libdax: "). any eventually printed message (default is "libiso: ").
@param flag Bitfield for control purposes (unused yet, submit 0) @param flag Bitfield for control purposes (unused yet, submit 0)
@return always 1 for now @return always 1 for now
*/ */
@ -256,7 +382,7 @@ int libiso_msgs_item_get_msg(struct libiso_msgs_item *item,
@return 1 on success, 0 on invalid item, <0 for servere errors @return 1 on success, 0 on invalid item, <0 for servere errors
*/ */
int libiso_msgs_item_get_origin(struct libiso_msgs_item *item, int libiso_msgs_item_get_origin(struct libiso_msgs_item *item,
double *timestamp, pid_t *process_id, int *driveno, double *timestamp, pid_t *process_id, int *origin,
int flag); int flag);
@ -276,7 +402,7 @@ int libiso_msgs_item_get_rank(struct libiso_msgs_item *item,
Format: error_code (LIBISO_MSGS_SEV_*,LIBISO_MSGS_PRIO_*) = explanation Format: error_code (LIBISO_MSGS_SEV_*,LIBISO_MSGS_PRIO_*) = explanation
If no severity or priority are fixely associates, use "(,)". If no severity or priority are fixely associated, use "(,)".
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Range "libiso_msgs" : 0x00000000 to 0x0000ffff Range "libiso_msgs" : 0x00000000 to 0x0000ffff
@ -284,6 +410,7 @@ Range "libiso_msgs" : 0x00000000 to 0x0000ffff
0x00000000 (ALL,ZERO) = Initial setting in new libiso_msgs_item 0x00000000 (ALL,ZERO) = Initial setting in new libiso_msgs_item
0x00000001 (DEBUG,ZERO) = Test error message 0x00000001 (DEBUG,ZERO) = Test error message
0x00000002 (DEBUG,ZERO) = Debugging message 0x00000002 (DEBUG,ZERO) = Debugging message
0x00000003 (FATAL,HIGH) = Out of virtual memory
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
@ -304,6 +431,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x00020006 (FATAL,HIGH) = Too many scsi siblings 0x00020006 (FATAL,HIGH) = Too many scsi siblings
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings 0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock 0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock
0x00020009 (SORRY,HIGH) = Neither stdio-path nor its directory exist
General library operations: General library operations:
@ -313,7 +441,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x00020104 (SORRY,HIGH) = NULL pointer caught 0x00020104 (SORRY,HIGH) = NULL pointer caught
0x00020105 (SORRY,HIGH) = Drive is already released 0x00020105 (SORRY,HIGH) = Drive is already released
0x00020106 (SORRY,HIGH) = Drive is busy on attempt to close 0x00020106 (SORRY,HIGH) = Drive is busy on attempt to close
0x00020107 (SORRY,HIGH) = Drive is busy on attempt to shut down library 0x00020107 (WARNING,HIGH) = A drive is still busy on shutdown of library
0x00020108 (SORRY,HIGH) = Drive is not grabbed on disc status inquiry 0x00020108 (SORRY,HIGH) = Drive is not grabbed on disc status inquiry
0x00020108 (FATAL,HIGH) = Could not allocate new drive object 0x00020108 (FATAL,HIGH) = Could not allocate new drive object
0x00020109 (FATAL,HIGH) = Library not running 0x00020109 (FATAL,HIGH) = Library not running
@ -371,49 +499,149 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x0002013d (DEBUG,LOW) = Waiting for free buffer space takes long time 0x0002013d (DEBUG,LOW) = Waiting for free buffer space takes long time
0x0002013e (SORRY,HIGH) = Timeout with waiting for free buffer. Now disabled 0x0002013e (SORRY,HIGH) = Timeout with waiting for free buffer. Now disabled
0x0002013f (DEBUG,LOW) = Reporting total time spent with waiting for buffer 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: libiso_audioxtr:
0x00020200 (SORRY,HIGH) = Cannot open audio source file 0x00020200 (SORRY,HIGH) = Cannot open audio source file
0x00020201 (SORRY,HIGH) = Audio source file has unsuitable format 0x00020201 (SORRY,HIGH) = Audio source file has unsuitable format
0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data 0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Range "vreixo" : 0x00030000 to 0x0003ffff Range "vreixo" : 0x00030000 to 0x0003ffff
General: 0x0003ffff (FAILURE,HIGH) = Operation canceled
0x00031001 (SORRY,HIGH) = Cannot read file (ignored) 0x0003fffe (FATAL,HIGH) = Unknown or unexpected fatal error
0x00031002 (FATAL,HIGH) = Cannot read file (operation canceled) 0x0003fffd (FAILURE,HIGH) = Unknown or unexpected error
0x00031003 (FATAL,HIGH) = File doesnt exist 0x0003fffc (FATAL,HIGH) = Internal programming error
0x00031004 (FATAL,HIGH) = Read access denied 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
Image reading:
0x00031000 (FATAL,HIGH) = Unsupported ISO-9660 image
0x00031001 (HINT,MEDIUM) = Unsupported Vol Desc that will be ignored
0x00031002 (FATAL,HIGH) = Damaged ISO-9660 image
0x00031003 (SORRY,HIGH) = Cannot read previous image file
Rock-Ridge:
0x00030101 (HINT,MEDIUM) = Unsupported SUSP entry that will be ignored
0x00030102 (SORRY,HIGH) = Wrong/damaged SUSP entry
0x00030103 (WARNING,MEDIUM)= Multiple SUSP ER entries where found
0x00030111 (SORRY,HIGH) = Unsupported RR feature
0x00030112 (SORRY,HIGH) = Error in a Rock Ridge entry
El-Torito:
0x00030201 (HINT,MEDIUM) = Unsupported Boot Vol Desc that will be ignored
0x00030202 (SORRY,HIGH) = Wrong El-Torito catalog
0x00030203 (HINT,MEDIUM) = Unsupported El-Torito feature
0x00030204 (SORRY,HIGH) = Invalid file to be an El-Torito image
0x00030205 (WARNING,MEDIUM)= Cannot properly patch isolinux image
0x00030206 (WARNING,MEDIUM)= Copying El-Torito from a previous image without
enought info about it
Joliet:
0x00030301 (NOTE,MEDIUM) = Unsupported file type for Joliet tree
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
#endif /* LIDBAX_MSGS_________________ */ #endif /* LIDBAX_MSGS_________________ */

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +1,249 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "libiso_msgs.h"
#include "libisofs.h" #include "libisofs.h"
#include "messages.h" #include "messages.h"
struct libiso_msgs *libiso_messenger = NULL; /*
* 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() int iso_init()
{ {
if (libiso_messenger == NULL) { if (libiso_msgr == NULL) {
if (libiso_msgs_new(&libiso_messenger, 0) <= 0) if (libiso_msgs_new(&libiso_msgr, 0) <= 0)
return 0; return ISO_FATAL_ERROR;
} }
libiso_msgs_set_severities(libiso_messenger, LIBISO_MSGS_SEV_NEVER, libiso_msgs_set_severities(libiso_msgr, LIBISO_MSGS_SEV_NEVER,
LIBISO_MSGS_SEV_FATAL, "libisofs: ", 0); LIBISO_MSGS_SEV_FATAL, "libisofs: ", 0);
return 1; return 1;
} }
void iso_finish() void iso_finish()
{ {
libiso_msgs_destroy(&libiso_messenger,0); libiso_msgs_destroy(&libiso_msgr, 0);
} }
void iso_msg_debug(char *msg_text) int iso_set_abort_severity(char *severity)
{ {
libiso_msgs_submit(libiso_messenger, -1, 0x00000002, int ret, sevno;
LIBISO_MSGS_SEV_DEBUG, LIBISO_MSGS_PRIO_ZERO,
msg_text, 0, 0); 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_note(int error_code, char *msg_text) void iso_msg_debug(int imgid, const char *fmt, ...)
{ {
libiso_msgs_submit(libiso_messenger, -1, error_code, char msg[MAX_MSG_LEN];
LIBISO_MSGS_SEV_NOTE, LIBISO_MSGS_PRIO_MEDIUM, va_list ap;
msg_text, 0, 0);
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);
} }
void iso_msg_hint(int error_code, char *msg_text) const char *iso_error_to_msg(int errcode)
{ {
libiso_msgs_submit(libiso_messenger, -1, error_code, switch(errcode) {
LIBISO_MSGS_SEV_HINT, LIBISO_MSGS_PRIO_MEDIUM, case ISO_CANCELED:
msg_text, 0, 0); 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";
}
} }
void iso_msg_warn(int error_code, char *msg_text) int iso_msg_submit(int imgid, int errcode, int causedby, const char *fmt, ...)
{ {
libiso_msgs_submit(libiso_messenger, -1, error_code, char msg[MAX_MSG_LEN];
LIBISO_MSGS_SEV_WARNING, LIBISO_MSGS_PRIO_MEDIUM, va_list ap;
msg_text, 0, 0);
} /* when called with ISO_CANCELED, we don't need to submit any message */
if (errcode == ISO_CANCELED && fmt == NULL) {
return ISO_CANCELED;
}
void iso_msg_sorry(int error_code, char *msg_text) if (fmt) {
{ va_start(ap, fmt);
libiso_msgs_submit(libiso_messenger, -1, error_code, vsnprintf(msg, MAX_MSG_LEN, fmt, ap);
LIBISO_MSGS_SEV_SORRY, LIBISO_MSGS_PRIO_HIGH, va_end(ap);
msg_text, 0, 0); } else {
} strncpy(msg, iso_error_to_msg(errcode), MAX_MSG_LEN);
}
void iso_msg_fatal(int error_code, char *msg_text) libiso_msgs_submit(libiso_msgr, imgid, ISO_ERR_CODE(errcode),
{ ISO_ERR_SEV(errcode), ISO_ERR_PRIO(errcode), msg, 0, 0);
libiso_msgs_submit(libiso_messenger, -1, error_code, if (causedby != 0) {
LIBISO_MSGS_SEV_FATAL, LIBISO_MSGS_PRIO_HIGH, snprintf(msg, MAX_MSG_LEN, " > Caused by: %s",
msg_text, 0, 0); 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;
}
} }
/** /**
@ -77,26 +259,24 @@ void iso_msg_fatal(int error_code, char *msg_text)
* @param print_id A text prefix to be printed before the message. * @param print_id A text prefix to be printed before the message.
* @return >0 for success, <=0 for error * @return >0 for success, <=0 for error
*/ */
int iso_msgs_set_severities(char *queue_severity, int iso_set_msgs_severities(char *queue_severity, char *print_severity,
char *print_severity, char *print_id) char *print_id)
{ {
int ret, queue_sevno, print_sevno; int ret, queue_sevno, print_sevno;
ret = libiso_msgs__text_to_sev(queue_severity, &queue_sevno, 0); ret = libiso_msgs__text_to_sev(queue_severity, &queue_sevno, 0);
if (ret <= 0) if (ret <= 0)
return 0; return 0;
ret = libiso_msgs__text_to_sev(print_severity, &print_sevno, 0); ret = libiso_msgs__text_to_sev(print_severity, &print_sevno, 0);
if (ret <= 0) if (ret <= 0)
return 0; return 0;
ret = libiso_msgs_set_severities(libiso_messenger, queue_sevno, ret = libiso_msgs_set_severities(libiso_msgr, queue_sevno, print_sevno,
print_sevno, print_id, 0); print_id, 0);
if (ret <= 0) if (ret <= 0)
return 0; return 0;
return 1; return 1;
} }
#define ISO_MSGS_MESSAGE_LEN 4096
/** /**
* Obtain the oldest pending libisofs message from the queue which has at * Obtain the oldest pending libisofs message from the queue which has at
* least the given minimum_severity. This message and any older message of * least the given minimum_severity. This message and any older message of
@ -107,54 +287,142 @@ int iso_msgs_set_severities(char *queue_severity,
* will discard the whole queue. * will discard the whole queue.
* *
* @param error_code Will become a unique error code as listed in messages.h * @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 msg_text Must provide at least ISO_MSGS_MESSAGE_LEN bytes.
* @param os_errno Will become the eventual errno related to the message
* @param severity Will become the severity related to the message and * @param severity Will become the severity related to the message and
* should provide at least 80 bytes. * should provide at least 80 bytes.
* @return 1 if a matching item was found, 0 if not, <0 for severe errors * @return 1 if a matching item was found, 0 if not, <0 for severe errors
*/ */
int iso_msgs_obtain(char *minimum_severity, int iso_obtain_msgs(char *minimum_severity, int *error_code, int *imgid,
int *error_code, char msg_text[], int *os_errno, char msg_text[], char severity[])
char severity[])
{ {
int ret, minimum_sevno, sevno, priority; int ret, minimum_sevno, sevno, priority, os_errno;
char *textpt, *sev_name; double timestamp;
struct libiso_msgs_item *item = NULL; pid_t pid;
char *textpt, *sev_name;
struct libiso_msgs_item *item= NULL;
if (libiso_messenger == NULL) ret = libiso_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
return 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__text_to_sev(minimum_severity, &minimum_sevno, 0); ret = libiso_msgs_item_get_origin(item, &timestamp, &pid, imgid, 0);
if (ret <= 0) if (ret <= 0)
return 0; goto ex;
ret = libiso_msgs_obtain(libiso_messenger, &item, minimum_sevno,
LIBISO_MSGS_PRIO_ZERO, 0); severity[0]= 0;
if (ret <= 0) ret = libiso_msgs_item_get_rank(item, &sevno, &priority, 0);
goto ex; if (ret <= 0)
ret = libiso_msgs_item_get_msg(item, error_code, &textpt, os_errno, 0); goto ex;
if (ret <= 0) ret = libiso_msgs__sev_to_text(sevno, &sev_name, 0);
goto ex; if (ret <= 0)
strncpy(msg_text, textpt, ISO_MSGS_MESSAGE_LEN-1); goto ex;
if(strlen(textpt) >= ISO_MSGS_MESSAGE_LEN) strcpy(severity, sev_name);
msg_text[ISO_MSGS_MESSAGE_LEN-1] = 0;
severity[0]= 0; ret = 1;
ret = libiso_msgs_item_get_rank(item, &sevno, &priority, 0); ex: ;
if(ret <= 0) libiso_msgs_destroy_item(libiso_msgr, &item, 0);
goto ex; return ret;
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_messenger, &item, 0);
return ret;
} }
void *iso_get_messenger(void)
/* 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)
{ {
return libiso_messenger; 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);
}

View File

@ -1,3 +1,11 @@
/*
* 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 * Message handling for libisofs
*/ */
@ -5,63 +13,37 @@
#ifndef MESSAGES_H_ #ifndef MESSAGES_H_
#define MESSAGES_H_ #define MESSAGES_H_
#include "libiso_msgs.h" /**
* Take and increment this variable to get a valid identifier for message
* origin.
*/
extern int iso_message_id;
/** Can't read file (ignored) */ /**
#define LIBISO_CANT_READ_FILE 0x00031001 * Submit a debug message.
/** Can't read file (operation canceled) */ */
#define LIBISO_FILE_READ_ERROR 0x00031002 void iso_msg_debug(int imgid, const char *fmt, ...);
/** File doesn't exist */
#define LIBISO_FILE_DOESNT_EXIST 0x00031003
/** Read access denied */
#define LIBISO_FILE_NO_READ_ACCESS 0x00031004
/** Unsupported image feature */ /**
#define LIBISO_IMG_UNSUPPORTED 0x00031000 *
/** Unsupported Vol Desc that will be ignored */ * @param errcode
#define LIBISO_UNSUPPORTED_VD 0x00031001 * The error code.
/** damaged image */ * @param causedby
#define LIBISO_WRONG_IMG 0x00031002 * Error that was caused the errcode. If this error is a FATAL error,
/** Can't read previous image file */ * < 0 will be returned in any case. Use 0 if there is no previous
#define LIBISO_CANT_READ_IMG 0x00031003 * 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, ...);
/* Unsupported SUSP entry */
#define LIBISO_SUSP_UNHANLED 0x00030101
/* Wrong SUSP entry, that cause RR to be ignored */
#define LIBISO_SUSP_WRONG 0x00030102
/* Unsupported multiple SUSP ER entries where found */
#define LIBISO_SUSP_MULTIPLE_ER 0x00030103
/** Unsupported RR feature. */
#define LIBISO_RR_UNSUPPORTED 0x00030111
/** Error in a Rock Ridge entry. */
#define LIBISO_RR_ERROR 0x00030112
/** Unsupported boot vol desc. */ /* ts A80222 */
#define LIBISO_BOOT_VD_UNHANLED 0x00030201 /* To be called with events which report incidents with individual input
/** Wrong or damaged el-torito catalog */ files from the local filesystem. Not with image nodes, files containing an
#define LIBISO_EL_TORITO_WRONG 0x00030202 image or similar file-like objects.
/** Unsupproted el-torito feature */ */
#define LIBISO_EL_TORITO_UNHANLED 0x00030203 int iso_report_errfile(char *path, int error_code, int os_errno, int flag);
/** Trying to add an invalid file as a El-Torito image */
#define LIBISO_EL_TORITO_WRONG_IMG 0x00030204
/** Can't properly patch isolinux image */
#define LIBISO_ISOLINUX_CANT_PATCH 0x00030205
/** Copying El-Torito from a previous image without enought info about it */
#define LIBISO_EL_TORITO_BLIND_COPY 0x00030206
/** Unsupported file type for Joliet tree */
#define LIBISO_JOLIET_WRONG_FILE_TYPE 0x00030301
void iso_msg_debug(char *msg_text);
void iso_msg_note(int error_code, char *msg_text);
void iso_msg_hint(int error_code, char *msg_text);
void iso_msg_warn(int error_code, char *msg_text);
void iso_msg_sorry(int error_code, char *msg_text);
void iso_msg_fatal(int error_code, char *msg_text);
#endif /*MESSAGES_H_*/ #endif /*MESSAGES_H_*/

1171
libisofs/node.c Normal file

File diff suppressed because it is too large Load Diff

344
libisofs/node.h Normal file
View File

@ -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 <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdint.h>
/* #define LIBISO_EXTENDED_INFORMATION */
#ifdef LIBISO_EXTENDED_INFORMATION
/**
* The extended information is a way to attach additional information to each
* IsoNode. External applications may want to use this extension system to
* store application speficic information related to each node. On the other
* side, libisofs may make use of this struct to attach information to nodes in
* some particular, uncommon, cases, without incrementing the size of the
* IsoNode struct.
*
* It is implemented like a chained list.
*/
typedef struct iso_extended_info IsoExtendedInfo;
struct iso_extended_info {
/**
* Next struct in the chain. NULL if it is the last item
*/
IsoExtendedInfo *next;
/**
* Function to handle this particular extended information. The function
* pointer acts as an identifier for the type of the information. Structs
* with same information type must use the same function.
*
* @param data
* Attached data
* @param flag
* What to do with the data. At this time the following values are
* defined:
* -> 1 the data must be freed
* @return
* 1
*/
int (*process)(void *data, int flag);
/**
* Pointer to information specific data.
*/
void *data;
};
#endif
/**
*
*/
struct Iso_Node
{
/*
* Initilized to 1, originally owned by user, until added to another node.
* Then it is owned by the parent node, so the user must take his own ref
* if needed. With the exception of the creation functions, none of the
* other libisofs functions that return an IsoNode increment its
* refcount. This is responsablity of the client, if (s)he needs it.
*/
int refcount;
/** Type of the IsoNode, do not confuse with mode */
enum IsoNodeType type;
char *name; /**< Real name, in default charset */
mode_t mode; /**< protection */
uid_t uid; /**< user ID of owner */
gid_t gid; /**< group ID of owner */
/* TODO #00001 : consider adding new timestamps */
time_t atime; /**< time of last access */
time_t mtime; /**< time of last modification */
time_t ctime; /**< time of last status change */
int hidden; /**< whether the node will be hidden, see IsoHideNodeFlag */
IsoDir *parent; /**< parent node, NULL for root */
/*
* Pointer to the linked list of children in a dir.
*/
IsoNode *next;
#ifdef LIBISO_EXTENDED_INFORMATION
/**
* Extended information for the node.
*/
IsoExtendedInfo *xinfo;
#endif
};
struct Iso_Dir
{
IsoNode node;
size_t nchildren; /**< The number of children of this directory. */
IsoNode *children; /**< list of children. ptr to first child */
};
struct Iso_File
{
IsoNode node;
/**
* Location of a file extent in a ms disc, 0 for newly added file
*/
uint32_t msblock;
/**
* It sorts the order in which the file data is written to the CD image.
* Higher weighting files are written at the beginning of image
*/
int sort_weight;
IsoStream *stream;
};
struct Iso_Symlink
{
IsoNode node;
char *dest;
};
struct Iso_Special
{
IsoNode node;
dev_t dev;
};
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_*/

File diff suppressed because it is too large Load Diff

View File

@ -1,112 +1,267 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
/**
* Functions and structures used for Rock Ridge support.
*
* See IEEE P1282, Rock Ridge Interchange Protocol, Draft Standard version
* 1.12 for further details.
*/
#ifndef ISO_ROCKRIDGE_H
#define ISO_ROCKRIDGE_H
struct ecma119_write_target;
struct ecma119_tree_node;
/**
* Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification.
*
* The "ER" System Use Entry is used to uniquely identify a specification
* compliant with SUSP. This method adds to the given tree node "." entry
* the "ER" corresponding to the RR protocol.
*
* See IEEE P1281, section 5.5 and IEEE P1282, section 4.3 for more details.
*/
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a PX System Use Entry to the given tree node and, if that node is
* a directory, to its "." and ".." entries. The PX System Use Entry is
* used to add POSIX file attributes, such as access permissions or user and
* group id, to a ECMA 119 directory record.
*
* See IEEE P1282, section 4.1.1 for more details.
*/
void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a PN System Use Entry to the given tree node.
* The PN System Use Entry is used to store the device number, and it's
* mandatory if the tree node corresponds to a character or block device.
*
* See IEEE P1282, section 4.1.2 for more details.
*/
void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a SL System Use Entry to the given tree node. This is used to store
* the content of a symbolic link, and is mandatory if the tree node
* indicates a symbolic link.
*
* See IEEE P1282, section 4.1.3 for more details.
*/
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
/**
* Add a NM System Use Entry to the given tree node. The purpose of this
* System Use Entry is to store the content of an Alternate Name to support
* POSIX-style or other names.
*
* See IEEE P1282, section 4.1.4 for more details.
*/
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
/* /*
* The next 3 System Use Entries are used to handle Deep Directory * Copyright (c) 2007 Vreixo Formoso
* Hierarchies, i.e., hierarchies where the number of directory levels * Copyright (c) 2007 Mario Danic
* exceed the eight limit of ECMA-119. *
* 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.
*/ */
/** /**
* Add to the given tree node a CL System Use Entry, that is used to record * This header defines the functions and structures needed to add RockRidge
* the new location of a directory which has been relocated. * extensions to an ISO image.
* *
* See IEEE P1282, section 4.1.5.1 for more details. * 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.
*/ */
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
#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))
/** /**
* Add a PL System Use Entry, used to record the location of the original * This contains the information about the System Use Fields (SUSP, 4.1),
* parent directory of a directory which has been relocated. * 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
* This is special because it doesn't modify the susp fields of the directory * defined by SUSP.
* that gets passed to it; it modifies the susp fields of the ".." entry in
* that directory.
*
* See IEEE P1282, section 4.1.5.2 for more details.
*/ */
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *); 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];
};
/** /**
* Add a RE System Use Entry to the given tree node. The purpose of the * Struct for a SUSP System User Entry (SUSP, 4.1)
* this System Use Entry is to indicate to an RRIP-compliant receiving
* system that the Directory Record in which an "RE" System Use Entry is
* recorded has been relocated from another position in the original
* Directory Hierarchy.
*
* See IEEE P1282, section 4.1.5.3 for more details.
*/ */
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *); 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 */
};
/** /**
* Add to the given tree node a TF System Use Entry, used to record some * Compute the length needed for write all RR and SUSP entries for a given
* time stamps related to the file. * node.
* *
* See IEEE P1282, section 4.1.6 for more details. * @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
*/ */
void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *); 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);
void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *); /**
* 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);
#endif /* ISO_ROCKRIDGE_H */ /**
* 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 */

419
libisofs/rockridge_read.c Normal file
View File

@ -0,0 +1,419 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
/*
* This file contains functions related to the reading of SUSP and
* Rock Ridge extensions on an ECMA-119 image.
*/
#include "libisofs.h"
#include "ecma119.h"
#include "util.h"
#include "rockridge.h"
#include "messages.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
struct susp_iterator
{
uint8_t* base;
int pos;
int size;
IsoDataSource *src;
int msgid;
/* block and offset for next continuation area */
uint32_t ce_block;
uint32_t ce_off;
/** Length of the next continuation area, 0 if no more CA are specified */
uint32_t ce_len;
uint8_t *buffer; /*< If there are continuation areas */
};
SuspIterator*
susp_iter_new(IsoDataSource *src, struct ecma119_dir_record *record,
uint8_t len_skp, int msgid)
{
int pad = (record->len_fi[0] + 1) % 2;
struct susp_iterator *iter = malloc(sizeof(struct susp_iterator));
if (iter == NULL) {
return NULL;
}
iter->base = record->file_id + record->len_fi[0] + pad;
iter->pos = len_skp; /* 0 in most cases */
iter->size = record->len_dr[0] - record->len_fi[0] - 33 - pad;
iter->src = src;
iter->msgid = msgid;
iter->ce_len = 0;
iter->buffer = NULL;
return iter;
}
int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue)
{
struct susp_sys_user_entry *entry;
entry = (struct susp_sys_user_entry*)(iter->base + iter->pos);
if ( (iter->pos + 4 > iter->size) || (SUSP_SIG(entry, 'S', 'T'))) {
/*
* End of the System Use Area or Continuation Area.
* Note that ST is not needed when the space left is less than 4.
* (IEEE 1281, SUSP. section 4)
*/
if (iter->ce_len) {
uint32_t block;
int nblocks;
/* A CE has found, there is another continuation area */
nblocks = DIV_UP(iter->ce_off + iter->ce_len, BLOCK_SIZE);
iter->buffer = realloc(iter->buffer, nblocks * BLOCK_SIZE);
/* read all blocks needed to cache the full CE */
for (block = 0; block < nblocks; ++block) {
int ret;
ret = iter->src->read_block(iter->src, iter->ce_block + block,
iter->buffer + block * BLOCK_SIZE);
if (ret < 0) {
return ret;
}
}
iter->base = iter->buffer + iter->ce_off;
iter->pos = 0;
iter->size = iter->ce_len;
iter->ce_len = 0;
entry = (struct susp_sys_user_entry*)iter->base;
} else {
return 0;
}
}
if (entry->len_sue[0] == 0) {
/* a wrong image with this lead us to a infinity loop */
iso_msg_submit(iter->msgid, ISO_WRONG_RR, 0,
"Damaged RR/SUSP information.");
return ISO_WRONG_RR;
}
iter->pos += entry->len_sue[0];
if (SUSP_SIG(entry, 'C', 'E')) {
/* Continuation entry */
if (iter->ce_len) {
int ret;
ret = iso_msg_submit(iter->msgid, ISO_UNSUPPORTED_SUSP, 0,
"More than one CE System user entry has found in a single "
"System Use field or continuation area. This breaks SUSP "
"standard and it's not supported. Ignoring last CE. Maybe "
"the image is damaged.");
if (ret < 0) {
return ret;
}
} else {
iter->ce_block = iso_read_bb(entry->data.CE.block, 4, NULL);
iter->ce_off = iso_read_bb(entry->data.CE.offset, 4, NULL);
iter->ce_len = iso_read_bb(entry->data.CE.len, 4, NULL);
}
/* we don't want to return CE entry to the user */
return susp_iter_next(iter, sue);
} else if (SUSP_SIG(entry, 'P', 'D')) {
/* skip padding */
return susp_iter_next(iter, sue);
}
*sue = entry;
return ISO_SUCCESS;
}
void susp_iter_free(SuspIterator *iter)
{
free(iter->buffer);
free(iter);
}
/**
* Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st)
{
if (px == NULL || st == NULL) {
return ISO_NULL_POINTER;
}
if (px->sig[0] != 'P' || px->sig[1] != 'X') {
return ISO_WRONG_ARG_VALUE;
}
if (px->len_sue[0] != 44 && px->len_sue[0] != 36) {
return ISO_WRONG_RR;
}
st->st_mode = iso_read_bb(px->data.PX.mode, 4, NULL);
st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL);
st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL);
st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL);
if (px->len_sue[0] == 44) {
/* this corresponds to RRIP 1.12, so we have inode serial number */
st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
}
return ISO_SUCCESS;
}
/**
* Fills a struct stat with the values of a Rock Ridge TF entry (RRIP, 4.1.6)
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st)
{
time_t time;
int s;
int nts = 0;
if (tf == NULL || st == NULL) {
return ISO_NULL_POINTER;
}
if (tf->sig[0] != 'T' || tf->sig[1] != 'F') {
return ISO_WRONG_ARG_VALUE;
}
if (tf->data.TF.flags[0] & (1 << 7)) {
/* long form */
s = 17;
} else {
s = 7;
}
/* 1. Creation time */
if (tf->data.TF.flags[0] & (1 << 0)) {
/* the creation is the recording time. we ignore this */
/* TODO maybe it would be good to manage it in ms discs, where
* the recording time could be different than now!! */
++nts;
}
/* 2. modify time */
if (tf->data.TF.flags[0] & (1 << 1)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
/* RR TF entry too short. */
return ISO_WRONG_RR;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_mtime = time;
++nts;
}
/* 3. access time */
if (tf->data.TF.flags[0] & (1 << 2)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
/* RR TF entry too short. */
return ISO_WRONG_RR;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_atime = time;
++nts;
}
/* 4. attributes time */
if (tf->data.TF.flags[0] & (1 << 3)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
/* RR TF entry too short. */
return ISO_WRONG_RR;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_ctime = time;
++nts;
}
/* we ignore backup, expire and effect times */
return ISO_SUCCESS;
}
/**
* Read a RR NM entry (RRIP, 4.1.4), and appends the name stored there to
* the given name. You can pass a pointer to NULL as name.
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_NM(struct susp_sys_user_entry *nm, char **name, int *cont)
{
if (nm == NULL || name == NULL) {
return ISO_NULL_POINTER;
}
if (nm->sig[0] != 'N' || nm->sig[1] != 'M') {
return ISO_WRONG_ARG_VALUE;
}
if (nm->len_sue[0] == 5) {
if (nm->data.NM.flags[0] & 0x2) {
/* it is a "." entry */
if (*name == NULL) {
return ISO_SUCCESS;
} else {
/* we can't have a previous not-NULL name */
return ISO_WRONG_RR;
}
}
}
if (nm->len_sue[0] <= 5) {
/* ".." entry is an error, as we will never call it */
return ISO_WRONG_RR;
}
/* concatenate the results */
if (*cont) {
*name = realloc(*name, strlen(*name) + nm->len_sue[0] - 5 + 1);
strncat(*name, (char*)nm->data.NM.name, nm->len_sue[0] - 5);
} else {
*name = strcopy((char*)nm->data.NM.name, nm->len_sue[0] - 5);
}
if (*name == NULL) {
return ISO_OUT_OF_MEM;
}
/* and set cond according to the value of CONTINUE flag */
*cont = nm->data.NM.flags[0] & 0x01;
return ISO_SUCCESS;
}
/**
* Read a SL RR entry (RRIP, 4.1.3), checking if the destination continues.
*
* @param cont
* 0 not continue, 1 continue, 2 continue component
* @return
* 1 on success, < 0 on error
*/
int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont)
{
int pos;
if (sl == NULL || dest == NULL) {
return ISO_NULL_POINTER;
}
if (sl->sig[0] != 'S' || sl->sig[1] != 'L') {
return ISO_WRONG_ARG_VALUE;
}
for (pos = 0; pos + 5 < sl->len_sue[0];
pos += 2 + sl->data.SL.comps[pos + 1]) {
char *comp;
uint8_t len;
uint8_t flags = sl->data.SL.comps[pos];
if (flags & 0x2) {
/* current directory */
len = 1;
comp = ".";
} else if (flags & 0x4) {
/* parent directory */
len = 2;
comp = "..";
} else if (flags & 0x8) {
/* root directory */
len = 1;
comp = "/";
} else if (flags & ~0x01) {
/* unsupported flag component */
return ISO_UNSUPPORTED_RR;
} else {
len = sl->data.SL.comps[pos + 1];
comp = (char*)&sl->data.SL.comps[pos + 2];
}
if (*cont == 1) {
/* new component */
size_t size = strlen(*dest);
*dest = realloc(*dest, strlen(*dest) + len + 2);
if (*dest == NULL) {
return ISO_OUT_OF_MEM;
}
/* it is a new compoenent, add the '/' */
if ((*dest)[size-1] != '/') {
(*dest)[size] = '/';
(*dest)[size+1] = '\0';
}
strncat(*dest, comp, len);
} else if (*cont == 2) {
/* the component continues */
*dest = realloc(*dest, strlen(*dest) + len + 1);
if (*dest == NULL) {
return ISO_OUT_OF_MEM;
}
/* we don't have to add the '/' */
strncat(*dest, comp, len);
} else {
*dest = strcopy(comp, len);
}
if (*dest == NULL) {
return ISO_OUT_OF_MEM;
}
/* do the component continue or not? */
*cont = (flags & 0x01) ? 2 : 1;
}
if (*cont == 2) {
/* TODO check that SL flag is set to continute too ?*/
} else {
*cont = sl->data.SL.flags[0] & 0x1 ? 1 : 0;
}
return ISO_SUCCESS;
}
/**
* Fills a struct stat with the values of a Rock Ridge PN entry (RRIP, 4.1.2).
*
* @return
* 1 on success, < 0 on error
*/
int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
{
if (pn == NULL || pn == NULL) {
return ISO_NULL_POINTER;
}
if (pn->sig[0] != 'P' || pn->sig[1] != 'N') {
return ISO_WRONG_ARG_VALUE;
}
if (pn->len_sue[0] != 20) {
return ISO_WRONG_RR;
}
st->st_rdev = (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) << 32)
|| (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
return ISO_SUCCESS;
}

622
libisofs/stream.c Normal file
View File

@ -0,0 +1,622 @@
/*
* Copyright (c) 2007 Vreixo Formoso
*
* This file is part of the libisofs project; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See COPYING file for details.
*/
#include "libisofs.h"
#include "stream.h"
#include "fsource.h"
#include "util.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
ino_t serial_id = (ino_t)1;
ino_t mem_serial_id = (ino_t)1;
ino_t cut_out_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 (data == 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;
}
struct cut_out_stream
{
IsoFileSource *src;
/* key for file identification inside filesystem */
dev_t dev_id;
ino_t ino_id;
off_t offset; /**< offset where read begins */
off_t size; /**< size of this file */
off_t pos; /* position on the file for read */
};
static
int cut_out_open(IsoStream *stream)
{
int ret;
struct stat info;
IsoFileSource *src;
struct cut_out_stream *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
src = data->src;
ret = iso_file_source_stat(data->src, &info);
if (ret < 0) {
return ret;
}
ret = iso_file_source_open(src);
if (ret < 0) {
return ret;
}
{
off_t ret;
if (data->offset > info.st_size) {
/* file is smaller than expected */
ret = iso_file_source_lseek(src, info.st_size, 0);
} else {
ret = iso_file_source_lseek(src, data->offset, 0);
}
if (ret < 0) {
return (int) ret;
}
}
data->pos = 0;
if (data->offset + data->size > info.st_size) {
return 3; /* file smaller than expected */
} else {
return ISO_SUCCESS;
}
}
static
int cut_out_close(IsoStream *stream)
{
IsoFileSource *src;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
src = ((struct cut_out_stream*)stream->data)->src;
return iso_file_source_close(src);
}
static
off_t cut_out_get_size(IsoStream *stream)
{
struct cut_out_stream *data = stream->data;
return data->size;
}
static
int cut_out_read(IsoStream *stream, void *buf, size_t count)
{
struct cut_out_stream *data = stream->data;
count = (size_t)MIN(data->size - data->pos, count);
if (count == 0) {
return 0;
}
return iso_file_source_read(data->src, buf, count);
}
static
int cut_out_is_repeatable(IsoStream *stream)
{
/* reg files are always repeatable */
return 1;
}
static
void cut_out_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 cut_out_free(IsoStream *stream)
{
struct cut_out_stream *data = stream->data;
iso_file_source_unref(data->src);
free(data);
}
IsoStreamIface cut_out_stream_class = {
0,
"cout",
cut_out_open,
cut_out_close,
cut_out_get_size,
cut_out_read,
cut_out_is_repeatable,
cut_out_get_id,
cut_out_free
};
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
IsoStream **stream)
{
int r;
struct stat info;
IsoStream *str;
struct cut_out_stream *data;
if (src == NULL || stream == NULL) {
return ISO_NULL_POINTER;
}
if (size == 0) {
return ISO_WRONG_ARG_VALUE;
}
r = iso_file_source_stat(src, &info);
if (r < 0) {
return r;
}
if (!S_ISREG(info.st_mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (offset > info.st_size) {
return ISO_FILE_OFFSET_TOO_BIG;
}
/* 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(struct cut_out_stream));
if (data == NULL) {
free(str);
return ISO_OUT_OF_MEM;
}
/* take a new ref to IsoFileSource */
data->src = src;
iso_file_source_ref(src);
data->offset = offset;
data->size = MIN(info.st_size - offset, size);
/* get the id numbers */
data->dev_id = (dev_t) 0;
data->ino_id = cut_out_serial_id++;
str->refcount = 1;
str->data = data;
str->class = &cut_out_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");
}
}

Some files were not shown because too many files have changed in this diff Show More