Compare commits

...

38 Commits

Author SHA1 Message Date
Thomas Schmitt c6136416c3 Marked libisofs SVN copy as outdated (use bzr on lp) 2010-02-08 11:10:47 +00:00
Mario Danic de3cf8e385 Moved libisofs trunk to attic, due to libisofs-ng 2008-02-02 18:56:45 +00:00
Vreixo Formoso Lopes 3028015ab8 Add setter and getters for atime and ctime on tree_node. 2007-10-22 09:30:43 +00:00
Vreixo Formoso Lopes 7b9834a315 Added getter and setter for mtime on tree_node. 2007-10-22 08:44:33 +00:00
Vreixo Formoso Lopes 63f2cfd673 Add get_size() method to tree_node. 2007-10-22 08:39:22 +00:00
Vreixo Formoso Lopes 2b92fbc31a Guard against a message retrieval before library initialization. 2007-10-19 07:36:14 +00:00
Vreixo Formoso Lopes b9c4f7ad1d Added iso_volset_ref(). 2007-10-18 07:32:37 +00:00
Vreixo Formoso Lopes 485607ce7b Fix bug in mangle_all. 2007-10-08 16:07:10 +00:00
Vreixo Formoso Lopes 08c53aa997 Return 0 on EOF in burn_source. 2007-10-08 07:57:23 +00:00
Vreixo Formoso Lopes 0224ad402d Some fixes in burn_source implementation 2007-10-03 16:32:09 +00:00
Vreixo Formoso Lopes 6546f1a197 Change burn_source implementation to fit libburn requirements. 2007-10-02 16:47:19 +00:00
Vreixo Formoso Lopes f4ad1c630b Add a set_size function to burn_source to fix sigsegv. 2007-10-02 07:16:50 +00:00
Thomas Schmitt b1966abe45 Removed apostrophes which my compiler does not like 2007-09-28 16:04:09 +00:00
Vreixo Formoso Lopes f5e31470bd Some new taks added to TODO file 2007-09-26 11:44:48 +00:00
Vreixo Formoso Lopes f811234b8f Migration to iso_file_src in file writing function. 2007-09-26 07:47:45 +00:00
Vreixo Formoso Lopes 8de9d35873 Add iso_file_src default implementation.
This will be the base class for file content writting, with support for 
on-the-file file modification, useful for things like compression or 
encryption.
2007-09-25 10:17:29 +00:00
Vreixo Formoso Lopes ead523ff27 update makefile to propertly deal with new file names. 2007-09-24 11:54:43 +00:00
Vreixo Formoso Lopes 0071d733fd Rename libdax_* message system to libiso_* 2007-09-24 11:53:22 +00:00
Mario Danic 9639d45b35 Updated doxygen.conf.in 2007-09-14 09:02:21 +00:00
Mario Danic 370fac83c1 Added licence reminder to TODO 2007-09-14 04:30:12 +00:00
Mario Danic d41a020cea Minor cleanup of authors file 2007-09-14 04:28:06 +00:00
Mario Danic 33ad67ee2c Added general tasks to TODO 2007-09-14 04:25:46 +00:00
Mario Danic 2629a25d4e Made minor changes to libisofs iso.c 2007-09-14 04:03:42 +00:00
Vreixo Formoso Lopes 5c82fc5108 Add -V option to test/iso.c little testing app. 2007-09-06 15:15:09 +00:00
Mario Danic d60193e2d5 Implemented support for eltorito on MS discs 2007-09-01 20:35:53 +00:00
Mario Danic 0746d622e4 Provide better support for overwriteable media 2007-08-30 21:55:36 +00:00
Mario Danic 139fb6496c Finally commited the patch :P 2007-08-28 10:29:55 +00:00
Mario Danic df04ee014e Done major changes to libisofs, including multisession and reading support 2007-08-27 22:51:48 +00:00
Mario Danic a4e0041128 Done some changes to configure.ac 2007-08-10 20:37:25 +00:00
Mario Danic a28e699d9b Fixed build system of libburn and libisofs in respect to .pc files 2007-08-10 11:41:18 +00:00
Mario Danic 4354e9598d Temporary usage of libburn readme 2007-08-10 09:55:17 +00:00
Mario Danic 0fece11399 Corrected pc-in file according to our sonumber 2007-08-10 09:45:55 +00:00
Mario Danic 170dfe21bf Added tests as part of MS patch 2007-08-10 09:37:39 +00:00
Mario Danic 3ea44305b4 Removed bindings, removed svn:executable properties 2007-08-10 09:37:16 +00:00
Mario Danic 1b7fec7751 Added files - part of MS patch 2007-08-10 09:36:34 +00:00
Mario Danic 0b1a9c5565 Implemented numeber of multisession options, reading, modifying tree, and a number of improvements 2007-08-10 09:35:10 +00:00
Mario Danic 2e073c258c Fixed relaxed constraints patch 2007-08-10 09:30:26 +00:00
Mario Danic b7573134cb Fixed broken SUSP handling 2007-08-02 19:10:08 +00:00
62 changed files with 8330 additions and 877 deletions

View File

@ -1,4 +1,2 @@
Developers:
Mario Danic

View File

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

View File

@ -32,8 +32,19 @@ libisofs_libisofs_la_SOURCES = \
libisofs/hash.c \
libisofs/file.h \
libisofs/file.c \
libisofs/file_src.h \
libisofs/file_src.c \
libisofs/eltorito.h \
libisofs/eltorito.c
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.c \
libisofs/messages.h \
libisofs/messages.c
libinclude_HEADERS = \
libisofs/libisofs.h
@ -42,12 +53,32 @@ libinclude_HEADERS = \
## Build test applications
noinst_PROGRAMS = \
test/iso
test/iso \
test/isoread \
test/isoms \
test/isoadd \
test/isogrow
test_iso_CPPFLAGS = -Ilibisofs
test_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_iso_SOURCES = test/iso.c
test_isoread_CPPFLAGS = -Ilibisofs
test_isoread_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoread_SOURCES = test/iso_read.c
test_isoms_CPPFLAGS = -Ilibisofs
test_isoms_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoms_SOURCES = test/iso_ms.c
test_isoadd_CPPFLAGS = -Ilibisofs
test_isoadd_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_isoadd_SOURCES = test/iso_add.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
check_PROGRAMS = \
@ -64,6 +95,8 @@ test_test_SOURCES = \
test/test_file_hashtable.c \
test/test_util.c \
test/test_volume.c \
test/test_data_source.c \
test/test_read.c \
test/test.c
## ========================================================================= ##
@ -116,10 +149,10 @@ indent: $(indent_files)
# Extra things
nodist_pkgconfig_DATA = \
libisofs-1.pc
libisofs-5.pc
EXTRA_DIST = \
libisofs-1.pc.in \
libisofs-5.pc.in \
version.h.in \
doc/comments \
doc/doxygen.conf.in \

77
README
View File

@ -1,25 +1,25 @@
------------------------------------------------------------------------------
libburnia.pykix.org
libburnia-project.org
------------------------------------------------------------------------------
This all is under GPL.
(See GPL reference, our clarification and commitment at the end of this text)
------------------------------------------------------------------------------
libburnia.pykix.org
libburnia-project.org
By Mario Danic <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
Copyright (C) 2006 Mario Danic, Thomas Schmitt
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.pykix.org
copyright holders and then libburnia.pykix.org is to be their sole copyright.
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.pykix.org toplevel README (C) 2006 Thomas Schmitt
This libburnia-project.org toplevel README (C) 2006-2007 Thomas Schmitt
------------------------------------------------------------------------------
Build and Installation
@ -27,16 +27,16 @@ This libburnia.pykix.org toplevel README (C) 2006 Thomas Schmitt
Our build system is based on autotools. For preparing the build of a SVN
snapshot you will need autotools of at least version 1.7.
Check out from SVN by
svn co http://libburnia-svn.pykix.org/libburn/trunk libburn_pykix
go into directory libburn_pykix and apply autotools by
svn co http://svn.libburnia-project.org/libburn/trunk libburn
go into directory libburn and apply autotools by
./bootstrap
Alternatively you may unpack a release tarball for which you do not need
autotools installed.
To build a libburnia.pykix.org subproject it should be sufficient to go
into its toplevel directory (here: "libburn_pykix") and execute
./configure
To build a libburnia-project.org subproject it should be sufficient to go
into its toplevel directory (here: "libburn") and execute
./configure --prefix=/usr
make
To make the libraries accessible for running resp. developing applications
@ -44,17 +44,18 @@ To make the libraries accessible for running resp. developing applications
The other half of the project, libisofs, is hosted in the libburnia SVN, too:
svn co http://libburnia-svn.pykix.org/libisofs/trunk libisofs_pykix
svn co http://svn.libburnia-project.org/libisofs/trunk libisofs
See README file there.
------------------------------------------------------------------------------
Overview of libburnia.pykix.org
Overview of libburnia-project.org
libburnia.pykix.org is an open-source software project for reading, mastering
and writing optical discs. For now this means only CD-R and CD-RW.
libburnia-project.org is an open-source software project for reading, mastering
and writing optical discs.
For now this means only CD media and all single layer DVD media except DVD+R.
The project comprises of several more or less interdependent parts which
together strive to be a usable foundation for application development.
@ -66,10 +67,10 @@ 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
We have a workable code base for burning CD and most single layer DVD.
The burn API is quite comprehensively documented and can be used to build a
presentable application.
We have a functional binary which emulates parts of cdrecord in order to
prove that usability, and in order to allow you to explore libburnia's scope
by help of existing cdrecord frontends.
@ -78,20 +79,25 @@ 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.
libburn is the foundation of our cdrecord emulation. Its code is
independent of cdrecord. Its DVD capabilities are learned from
studying the code of dvd+rw-tools and MMC-5 specs. No code but only
the pure SCSI knowledge has been taken from dvd+rw-tools, though.
- libisofs is the library to pack up hard disk files and directories into a
ISO 9660 disk image. This may then be brought to CD via libburn.
ISO 9660 disk image. This may then be brought to media via libburn.
libisofs is to be the foundation of our upcoming mkisofs emulation.
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
Cdrecord is a powerful GPL'ed burn program included in Joerg
Schilling's cdrtools. cdrskin strives to be a second source for
the services traditionally provided by cdrecord.
the services traditionally provided by cdrecord. Additionally it
provides libburn's DVD capabilities, where only -sao is compatible
with cdrecord.
cdrskin does not contain any bytes copied from cdrecord's sources.
Many bytes have been copied from the message output of cdrecord
runs, though.
See cdrskin/README for more.
See cdrskin/README and man cdrskin/cdrskin.1 for more.
- test is a collection of application gestures and examples given by the
authors of the library features. The main API example for libburn
@ -121,7 +127,7 @@ Project history as far as known to me:
It has meanwhile moved to use vanilla libburn.pykix.org , though.
Version 0.1.4 constitutes the first release of this kind.
- In Juli 2006 our team mate Mario Danic announced a revival of libburn
- In July 2006 our team mate Mario Danic announced a revival of libburn
which by about nearly everybody else was perceived as unfriendly fork.
Derek Foreman four days later posted a message which expressed his
discontent.
@ -178,13 +184,32 @@ Project history as far as known to me:
libburn, is now called libburnia. For the origin of this name, see
http://en.wikipedia.org/wiki/Liburnians .
- 16th January 2007 release of libburn-0.3.0 and cdrskin-0.3.0 . Now the scope
is widened to a first class of DVD media: overwriteable single layer types
DVD-RAM, DVD+RW, DVD-RW. This is not a cdrecord emulation but rather inspired
by dvd+rw-tools' "poor man" writing facility for this class of media.
Taking a bow towards Andy Polyakov.
- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
multi-session and with DAO.
- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
yet.
- 23th April 2007 version 0.3.6 follows the unanimous opinion of Linux kernel
people that one should not use /dev/sg on kernel 2.6.
- 31st July 2007 version 0.3.8 marks the first anniversary of libburn revival.
We look back on improved stability, a substantially extended list of media
and write modes, and better protection against typical user mishaps.
------------------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
the Free Software Foundation. To be exact: version 2 of that License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of

47
TODO
View File

@ -1,3 +1,10 @@
GENERAL
=======
Improve documentation
Build system improvements
Clarify licencing (GPL2 only (!) with exception)
FEATURES
========
@ -5,25 +12,53 @@ FEATURES
Support for multiple images
HFS/HFS+
CD reading
Multisession
[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
ISO relaxed contraints
[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
=====
[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!!
Error message queue
Public API for all things already implemented
[ok] Error message queue
Better charset support
default input charset to locale one, no always UTF-8
[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
RR Continuation Areas can't be in Directory Record block
[ok] Fix mangle names when iso relaxed constraints

View File

@ -1,17 +0,0 @@
libisofs python bindings
========================
The Python bindings are layered on two levels. The low-level 1:1 mapping of
the C API is done through ctypes. The higher level bindings build a
pythonic API on that mapping.
The low-level API is in isofs.core. That file is autogenerated using
pyglet's ctypes code generator, which can be found at:
http://pyglet.googlecode.com/svn/trunk/tools/wraptypes/
Note that this is not a permanent solution. Right now the generated code
is committed to the repository, to facilitate development. In the longer
term, the wraptypes tool should be added to the libburnia repository and
the core binding generated by the build system.

View File

@ -1,2 +0,0 @@
from defines import *
from isofs import IsoFS

View File

@ -1,185 +0,0 @@
'''Wrapper for isofs
Generated with:
../wraptypes/wrap.py -ocore.py -lisofs ../../../libisofs/libisofs.h
Do not modify this file.
'''
__docformat__ = 'restructuredtext'
__version__ = '$Id: wrap.py 738 2007-03-12 04:53:42Z Alex.Holkner $'
import ctypes
from ctypes import *
from ctypes.util import find_library as _find_library
#_libpath = _find_library('isofs')
#if not _libpath:
# raise ImportError('Could not locate isofs library')
# If you are a developer, comment the above three lines and uncomment
# the following line, to hardcode the library path.
_libpath = 'libisofs.so'
_lib = cdll.LoadLibrary(_libpath)
_int_types = (c_int16, c_int32)
if hasattr(ctypes, 'c_int64'):
# Some builds of ctypes apparently do not have c_int64
# defined; it's a pretty good bet that these builds do not
# have 64-bit pointers.
_int_types += (ctypes.c_int64,)
for t in _int_types:
if sizeof(t) == sizeof(c_size_t):
c_ptrdiff_t = t
class c_void(Structure):
# c_void_p is a buggy return type, converting to int, so
# POINTER(None) == c_void_p is actually written as
# POINTER(c_void), so it can be treated as a real pointer.
_fields_ = [('dummy', c_int)]
class struct_iso_volume(Structure):
__slots__ = [
]
struct_iso_volume._fields_ = [
('_opaque_struct', c_int)
]
class struct_iso_tree_node(Structure):
__slots__ = [
]
struct_iso_tree_node._fields_ = [
('_opaque_struct', c_int)
]
class struct_iso_volset(Structure):
__slots__ = [
]
struct_iso_volset._fields_ = [
('_opaque_struct', c_int)
]
class struct_burn_source(Structure):
__slots__ = [
]
struct_burn_source._fields_ = [
('_opaque_struct', c_int)
]
# ../../../libisofs/libisofs.h:45
iso_volume_new = _lib.iso_volume_new
iso_volume_new.restype = POINTER(struct_iso_volume)
iso_volume_new.argtypes = [c_char_p, c_char_p, c_char_p]
# ../../../libisofs/libisofs.h:49
iso_volume_new_with_root = _lib.iso_volume_new_with_root
iso_volume_new_with_root.restype = POINTER(struct_iso_volume)
iso_volume_new_with_root.argtypes = [c_char_p, c_char_p, c_char_p, POINTER(struct_iso_tree_node)]
# ../../../libisofs/libisofs.h:57
iso_volume_free = _lib.iso_volume_free
iso_volume_free.restype = None
iso_volume_free.argtypes = [POINTER(struct_iso_volume)]
# ../../../libisofs/libisofs.h:62
iso_volset_free = _lib.iso_volset_free
iso_volset_free.restype = None
iso_volset_free.argtypes = [POINTER(struct_iso_volset)]
# ../../../libisofs/libisofs.h:67
iso_volume_get_root = _lib.iso_volume_get_root
iso_volume_get_root.restype = POINTER(struct_iso_tree_node)
iso_volume_get_root.argtypes = [POINTER(struct_iso_volume)]
# ../../../libisofs/libisofs.h:72
iso_volume_set_volume_id = _lib.iso_volume_set_volume_id
iso_volume_set_volume_id.restype = None
iso_volume_set_volume_id.argtypes = [POINTER(struct_iso_volume), c_char_p]
# ../../../libisofs/libisofs.h:78
iso_volume_set_publisher_id = _lib.iso_volume_set_publisher_id
iso_volume_set_publisher_id.restype = None
iso_volume_set_publisher_id.argtypes = [POINTER(struct_iso_volume), c_char_p]
# ../../../libisofs/libisofs.h:84
iso_volume_set_data_preparer_id = _lib.iso_volume_set_data_preparer_id
iso_volume_set_data_preparer_id.restype = None
iso_volume_set_data_preparer_id.argtypes = [POINTER(struct_iso_volume), c_char_p]
# ../../../libisofs/libisofs.h:96
iso_tree_volume_path_to_node = _lib.iso_tree_volume_path_to_node
iso_tree_volume_path_to_node.restype = POINTER(struct_iso_tree_node)
iso_tree_volume_path_to_node.argtypes = [POINTER(struct_iso_volume), c_char_p]
# ../../../libisofs/libisofs.h:107
iso_tree_volume_add_path = _lib.iso_tree_volume_add_path
iso_tree_volume_add_path.restype = POINTER(struct_iso_tree_node)
iso_tree_volume_add_path.argtypes = [POINTER(struct_iso_volume), c_char_p, c_char_p]
# ../../../libisofs/libisofs.h:119
iso_tree_volume_add_new_dir = _lib.iso_tree_volume_add_new_dir
iso_tree_volume_add_new_dir.restype = POINTER(struct_iso_tree_node)
iso_tree_volume_add_new_dir.argtypes = [POINTER(struct_iso_volume), c_char_p]
# ../../../libisofs/libisofs.h:128
iso_volset_new = _lib.iso_volset_new
iso_volset_new.restype = POINTER(struct_iso_volset)
iso_volset_new.argtypes = [POINTER(struct_iso_volume), c_char_p]
# ../../../libisofs/libisofs.h:141
iso_tree_add_node = _lib.iso_tree_add_node
iso_tree_add_node.restype = POINTER(struct_iso_tree_node)
iso_tree_add_node.argtypes = [POINTER(struct_iso_tree_node), c_char_p]
# ../../../libisofs/libisofs.h:157
iso_tree_radd_dir = _lib.iso_tree_radd_dir
iso_tree_radd_dir.restype = POINTER(struct_iso_tree_node)
iso_tree_radd_dir.argtypes = [POINTER(struct_iso_tree_node), c_char_p]
# ../../../libisofs/libisofs.h:166
iso_exclude_add_path = _lib.iso_exclude_add_path
iso_exclude_add_path.restype = None
iso_exclude_add_path.argtypes = [c_char_p]
# ../../../libisofs/libisofs.h:173
iso_exclude_remove_path = _lib.iso_exclude_remove_path
iso_exclude_remove_path.restype = None
iso_exclude_remove_path.argtypes = [c_char_p]
# ../../../libisofs/libisofs.h:178
iso_exclude_empty = _lib.iso_exclude_empty
iso_exclude_empty.restype = None
iso_exclude_empty.argtypes = []
# ../../../libisofs/libisofs.h:191
iso_tree_add_new_dir = _lib.iso_tree_add_new_dir
iso_tree_add_new_dir.restype = POINTER(struct_iso_tree_node)
iso_tree_add_new_dir.argtypes = [POINTER(struct_iso_tree_node), c_char_p]
# ../../../libisofs/libisofs.h:197
iso_tree_node_set_name = _lib.iso_tree_node_set_name
iso_tree_node_set_name.restype = None
iso_tree_node_set_name.argtypes = [POINTER(struct_iso_tree_node), c_char_p]
# ../../../libisofs/libisofs.h:204
iso_tree_print = _lib.iso_tree_print
iso_tree_print.restype = None
iso_tree_print.argtypes = [POINTER(struct_iso_tree_node), c_int]
# ../../../libisofs/libisofs.h:220
iso_source_new_ecma119 = _lib.iso_source_new_ecma119
iso_source_new_ecma119.restype = POINTER(struct_burn_source)
iso_source_new_ecma119.argtypes = [POINTER(struct_iso_volset), c_int, c_int, c_int]
__all__ = ['iso_volume_new', 'iso_volume_new_with_root', 'iso_volume_free',
'iso_volset_free', 'iso_volume_get_root', 'iso_volume_set_volume_id',
'iso_volume_set_publisher_id', 'iso_volume_set_data_preparer_id',
'iso_tree_volume_path_to_node', 'iso_tree_volume_add_path',
'iso_tree_volume_add_new_dir', 'iso_volset_new', 'iso_tree_add_node',
'iso_tree_radd_dir', 'iso_exclude_add_path', 'iso_exclude_remove_path',
'iso_exclude_empty', 'iso_tree_add_new_dir', 'iso_tree_node_set_name',
'iso_tree_print', 'iso_source_new_ecma119']

View File

@ -1,9 +0,0 @@
# The automatic code generator does not wrap enums into python. As
# isofs has only two enum values publicly defined, they are hardcoded
# here.
# from enum ecma119_extension_flag
ECMA119_ROCKRIDGE = 1
ECMA119_JOLIET = 2
__all__ = ['ECMA119_ROCKRIDGE', 'ECMA119_JOLIET']

View File

@ -1,58 +0,0 @@
# High level interface to the isofs library.
import core
import defines
import os.path
def _wrap_volume_property(var_name, core_setter):
def get(self):
return getattr(self, var_name)
def set(self, value):
setattr(self, var_name, value)
core_setter(self._volume, value)
return property(get, set)
class IsoFS(object):
def __init__(self, volume_id='', publisher_id='',
data_preparer_id=''):
self._volume_id = volume_id
self._publisher_id = publisher_id
self._data_preparer_id = data_preparer_id
self._volume = core.iso_volume_new(
volume_id, publisher_id, data_preparer_id)
self._volset = core.iso_volset_new(self._volume, volume_id)
def __del__(self):
core.iso_volume_free(self._volume)
core.iso_volset_free(self._volset)
volume_id = _wrap_volume_property(
'_volume_id', core.iso_volume_set_volume_id)
publisher_id = _wrap_volume_property(
'_publisher_id', core.iso_volume_set_publisher_id)
data_preparer_id = _wrap_volume_property(
'_data_preparer_id', core.iso_volume_set_data_preparer_id)
def add(self, disc_path, path, exclude=None): #, make_parents=False):
disc_path = os.path.normpath(disc_path)
path = os.path.abspath(os.path.normpath(path))
exclude = exclude or []
# Does the disc parent exist?
disc_parent, _ = os.path.split(disc_path)
if not core.iso_tree_volume_path_to_node(self._volume, disc_parent):
print "No such parent"
return # TODO: Raise exception and/or create all missing
# parents.
# Flush all ignores that may have stayed over.
core.iso_exclude_empty()
for exclude_path in exclude:
core.iso_exclude_add_path(exclude_path)
core.iso_tree_volume_add_path(self._volume, disc_path, path)
def display(self):
root = core.iso_volume_get_root(self._volume)
core.iso_tree_print(root, 0)

View File

@ -1,4 +1,4 @@
AC_INIT([libisofs], [0.2.4], [http://libburnia.pykix.org])
AC_INIT([libisofs], [0.2.9], [http://libburnia-project.org])
AC_PREREQ([2.50])
dnl AC_CONFIG_HEADER([config.h])
@ -112,6 +112,6 @@ AC_CONFIG_FILES([
Makefile
doc/doxygen.conf
version.h
libisofs-1.pc
libisofs-5.pc
])
AC_OUTPUT

File diff suppressed because it is too large Load Diff

0
libisofs/Makefile Executable file → Normal file
View File

107
libisofs/data_source.c Normal file
View File

@ -0,0 +1,107 @@
/*
* Contains a simple implementation of a data source that reads from a
* given file.
*/
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "libisofs.h"
#define BLOCK_SIZE 2048
#define BLOCK_OUT_OF_FILE -1;
#define READ_ERROR -2;
#define SEEK_ERROR -3;
struct file_data_src {
int fd;
int nblocks;
};
static int
ds_read_block(struct data_source *src, int lba, unsigned char *buffer)
{
struct file_data_src *data;
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)
{
if (--src->refcount == 0) {
src->free_data(src);
free(src);
}
}

248
libisofs/ecma119.c Executable file → Normal file
View File

@ -7,6 +7,9 @@
#include <time.h>
#include <assert.h>
#include <err.h>
#include <locale.h>
#include <langinfo.h>
#include <limits.h>
#include "ecma119.h"
#include "ecma119_tree.h"
@ -17,9 +20,11 @@
#include "tree.h"
#include "util.h"
#include "file.h"
#include "file_src.h"
#include "libisofs.h"
#include "libburn/libburn.h"
#include "eltorito.h"
#include "messages.h"
/* burn-source compatible stuff */
static int
@ -180,15 +185,9 @@ calc_dir_size(struct ecma119_write_target *t,
for (i = 0; i < dir->info.dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->info.dir.children[i];
//struct iso_tree_node *iso = ch->iso_self;
if (ch->type == ECMA119_DIR) {
calc_dir_size(t, ch);
}
// else if (iso && iso->attrib.st_size
// && iso->loc.type == LIBISO_FILESYS
// && iso->loc.path) {
// t->filelist_len++;
// }
}
}
}
@ -227,12 +226,11 @@ cmp_file(const void *f1, const void *f2)
* Fill out the block field for each file and fill out t->filelist.
*/
static void
calc_file_pos(struct ecma119_write_target *t,
struct ecma119_tree_node *dir)
calc_file_pos(struct ecma119_write_target *t)
{
size_t i;
assert(dir->type == ECMA119_DIR);
assert(t);
t->filelist = calloc(1, sizeof(struct iso_file *) * t->file_table->count);
@ -246,7 +244,14 @@ calc_file_pos(struct ecma119_write_target *t,
do {
struct iso_file *file = node->file;
if (file->size)
/*
* We only need to write the file when.
* a) The size is greater than 0.
* b) The file is new (not from a previous image) or we
* are writting an image not for ms (i.e., we are modifying an
* image).
*/
if ( file->size && (!file->prev_img || !t->ms_block) )
t->filelist[t->curfile++] = file;
node = node->next;
} while (node);
@ -280,7 +285,7 @@ calc_file_pos(struct ecma119_write_target *t,
*/
static struct ecma119_write_target*
ecma119_target_new(struct iso_volset *volset,
const struct ecma119_source_opts *opts)
struct ecma119_source_opts *opts)
{
struct ecma119_write_target *t =
calloc(1, sizeof(struct ecma119_write_target));
@ -303,10 +308,18 @@ ecma119_target_new(struct iso_volset *volset,
t->gid = opts->gid;
t->uid = opts->uid;
//TODO get defailt values for current locale, no UTF-8
t->input_charset = opts->input_charset ? opts->input_charset : "UTF-8";
if (opts->input_charset) {
t->input_charset = opts->input_charset;
} else {
/* default to locale charset */
setlocale(LC_CTYPE, "");
t->input_charset = nl_langinfo(CODESET);
}
t->ouput_charset = opts->ouput_charset ? opts->ouput_charset : "UTF-8";
t->sort_files = opts->sort_files;
t->ms_block = opts->ms_block;
t->src = opts->src;
t->file_table = iso_file_table_new(t->cache_inodes);
volset->refcount++;
@ -319,7 +332,17 @@ ecma119_target_new(struct iso_volset *volset,
t->catalog = volset->volume[opts->volnum]->bootcat;
t->eltorito = t->catalog ? 1 : 0;
t->write_eltorito = opts->copy_eltorito;
if (t->eltorito && (!t->ms_block || !t->catalog->proc) ) {
/*
* For new and modified images we always need to write el-torito.
* For ms images, if the boot catalog was newly added, we also need
* to write it!
*/
t->write_eltorito = 1;
}
/* create the trees */
t->root = ecma119_tree_create(t, iso_root);
if (t->joliet)
t->joliet_root = joliet_tree_create(t, iso_root);
@ -356,9 +379,10 @@ ecma119_target_new(struct iso_volset *volset,
}
}
t->curblock = 16 /* system area */
+ 1 /* volume desc */
+ 1; /* volume desc terminator */
t->curblock = t->ms_block /* nwa for ms, usually 0 */
+ 16 /* system area */
+ 1 /* primary volume desc */
+ 1; /* volume desc terminator */
if (t->eltorito)
t->curblock += 1; /* boot record volume descriptor */
@ -391,29 +415,71 @@ ecma119_target_new(struct iso_volset *volset,
/* el-torito? */
if (t->eltorito) {
/* add catalog block */
t->catalog->file->block = t->curblock;
t->curblock += div_up(2048, t->block_size);
el_torito_get_image_files(t);
if (t->write_eltorito) {
/* add catalog block */
t->catblock = t->curblock;
t->curblock += div_up(2048, t->block_size);
/* add img block */
t->imgblock = t->curblock;
t->curblock += div_up(t->catalog->image->node->node.attrib.st_size,
t->block_size);
} else {
assert(t->ms_block);
assert(t->catalog->proc);
t->catblock = t->catalog->node->loc.block;
t->imgblock = t->catalog->image->node->loc.block;
}
}
calc_file_pos(t, t->root);
if (t->eltorito)
el_torito_patch_image_files(t);
calc_file_pos(t);
if (t->rockridge) {
susp_finalize(t, t->root);
rrip_finalize(t, t->root);
}
t->total_size = t->curblock * t->block_size;
t->vol_space_size = t->curblock;
t->total_size = (t->curblock - t->ms_block) * t->block_size;
if (opts->overwrite) {
/*
* Get a copy of the volume descriptors to be written in a DVD+RW
* disc
*/
uint8_t *buf;
/* skip the first 16 blocks (system area) */
buf = opts->overwrite + 16 * t->block_size;
/*
* In the PVM to be written in the 16th sector of the disc, we
* need to specify the full size.
*/
t->vol_space_size = t->curblock;
write_pri_vol_desc(t, buf);
buf += t->block_size;
if (t->joliet) {
joliet_write_sup_vol_desc(t, buf);
buf += t->block_size;
}
if (t->eltorito) {
el_torito_write_boot_vol_desc(t, buf);
buf += t->block_size;
}
write_vol_desc_terminator(t, buf);
}
/*
* The volume space size is just the size of the last session, in
* case of ms images.
*/
t->vol_space_size = t->curblock - t->ms_block;
/* prepare for writing */
t->curblock = 0;
t->state = ECMA119_WRITE_SYSTEM_AREA;
t->bytes_read = 2048;
return t;
}
@ -437,12 +503,15 @@ is_eltorito_state(enum ecma119_write_state state)
static void
next_state(struct ecma119_write_target *t)
{
char msg[42];
t->state++;
while ( (!t->joliet && is_joliet_state(t->state))
||(!t->eltorito && is_eltorito_state(t->state)) )
||(!t->eltorito && is_eltorito_state(t->state))
||(!t->write_eltorito && t->state == ECMA119_WRITE_ELTORITO_CATALOG) )
t->state++;
printf ("now in state %d, curblock=%d\n", (int)t->state, (int)t->curblock);
sprintf(msg, "Now in state %d, curblock=%d.", t->state, t->curblock);
iso_msg_debug(msg);
}
static void
@ -486,31 +555,33 @@ wr_dir_records(struct ecma119_write_target *t, uint8_t *buf)
static void
wr_files(struct ecma119_write_target *t, uint8_t *buf)
{
int res;
struct state_files *f_st = &t->state_files;
size_t nread;
struct iso_file *f = t->filelist[f_st->file];
const char *path = f->path;
if (!f_st->fd) {
printf("Writing file %s\n", path);
f_st->data_len = f->size;
f_st->fd = fopen(path, "r");
if (!f_st->fd)
err(1, "couldn't open %s for reading", path);
assert(t->curblock == f->block);
if (!f_st->src) {
if (!f->prev_img) {
char msg[PATH_MAX + 14];
sprintf(msg, "Writing file %s", f->path);
iso_msg_debug(msg);
}
f_st->src = f->src;
if ( f->src->open(f->src) <= 0) {
//FIXME instead of exit, just print a msg error and
//skip file (what about reading from /dev/zero? instead)
/* can only happen with new files */
err(1, "couldn't open %s for reading", f->path);
}
assert(t->curblock + t->ms_block == f->block);
}
nread = fread(buf, 1, t->block_size, f_st->fd);
f_st->pos += t->block_size;
if (nread < 0)
warn("problem reading from %s", path);
else if (nread != t->block_size && f_st->pos < f_st->data_len)
warnx("incomplete read from %s", path);
if (f_st->pos >= f_st->data_len) {
fclose(f_st->fd);
f_st->fd = 0;
f_st->pos = 0;
res = f_st->src->read_block(f_st->src, buf);
if (res == 0) {
/* we have read the expected bytes from file */
f_st->src->close(f_st->src);
f_st->src = NULL;
f_st->file++;
if (f_st->file >= t->filelist_len)
next_state(t);
@ -657,6 +728,16 @@ write_one_dir_record(struct ecma119_write_target *t,
} else if (node->type == ECMA119_FILE) {
len = node->info.file->size;
block = node->info.file->block;
} else if (node->type == ECMA119_BOOT) {
assert(t->eltorito);
if (node->info.boot_img) {
block = t->imgblock;
len = t->catalog->image->node->node.attrib.st_size;
} else {
/* we always assume 2048 as catalog len */
block = t->catblock;
len = 2048;
}
} else {
/* for nodes other than files and dirs, we set both len and block to 0 */
len = 0;
@ -783,22 +864,57 @@ write_data_chunk(struct ecma119_write_target *t, uint8_t *buf)
}
static int
bs_read(struct burn_source *bs, unsigned char *buf, int size)
bs_read_block(struct burn_source *bs)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
if (size != t->block_size) {
warnx("you must read data in block-sized chunks (%d bytes)",
(int)t->block_size);
return 0;
} else if (t->curblock >= t->vol_space_size) {
if (t->curblock >= t->vol_space_size) {
/* total_size could be setted by libburn */
if ( t->curblock < (t->total_size / (off_t) t->block_size) ) {
/* we pad the image */
memset(t->buffer, 0, t->block_size);
t->curblock++;
return t->block_size;
}
return 0;
}
if (t->state_data_valid)
write_data_chunk(t, buf);
write_data_chunk(t, t->buffer);
else
writers[t->state](t, buf);
writers[t->state](t, t->buffer);
t->curblock++;
return size;
return t->block_size;
}
static int
bs_read(struct burn_source *bs, unsigned char *buf, int size)
{
int ret = 0,summed_ret = 0;
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
/* make safe against partial buffer returns */
while (1) {
if (t->bytes_read == 2048) {
/* we need to read next block */
t->bytes_read = 0;
ret = bs_read_block(bs);
if (ret <= 0)
return ret;
}
int bytes_to_read = 2048 - t->bytes_read;
if (summed_ret + bytes_to_read > size) {
bytes_to_read = size - summed_ret;
}
memcpy(buf + summed_ret, t->buffer, bytes_to_read);
t->bytes_read += bytes_to_read;
summed_ret += bytes_to_read;
if (summed_ret >= size)
break;
}
return summed_ret;
}
static off_t
@ -823,10 +939,19 @@ bs_free_data(struct burn_source *bs)
free(t->state_data);
if (t->joliet)
joliet_tree_free(t->joliet_root);
if (t->state_files.fd)
fclose(t->state_files.fd);
// TODO is this needed?
if (t->state_files.src)
t->state_files.src->close(t->state_files.src);
}
int bs_set_size(struct burn_source *bs, off_t size)
{
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
t->total_size = size;
return 1;
}
struct burn_source *iso_source_new_ecma119(struct iso_volset *volset,
struct ecma119_source_opts *opts)
{
@ -834,6 +959,7 @@ struct burn_source *iso_source_new_ecma119(struct iso_volset *volset,
ret->refcount = 1;
ret->read = bs_read;
ret->get_size = bs_get_size;
ret->set_size = bs_set_size;
ret->free_data = bs_free_data;
ret->data = ecma119_target_new(volset, opts);
return ret;

30
libisofs/ecma119.h Executable file → Normal file
View File

@ -65,9 +65,22 @@ struct ecma119_write_target
unsigned int iso_level:2;
unsigned int eltorito:1;
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
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
*
@ -98,6 +111,9 @@ struct ecma119_write_target
*/
ino_t ino;
uint32_t ms_block; /**< if != 0, nwa for multisession */
struct data_source* src;
int curblock;
uint16_t block_size;
uint32_t path_table_size;
@ -158,16 +174,14 @@ struct ecma119_write_target
/* for writing out files */
struct state_files {
off_t pos; /* The number of bytes we have written
* so far in the current file.
*/
off_t data_len;/* The number of bytes in the currently
* open file.
*/
FILE *fd; /* The currently open file. */
struct iso_file_src *src; /* source for reading from the file */
int file; /* The index in filelist that we are
* currently writing (or about to write). */
} state_files;
/* temp buffer for read functions */
uint8_t buffer[2048];
int bytes_read;
};
#define BP(a,b) [(b) - (a) + 1]

888
libisofs/ecma119_read.c Normal file
View File

@ -0,0 +1,888 @@
/*
* 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;
}

76
libisofs/ecma119_read.h Normal file
View File

@ -0,0 +1,76 @@
/*
* 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_*/

316
libisofs/ecma119_read_rr.c Normal file
View File

@ -0,0 +1,316 @@
/*
* 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);
}

144
libisofs/ecma119_read_rr.h Normal file
View File

@ -0,0 +1,144 @@
/*
* 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_*/

View File

@ -183,7 +183,16 @@ create_file(struct ecma119_write_target *t,
* If the file is not already added to the disc, we add it now
* to the file table, and get a new inode number for it.
*/
file = iso_file_new(iso);
file = iso_file_new(t, iso);
if (!file) {
/*
* That was an error.
* TODO currently this cause the file to be ignored... Maybe
* throw an error is a better alternative
*/
ecma119_tree_free(ret);
return NULL;
}
iso_file_table_add_file(t->file_table, file);
file->ino = ++t->ino;
} else {
@ -251,10 +260,6 @@ create_symlink(struct ecma119_write_target *t,
assert(t && iso && parent && parent->type == ECMA119_DIR);
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
ret->iso_name = iso->node.name ? ((t->iso_level == 1) ?
iso_1_fileid(iso->node.name, t->input_charset)
: iso_2_fileid(iso->node.name, t->input_charset))
: NULL;
ret->type = ECMA119_SYMLINK;
ret->info.dest = iso->dest; /* TODO strdup? */
ret->attrib.st_nlink = 1;
@ -263,37 +268,29 @@ create_symlink(struct ecma119_write_target *t,
}
/**
* Create a new ECMA-119 node representing a boot catalog. This is like a
* regular file, but its contents are taken from a El-Torito boot catalog,
* and not from a file in the local filesystem.
* Create a new ECMA-119 node representing a boot catalog or image.
* This will be treated as a normal file when written the directory record,
* but its contents are written in a different way.
*
* See "El Torito" Bootable CD-ROM Format Specification Version 1.0 for
* more details.
*/
static struct ecma119_tree_node*
create_boot_catalog(struct ecma119_write_target *t,
create_boot(struct ecma119_write_target *t,
struct ecma119_tree_node *parent,
struct iso_tree_node_boot_catalog *iso)
struct iso_tree_node_boot *iso)
{
struct ecma119_tree_node *ret;
struct iso_file *file;
assert(t && iso && parent && parent->type == ECMA119_DIR);
/*
* This will simply create a ECMA119 file, with the only difference
* that the iso_file is not taken from table, but from boot catalog
*/
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
ret->type = ECMA119_FILE;
ret->type = ECMA119_BOOT;
file = iso->catalog->file;
file->ino = ++t->ino;
ret->info.boot_img = iso->img;
ret->attrib.st_nlink = file->nlink;
ret->attrib.st_ino = file->ino;
ret->info.file = file;
ret->attrib.st_nlink = 1;
ret->attrib.st_ino = ++t->ino;
return ret;
}
@ -338,9 +335,8 @@ create_tree(struct ecma119_write_target *t,
}
}
break;
case LIBISO_NODE_BOOTCATALOG:
ret = create_boot_catalog(t, parent,
(struct iso_tree_node_boot_catalog*)iso);
case LIBISO_NODE_BOOT:
ret = create_boot(t, parent, (struct iso_tree_node_boot*)iso);
break;
default:
/* should never happen */
@ -512,7 +508,7 @@ sort_tree(struct ecma119_tree_node *root)
* "HELLOTHE03.TXT"
*/
static void
mangle_name(char **name, int num_change, int level, int seq_num)
mangle_name(char **name, int num_change, int level, int relaxed, int seq_num)
{
char *dot = strrchr(*name, '.');
char *semi = strrchr(*name, ';');
@ -525,6 +521,24 @@ mangle_name(char **name, int num_change, int level, int seq_num)
return;
}
strncpy(base, *name, len+1);
if (relaxed & ECMA119_RELAXED_FILENAMES) {
/* relaxed filenames, don't care about extension */
int maxlen = (relaxed & (1<<1)) ? 37 : 31;
base[maxlen - num_change] = '\0';
baselen = strlen(base);
if (relaxed & ECMA119_OMIT_VERSION_NUMBERS) {
sprintf(fmt, "%%s%%0%1dd", num_change);
*name = realloc(*name, baselen + num_change + 1);
} else {
sprintf(fmt, "%%s%%0%1dd;1", num_change);
*name = realloc(*name, baselen + num_change + 3);
}
sprintf(*name, fmt, base, seq_num);
return;
}
if (dot) {
base[dot - *name] = '\0';
strncpy(ext, dot+1, len+1);
@ -537,14 +551,24 @@ mangle_name(char **name, int num_change, int level, int seq_num)
}
baselen = strlen(base);
extlen = strlen(ext);
if (level == 1 && baselen + num_change > 8) {
if (relaxed & (1<<1)) {
/* 37 char filenames */
base[36 - extlen - num_change] = '\0';
} else if (level == 1 && baselen + num_change > 8) {
base[8 - num_change] = '\0';
} else if (level != 1 && baselen + extlen + num_change > 30) {
base[30 - extlen - num_change] = '\0';
}
sprintf(fmt, "%%s%%0%1dd.%%s;1", num_change);
*name = realloc(*name, baselen + extlen + num_change + 4);
if (relaxed & ECMA119_OMIT_VERSION_NUMBERS) {
sprintf(fmt, "%%s%%0%1dd.%%s", num_change);
*name = realloc(*name, baselen + extlen + num_change + 1);
} else {
sprintf(fmt, "%%s%%0%1dd.%%s;1", num_change);
*name = realloc(*name, baselen + extlen + num_change + 4);
}
sprintf(*name, fmt, base, seq_num, ext);
}
@ -559,8 +583,10 @@ mangle_all(struct ecma119_tree_node *dir)
struct ecma119_dir_info d = dir->info.dir;
size_t n_change;
int changed;
size_t digits;
assert(dir->type == ECMA119_DIR);
digits = 1;
do {
changed = 0;
for (i=0; i < d.nchildren; i++) {
@ -574,11 +600,12 @@ mangle_all(struct ecma119_tree_node *dir)
/* mangle the names */
changed = 1;
n_change = j / 10 + 1;
n_change = j / 10 + digits;
for (k=0; k < j; k++) {
mangle_name(&(d.children[i+k]->iso_name),
n_change,
dir->target->iso_level,
dir->target->relaxed_constraints,
k);
d.children[i+k]->dirent_len =
calc_dirent_len(d.children[i+k]);
@ -587,6 +614,12 @@ mangle_all(struct ecma119_tree_node *dir)
/* skip ahead by the number of mangled names */
i += j - 1;
}
if (changed) {
/* we need to reorder */
qsort(dir->info.dir.children, dir->info.dir.nchildren,
sizeof(void*), cmp_node);
}
digits++;
} while (changed);
for (i=0; i < d.nchildren; i++) {

View File

@ -21,7 +21,8 @@ enum ecma119_node_type {
ECMA119_FILE,
ECMA119_SYMLINK,
ECMA119_DIR,
ECMA119_PLACEHOLDER /**< placeholder for a relocated dir. */
ECMA119_PLACEHOLDER, /**< placeholder for a relocated dir. */
ECMA119_BOOT
};
struct ecma119_dir_info {
@ -53,7 +54,7 @@ struct ecma119_tree_node
{
char *iso_name; /**< in ASCII, conforming to the
* current ISO level. */
char *full_name; /**< full name, in current locale (TODO put this in UTF-8?) */
char *full_name; /**< full name, in current locale */
size_t dirent_len; /**< Length of the directory record,
* not including SU. */
@ -72,6 +73,10 @@ struct ecma119_tree_node
struct ecma119_tree_node *real_me; /**< this field points to
* the relocated directory.
*/
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;
};

View File

@ -3,6 +3,7 @@
#include "eltorito.h"
#include "volume.h"
#include "util.h"
#include "messages.h"
#include <assert.h>
#include <malloc.h>
@ -15,46 +16,6 @@
#include <fcntl.h>
struct el_torito_validation_entry {
uint8_t header_id BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t reserved BP(3, 4);
uint8_t id_string BP(5, 28);
uint8_t checksum BP(29, 30);
uint8_t key_byte1 BP(31, 31);
uint8_t key_byte2 BP(32, 32);
};
struct el_torito_default_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t unused2 BP(13, 32);
};
struct el_torito_section_header_entry {
uint8_t header_indicator BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t number BP(3, 4);
uint8_t character BP(5, 32);
};
struct el_torito_section_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t selec_criteria BP(13, 13);
uint8_t vendor_sc BP(14, 32);
};
/**
* This table should be written with accuracy values at offset
* 8 of boot image, when used ISOLINUX boot loader
@ -85,18 +46,67 @@ struct hard_disc_mbr {
uint8_t sign2;
};
static void
el_torito_image_free(struct el_torito_boot_image *image)
{
assert(image);
/* unref image node */
iso_tree_free((struct iso_tree_node*)image->node);
free(image);
}
static struct iso_tree_node_boot*
create_boot_image_node(struct iso_tree_node_file *image)
{
struct iso_tree_node_boot *boot;
struct iso_tree_node_dir *parent;
assert(image);
boot = calloc(1, sizeof(struct iso_tree_node_boot));
boot->node.attrib = image->node.attrib;
boot->node.type = LIBISO_NODE_BOOT;
boot->node.name = strdup(image->node.name);
boot->node.hide_flags = image->node.hide_flags;
boot->node.refcount = 2; /* mine and tree */
boot->loc.path = strdup(image->loc.path);
boot->img = 1; /* it refers to image */
/* replace iso_tree_node_file with the image */
parent = image->node.parent;
iso_tree_node_remove(parent, (struct iso_tree_node*)image);
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
return boot;
}
static struct el_torito_boot_image *
create_image(struct iso_tree_node *image,
create_image(const char *path,
enum eltorito_boot_media_type type)
{
struct stat attrib;
struct el_torito_boot_image *boot;
int boot_media_type = 0;
int load_sectors = 0; /* number of sector to load */
unsigned char partition_type = 0;
if (stat(path, &attrib)) {
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't access file.");
libisofs_errno = NO_FILE;
return NULL;
}
if ( !S_ISREG(attrib.st_mode) ) {
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
"We can only create boot images from regular files");
libisofs_errno = ELTORITO_WRONG_IMAGE;
return NULL;
}
switch (type) {
case ELTORITO_FLOPPY_EMUL:
switch (image->attrib.st_size) {
switch (attrib.st_size) {
case 1200 * 1024:
boot_media_type = 1; /* 1.2 meg diskette */
break;
@ -107,10 +117,14 @@ create_image(struct iso_tree_node *image,
boot_media_type = 3; /* 2.88 meg diskette */
break;
default:
fprintf(stderr, "Invalid image size %d Kb. Must be one of 1.2, 1.44"
"or 2.88 Mb", (int) image->attrib.st_size / 1024);
{
char msg[72];
sprintf(msg, "Invalid image size %d Kb. Must be one of 1.2, 1.44"
"or 2.88 Mb", (int) attrib.st_size / 1024);
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, msg);
libisofs_errno = ELTORITO_WRONG_IMAGE_SIZE;
return NULL;
}
break;
}
/* it seems that for floppy emulation we need to load
@ -125,13 +139,16 @@ create_image(struct iso_tree_node *image,
int used_partition;
/* read the MBR on disc and get the type of the partition */
fd = open(((struct iso_tree_node_file*)image)->path, O_RDONLY);
fd = open(path, O_RDONLY);
if ( fd == -1 ) {
fprintf(stderr, "Can't open image file\n");
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't open image file.");
libisofs_errno = NO_READ_ACCESS;
return NULL;
}
if ( read(fd, &mbr, sizeof(mbr)) ) {
fprintf(stderr, "Can't read MBR from image file\n");
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
"Can't read MBR from image file.");
libisofs_errno = ELTORITO_WRONG_IMAGE;
close(fd);
return NULL;
}
@ -139,7 +156,9 @@ create_image(struct iso_tree_node *image,
/* check valid MBR signature */
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
fprintf(stderr, "Invalid MBR. Wrong signature.\n");
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
"Invalid MBR. Wrong signature.");
libisofs_errno = ELTORITO_WRONG_IMAGE;
return NULL;
}
@ -149,8 +168,11 @@ create_image(struct iso_tree_node *image,
if (mbr.partition[i].type != 0) {
/* it's an used partition */
if (used_partition != -1) {
fprintf(stderr, "Invalid MBR. At least 2 paritions: %d and "
char msg[72];
sprintf(msg, "Invalid MBR. At least 2 partitions: %d and "
"%d, are being used\n", used_partition, i);
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, msg);
libisofs_errno = ELTORITO_WRONG_IMAGE;
return NULL;
} else
used_partition = i;
@ -170,67 +192,180 @@ create_image(struct iso_tree_node *image,
boot = calloc(1, sizeof(struct el_torito_boot_image));
boot->bootable = 1;
boot->image = (struct iso_tree_node_file *) image;
boot->type = boot_media_type;
boot->load_size = load_sectors;
boot->partition_type = partition_type;
return boot;
}
static struct iso_tree_node_boot_catalog*
/* parent and name can be null */
static struct iso_tree_node_boot*
create_boot_catalog_node(struct iso_tree_node_dir *parent,
const char *name)
{
struct iso_tree_node_boot_catalog *boot;
struct iso_tree_node_boot *boot;
assert( parent && name );
assert( (parent && name) || (!parent && !name) );
boot = calloc(1, sizeof(struct iso_tree_node_boot_catalog));
boot = calloc(1, sizeof(struct iso_tree_node_boot));
boot->node.attrib.st_mode = S_IFREG | 0444;
boot->node.attrib.st_atime =
boot->node.attrib.st_mtime =
boot->node.attrib.st_ctime = time(NULL);
boot->node.type = LIBISO_NODE_BOOTCATALOG;
boot->node.name = strdup(name);
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
boot->node.attrib.st_size = 2048;
boot->node.type = LIBISO_NODE_BOOT;
boot->node.name = name ? strdup(name) : NULL;
boot->node.refcount = 1; /* mine */
if (parent) {
boot->node.refcount++; /* add tree ref */
iso_tree_add_child(parent, (struct iso_tree_node*) boot);
}
return boot;
}
struct el_torito_boot_image *
iso_volume_create_boot_catalog(struct iso_volume *volume,
struct iso_tree_node *image,
enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir,
char *name)
struct el_torito_boot_image*
iso_volume_set_boot_image(struct iso_volume *volume,
struct iso_tree_node *image,
enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir,
char *name)
{
struct el_torito_boot_image *boot_image;
struct iso_tree_node_boot_catalog *boot_node;
struct iso_tree_node_boot *cat_node;
struct el_torito_boot_catalog *catalog;
struct iso_tree_node_file *imgfile;
assert( volume && !volume->bootcat);
assert( image && ISO_ISREG(image) && dir && name);
assert(volume && !volume->bootcat);
assert(image && ISO_ISREG(image));
assert(dir && name);
boot_image = create_image(image, type);
imgfile = (struct iso_tree_node_file*)image;
if (image->procedence == LIBISO_PREVIMG) {
/* FIXME mmm, what to do here? */
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG, "Can't use prev. image files "
"as boot images");
return NULL;
}
boot_image = create_image(imgfile->loc.path, type);
if ( !boot_image )
return NULL;
/* create image node */
boot_image->node = create_boot_image_node(imgfile);
/* creates the catalog with the given default image */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
catalog->nentries = 1;
catalog->entries = malloc(sizeof(struct el_torito_boot_image *));
catalog->entries[0] = boot_image;
catalog->file = malloc(sizeof(struct iso_file));
catalog->file->size = 2048;
if (!catalog) {
el_torito_image_free(boot_image);
return NULL;
}
catalog->image = boot_image;
/* add catalog file */
boot_node = create_boot_catalog_node(dir, name);
boot_node->catalog = catalog;
cat_node = create_boot_catalog_node(dir, name);
catalog->node = cat_node;
volume->bootcat = catalog;
return boot_image;
}
struct el_torito_boot_image*
iso_volume_set_boot_image_hidden(struct iso_volume *volume, const char* path,
enum eltorito_boot_media_type type)
{
struct el_torito_boot_image *boot_image;
struct iso_tree_node_boot *cat_node;
struct el_torito_boot_catalog *catalog;
assert(volume && !volume->bootcat);
assert(path);
boot_image = create_image(path, type);
if ( !boot_image )
return NULL;
/* create image node */
{
struct iso_tree_node_boot *boot;
boot = calloc(1, sizeof(struct iso_tree_node_boot));
/* we assume the stat won't fail, as we already stat the same file above */
stat(path, &boot->node.attrib);
boot->node.type = LIBISO_NODE_BOOT;
boot->node.refcount = 1; /* mine */
boot->loc.path = strdup(path);
boot->img = 1; /* it refers to image */
boot_image->node = boot;
}
/* creates the catalog with the given default image */
catalog = malloc(sizeof(struct el_torito_boot_catalog));
if (!catalog) {
el_torito_image_free(boot_image);
return NULL;
}
catalog->image = boot_image;
/* add catalog file */
cat_node = create_boot_catalog_node(NULL, NULL);
catalog->node = cat_node;
volume->bootcat = catalog;
return boot_image;
}
struct el_torito_boot_image*
iso_volume_get_boot_image(struct iso_volume *volume,
struct iso_tree_node **imgnode,
struct iso_tree_node **catnode)
{
struct el_torito_boot_catalog *catalog;
assert(volume);
catalog = volume->bootcat;
if (!catalog)
return NULL;
if (imgnode)
*imgnode = (struct iso_tree_node*)catalog->image->node;
if (catnode)
*catnode = (struct iso_tree_node*)catalog->node;
return catalog->image;
}
void
iso_volume_remove_boot_image(struct iso_volume *volume)
{
struct el_torito_boot_catalog *catalog;
struct iso_tree_node *catnode;
struct iso_tree_node *imgnode;
assert(volume);
catalog = volume->bootcat;
if (!catalog)
return;
/* remove node from tree */
catnode = (struct iso_tree_node*)catalog->node;
if (catnode->parent)
iso_tree_node_remove(catnode->parent, catnode);
/* remove image from tree */
imgnode = (struct iso_tree_node*)catalog->image->node;
if (imgnode->parent)
iso_tree_node_remove(imgnode->parent, imgnode);
/* remove catalog */
el_torito_boot_catalog_free(catalog);
volume->bootcat = NULL;
}
void
el_torito_set_load_seg(struct el_torito_boot_image *bootimg, int segment)
{
@ -254,48 +389,25 @@ el_torito_set_no_bootable(struct el_torito_boot_image *bootimg)
}
void
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg)
el_torito_patch_isolinux_image(struct el_torito_boot_image *bootimg)
{
bootimg->patch_isolinux = 1;
bootimg->isolinux = 1;
}
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
{
size_t i;
assert(cat);
for(i = 0; i < cat->nentries; ++i) {
free(cat->entries[i]);
}
free(cat->entries);
free(cat->file);
el_torito_image_free(cat->image);
iso_tree_free((struct iso_tree_node*)cat->node);
free(cat);
}
void el_torito_get_image_files(struct ecma119_write_target *t)
{
size_t i;
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
for(i = 0; i < cat->nentries; ++i) {
struct iso_tree_node_file *image = cat->entries[i]->image;
struct iso_file *file = iso_file_table_lookup(t->file_table, image);
if ( file == NULL ) {
file = iso_file_new(image);
iso_file_table_add_file(t->file_table, file);
}
cat->entries[i]->file = file;
}
}
/**
* Write the Boot Record Volume Descriptor
*/
static void
write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
void
el_torito_write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
struct el_torito_boot_catalog *cat = t->catalog;
struct ecma119_boot_rec_vol_desc *vol =
@ -307,7 +419,7 @@ write_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
memcpy(vol->std_identifier, "CD001", 5);
vol->vol_desc_version[0] = 1;
memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23);
iso_lsb(vol->boot_catalog, cat->file->block, 4);
iso_lsb(vol->boot_catalog, t->catblock, 4);
}
static void
@ -333,104 +445,139 @@ write_validation_entry(struct ecma119_write_target *t, uint8_t *buf)
}
static void
patch_boot_file(struct el_torito_boot_image *img)
patch_boot_image(uint8_t *buf, struct ecma119_write_target *t, ssize_t imgsize)
{
struct boot_info_table info;
int fd;
struct boot_info_table *info;
uint32_t checksum;
ssize_t len;
uint8_t buf[4];
ssize_t offset;
memset(&info, 0, sizeof(info));
/* open image */
fd = open(img->image->path, O_RDWR);
if ( fd == -1 ) {
//TODO what do do? exit or just continue?
fprintf(stderr, "Can't patch boot image %s\n", img->image->path);
close(fd);
return;
}
/* compute checksum, as the the sum of all 32 bit words in boot image
* from offset 64 */
checksum = 0;
lseek(fd, (off_t) 64, SEEK_SET);
offset = (ssize_t) 64;
//TODO this can (must) be optimizied by reading to a longer buffer
while ( (len = read(fd, buf, 4) ) == 4 ) {
checksum += iso_read_lsb(buf, 4);
while (offset < imgsize) {
checksum += iso_read_lsb(buf + offset, 4);
offset += 4;
}
if ( len != 0 ) {
/* error reading file, or file length not multiple of 4 */
//TODO what do do? exit or just continue?
fprintf(stderr, "Can't patch boot image %s\n", img->image->path);
close(fd);
return;
if (offset != imgsize) {
/* file length not multiple of 4 */
iso_msg_warn(LIBISO_ISOLINUX_CANT_PATCH,
"Unexpected isolinux image length. Patch might not work.");
}
/* fill boot info table */
iso_lsb(info.bi_pvd, 16, 4); //FIXME this should be changed when we implement ms
iso_lsb(info.bi_file, img->file->block, 4);
iso_lsb(info.bi_length, img->image->node.attrib.st_size, 4);
iso_lsb(info.bi_csum, checksum, 4);
/* patch file */
lseek(fd, (off_t) 8, SEEK_SET);
write(fd, &info, sizeof(info));
close(fd);
}
/* patch boot info table */
info = (struct boot_info_table*)(buf + 8);
memset(info, 0, sizeof(struct boot_info_table));
iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
iso_lsb(info->bi_file, t->imgblock, 4);
iso_lsb(info->bi_length, imgsize, 4);
iso_lsb(info->bi_csum, checksum, 4);
}
void
el_torito_patch_image_files(struct ecma119_write_target *t)
static void
write_boot_image(uint8_t *buf, struct ecma119_write_target *t)
{
size_t i;
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
ssize_t imgsize;
struct el_torito_boot_image *image;
for (i = 0; i < cat->nentries; ++i) {
struct el_torito_boot_image *img = cat->entries[i];
if ( img->patch_isolinux )
patch_boot_file(img);
image = t->catalog->image;
imgsize= image->node->node.attrib.st_size;
/* copy image contents to memory buffer */
if (image->node->node.procedence == LIBISO_PREVIMG) {
int block, nblocks;
uint8_t *memloc;
assert(t->src);
block = 0;
memloc = buf;
nblocks = imgsize ? div_up(imgsize, 2048) : 1;
while (block < nblocks) {
if (t->src->read_block(t->src,
image->node->loc.block + block, memloc)) {
iso_msg_sorry(LIBISO_CANT_READ_IMG,
"Unable to read boot image from previous image.");
break; /* exit loop */
}
memloc += 2048;
++block;
}
} else {
int fd;
ssize_t nread, tread;
uint8_t *memloc;
const char *path = image->node->loc.path;
memloc = buf;
fd = open(path, O_RDONLY);
if (fd == -1) {
iso_msg_sorry(LIBISO_CANT_READ_FILE,
"Can't open boot image file for reading. Skipping");
return;
}
tread = 0;
while (tread < imgsize) {
nread = read(fd, memloc, t->block_size);
if (nread <= 0) {
iso_msg_sorry(LIBISO_CANT_READ_FILE,
"Problem reading boot image file. Skipping");
break; /* exit loop */
}
tread += nread;
memloc += nread;
}
close(fd);
}
if (image->isolinux) {
/* we need to patch the image */
patch_boot_image(buf, t, imgsize);
}
}
/**
* Write one section entry.
* Currently this is used for both default and other entries since we
* put selection criteria no 0 (no sel. criteria)
* Currently this is used only for default image (the only supported just now)
*/
static void
write_section_entry(uint8_t *buf, struct el_torito_boot_image *img)
write_section_entry(uint8_t *buf, struct ecma119_write_target *t)
{
struct el_torito_boot_image *img;
struct el_torito_section_entry *se =
(struct el_torito_section_entry*)buf;
img = t->catalog->image;
assert(img);
se->boot_indicator[0] = img->bootable ? 0x88 : 0x00;
se->boot_media_type[0] = img->type;
iso_lsb(se->load_seg, img->load_seg, 2);
se->system_type[0] = 0; //TODO need to get the partition type
se->system_type[0] = img->partition_type;
iso_lsb(se->sec_count, img->load_size, 2);
iso_lsb(se->block, img->file->block, 4);
iso_lsb(se->block, t->imgblock, 4);
}
/**
* Write El-Torito Boot Catalog
* Write El-Torito Boot Catalog plus image
*/
static void
write_catalog(struct ecma119_write_target *t, uint8_t *buf)
{
struct el_torito_boot_catalog *cat = t->catalog;
assert(cat);
assert(cat->nentries >= 1 && cat->nentries < 63);
assert(cat->image);
write_validation_entry(t, buf);
/* write default entry */
write_section_entry(buf + 32, cat->entries[0]);
write_section_entry(buf + 32, t);
//TODO write all images
write_boot_image(buf + 2048, t);
}
void
@ -438,7 +585,7 @@ el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
assert(t->catalog);
ecma119_start_chunking(t,
write_boot_vol_desc,
el_torito_write_boot_vol_desc,
2048,
buf);
}
@ -446,9 +593,27 @@ el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
void
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf)
{
off_t size;
off_t imgsize;
assert(t->catalog);
/*
* Note that when this is called, we need to write el-torito info to
* image. Note, however, that the image could come from a previous session
* and maybe we don't know its size
*/
imgsize = t->catalog->image->node->node.attrib.st_size;
if (imgsize == 0) {
iso_msg_warn(LIBISO_EL_TORITO_BLIND_COPY,
"Can get boot image size, only one block will be copied");
imgsize = 2048;
}
size = 2048 + div_up(imgsize, t->block_size);
ecma119_start_chunking(t,
write_catalog,
2048,
size,
buf);
}

View File

@ -5,55 +5,78 @@
#include "file.h"
#include "ecma119.h"
/**
* Location of the boot catalog
*/
struct iso_tree_node_boot_catalog
{
struct iso_tree_node node;
struct el_torito_boot_catalog *catalog;
};
struct el_torito_boot_catalog {
int nentries;
struct el_torito_boot_image **entries;
struct iso_file *file; /**< The catalog file */
struct iso_tree_node_boot *node; /* node of the catalog */
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 {
unsigned char bootable; /**< If the entry is bootable. */
unsigned char patch_isolinux; /**< If the image will be patched */
struct iso_tree_node_boot *node;
unsigned int bootable:1; /**< If the entry is bootable. */
unsigned int isolinux:1; /**< If the image will be patched */
unsigned char type; /**< The type of image */
unsigned char partition_type; /**< type of partition for HD-emul images */
short load_seg; /**< Load segment for the initial boot image. */
short load_size; /**< Number of sector to load. */
struct iso_tree_node_file *image;
struct iso_file *file;
};
/*struct el_torito_boot_entry *
el_torito_add_boot_entry(struct el_torito_boot_catalog *cat,
struct iso_tree_node_file *image);
*/
struct el_torito_validation_entry {
uint8_t header_id BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t reserved BP(3, 4);
uint8_t id_string BP(5, 28);
uint8_t checksum BP(29, 30);
uint8_t key_byte1 BP(31, 31);
uint8_t key_byte2 BP(32, 32);
};
struct el_torito_default_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t unused2 BP(13, 32);
};
struct el_torito_section_header_entry {
uint8_t header_indicator BP(1, 1);
uint8_t platform_id BP(2, 2);
uint8_t number BP(3, 4);
uint8_t character BP(5, 32);
};
struct el_torito_section_entry {
uint8_t boot_indicator BP(1, 1);
uint8_t boot_media_type BP(2, 2);
uint8_t load_seg BP(3, 4);
uint8_t system_type BP(5, 5);
uint8_t unused1 BP(6, 6);
uint8_t sec_count BP(7, 8);
uint8_t block BP(9, 12);
uint8_t selec_criteria BP(13, 13);
uint8_t vendor_sc BP(14, 32);
};
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat);
/**
* For each boot image file, this gets the related iso_file object.
* In most cases, the file is already in the hash table. However, if the
* boot record is hidden in both ISO/RR and joliet trees, this ensures
* that boot images will be written to image.
* Write the Boot Record Volume Descriptor
*/
void el_torito_get_image_files(struct ecma119_write_target *t);
/**
* Patch image files if selected. This is needed for isolinux boot images
*/
void el_torito_patch_image_files(struct ecma119_write_target *t);
void
el_torito_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
*/
void
el_torito_wr_catalog(struct ecma119_write_target *t, uint8_t *buf);

View File

@ -9,15 +9,6 @@ iso_exclude_add_path(struct iso_hash_table *table, const char *path)
table->num += iso_hash_insert(table->table, path);
}
/*void
iso_exclude_remove_path(struct iso_hash_table *table, const char *path)
{
if (!table->num || !path)
return;
table->num -= iso_hash_remove(table->table, path);
}*/
void
iso_exclude_empty(struct iso_hash_table *table)
{

View File

@ -22,13 +22,6 @@ int iso_exclude_lookup(struct iso_hash_table *table, const char *path);
*/
void iso_exclude_add_path(struct iso_hash_table *table, const char *path);
/**
* Remove a path that was set to be ignored when adding a directory recusively.
*
* \param path The path, on the local filesystem, of the file.
*/
//void iso_exclude_remove_path(struct iso_hash_table *table, const char *path);
/**
* Remove all paths that were set to be ignored when adding a directory recusively.
*/

View File

@ -1,26 +1,61 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.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!!
//TODO: refactor both hash and this hash table into a single one??
struct iso_file *
iso_file_new(struct iso_tree_node_file *f)
iso_file_new(struct ecma119_write_target *t, struct iso_tree_node_file *f)
{
struct iso_file *file = calloc(1, sizeof(struct iso_file));
file->path = f->path; /*TODO strdup? it needs to be free on clear then */
file->size = f->node.attrib.st_size;
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->real_dev = f->node.attrib.st_dev;
file->real_ino = f->node.attrib.st_ino;
file->sort_weight = f->sort_weight;
return file;
creation_error:;
free(file);
return NULL;
}
static unsigned int
@ -62,6 +97,7 @@ iso_file_table_node_new(struct iso_file *file)
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);
}
@ -98,6 +134,13 @@ 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 {
@ -111,8 +154,12 @@ 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 (ft->cache_inodes)
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);
@ -146,6 +193,27 @@ iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f)
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)
{
@ -153,32 +221,30 @@ iso_file_table_lookup(struct iso_file_table *ft, struct iso_tree_node_file *f)
unsigned int hash_num;
int equal;
assert(ft && f);
/* find the hash number */
if ( ft->cache_inodes )
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->path);
hash_num = iso_file_table_hash(f->loc.path);
node = ft->table[hash_num];
if (!node)
return NULL;
equal = ft->cache_inodes ?
((f->node.attrib.st_dev == node->file->real_dev)
&& (f->node.attrib.st_ino == node->file->real_ino))
: !strcmp(f->path, node->file->path);
equal = !iso_table_compare_node_file(ft, f, node->file);
if (equal)
return node->file;
while (node->next) {
node = node->next;
equal = ft->cache_inodes ?
((f->node.attrib.st_dev == node->file->real_dev)
&& (f->node.attrib.st_ino == node->file->real_ino))
: !strcmp(f->path, node->file->path);
equal = !iso_table_compare_node_file(ft, f, node->file);
if (equal)
return node->file;
}

View File

@ -17,17 +17,20 @@
#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) */
size_t block; /**< Block where this file is to be written on image */
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 {
@ -42,12 +45,14 @@ struct iso_file_table {
};
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 iso_tree_node_file*);
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);

306
libisofs/file_src.c Normal file
View File

@ -0,0 +1,306 @@
/*
* 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;
}

94
libisofs/file_src.h Normal file
View File

@ -0,0 +1,94 @@
/*
* 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_*/

View File

@ -8,6 +8,7 @@
#include "util.h"
#include "volume.h"
#include "eltorito.h"
#include "messages.h"
#include <assert.h>
#include <string.h>
@ -35,19 +36,28 @@ create_node(struct ecma119_write_target *t,
struct iso_file *file;
file = iso_file_table_lookup(t->file_table, iso_f);
if ( file == NULL ) {
file = iso_file_new(iso_f);
file = iso_file_new(t, iso_f);
if (!file) {
/*
* That was an error.
* TODO currently this cause the file to be ignored... Maybe
* throw an error is a better alternative
*/
joliet_tree_free(ret);
return NULL;
}
iso_file_table_add_file(t->file_table, file);
}
ret->info.file = file;
ret->type = JOLIET_FILE;
} else {
} else if (ISO_ISBOOT(iso)) {
/* it's boot catalog info */
struct iso_tree_node_boot_catalog *iso_b =
(struct iso_tree_node_boot_catalog *) iso;
struct iso_file *file;
file = iso_b->catalog->file;
ret->info.file = file;
ret->type = JOLIET_FILE;
struct iso_tree_node_boot *boot = (struct iso_tree_node_boot*) iso;
ret->info.boot_img = boot->img;
ret->type = JOLIET_BOOT;
} else {
/* this should never happen */
assert(0);
}
return ret;
@ -66,7 +76,7 @@ create_tree(struct ecma119_write_target *t,
switch (iso->type) {
case LIBISO_NODE_FILE:
case LIBISO_NODE_BOOTCATALOG:
case LIBISO_NODE_BOOT:
root = create_node(t, parent, iso);
break;
case LIBISO_NODE_DIR:
@ -85,9 +95,13 @@ create_tree(struct ecma119_write_target *t,
}
break;
default:
//TODO replace this printf
printf("Can't add this kind of node to a Joliet tree");
{
char msg[512];
sprintf(msg, "Can't add %s to Joliet tree. This kind of files "
"can only be added to a Rock Ridget tree. Skipping", iso->name);
iso_msg_note(LIBISO_JOLIET_WRONG_FILE_TYPE, msg);
return NULL;
}
break;
}
return root;
@ -271,8 +285,19 @@ write_one_dir_record(struct ecma119_write_target *t,
if (node->type == JOLIET_DIR) {
len = node->info.dir.len;
block = node->info.dir.block;
} else if (node->type == JOLIET_BOOT) {
assert(t->eltorito);
if (node->info.boot_img) {
block = t->imgblock;
len = t->catalog->image->node->node.attrib.st_size;
} else {
/* we always assume 2048 as catalog len */
block = t->catblock;
len = 2048;
}
} else {
/* file */
assert(node->type == JOLIET_FILE);
len = node->info.file->size;
block = node->info.file->block;
}
@ -302,8 +327,8 @@ write_m_path_table(struct ecma119_write_target *t, uint8_t *buf)
write_path_table (t, 0, buf);
}
static void
write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
void
joliet_write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
{
struct ecma119_sup_vol_desc *vol = (struct ecma119_sup_vol_desc*)buf;
struct iso_volume *volume = t->volset->volume[t->volnum];
@ -414,7 +439,7 @@ write_dirs(struct ecma119_write_target *t, uint8_t *buf)
size_t i;
struct joliet_tree_node *dir;
assert (t->curblock == t->dirlist_joliet[0]->info.dir.block);
assert (t->curblock + t->ms_block == t->dirlist_joliet[0]->info.dir.block);
for (i = 0; i < t->dirlist_len_joliet; i++) {
dir = t->dirlist_joliet[i];
write_one_dir(t, dir, buf);
@ -427,7 +452,7 @@ joliet_wr_sup_vol_desc(struct ecma119_write_target *t,
uint8_t *buf)
{
ecma119_start_chunking(t,
write_sup_vol_desc,
joliet_write_sup_vol_desc,
2048,
buf);
}

View File

@ -19,7 +19,8 @@ struct iso_tree_node;
enum joliet_node_type {
JOLIET_FILE,
JOLIET_DIR
JOLIET_DIR,
JOLIET_BOOT
};
struct joliet_dir_info {
@ -41,6 +42,10 @@ struct joliet_tree_node
union {
struct iso_file *file;
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;
};
@ -74,6 +79,9 @@ 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);

404
libisofs/libiso_msgs.c Normal file
View File

@ -0,0 +1,404 @@
/* libiso_msgs
Message handling facility of libiso.
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
/* Only this single source module is entitled to do this */
#define LIBISO_MSGS_H_INTERNAL 1
/* All participants in the messaging system must do this */
#include "libiso_msgs.h"
/* ----------------------------- libiso_msgs_item ------------------------- */
static int libiso_msgs_item_new(struct libiso_msgs_item **item,
struct libiso_msgs_item *link, int flag)
{
int ret;
struct libiso_msgs_item *o;
struct timeval tv;
struct timezone tz;
(*item)= o=
(struct libiso_msgs_item *) malloc(sizeof(struct libiso_msgs_item));
if(o==NULL)
return(-1);
o->timestamp= 0.0;
ret= gettimeofday(&tv,&tz);
if(ret==0)
o->timestamp= tv.tv_sec+0.000001*tv.tv_usec;
o->process_id= getpid();
o->driveno= -1;
o->severity= LIBISO_MSGS_SEV_ALL;
o->priority= LIBISO_MSGS_PRIO_ZERO;
o->error_code= 0;
o->msg_text= NULL;
o->os_errno= 0;
o->prev= link;
o->next= NULL;
if(link!=NULL) {
if(link->next!=NULL) {
link->next->prev= o;
o->next= link->next;
}
link->next= o;
}
return(1);
}
/** Detaches item from its queue and eventually readjusts start, end pointers
of the queue */
int libiso_msgs_item_unlink(struct libiso_msgs_item *o,
struct libiso_msgs_item **chain_start,
struct libiso_msgs_item **chain_end, int flag)
{
if(o->prev!=NULL)
o->prev->next= o->next;
if(o->next!=NULL)
o->next->prev= o->prev;
if(chain_start!=NULL)
if(*chain_start == o)
*chain_start= o->next;
if(chain_end!=NULL)
if(*chain_end == o)
*chain_end= o->prev;
o->next= o->prev= NULL;
return(1);
}
int libiso_msgs_item_destroy(struct libiso_msgs_item **item,
int flag)
{
struct libiso_msgs_item *o;
o= *item;
if(o==NULL)
return(0);
libiso_msgs_item_unlink(o,NULL,NULL,0);
if(o->msg_text!=NULL)
free((char *) o->msg_text);
free((char *) o);
*item= NULL;
return(1);
}
int libiso_msgs_item_get_msg(struct libiso_msgs_item *item,
int *error_code, char **msg_text, int *os_errno,
int flag)
{
*error_code= item->error_code;
*msg_text= item->msg_text;
*os_errno= item->os_errno;
return(1);
}
int libiso_msgs_item_get_origin(struct libiso_msgs_item *item,
double *timestamp, pid_t *process_id, int *driveno,
int flag)
{
*timestamp= item->timestamp;
*process_id= item->process_id;
*driveno= item->driveno;
return(1);
}
int libiso_msgs_item_get_rank(struct libiso_msgs_item *item,
int *severity, int *priority, int flag)
{
*severity= item->severity;
*priority= item->priority;
return(1);
}
/* ------------------------------- libiso_msgs ---------------------------- */
int libiso_msgs_new(struct libiso_msgs **m, int flag)
{
struct libiso_msgs *o;
(*m)= o= (struct libiso_msgs *) malloc(sizeof(struct libiso_msgs));
if(o==NULL)
return(-1);
o->oldest= NULL;
o->youngest= NULL;
o->count= 0;
o->queue_severity= LIBISO_MSGS_SEV_ALL;
o->print_severity= LIBISO_MSGS_SEV_NEVER;
strcpy(o->print_id,"libiso: ");
#ifndef LIBISO_MSGS_SINGLE_THREADED
pthread_mutex_init(&(o->lock_mutex),NULL);
#endif
return(1);
}
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)
{
#ifndef LIBISO_MSGS_SINGLE_THREADED
int ret;
ret= pthread_mutex_lock(&(m->lock_mutex));
if(ret!=0)
return(0);
#endif
return(1);
}
static int libiso_msgs_unlock(struct libiso_msgs *m, int flag)
{
#ifndef LIBISO_MSGS_SINGLE_THREADED
int ret;
ret= pthread_mutex_unlock(&(m->lock_mutex));
if(ret!=0)
return(0);
#endif
return(1);
}
int libiso_msgs__text_to_sev(char *severity_name, int *severity,
int flag)
{
if(strncmp(severity_name,"NEVER",5)==0)
*severity= LIBISO_MSGS_SEV_NEVER;
else if(strncmp(severity_name,"ABORT",5)==0)
*severity= LIBISO_MSGS_SEV_ABORT;
else if(strncmp(severity_name,"FATAL",5)==0)
*severity= LIBISO_MSGS_SEV_FATAL;
else if(strncmp(severity_name,"SORRY",5)==0)
*severity= LIBISO_MSGS_SEV_SORRY;
else if(strncmp(severity_name,"WARNING",7)==0)
*severity= LIBISO_MSGS_SEV_WARNING;
else if(strncmp(severity_name,"HINT",4)==0)
*severity= LIBISO_MSGS_SEV_HINT;
else if(strncmp(severity_name,"NOTE",4)==0)
*severity= LIBISO_MSGS_SEV_NOTE;
else if(strncmp(severity_name,"UPDATE",6)==0)
*severity= LIBISO_MSGS_SEV_UPDATE;
else if(strncmp(severity_name,"DEBUG",5)==0)
*severity= LIBISO_MSGS_SEV_DEBUG;
else if(strncmp(severity_name,"ALL",3)==0)
*severity= LIBISO_MSGS_SEV_ALL;
else {
*severity= LIBISO_MSGS_SEV_NEVER;
return(0);
}
return(1);
}
int libiso_msgs__sev_to_text(int severity, char **severity_name,
int flag)
{
if(flag&1) {
*severity_name=
"NEVER\nABORT\nFATAL\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
return(1);
}
*severity_name= "";
if(severity>=LIBISO_MSGS_SEV_NEVER)
*severity_name= "NEVER";
else if(severity>=LIBISO_MSGS_SEV_ABORT)
*severity_name= "ABORT";
else if(severity>=LIBISO_MSGS_SEV_FATAL)
*severity_name= "FATAL";
else if(severity>=LIBISO_MSGS_SEV_SORRY)
*severity_name= "SORRY";
else if(severity>=LIBISO_MSGS_SEV_WARNING)
*severity_name= "WARNING";
else if(severity>=LIBISO_MSGS_SEV_HINT)
*severity_name= "HINT";
else if(severity>=LIBISO_MSGS_SEV_NOTE)
*severity_name= "NOTE";
else if(severity>=LIBISO_MSGS_SEV_UPDATE)
*severity_name= "UPDATE";
else if(severity>=LIBISO_MSGS_SEV_DEBUG)
*severity_name= "DEBUG";
else if(severity>=LIBISO_MSGS_SEV_ALL)
*severity_name= "ALL";
else {
*severity_name= "";
return(0);
}
return(1);
}
int libiso_msgs_submit(struct libiso_msgs *m, int driveno, int error_code,
int severity, int priority, char *msg_text,
int os_errno, int flag)
{
int ret;
char *textpt,*sev_name,sev_text[81];
struct libiso_msgs_item *item= NULL;
if(severity >= m->print_severity) {
if(msg_text==NULL)
textpt= "";
else
textpt= msg_text;
sev_text[0]= 0;
ret= libiso_msgs__sev_to_text(severity,&sev_name,0);
if(ret>0)
sprintf(sev_text,"%s : ",sev_name);
fprintf(stderr,"%s%s%s\n",m->print_id,sev_text,textpt);
if(os_errno!=0) {
ret= libiso_msgs_lock(m,0);
if(ret<=0)
return(-1);
fprintf(stderr,"%s( Most recent system error: %d '%s' )\n",
m->print_id,os_errno,strerror(os_errno));
libiso_msgs_unlock(m,0);
}
}
if(severity < m->queue_severity)
return(0);
ret= libiso_msgs_lock(m,0);
if(ret<=0)
return(-1);
ret= libiso_msgs_item_new(&item,m->youngest,0);
if(ret<=0)
goto failed;
item->driveno= driveno;
item->error_code= error_code;
item->severity= severity;
item->priority= priority;
if(msg_text!=NULL) {
item->msg_text= malloc(strlen(msg_text)+1);
if(item->msg_text==NULL)
goto failed;
strcpy(item->msg_text,msg_text);
}
item->os_errno= os_errno;
if(m->oldest==NULL)
m->oldest= item;
m->youngest= item;
m->count++;
libiso_msgs_unlock(m,0);
/*
fprintf(stderr,"libiso_experimental: message submitted to queue (now %d)\n",
m->count);
*/
return(1);
failed:;
libiso_msgs_item_destroy(&item,0);
libiso_msgs_unlock(m,0);
return(-1);
}
int libiso_msgs_obtain(struct libiso_msgs *m, struct libiso_msgs_item **item,
int severity, int priority, int flag)
{
int ret;
struct libiso_msgs_item *im, *next_im= NULL;
*item= NULL;
ret= libiso_msgs_lock(m,0);
if(ret<=0)
return(-1);
for(im= m->oldest; im!=NULL; im= next_im) {
for(; im!=NULL; im= next_im) {
next_im= im->next;
if(im->severity>=severity)
break;
libiso_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
libiso_msgs_item_destroy(&im,0); /* severity too low: delete */
}
if(im==NULL)
break;
if(im->priority>=priority)
break;
}
if(im==NULL)
{ret= 0; goto ex;}
libiso_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
*item= im;
ret= 1;
ex:;
libiso_msgs_unlock(m,0);
return(ret);
}
int libiso_msgs_destroy_item(struct libiso_msgs *m,
struct libiso_msgs_item **item, int flag)
{
int ret;
ret= libiso_msgs_lock(m,0);
if(ret<=0)
return(-1);
ret= libiso_msgs_item_destroy(item,0);
libiso_msgs_unlock(m,0);
return(ret);
}

454
libisofs/libiso_msgs.h Normal file
View File

@ -0,0 +1,454 @@
/* libiso_msgs
Message handling facility of libisofs.
Copyright (C) 2006-2007 Thomas Schmitt <scdbackup@gmx.net>,
provided under GPL
*/
/*
*Never* set this macro outside libiso_msgs.c !
The entrails of the message handling facility are not to be seen by
the other library components or the applications.
*/
#ifdef LIBISO_MSGS_H_INTERNAL
#ifndef LIBISO_MSGS_SINGLE_THREADED
#include <pthread.h>
#endif
struct libiso_msgs_item {
double timestamp;
pid_t process_id;
int driveno;
int severity;
int priority;
/* Apply for your developer's error code range at
libburn-hackers@pykix.org
Report introduced codes in the list below. */
int error_code;
char *msg_text;
int os_errno;
struct libiso_msgs_item *prev,*next;
};
struct libiso_msgs {
struct libiso_msgs_item *oldest;
struct libiso_msgs_item *youngest;
int count;
int queue_severity;
int print_severity;
char print_id[81];
#ifndef LIBISO_MSGS_SINGLE_THREADED
pthread_mutex_t lock_mutex;
#endif
};
#endif /* LIBISO_MSGS_H_INTERNAL */
#ifndef LIBISO_MSGS_H_INCLUDED
#define LIBISO_MSGS_H_INCLUDED 1
#ifndef LIBISO_MSGS_H_INTERNAL
/* Public Opaque Handles */
/** A pointer to this is a opaque handle to a message handling facility */
struct libiso_msgs;
/** A pointer to this is a opaque handle to a single message item */
struct libiso_msgs_item;
#endif /* ! LIBISO_MSGS_H_INTERNAL */
/* Public Macros */
/* Registered Severities */
/* It is well advisable to let applications select severities via strings and
forwarded functions libiso_msgs__text_to_sev(), libiso_msgs__sev_to_text().
These macros are for use by libdax/libburn only.
*/
/** Use this to get messages of any severity. Do not use for submitting.
*/
#define LIBISO_MSGS_SEV_ALL 0x00000000
/** Debugging messages not to be visible to normal users by default
*/
#define LIBISO_MSGS_SEV_DEBUG 0x10000000
/** Update of a progress report about long running actions
*/
#define LIBISO_MSGS_SEV_UPDATE 0x20000000
/** Not so usual events which were gracefully handled
*/
#define LIBISO_MSGS_SEV_NOTE 0x30000000
/** Possibilities to achieve a better result
*/
#define LIBISO_MSGS_SEV_HINT 0x40000000
/** Warnings about problems which could not be handled optimally
*/
#define LIBISO_MSGS_SEV_WARNING 0x50000000
/** Non-fatal error messages indicating that parts of the action failed
but processing will/should go on
*/
#define LIBISO_MSGS_SEV_SORRY 0x60000000
/** An error message which puts the whole operation of libdax in question
*/
#define LIBISO_MSGS_SEV_FATAL 0x70000000
/** A message from an abort handler which will finally finish libburn
*/
#define LIBISO_MSGS_SEV_ABORT 0x71000000
/** A severity to exclude resp. discard any possible message.
Do not use this severity for submitting.
*/
#define LIBISO_MSGS_SEV_NEVER 0x7fffffff
/* Registered Priorities */
/* Priorities are to be used by libburn/libdax only. */
#define LIBISO_MSGS_PRIO_ZERO 0x00000000
#define LIBISO_MSGS_PRIO_LOW 0x10000000
#define LIBISO_MSGS_PRIO_MEDIUM 0x20000000
#define LIBISO_MSGS_PRIO_HIGH 0x30000000
#define LIBISO_MSGS_PRIO_TOP 0x7ffffffe
/* Do not use this priority for submitting */
#define LIBISO_MSGS_PRIO_NEVER 0x7fffffff
/* Public Functions */
/* Calls initiated from inside libdax/libburn */
/** Create new empty message handling facility with queue.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success, <=0 failure
*/
int libiso_msgs_new(struct libiso_msgs **m, int flag);
/** Destroy a message handling facility and all its eventual messages.
The submitted pointer gets set to NULL.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 for success, 0 for pointer to NULL
*/
int libiso_msgs_destroy(struct libiso_msgs **m, int flag);
/** Submit a message to a message handling facility.
@param driveno libdax drive number. Use -1 if no number is known.
@param error_code Unique error code. Use only registered codes. See below.
The same unique error_code may be issued at different
occasions but those should be equivalent out of the view
of a libdax application. (E.g. "cannot open ATA drive"
versus "cannot open SCSI drive" would be equivalent.)
@param severity The LIBISO_MSGS_SEV_* of the event.
@param priority The LIBISO_MSGS_PRIO_* number of the event.
@param msg_text Printable and human readable message text.
@param os_errno Eventual error code from operating system (0 if none)
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on rejection, <0 for severe errors
*/
int libiso_msgs_submit(struct libiso_msgs *m, int driveno, int error_code,
int severity, int priority, char *msg_text,
int os_errno, int flag);
/* Calls from applications (to be forwarded by libdax/libburn) */
/** Convert a registered severity number into a severity name
@param flag Bitfield for control purposes:
bit0= list all severity names in a newline separated string
@return >0 success, <=0 failure
*/
int libiso_msgs__sev_to_text(int severity, char **severity_name,
int flag);
/** Convert a severity name into a severity number,
@param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success, <=0 failure
*/
int libiso_msgs__text_to_sev(char *severity_name, int *severity,
int flag);
/** Set minimum severity for messages to be queued (default
LIBISO_MSGS_SEV_ALL) and for messages to be printed directly to stderr
(default LIBISO_MSGS_SEV_NEVER).
@param print_id A text of at most 80 characters to be printed before
any eventually printed message (default is "libdax: ").
@param flag Bitfield for control purposes (unused yet, submit 0)
@return always 1 for now
*/
int libiso_msgs_set_severities(struct libiso_msgs *m, int queue_severity,
int print_severity, char *print_id, int flag);
/** Obtain a message item that has at least the given severity and priority.
Usually all older messages of lower severity are discarded then. If no
item of sufficient severity was found, all others are discarded from the
queue.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 if a matching item was found, 0 if not, <0 for severe errors
*/
int libiso_msgs_obtain(struct libiso_msgs *m, struct libiso_msgs_item **item,
int severity, int priority, int flag);
/** Destroy a message item obtained by libiso_msgs_obtain(). The submitted
pointer gets set to NULL.
Caution: Copy eventually obtained msg_text before destroying the item,
if you want to use it further.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 for success, 0 for pointer to NULL, <0 for severe errors
*/
int libiso_msgs_destroy_item(struct libiso_msgs *m,
struct libiso_msgs_item **item, int flag);
/** Obtain from a message item the three application oriented components as
submitted with the originating call of libiso_msgs_submit().
Caution: msg_text becomes a pointer into item, not a copy.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on invalid item, <0 for servere errors
*/
int libiso_msgs_item_get_msg(struct libiso_msgs_item *item,
int *error_code, char **msg_text, int *os_errno,
int flag);
/** Obtain from a message item the submitter identification submitted
with the originating call of libiso_msgs_submit().
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on invalid item, <0 for servere errors
*/
int libiso_msgs_item_get_origin(struct libiso_msgs_item *item,
double *timestamp, pid_t *process_id, int *driveno,
int flag);
/** Obtain from a message item severity and priority as submitted
with the originating call of libiso_msgs_submit().
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on invalid item, <0 for servere errors
*/
int libiso_msgs_item_get_rank(struct libiso_msgs_item *item,
int *severity, int *priority, int flag);
#ifdef LIDBAX_MSGS_________________
/* Registered Error Codes */
Format: error_code (LIBISO_MSGS_SEV_*,LIBISO_MSGS_PRIO_*) = explanation
If no severity or priority are fixely associates, use "(,)".
------------------------------------------------------------------------------
Range "libiso_msgs" : 0x00000000 to 0x0000ffff
0x00000000 (ALL,ZERO) = Initial setting in new libiso_msgs_item
0x00000001 (DEBUG,ZERO) = Test error message
0x00000002 (DEBUG,ZERO) = Debugging message
------------------------------------------------------------------------------
Range "elmom" : 0x00010000 to 0x0001ffff
------------------------------------------------------------------------------
Range "scdbackup" : 0x00020000 to 0x0002ffff
Acessing and defending drives:
0x00020001 (SORRY,LOW) = Cannot open busy device
0x00020002 (SORRY,HIGH) = Encountered error when closing drive
0x00020003 (SORRY,HIGH) = Could not grab drive
0x00020004 (NOTE,HIGH) = Opened O_EXCL scsi sibling
0x00020005 (SORRY,HIGH) = Failed to open device
0x00020006 (FATAL,HIGH) = Too many scsi siblings
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock
General library operations:
0x00020101 (WARNING,HIGH) = Cannot find given worker item
0x00020102 (SORRY,HIGH) = A drive operation is still going on
0x00020103 (WARNING,HIGH) = After scan a drive operation is still going on
0x00020104 (SORRY,HIGH) = NULL pointer caught
0x00020105 (SORRY,HIGH) = Drive is already released
0x00020106 (SORRY,HIGH) = Drive is busy on attempt to close
0x00020107 (SORRY,HIGH) = Drive is busy on attempt to shut down library
0x00020108 (SORRY,HIGH) = Drive is not grabbed on disc status inquiry
0x00020108 (FATAL,HIGH) = Could not allocate new drive object
0x00020109 (FATAL,HIGH) = Library not running
0x0002010a (FATAL,HIGH) = Unsuitable track mode
0x0002010b (FATAL,HIGH) = Burn run failed
0x0002010c (FATAL,HIGH) = Failed to transfer command to drive
0x0002010d (DEBUG,HIGH) = Could not inquire TOC
0x0002010e (FATAL,HIGH) = Attempt to read ATIP from ungrabbed drive
0x0002010f (DEBUG,HIGH) = SCSI error condition on command
0x00020110 (FATAL,HIGH) = Persistent drive address too long
0x00020111 (FATAL,HIGH) = Could not allocate new auxiliary object
0x00020112 (SORRY,HIGH) = Bad combination of write_type and block_type
0x00020113 (FATAL,HIGH) = Drive capabilities not inquired yet
0x00020114 (SORRY,HIGH) = Attempt to set ISRC with bad data
0x00020115 (SORRY,HIGH) = Attempt to set track mode to unusable value
0x00020116 (FATAL,HIGH) = Track mode has unusable value
0x00020117 (FATAL,HIGH) = toc_entry of drive is already in use
0x00020118 (DEBUG,HIGH) = Closing track
0x00020119 (DEBUG,HIGH) = Closing session
0x0002011a (NOTE,HIGH) = Padding up track to minimum size
0x0002011b (FATAL,HIGH) = Attempt to read track info from ungrabbed drive
0x0002011c (FATAL,HIGH) = Attempt to read track info from busy drive
0x0002011d (FATAL,HIGH) = SCSI error on write
0x0002011e (SORRY,HIGH) = Unsuitable media detected
0x0002011f (SORRY,HIGH) = Burning is restricted to a single track
0x00020120 (NOTE,HIGH) = FORMAT UNIT ignored
0x00020121 (FATAL,HIGH) = Write preparation setup failed
0x00020122 (FATAL,HIGH) = SCSI error on format_unit
0x00020123 (SORRY,HIGH) = DVD Media are unsuitable for desired track type
0x00020124 (SORRY,HIGH) = SCSI error on set_streaming
0x00020125 (SORRY,HIGH) = Write start address not supported
0x00020126 (SORRY,HIGH) = Write start address not properly aligned
0x00020127 (NOTE,HIGH) = Write start address is ...
0x00020128 (FATAL,HIGH) = Unsupported inquiry_type with mmc_get_performance
0x00020129 (SORRY,HIGH) = Will not format media type
0x0002012a (FATAL,HIGH) = Cannot inquire write mode capabilities
0x0002012b (FATAL,HIGH) = Drive offers no suitable write mode with this job
0x0002012c (SORRY,HIGH) = Too many logical tracks recorded
0x0002012d (FATAL,HIGH) = Exceeding range of permissible write addresses
0x0002012e (NOTE,HIGH) = Activated track default size
0x0002012f (SORRY,HIGH) = SAO is restricted to single fixed size session
0x00020130 (SORRY,HIGH) = Drive and media state unsuitable for blanking
0x00020131 (SORRY,HIGH) = No suitable formatting type offered by drive
0x00020132 (SORRY,HIGH) = Selected format is not suitable for libburn
0x00020133 (SORRY,HIGH) = Cannot mix data and audio in SAO mode
0x00020134 (NOTE,HIGH) = Defaulted TAO to DAO
0x00020135 (SORRY,HIGH) = Cannot perform TAO, job unsuitable for DAO
0x00020136 (SORRY,HIGH) = DAO burning restricted to single fixed size track
0x00020137 (HINT,HIGH) = TAO would be possible
0x00020138 (FATAL,HIGH) = Cannot reserve track
0x00020139 (SORRY,HIGH) = Write job parameters are unsuitable
0x0002013a (FATAL,HIGH) = No suitable media detected
0x0002013b (DEBUG,HIGH) = SCSI command indicates host or driver error
0x0002013c (SORRY,HIGH) = Malformed capabilities page 2Ah received
0x0002013d (DEBUG,LOW) = Waiting for free buffer space takes long time
0x0002013e (SORRY,HIGH) = Timeout with waiting for free buffer. Now disabled
0x0002013f (DEBUG,LOW) = Reporting total time spent with waiting for buffer
libiso_audioxtr:
0x00020200 (SORRY,HIGH) = Cannot open audio source file
0x00020201 (SORRY,HIGH) = Audio source file has unsuitable format
0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data
------------------------------------------------------------------------------
Range "vreixo" : 0x00030000 to 0x0003ffff
General:
0x00031001 (SORRY,HIGH) = Cannot read file (ignored)
0x00031002 (FATAL,HIGH) = Cannot read file (operation canceled)
0x00031003 (FATAL,HIGH) = File doesnt exist
0x00031004 (FATAL,HIGH) = Read access denied
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_________________ */
#ifdef LIBISO_MSGS_H_INTERNAL
/* Internal Functions */
/** Lock before doing side effect operations on m */
static int libiso_msgs_lock(struct libiso_msgs *m, int flag);
/** Unlock after effect operations on m are done */
static int libiso_msgs_unlock(struct libiso_msgs *m, int flag);
/** Create new empty message item.
@param link Previous item in queue
@param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success, <=0 failure
*/
static int libiso_msgs_item_new(struct libiso_msgs_item **item,
struct libiso_msgs_item *link, int flag);
/** Destroy a message item obtained by libiso_msgs_obtain(). The submitted
pointer gets set to NULL.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 for success, 0 for pointer to NULL
*/
static int libiso_msgs_item_destroy(struct libiso_msgs_item **item, int flag);
#endif /* LIBISO_MSGS_H_INTERNAL */
#endif /* ! LIBISO_MSGS_H_INCLUDED */

645
libisofs/libisofs.h Executable file → Normal file
View File

@ -13,6 +13,7 @@
#define LIBISO_LIBISOFS_H
#include <sys/types.h>
#include <stdint.h>
/* #include <libburn.h> */
struct burn_source;
@ -31,15 +32,44 @@ struct iso_volset;
/**
* A node in the filesystem tree.
*
* This is opaque struct that represent any kind of nodes. When needed,
* you can get the type with iso_tree_node_get_type and cast it to the
* appropiate subtype:
*
* iso_tree_node_dir
* iso_tree_node_file
* iso_tree_node_symlink
*
* \see tree.h
*/
struct iso_tree_node;
/**
* El-Torito boot image
* \see eltorito.h
* The type of an iso_tree_node.
* When an user gets an iso_tree_node from libisofs, (s)he can use
* iso_tree_node_get_type to get the current type of the node, and then
* cast to the appropriate subtype. For example:
*
* ...
* struct iso_tree_node *node = iso_tree_iter_next(iter);
* if ( iso_tree_node_get_type(node) == LIBISO_NODE_DIR ) {
* struct iso_tree_node_dir *dir = (struct iso_tree_node_dir *)node;
* ...
* }
*
* Useful macros are provided.
*/
struct el_torito_boot_image;
enum iso_tree_node_type {
LIBISO_NODE_DIR,
LIBISO_NODE_FILE,
LIBISO_NODE_SYMLINK,
LIBISO_NODE_BOOT
};
#define LIBISO_ISDIR(n) (iso_tree_node_get_type(n) == LIBISO_NODE_DIR)
#define LIBISO_ISREG(n) (iso_tree_node_get_type(n) == LIBISO_NODE_FILE)
#define LIBISO_ISLNK(n) (iso_tree_node_get_type(n) == LIBISO_NODE_SYMLINK)
/**
* A directory in the filesystem tree.
@ -48,6 +78,43 @@ struct el_torito_boot_image;
*/
struct iso_tree_node_dir;
/**
* A node in the filesystem tree that represents a regular file
*/
struct iso_tree_node_file;
/**
* A node in the filesystem tree that represents a symbolic link
*/
struct iso_tree_node_symlink;
/**
* A node that represents an El-Torito file.
*/
struct iso_tree_node_boot;
/**
* Information about El-Torito boot image.
* \see eltorito.h
*/
struct el_torito_boot_image;
/** Iterator for dir children. */
struct iso_tree_iter;
/**
* The procedence of the node.
*/
enum tree_node_from {
/** The node has been added by the user */
LIBISO_NEW = 0,
/**
* The node comes from a previous image. That can be from a previous
* session on disc, or from an ISO file we want to modify.
*/
LIBISO_PREVIMG
};
/**
* Extensions addition to ECMA-119 (ISO-9660) image. Usage of at least
* one of these flags is highly recommended if the disc will be used on a
@ -94,12 +161,47 @@ enum eltorito_boot_media_type {
ELTORITO_NO_EMUL
};
/**
* ISO-9660 (ECMA-119) has important restrictions in both file/dir names
* and deep of the directory hierarchy. These are intented for compatibility
* with old systems, and most modern operative system can safety deal with
* ISO filesystems with relaxed constraints.
* You can use some of these flags to generate that kind of filesystems with
* libisofs. Of course, all these options will lead to an image not conforming
* with ISO-9660 specification, so use them with caution.
* Moreover, note that there are much better options to have an ISO-9660 image
* compliant with modern systems, such as the Rock Ridge and Joliet extensions,
* that add support for longer filenames, deeper directory hierarchy and even
* file permissions (in case of RR), while keeping a standard ISO structure
* suitable for old systems.
* Thus, in most cases you don't want to use the relaxed constraints.
*/
enum ecma119_relaxed_constraints_flag {
ECMA119_OMIT_VERSION_NUMBERS = (1<<0),
/* 37 char filenames involves no version number */
/**<
* ISO-9660 requires a version number at the end of each file name.
* That number is just ignored on most systems, so you can omit them
* if you want.
*/
ECMA119_37_CHAR_FILENAMES = (1<<1) | (1<<0),
/**<
* Allow ISO-9660 filenames to be up to 37 characters long. The extra
* space is taken from the version number, so this option involves
* no version number
*/
ECMA119_NO_DIR_REALOCATION = (1<<2),
/**<
* In ISO-9660 images the depth of the directory hierarchy can't be
* greater than 8 levels. In addition, a path to a file on disc can't
* be more than 255 characteres. Use the ECMA119_NO_DIR_REALOCATION
* to disable this restriction.
*/
ECMA119_RELAXED_FILENAMES = (1<<3)
/**<
* Allow filenames with any character. Note that with this flag, the
* filename provide by the user will be used without any modification
* other that a truncate to max. length.
*/
};
/**
@ -110,6 +212,16 @@ struct ecma119_source_opts {
int level; /**< ISO level to write at. */
int flags; /**< Which extensions to support. */
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
unsigned int copy_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.
*/
unsigned int no_cache_inodes:1;
/**< If use inode caching or not. Set it to 1 to prevent
* inode caching.
@ -155,6 +267,120 @@ struct ecma119_source_opts {
uid_t uid; /**< uid to use when replace_uid is set. */
char *input_charset; /**< NULL to use default charset */
char *ouput_charset; /**< NULL to use default charset */
uint32_t ms_block;
/**<
* Start block for multisession. When this is greater than 0,
* it's suppossed to be the lba of the next writable address
* on disc; all block lba on image will take this into account,
* and files from a previous session will not be written on
* image. This behavior is only suitable for images to be
* appended to a multisession disc.
* When this is 0, no multisession image will be created. If
* some files are taken from a previous image, its contents
* will be written again to the new image. Use this with new
* images or if you plan to modify an existin image.
*/
struct data_source* src;
/**<
* When modifying a image, this is the source of the original
* image, used to read file contents.
* Otherwise it can be NULL.
*/
uint8_t *overwrite;
/**<
* When not NULL, it should point to a buffer of at least
* 64KiB, where libisofs will write the contents that should
* be written at the beginning of a overwriteable media, to
* grow the image.
* You shoudl 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.
*/
};
/**
* Options for image reading.
* There are four kind of options:
* - Related to multisession support.
* In most cases, an image begins at LBA 0 of the data source. However,
* in multisession discs, the later image begins in the last session on
* disc. The block option can be used to specify the start of that last
* session.
* - Related to the tree that will be read.
* As default, when Rock Ridge extensions are present in the image, that
* will be used to get the tree. If RR extensions are not present, libisofs
* will use the Joliet extensions if available. Finally, the plain ISO-9660
* tree is used if neither RR nor Joliet extensions are available. With
* norock, nojoliet, and preferjoliet options, you can change this
* default behavior.
* - Related to default POSIX attributes.
* When Rock Ridege extensions are not used, libisofs can't figure out what
* are the the permissions, uid or gid for the files. You should supply
* default values for that.
* - Return information for image.
* Both size, hasRR and hasJoliet will be filled by libisofs with suitable values.
* Also, error is set to non-0 if some error happens (error codes are
* private now)
*/
struct ecma119_read_opts {
uint32_t block; /** Block where the image begins, usually 0, can be
* different on a multisession disc.
*/
unsigned int norock:1; /*< Do not read Rock Ridge extensions */
unsigned int nojoliet:1; /*< Do not read Joliet extensions */
unsigned int preferjoliet:1;
/*< When both Joliet and RR extensions are present, the RR
* tree is used. If you prefer using Joliet, set this to 1. */
uid_t uid; /**< Default uid when no RR */
gid_t gid; /**< Default uid when no RR */
mode_t mode; /**< Default mode when no RR (only permissions) */
//TODO differ file and dir mode
//option to convert names to lower case?
/* modified by the function */
unsigned int hasRR:1; /*< It will be set to 1 if RR extensions are present,
to 0 if not. */
unsigned int hasJoliet:1; /*< It will be set to 1 if Joliet extensions are
present, to 0 if not. */
uint32_t size; /**< Will be filled with the size (in 2048 byte block) of
* the image, as reported in the PVM. */
int error;
};
/**
* Data source used by libisofs for reading an existing image.
* It contains suitable methods to read arbitrary block. Usually, the block
* size is 2048 bytes.
*/
struct data_source {
/**
* Reference count for the data source. Should be 1 when a new source
* is created. Increment it to take a reference for yourself. Use
* data_source_free to destroy your reference to it.
*/
int refcount;
/**
* Read data from the source.
* @param lba Block to be read.
* @param buffer Buffer where the data will be written. Its size must
* be at least 2048 bytes.
* @return
* 0 if ok, < 0 on error
*/
int (*read_block)(struct data_source *src, int lba, unsigned char *buffer);
/** Get the size (number of block) of the source's data */
int (*get_size)(struct data_source *);
/** Clean up the source specific data */
void (*free_data)(struct data_source *);
/** Source specific data */
void *data;
};
/**
@ -172,6 +398,8 @@ int libisofs_errno;
#define UNEXPECTED_FILE_TYPE 3
/* invalid boot image size */
#define ELTORITO_WRONG_IMAGE_SIZE 4
/* invalid image */
#define ELTORITO_WRONG_IMAGE 5
/**
* Controls the bahavior of iso_tree_radd_dir function
@ -185,6 +413,17 @@ struct iso_tree_radd_dir_behavior {
//char** errors;
};
/**
* Initialize libisofs. You must call this before any usage of the library.
* @return 1 on success, 0 on error
*/
int iso_init();
/**
* Finalize libisofs.
*/
void iso_finish();
/**
* Create a new volume.
* The parameters can be set to NULL if you wish to set them later.
@ -203,11 +442,18 @@ struct iso_volume *iso_volume_new_with_root(const char *volume_id,
*/
void iso_volume_free(struct iso_volume *volume);
void iso_volset_ref(struct iso_volset *volset);
/**
* Free a set of data volumes.
*/
void iso_volset_free(struct iso_volset *volume);
/**
* Get a volume from a volume set.
*/
struct iso_volume *iso_volset_get_volume(struct iso_volset *volset, int volnum);
/**
* Get the root directory for a volume.
*/
@ -219,30 +465,65 @@ struct iso_tree_node_dir *iso_volume_get_root(const struct iso_volume *volume);
void iso_volume_set_volume_id(struct iso_volume *volume,
const char *volume_id);
/**
* Get the volume identifier.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_volume_id(struct iso_volume *volume);
/**
* Fill in the publisher for a volume.
*/
void iso_volume_set_publisher_id(struct iso_volume *volume,
const char *publisher_id);
/**
* Get the publisher of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_publisher_id(struct iso_volume *volume);
/**
* Fill in the data preparer for a volume.
*/
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
const char *data_preparer_id);
/**
* Get the data preparer of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_data_preparer_id(struct iso_volume *volume);
/**
* Fill in the system id for a volume. Up to 32 characters.
*/
void iso_volume_set_system_id(struct iso_volume *volume,
const char *system_id);
/**
* Get the system id of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_system_id(struct iso_volume *volume);
/**
* Fill in the application id for a volume. Up to 128 chars.
*/
void iso_volume_set_application_id(struct iso_volume *volume,
const char *application_id);
/**
* Get the application id of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_application_id(struct iso_volume *volume);
/**
* Fill copyright information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
@ -250,6 +531,13 @@ void iso_volume_set_application_id(struct iso_volume *volume,
void iso_volume_set_copyright_file_id(struct iso_volume *volume,
const char *copyright_file_id);
/**
* Get the copyright information of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_copyright_file_id(struct iso_volume *volume);
/**
* Fill abstract information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
@ -257,6 +545,13 @@ void iso_volume_set_copyright_file_id(struct iso_volume *volume,
void iso_volume_set_abstract_file_id(struct iso_volume *volume,
const char *abstract_file_id);
/**
* Get the abstract information of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_abstract_file_id(struct iso_volume *volume);
/**
* Fill biblio information for the volume. Usually this refers
* to a file on disc. Up to 37 characters.
@ -264,9 +559,20 @@ void iso_volume_set_abstract_file_id(struct iso_volume *volume,
void iso_volume_set_biblio_file_id(struct iso_volume *volume,
const char *biblio_file_id);
/**
* Get the biblio information of a volume.
* The returned string is owned by libisofs and should not be freed nor
* changed.
*/
const char *iso_volume_get_biblio_file_id(struct iso_volume *volume);
/**
* Create a bootable volume by adding a El-Torito boot image.
*
* This also add a catalog tree node to the image filesystem tree. The tree
* node for the image will be replaced with a iso_tree_node_boot node, that
* acts as a placeholder for the real image.
*
* \param volume The volume to make bootable.
* \param image The tree node with the file to use as default boot image.
* \param type The boot media type. This can be one of 3 types:
@ -287,16 +593,60 @@ void iso_volume_set_biblio_file_id(struct iso_volume *volume,
*
* \pre \p volume is a volume without any boot catalog yet
* \pre \p image is a file tree node already inserted in the volume tree.
* \pre \p image is a file tree node that refers to a newly added file, not
* one from a previous session. FIXME allow prev session files too
* \pre \p dir is a directory node already inserted in the volume tree.
* \pre \p name There isn't any dir child with the same name.
*
*/
struct el_torito_boot_image *
iso_volume_create_boot_catalog(struct iso_volume *volume,
struct iso_tree_node *image,
enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir,
char *name);
struct el_torito_boot_image*
iso_volume_set_boot_image(struct iso_volume *volume,
struct iso_tree_node *image,
enum eltorito_boot_media_type type,
struct iso_tree_node_dir *dir,
char *name);
struct el_torito_boot_image*
iso_volume_set_boot_image_hidden(struct iso_volume *volume,
const char* path,
enum eltorito_boot_media_type type);
/**
* Get El-Torito boot image of the volume, if any.
*
* This can be useful, for example, to check if a volume read from a previous
* session or an existing image is bootable. It can also be useful to get
* the image and catalog tree nodes. An application would want those, for
* example, to prevent the user removing it.
*
* Both tree nodes are owned by libisofs and should not be freed. You can check
* if the node is already on the tree by getting its parent (note that when
* reading El-Torito info from a previous image, the nodes might not be on
* the tree even if you haven't removed them). Remember that you'll need to
* get a new ref (with iso_tree_node_ref()) before inserting them again to the
* tree, and probably you will also need to set the name or permissions.
*
* \param imgnode When not NULL, it will be filled with the image tree node, if
* any.
* \param catnode When not NULL, it will be filled with the catalog tree node,
* if any.
*
* \return The default El-Torito bootable image, or NULL is the volume is not
* bootable.
*/
struct el_torito_boot_image*
iso_volume_get_boot_image(struct iso_volume *volume,
struct iso_tree_node **imgnode,
struct iso_tree_node **catnode);
/**
* Removes the El-Torito bootable image. Both the catalog and image tree nodes
* are also removed from the image filesystem tree, if there.
* If the volume is not bootable (don't have el-torito image) this function is
* a nop.
*/
void
iso_volume_remove_boot_image(struct iso_volume *volume);
/**
* Sets the load segment for the initial boot image. This is only for
@ -322,12 +672,11 @@ el_torito_set_no_bootable(struct el_torito_boot_image *bootimg);
/**
* Specifies that this image needs to be patched. This involves the writting
* of a 56 bytes boot information table at offset 8 of the boot image file.
* Be aware that libisofs will modify original boot image file, so do a backup
* if needed.
* The original boot image file won't be modified.
* This is needed for isolinux boot images.
*/
void
el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg);
el_torito_patch_isolinux_image(struct el_torito_boot_image *bootimg);
/**
* Locate a node by its path on disc.
@ -336,13 +685,12 @@ el_torito_set_write_boot_info(struct el_torito_boot_image *bootimg);
* \param path The path, in the image, of the file.
*
* \return The node found or NULL.
*
* TODO we need a way to allow developers know which kind of node is.
* Think about this when designing the read api
*/
struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path);
/**
* TODO I don't like this kind of functions here. I think it should be
* in genisofs
* Add a file or a directory (recursively) to a volume by specifying its path on the volume.
*
* \param volume The volume to add the file to.
@ -356,6 +704,8 @@ struct iso_tree_node *iso_tree_volume_path_to_node(struct iso_volume *volume, co
// const char *path);
/**
* TODO I don't like this kind of functions here. I think it should be
* in genisofs
* Creates a new, empty directory on the volume.
*
* \param volume The volume to add the directory to.
@ -448,6 +798,9 @@ struct iso_tree_node *iso_tree_add_node(struct iso_tree_node_dir *parent,
const char *path);
/**
* TODO I don't like this kind of functions here. I think it should be
* in genisofs
*
* Recursively add an existing directory to the tree.
* Warning: when using this, you'll lose pointers to files or subdirectories.
* If you want to have pointers to all files and directories,
@ -462,11 +815,23 @@ struct iso_tree_node *iso_tree_add_node(struct iso_tree_node_dir *parent,
void iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
struct iso_tree_radd_dir_behavior *behavior);
/**
* Get the type of an iso_tree_node
*/
enum iso_tree_node_type iso_tree_node_get_type(struct iso_tree_node *node);
/**
* Set the name of a tree node (using the current locale).
*/
void iso_tree_node_set_name(struct iso_tree_node *node, const char *name);
/**
* Get the name of a tree node (using the current locale).
* The returned string belongs to the node and should not be modified nor
* freed. Use strdup if you really need your own copy.
*/
const char *iso_tree_node_get_name(struct iso_tree_node *node);
/**
* Set if the node will be hidden in RR/ISO tree, Joliet tree or both.
*
@ -485,18 +850,37 @@ void iso_tree_node_set_name(struct iso_tree_node *node, const char *name);
*/
void iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs);
/**
* Check if a node will be hidden in RR/ISO tree, Joliet tree or both.
*
* @return
* 0 if the node won't be hidden, otherwise you can AND the return value
* with hide_node_flag's to get in what trees the node will be hidden.
*/
int iso_tree_node_is_hidden(struct iso_tree_node *node);
/**
* Set the group id for the node. This attribute is only useful when
* Rock Ridge extensions are enabled.
*/
void iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid);
/**
* Get the group id of the node.
*/
gid_t iso_tree_node_get_gid(struct iso_tree_node *node);
/**
* Set the user id for the node. This attribute is only useful when
* Rock Ridge extensions are enabled.
*/
void iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid);
/**
* Get the user id of the node.
*/
uid_t iso_tree_node_get_uid(struct iso_tree_node *node);
/**
* Set the permissions for the node. This attribute is only useful when
* Rock Ridge extensions are enabled.
@ -507,6 +891,30 @@ void iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid);
*/
void iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode);
/** Get the permissions for the node */
mode_t iso_tree_node_get_permissions(struct iso_tree_node *node);
/** Get the size of the node, in bytes */
off_t iso_tree_node_get_size(struct iso_tree_node *node);
/** Set the time of last modification of the file */
void iso_tree_node_set_mtime(struct iso_tree_node *node, time_t time);
/** Get the time of last modification of the file */
time_t iso_tree_node_get_mtime(struct iso_tree_node *node);
/** Set the time of last access to the file */
void iso_tree_node_set_atime(struct iso_tree_node *node, time_t time);
/** Get the time of last access to the file */
time_t iso_tree_node_get_atime(struct iso_tree_node *node);
/** Set the time of last status change of the file */
void iso_tree_node_set_ctime(struct iso_tree_node *node, time_t time);
/** Get the time of last status change of the file */
time_t iso_tree_node_get_ctime(struct iso_tree_node *node);
/**
* Sets the order in which a node will be written on image. High weihted files
* will be written first, so in a disc them will be written near the center.
@ -519,6 +927,147 @@ void iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode);
*/
void iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w);
/**
* Sets the destination of a symbolic link
*/
void iso_tree_node_symlink_set_dest(struct iso_tree_node_symlink *node, const char *dest);
/**
* Get the destination of a symbolic link.
* The returned string is owned by libisofs and should not be freed nor modified.
*/
const char *iso_tree_node_symlink_get_dest(struct iso_tree_node_symlink *node);
/**
* Get an iterator for the children of the given dir.
* You can iterate over the children with iso_tree_iter_next. When finished,
* you should free the iterator with iso_tree_iter_free.
* You musn't delete a child of the same dir, using iso_tree_node_take() or
* iso_tree_node_remove(), while you're using the iterator. You can use
* iso_tree_node_take_iter() or iso_tree_node_remove_iter() instead.
*
* The usage of an iterator is:
*
* struct iso_tree_iter *iter;
* struct iso_tree_node *node;
* iter = iso_tree_node_children(dir);
* while ( (node = iso_tree_iter_next(iter)) != NULL ) {
* // do something with the child
* }
* iso_tree_iter_free(iter);
*
* An iterator is intended to be used in a single iteration over the
* children of a dir. Thus, it should be treated as a temporary object,
* and free as soon as possible.
*/
struct iso_tree_iter *iso_tree_node_children(struct iso_tree_node_dir *dir);
/**
* Get the next child.
* Take care that the node is owned by libisofs, and will be freed whit the
* tree it belongs. If you want your own ref to it, call iso_tree_node_ref()
* on it.
* This returns NULL if no more children are available.
*/
struct iso_tree_node *iso_tree_iter_next(struct iso_tree_iter *iter);
/**
* Check if there're more children.
* @return
* 1 if next call to iso_tree_iter_next() will return != NULL,
* 0 otherwise
*/
int iso_tree_iter_has_next(struct iso_tree_iter *iter);
/** Free an iteration */
void iso_tree_iter_free(struct iso_tree_iter *iter);
/**
* Removes a child from a directory.
* The child is not freed, so you will become the owner of the node. Later
* you can add the node to another dir (calling iso_tree_add_child), or free
* it if you don't need it (with iso_tree_free).
*
* @return 0 on success, -1 if the node doesn't belong to the dir.
*/
int iso_tree_node_take(struct iso_tree_node_dir *dir,
struct iso_tree_node *node);
/**
* Removes a child from a directory and free (unref) it.
* If you want to keep the child alive, you need to iso_tree_node_ref() it
* before this call, but in that case iso_tree_node_take() is a better
* alternative.
*
* @return 0 on success, -1 if the node doesn't belong to the dir (in this
* last case the node is not freed).
*/
int iso_tree_node_remove(struct iso_tree_node_dir *dir,
struct iso_tree_node *node);
/**
* Removes a child from a directory during an iteration, without freeing it.
* It's like iso_tree_node_take(), but to be used during a directory
* iteration.
* The node removed will be the last returned by the iteration.
*
* The behavior on two call to this function without calling iso_tree_iter_next
* between then is undefined, and should never occur. (TODO protect against this?)
*
* @return 0 on success, < 0 on an invalid usage, i.e., if the user call this
* before an inicial iso_tree_iter_next() or if last
* iso_tree_iter_next() has returned NULL.
*/
int iso_tree_node_take_iter(struct iso_tree_iter *iter);
/**
* Removes a child from a directory during an iteration and free it.
* It's like iso_tree_node_remove(), but to be used during a directory
* iteration.
* The node removed will be the last returned by the iteration.
*
* The behavior on two call to this function without calling iso_tree_iter_next
* between then is undefined, and should never occur. (TODO protect against this?)
*
* @return 0 on success, < 0 on an invalid usage, i.e., if the user call this
* before an inicial iso_tree_iter_next() or if last
* iso_tree_iter_next() has returned NULL.
*/
int iso_tree_node_remove_iter(struct iso_tree_iter *iter);
/*
* Get the parent of the given iso tree node.
* This returns NULL if the node is the root of the tree, or is a node
* that doesn't pertain to any tree (it was removed/take)
*/
struct iso_tree_node_dir *iso_tree_node_get_parent(struct iso_tree_node *node);
/**
* Adds a child to a directory.
* The child will be freed when the parent is freed, so you must be the
* owner of the child (maybe calling iso_tree_node_ref) before calling this.
*
* \pre parent has no child with the same name as \p child
*/
void iso_tree_add_child(struct iso_tree_node_dir *parent,
struct iso_tree_node *child);
/**
* Increments the reference counting of the given node.
* If you call this, you must remember call iso_tree_free when the
* node is no more needed.
*/
void iso_tree_node_ref(struct iso_tree_node *node);
/**
* Recursively free a directory.
*
* \param root The root of the directory heirarchy to free.
*
* \pre \p root is non-NULL.
*/
void iso_tree_free(struct iso_tree_node *root);
/**
* Recursively print a directory to stdout.
* \param spaces The initial number of spaces on the left. Set to 0 if you
@ -541,4 +1090,68 @@ void iso_tree_print(const struct iso_tree_node *root, int spaces);
struct burn_source* iso_source_new_ecma119(struct iso_volset *volumeset,
struct ecma119_source_opts *opts);
/**
* Creates a new data source from the given file.
*
* Returns NULL on error
*/
struct data_source *data_source_from_file(const char *path);
/** Free a given data source (decrease its refcount and maybe free it) */
void data_source_free(struct data_source*);
/**
* Read an existing ISO image.
*
* TODO documentar
*/
struct iso_volset *iso_volset_read(struct data_source *src,
struct ecma119_read_opts *opts);
/**
* Control queueing and stderr printing of messages from libisofs.
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
* "NOTE", "UPDATE", "DEBUG", "ALL".
*
* @param queue_severity Gives the minimum limit for messages to be queued.
* Default: "NEVER". If you queue messages then you
* must consume them by iso_msgs_obtain().
* @param print_severity Does the same for messages to be printed directly
* to stderr.
* @param print_id A text prefix to be printed before the message.
* @return >0 for success, <=0 for error
*/
int iso_msgs_set_severities(char *queue_severity,
char *print_severity, char *print_id);
#define ISO_MSGS_MESSAGE_LEN 4096
/**
* Obtain the oldest pending libisofs message from the queue which has at
* least the given minimum_severity. This message and any older message of
* lower severity will get discarded from the queue and is then lost forever.
*
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
* "NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
* will discard the whole queue.
*
* @param error_code Will become a unique error code as listed in messages.h
* @param 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
* should provide at least 80 bytes.
* @return 1 if a matching item was found, 0 if not, <0 for severe errors
*/
int iso_msgs_obtain(char *minimum_severity,
int *error_code, char msg_text[], int *os_errno,
char severity[]);
/** Return the messenger object handle used by libisofs. This handle
may be used by related libraries to replace 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(void);
#endif /* LIBISO_LIBISOFS_H */

160
libisofs/messages.c Normal file
View File

@ -0,0 +1,160 @@
#include <stdlib.h>
#include <string.h>
#include "libisofs.h"
#include "messages.h"
struct libiso_msgs *libiso_messenger = NULL;
int iso_init()
{
if (libiso_messenger == NULL) {
if (libiso_msgs_new(&libiso_messenger, 0) <= 0)
return 0;
}
libiso_msgs_set_severities(libiso_messenger, LIBISO_MSGS_SEV_NEVER,
LIBISO_MSGS_SEV_FATAL, "libisofs: ", 0);
return 1;
}
void iso_finish()
{
libiso_msgs_destroy(&libiso_messenger,0);
}
void iso_msg_debug(char *msg_text)
{
libiso_msgs_submit(libiso_messenger, -1, 0x00000002,
LIBISO_MSGS_SEV_DEBUG, LIBISO_MSGS_PRIO_ZERO,
msg_text, 0, 0);
}
void iso_msg_note(int error_code, char *msg_text)
{
libiso_msgs_submit(libiso_messenger, -1, error_code,
LIBISO_MSGS_SEV_NOTE, LIBISO_MSGS_PRIO_MEDIUM,
msg_text, 0, 0);
}
void iso_msg_hint(int error_code, char *msg_text)
{
libiso_msgs_submit(libiso_messenger, -1, error_code,
LIBISO_MSGS_SEV_HINT, LIBISO_MSGS_PRIO_MEDIUM,
msg_text, 0, 0);
}
void iso_msg_warn(int error_code, char *msg_text)
{
libiso_msgs_submit(libiso_messenger, -1, error_code,
LIBISO_MSGS_SEV_WARNING, LIBISO_MSGS_PRIO_MEDIUM,
msg_text, 0, 0);
}
void iso_msg_sorry(int error_code, char *msg_text)
{
libiso_msgs_submit(libiso_messenger, -1, error_code,
LIBISO_MSGS_SEV_SORRY, LIBISO_MSGS_PRIO_HIGH,
msg_text, 0, 0);
}
void iso_msg_fatal(int error_code, char *msg_text)
{
libiso_msgs_submit(libiso_messenger, -1, error_code,
LIBISO_MSGS_SEV_FATAL, LIBISO_MSGS_PRIO_HIGH,
msg_text, 0, 0);
}
/**
* Control queueing and stderr printing of messages from libisofs.
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
* "NOTE", "UPDATE", "DEBUG", "ALL".
*
* @param queue_severity Gives the minimum limit for messages to be queued.
* Default: "NEVER". If you queue messages then you
* must consume them by iso_msgs_obtain().
* @param print_severity Does the same for messages to be printed directly
* to stderr.
* @param print_id A text prefix to be printed before the message.
* @return >0 for success, <=0 for error
*/
int iso_msgs_set_severities(char *queue_severity,
char *print_severity, char *print_id)
{
int ret, queue_sevno, print_sevno;
ret = libiso_msgs__text_to_sev(queue_severity, &queue_sevno, 0);
if (ret <= 0)
return 0;
ret = libiso_msgs__text_to_sev(print_severity, &print_sevno, 0);
if (ret <= 0)
return 0;
ret = libiso_msgs_set_severities(libiso_messenger, queue_sevno,
print_sevno, print_id, 0);
if (ret <= 0)
return 0;
return 1;
}
#define ISO_MSGS_MESSAGE_LEN 4096
/**
* Obtain the oldest pending libisofs message from the queue which has at
* least the given minimum_severity. This message and any older message of
* lower severity will get discarded from the queue and is then lost forever.
*
* Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
* "NOTE", "UPDATE", "DEBUG", "ALL". To call with minimum_severity "NEVER"
* will discard the whole queue.
*
* @param error_code Will become a unique error code as listed in messages.h
* @param 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
* should provide at least 80 bytes.
* @return 1 if a matching item was found, 0 if not, <0 for severe errors
*/
int iso_msgs_obtain(char *minimum_severity,
int *error_code, char msg_text[], int *os_errno,
char severity[])
{
int ret, minimum_sevno, sevno, priority;
char *textpt, *sev_name;
struct libiso_msgs_item *item = NULL;
if (libiso_messenger == NULL)
return 0;
ret = libiso_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
if (ret <= 0)
return 0;
ret = libiso_msgs_obtain(libiso_messenger, &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;
severity[0]= 0;
ret = libiso_msgs_item_get_rank(item, &sevno, &priority, 0);
if(ret <= 0)
goto ex;
ret = libiso_msgs__sev_to_text(sevno, &sev_name, 0);
if(ret <= 0)
goto ex;
strcpy(severity,sev_name);
ret = 1;
ex:
libiso_msgs_destroy_item(libiso_messenger, &item, 0);
return ret;
}
void *iso_get_messenger(void)
{
return libiso_messenger;
}

67
libisofs/messages.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Message handling for libisofs
*/
#ifndef MESSAGES_H_
#define MESSAGES_H_
#include "libiso_msgs.h"
/** Can't read file (ignored) */
#define LIBISO_CANT_READ_FILE 0x00031001
/** Can't read file (operation canceled) */
#define LIBISO_FILE_READ_ERROR 0x00031002
/** 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 */
#define LIBISO_UNSUPPORTED_VD 0x00031001
/** damaged image */
#define LIBISO_WRONG_IMG 0x00031002
/** Can't read previous image file */
#define LIBISO_CANT_READ_IMG 0x00031003
/* 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. */
#define LIBISO_BOOT_VD_UNHANLED 0x00030201
/** Wrong or damaged el-torito catalog */
#define LIBISO_EL_TORITO_WRONG 0x00030202
/** Unsupproted el-torito feature */
#define LIBISO_EL_TORITO_UNHANLED 0x00030203
/** 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_*/

2
libisofs/rockridge.c Executable file → Normal file
View File

@ -14,7 +14,7 @@
#include <unistd.h>
#include <sys/stat.h>
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
/** See IEEE P1281 Draft Version 1.12/5.5 */
void
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{

0
libisofs/rockridge.h Executable file → Normal file
View File

6
libisofs/susp.c Executable file → Normal file
View File

@ -205,10 +205,8 @@ susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
assert(dir->type = ECMA119_DIR);
if (dir->info.dir.depth != 1) {
susp_fin_CE(t, dir);
}
susp_fin_CE(t, dir);
for (i = 0; i < dir->info.dir.nchildren; i++) {
if (dir->info.dir.children[i]->type == ECMA119_DIR)
susp_finalize(t, dir->info.dir.children[i]);

0
libisofs/susp.h Executable file → Normal file
View File

305
libisofs/tree.c Executable file → Normal file
View File

@ -36,7 +36,8 @@ void
iso_tree_add_child(struct iso_tree_node_dir *parent,
struct iso_tree_node *child)
{
assert( parent && child);
assert(parent && child);
assert(!child->parent);
parent->nchildren++;
parent->children =
@ -53,6 +54,7 @@ iso_tree_new_root()
root = calloc(1, sizeof(struct iso_tree_node_dir));
set_default_stat(&root->node.attrib);
root->node.refcount = 1;
root->node.attrib.st_mode = S_IFDIR | 0777;
root->node.type = LIBISO_NODE_DIR;
return root;
@ -85,8 +87,9 @@ iso_tree_add_file(struct iso_tree_node_dir *parent, const char *path)
f = calloc(1, sizeof(struct iso_tree_node_file));
/* fill fields */
f->node.refcount = 1;
f->node.attrib = st;
f->path = strdup(path);
f->loc.path = strdup(path);
f->node.type = LIBISO_NODE_FILE;
p = strdup(path); /* because basename() might modify its arg */
@ -111,7 +114,8 @@ iso_tree_add_symlink(struct iso_tree_node_dir *parent,
/* fill fields */
set_default_stat(&link->node.attrib);
link->node.attrib.st_mode |= S_IFLNK;//TODO Not needed
link->node.refcount = 1;
link->node.attrib.st_mode |= S_IFLNK;
link->node.name = strdup(name);
link->node.type = LIBISO_NODE_SYMLINK;
link->dest = strdup(dest);
@ -132,6 +136,7 @@ iso_tree_add_dir(struct iso_tree_node_dir *parent,
dir = calloc(1, sizeof(struct iso_tree_node_dir));
dir->node.refcount = 1;
dir->node.attrib = parent->node.attrib;
dir->node.type = LIBISO_NODE_DIR;
dir->node.name = strdup(name);
@ -140,6 +145,13 @@ iso_tree_add_dir(struct iso_tree_node_dir *parent,
return dir;
}
enum iso_tree_node_type
iso_tree_node_get_type(struct iso_tree_node *node)
{
assert(node);
return node->type;
}
void
iso_tree_node_set_name(struct iso_tree_node *node, const char *name)
{
@ -147,6 +159,13 @@ iso_tree_node_set_name(struct iso_tree_node *node, const char *name)
node->name = strdup(name);
}
const char *
iso_tree_node_get_name(struct iso_tree_node *node)
{
assert(node);
return node->name;
}
void
iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs)
{
@ -154,6 +173,13 @@ iso_tree_node_set_hidden(struct iso_tree_node *node, int hide_attrs)
node->hide_flags = hide_attrs;
}
int
iso_tree_node_is_hidden(struct iso_tree_node *node)
{
assert(node);
return node->hide_flags;
}
void
iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid)
{
@ -161,6 +187,13 @@ iso_tree_node_set_gid(struct iso_tree_node *node, gid_t gid)
node->attrib.st_gid = gid;
}
gid_t
iso_tree_node_get_gid(struct iso_tree_node *node)
{
assert(node);
return node->attrib.st_gid;
}
void
iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid)
{
@ -168,6 +201,13 @@ iso_tree_node_set_uid(struct iso_tree_node *node, uid_t uid)
node->attrib.st_uid = uid;
}
uid_t
iso_tree_node_get_uid(struct iso_tree_node *node)
{
assert(node);
return node->attrib.st_uid;
}
void
iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode)
{
@ -176,6 +216,55 @@ iso_tree_node_set_permissions(struct iso_tree_node *node, mode_t mode)
(mode & ~S_IFMT);
}
mode_t
iso_tree_node_get_permissions(struct iso_tree_node *node)
{
assert(node);
return node->attrib.st_mode & ~S_IFMT;
}
off_t
iso_tree_node_get_size(struct iso_tree_node *node)
{
return node->attrib.st_size;
}
void
iso_tree_node_set_mtime(struct iso_tree_node *node, time_t time)
{
node->attrib.st_mtime = time;
}
time_t
iso_tree_node_get_mtime(struct iso_tree_node *node)
{
return node->attrib.st_mtime;
}
void
iso_tree_node_set_atime(struct iso_tree_node *node, time_t time)
{
node->attrib.st_atime = time;
}
time_t
iso_tree_node_get_atime(struct iso_tree_node *node)
{
return node->attrib.st_atime;
}
void
iso_tree_node_set_ctime(struct iso_tree_node *node, time_t time)
{
node->attrib.st_ctime = time;
}
time_t
iso_tree_node_get_ctime(struct iso_tree_node *node)
{
return node->attrib.st_ctime;
}
void
iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w)
{
@ -194,6 +283,22 @@ iso_tree_node_set_sort_weight(struct iso_tree_node *node, int w)
}
}
void
iso_tree_node_symlink_set_dest(struct iso_tree_node_symlink *node,
const char *dest)
{
assert(node && dest);
free(node->dest);
node->dest = strdup(dest);
}
const char *
iso_tree_node_symlink_get_dest(struct iso_tree_node_symlink *node)
{
assert(node);
return node->dest;
}
struct iso_tree_node*
iso_tree_add_node(struct iso_tree_node_dir *parent,
const char *path)
@ -255,28 +360,186 @@ iso_tree_add_node(struct iso_tree_node_dir *parent,
return node;
}
struct iso_tree_iter *
iso_tree_node_children(struct iso_tree_node_dir *dir)
{
struct iso_tree_iter *iter;
assert(dir);
iter = malloc(sizeof(struct iso_tree_iter));
iter->dir = dir;
iter->index = -1;
return iter;
}
struct iso_tree_node *
iso_tree_iter_next(struct iso_tree_iter *iter)
{
assert(iter);
if ( ++iter->index < iter->dir->nchildren )
return iter->dir->children[iter->index];
else
return NULL;
}
int
iso_tree_iter_has_next(struct iso_tree_iter *iter)
{
assert(iter);
return iter->index + 1 < iter->dir->nchildren;
}
void
iso_tree_iter_free(struct iso_tree_iter *iter)
{
free(iter);
}
int
iso_tree_node_take(struct iso_tree_node_dir *dir, struct iso_tree_node *node)
{
int i;
assert(dir && node);
/* search for the node in the dir */
for (i = 0; i < dir->nchildren; ++i) {
if ( dir->children[i] == node )
break;
}
if (i < dir->nchildren) {
int j;
for (j = i+1; j < dir->nchildren; ++j) {
dir->children[j-1] = dir->children[j];
}
--dir->nchildren;
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
node->parent = NULL;
return 0;
} else {
/* the node doesn't exist on dir */
return -1;
}
}
int
iso_tree_node_remove(struct iso_tree_node_dir *dir, struct iso_tree_node *node)
{
int res;
assert(dir && node);
res = iso_tree_node_take(dir, node);
if (!res)
iso_tree_free(node);
return res;
}
int
iso_tree_node_take_iter(struct iso_tree_iter *iter)
{
int j;
struct iso_tree_node_dir *dir;
struct iso_tree_node *node;
assert(iter);
dir = iter->dir;
if (iter->index < 0)
return -1; /* index before beginning */
if (iter->index >= dir->nchildren)
return -2; /* index after end */
node = dir->children[iter->index];
node->parent = NULL;
for (j = iter->index+1; j < dir->nchildren; ++j) {
dir->children[j-1] = dir->children[j];
}
--dir->nchildren;
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
/* update iter index */
--iter->index;
return 0;
}
int
iso_tree_node_remove_iter(struct iso_tree_iter *iter)
{
int j;
struct iso_tree_node_dir *dir;
struct iso_tree_node *node;
assert(iter);
dir = iter->dir;
if (iter->index < 0)
return -1; /* index before beginning */
if (iter->index >= dir->nchildren)
return -2; /* index after end */
node = dir->children[iter->index];
for (j = iter->index+1; j < dir->nchildren; ++j) {
dir->children[j-1] = dir->children[j];
}
--dir->nchildren;
dir->children = realloc(dir->children, dir->nchildren * sizeof(void*));
/* update iter index */
--iter->index;
/* and free node */
node->parent = NULL;
iso_tree_free(node);
return 0;
}
struct iso_tree_node_dir *
iso_tree_node_get_parent(struct iso_tree_node *node)
{
assert(node);
return node->parent;
}
void
iso_tree_node_ref(struct iso_tree_node *node)
{
++node->refcount;
}
void
iso_tree_free(struct iso_tree_node *root)
{
if ( ISO_ISDIR(root) ) {
size_t i;
struct iso_tree_node_dir *dir;
dir = (struct iso_tree_node_dir *) root;
for (i=0; i < dir->nchildren; i++) {
iso_tree_free(dir->children[i]);
if (!root)
return;
if (--root->refcount < 1) {
if ( ISO_ISDIR(root) ) {
size_t i;
struct iso_tree_node_dir *dir;
dir = (struct iso_tree_node_dir *) root;
for (i=0; i < dir->nchildren; i++) {
iso_tree_free(dir->children[i]);
}
free(dir->children);
} else if ( ISO_ISLNK(root) ) {
struct iso_tree_node_symlink *link;
link = (struct iso_tree_node_symlink *) root;
free(link->dest);
} else if ( ISO_ISREG(root) ) {
struct iso_tree_node_file *file;
file = (struct iso_tree_node_file *) root;
if (root->procedence == LIBISO_NEW)
free(file->loc.path);
} else if ( ISO_ISBOOT(root) ) {
struct iso_tree_node_boot *boot;
boot = (struct iso_tree_node_boot *) root;
if (root->procedence == LIBISO_NEW && boot->img)
free(boot->loc.path);
}
free(dir->children);
} else if ( ISO_ISLNK(root) ) {
struct iso_tree_node_symlink *link;
link = (struct iso_tree_node_symlink *) root;
free(link->dest);
} else if ( ISO_ISREG(root) ) {
struct iso_tree_node_file *file;
file = (struct iso_tree_node_file *) root;
free(file->path);
free(root->name);
free(root);
}
free(root->name);
free(root);
}
static void
@ -352,8 +615,6 @@ iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
/* clear hashtable */
iso_exclude_empty(&table);
return dir;
}
void

91
libisofs/tree.h Executable file → Normal file
View File

@ -8,7 +8,7 @@
* (for multisession).
*
* This tree preserves as much information as it can about the files; names
* are stored in wchar_t and we preserve POSIX attributes. This tree does
* are stored in UTF-8 and we preserve POSIX attributes. This tree does
* *not* include information that is necessary for writing out, for example,
* an ISO level 1 tree. That information will go in a different tree because
* the structure is sufficiently different.
@ -20,42 +20,29 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <wchar.h>
#include "libisofs.h"
//enum file_location {
// LIBISO_FILESYS,
// LIBISO_PREVSESSION,
// LIBISO_NONE /**< for files/dirs that were added with
// * iso_tree_add_new_XXX. */
//};
/**
* This tells us where to read the data from a file. Either we read from the
* local filesystem or we just point to the block on a previous session.
*/
//struct iso_file_location
//{
// enum file_location type;
// /* union {*/
// char *path; /* in the current locale */
// uint32_t block;
// /* };*/
//};
enum iso_tree_node_type {
LIBISO_NODE_DIR,
LIBISO_NODE_FILE,
LIBISO_NODE_SYMLINK,
LIBISO_NODE_BOOTCATALOG
};
/**
* A node in the filesystem tree.
*/
struct iso_tree_node
{
/*
* Reference counter:
* - When created, refcount is set to 1
* - One node is automatically free when free the tree (i.e., dir) it
* belongs, and the tree is automatically freed when the volume it
* belongs is also freed.
* - If the user deon't add the tree to a volume, (s)he has to free the
* tree.
* - If the user doesn't add a node to a tree (dir), for example after
* taken it with iso_tree_node_take(), it should free the node when
* no more needed.
* - If the user wants an own ref, it should call iso_tree_node_ref()
* function to get that ref, and free the node when no more needed.
*/
int refcount;
struct iso_tree_node_dir *parent;
char *name;
struct stat attrib; /**< The POSIX attributes of this node as
@ -63,7 +50,8 @@ struct iso_tree_node
int hide_flags; /**< If the node is to be hidden in RR/ISO or
* Joilet tree */
enum iso_tree_node_type type;
enum tree_node_from procedence; /**< Procedence of the node. */
enum iso_tree_node_type type; /**< Type of the node. */
};
/**
@ -73,20 +61,16 @@ struct iso_tree_node_file
{
struct iso_tree_node node;
char *path; /**< the path of the file on local filesystem */
int sort_weight; /**< It sorts the order in which the file data is
* written to the CD image. Higher weighting files
* are written at the beginning of image */
/* when read from an existing ISO image, we need to store the
* block where file contents are written, and not the path.
* Maybe instead of a char *path we will need to go back to
* struct iso_file_location loc;
*/
/* struct iso_file_location loc; */
/**< Only used for regular files and symbolic
* links (ie. files for which we might have to
* copy data). */
union {
char *path; /**< the path of the file on local filesystem */
uint32_t block; /**< If the file is from a previous session.
* Maybe we can put this in iso_tree_node later.
*/
} loc;
};
/**
@ -112,19 +96,27 @@ struct iso_tree_node_dir
};
/**
* Recursively free a directory.
*
* \param root The root of the directory heirarchy to free.
*
* \pre \p root is non-NULL.
* Tree node that corresponds to some El-Torito artifact.
* This can be either the boot catalog or a bootable image.
*/
void iso_tree_free(struct iso_tree_node *root);
struct iso_tree_node_boot
{
struct iso_tree_node node;
unsigned int img:1; /*< 1 if img, 0 if catalog */
union {
char *path; /**< the path of the file on local filesystem */
uint32_t block; /**< If the file is from a previous session.*/
} loc;
};
/**
* Adds a child to a directory
* An iterator for directory children.
*/
void iso_tree_add_child(struct iso_tree_node_dir *parent,
struct iso_tree_node *child);
struct iso_tree_iter
{
struct iso_tree_node_dir *dir;
int index;
};
/**
* A function that prints verbose information about a directory.
@ -173,5 +165,6 @@ void iso_tree_print_verbose(const struct iso_tree_node *root,
#define ISO_ISDIR(n) (n->type == LIBISO_NODE_DIR)
#define ISO_ISREG(n) (n->type == LIBISO_NODE_FILE)
#define ISO_ISLNK(n) (n->type == LIBISO_NODE_SYMLINK)
#define ISO_ISBOOT(n) (n->type == LIBISO_NODE_BOOT)
#endif /* LIBISO_TREE_H */

80
libisofs/util.c Executable file → Normal file
View File

@ -16,6 +16,7 @@
#include <ctype.h>
#include <assert.h>
#include <errno.h>
#include <langinfo.h>
#include <locale.h>
#include <limits.h>
@ -546,6 +547,7 @@ iso_r_fileid(const char *src_arg, const char *icharset, int flag)
char *dest;
char *dot;
int lname, lext, lnname, lnext, pos, i;
size_t max;
size_t size = flag & (1<<1) ? 37 : 33;
@ -570,7 +572,7 @@ iso_r_fileid(const char *src_arg, const char *icharset, int flag)
/* no relaxed filenames */
dot = strrchr(src, '.');
size_t max = size == 37 ? 36 : 30;
max = (size == 37 ? 36 : 30);
/* Since the maximum length can be divided freely over the name and
extension, we need to calculate their new lengths (lnname and
lnext). If the original filename is too long, we start by trimming
@ -713,13 +715,12 @@ time_t iso_datetime_read_7(const uint8_t *buf)
struct tm tm;
tm.tm_year = buf[0];
tm.tm_mon = buf[1] + 1;
tm.tm_mon = buf[1] - 1;
tm.tm_mday = buf[2];
tm.tm_hour = buf[3];
tm.tm_min = buf[4];
tm.tm_sec = buf[5];
return mktime(&tm) - buf[6] * 60 * 60;
return timegm(&tm) - buf[6] * 60 * 15;
}
void iso_datetime_17(unsigned char *buf, time_t t)
@ -771,7 +772,7 @@ time_t iso_datetime_read_17(const uint8_t *buf)
tm.tm_year -= 1900;
tm.tm_mon -= 1;
return mktime(&tm) - buf[16] * 60 * 60;
return timegm(&tm) - buf[16] * 60 * 15;
}
size_t ucslen(const uint16_t *str)
@ -832,11 +833,74 @@ uint32_t iso_read_msb(const uint8_t *buf, int bytes)
return ret;
}
uint32_t iso_read_bb(const uint8_t *buf, int bytes)
uint32_t iso_read_bb(const uint8_t *buf, int bytes, int *error)
{
uint32_t v1 = iso_read_lsb(buf, bytes);
uint32_t v2 = iso_read_msb(buf+bytes, bytes);
assert(v1 == v2);
if (error) {
uint32_t v2 = iso_read_msb(buf+bytes, bytes);
if (v1 != v2)
*error = 1;
}
return v1;
}
char *strcopy(const char *buf, size_t len)
{
char *str;
str = malloc( (len+1) * sizeof(char) );
strncpy(str, buf, len);
str[len] = '\0';
/* remove trailing spaces */
for (len = len-1; str[len] == ' ' && len > 0; --len)
str[len] = '\0';
return str;
}
char *ucs2str(const char *buf, size_t len)
{
size_t outbytes, inbytes;
char *str;
inbytes = len;
outbytes = (inbytes+1) * MB_LEN_MAX;
{
/* ensure enought space */
char out[outbytes];
char *src;
iconv_t conv;
size_t n;
/* convert to local charset */
setlocale(LC_CTYPE, "");
conv = iconv_open(nl_langinfo(CODESET), "UCS-2BE");
if (conv == (iconv_t)(-1)) {
printf("Can't convert from %s to %s\n", "UCS-2BE", nl_langinfo(CODESET));
return NULL;
}
src = (char *)buf;
str = (char *)out;
n = iconv(conv, &src, &inbytes, &str, &outbytes);
if (n == -1) {
/* error just return input stream */
perror("Convert error.");
printf("Maybe string is not encoded in UCS-2BE.\n");
iconv_close(conv);
return NULL;
}
iconv_close(conv);
*str = '\0';
/* remove trailing spaces */
for (len = strlen(out) - 1; out[len] == ' ' && len > 0; --len)
out[len] = '\0';
str = strdup(out);
}
return str;
}

19
libisofs/util.h Executable file → Normal file
View File

@ -112,7 +112,12 @@ void iso_bb(uint8_t *buf, uint32_t num, int bytes);
uint32_t iso_read_lsb(const uint8_t *buf, int bytes);
uint32_t iso_read_msb(const uint8_t *buf, int bytes);
uint32_t iso_read_bb(const uint8_t *buf, int bytes);
/**
* if error != NULL it will be set to 1 if LSB and MSB integers
* don't match
*/
uint32_t iso_read_bb(const uint8_t *buf, int bytes, int *error);
/** Records the date/time into a 7 byte buffer (9.1.5) */
void iso_datetime_7(uint8_t *buf, time_t t);
@ -133,4 +138,16 @@ size_t ucslen(const uint16_t *str);
*/
int ucscmp(const uint16_t *s1, const uint16_t *s2);
/**
* Copy up to \p len chars from \p buf and return this newly allocated
* string. The new string is null-terminated.
*/
char *strcopy(const char *buf, size_t len);
/**
* Convert a Joliet string with a length of \p len bytes to a new string
* in local charset.
*/
char *ucs2str(const char *buf, size_t len);
#endif /* LIBISO_UTIL_H */

82
libisofs/volume.c Executable file → Normal file
View File

@ -1,6 +1,7 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set ts=8 sts=8 sw=8 noet : */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
@ -24,6 +25,12 @@ iso_volset_new(struct iso_volume *vol, const char *id)
return volset;
}
void
iso_volset_ref(struct iso_volset *volset)
{
++volset->refcount;
}
void
iso_volset_free(struct iso_volset *volset)
{
@ -38,6 +45,16 @@ iso_volset_free(struct iso_volset *volset)
}
}
struct iso_volume *
iso_volset_get_volume(struct iso_volset *volset, int volnum)
{
assert(volset);
if (volnum < volset->volset_size)
return volset->volume[volnum];
else
return NULL;
}
struct iso_volume*
iso_volume_new(const char *volume_id,
const char *publisher_id,
@ -95,65 +112,130 @@ iso_volume_free(struct iso_volume *volume)
struct iso_tree_node_dir *
iso_volume_get_root(const struct iso_volume *volume)
{
assert(volume);
return volume->root;
}
void iso_volume_set_volume_id(struct iso_volume *volume,
const char *volume_id)
{
assert(volume);
free(volume->volume_id);
volume->volume_id = strdup(volume_id);
}
const char *
iso_volume_get_volume_id(struct iso_volume *volume)
{
assert(volume);
return volume->volume_id;
}
void iso_volume_set_publisher_id(struct iso_volume *volume,
const char *publisher_id)
{
assert(volume);
free(volume->publisher_id);
volume->publisher_id = strdup(publisher_id);
}
const char *
iso_volume_get_publisher_id(struct iso_volume *volume)
{
assert(volume);
return volume->publisher_id;
}
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
const char *data_preparer_id)
{
assert(volume);
free(volume->data_preparer_id);
volume->data_preparer_id = strdup(data_preparer_id);
}
const char *
iso_volume_get_data_preparer_id(struct iso_volume *volume)
{
assert(volume);
return volume->data_preparer_id;
}
void iso_volume_set_system_id(struct iso_volume *volume,
const char *system_id)
{
assert(volume);
free(volume->system_id);
volume->system_id = strdup(system_id);
}
const char *
iso_volume_get_system_id(struct iso_volume *volume)
{
assert(volume);
return volume->system_id;
}
void iso_volume_set_application_id(struct iso_volume *volume,
const char *application_id)
{
assert(volume);
free(volume->application_id);
volume->application_id = strdup(application_id);
}
const char *
iso_volume_get_application_id(struct iso_volume *volume)
{
assert(volume);
return volume->application_id;
}
void iso_volume_set_copyright_file_id(struct iso_volume *volume,
const char *copyright_file_id)
{
assert(volume);
free(volume->copyright_file_id);
volume->copyright_file_id = strdup(copyright_file_id);
}
const char *
iso_volume_get_copyright_file_id(struct iso_volume *volume)
{
assert(volume);
return volume->copyright_file_id;
}
void iso_volume_set_abstract_file_id(struct iso_volume *volume,
const char *abstract_file_id)
{
assert(volume);
free(volume->abstract_file_id);
volume->abstract_file_id = strdup(abstract_file_id);
}
const char *
iso_volume_get_abstract_file_id(struct iso_volume *volume)
{
assert(volume);
return volume->abstract_file_id;
}
void iso_volume_set_biblio_file_id(struct iso_volume *volume,
const char *biblio_file_id)
{
assert(volume);
free(volume->biblio_file_id);
volume->biblio_file_id = strdup(biblio_file_id);
}
const char *
iso_volume_get_biblio_file_id(struct iso_volume *volume)
{
assert(volume);
return volume->biblio_file_id;
}
struct iso_tree_node *
iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
{

0
libisofs/volume.h Executable file → Normal file
View File

View File

@ -20,29 +20,32 @@
#define SECSIZE 2048
const char * const optstring = "JRL:b:h";
const char * const optstring = "JRL:b:hV:";
extern char *optarg;
extern int optind;
void usage()
void usage(char **argv)
{
printf("test [OPTIONS] DIRECTORY OUTPUT\n");
printf("%s [OPTIONS] DIRECTORY OUTPUT\n", argv[0]);
help();
}
void help()
{
printf(
"Options:\n"
" -J Add Joliet support\n"
" -R Add Rock Ridge support\n"
" -L <num> Set the ISO level (1 or 2)\n"
" -b file Specifies a boot image to add to image\n"
" -h Print this message\n"
" -J Add Joliet support\n"
" -R Add Rock Ridge 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 main(int argc, char **argv)
{
struct ecma119_source_opts opts;
struct iso_volset *volset;
struct iso_volume *volume;
struct iso_tree_node_dir *root;
@ -50,14 +53,16 @@ int main(int argc, char **argv)
unsigned char buf[2048];
FILE *fd;
int c;
int constraints;
struct iso_tree_radd_dir_behavior behav = {0,0,0};
int level=1, flags=0;
char *boot_img = NULL;
char *volid = "VOLID";
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
case 'h':
usage();
usage(argv);
help();
exit(0);
break;
@ -73,8 +78,11 @@ int main(int argc, char **argv)
case 'b':
boot_img = optarg;
break;
case 'V':
volid = optarg;
break;
case '?':
usage();
usage(argv);
exit(1);
break;
}
@ -82,14 +90,20 @@ int main(int argc, char **argv)
if (argc < 2) {
printf ("Please pass directory from which to build ISO\n");
usage();
usage(argv);
return 1;
}
if (argc < 3) {
printf ("Please supply output file\n");
usage();
usage(argv);
return 1;
}
if (!iso_init()) {
err(1, "Can't init libisofs");
}
iso_msgs_set_severities("NEVER", "ALL", "");
fd = fopen(argv[optind+1], "w");
if (!fd) {
err(1, "error opening output file");
@ -100,21 +114,25 @@ int main(int argc, char **argv)
if (!root) {
err(1, "error opening input directory");
}
volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root );
volume = iso_volume_new_with_root(volid, "PUBID", "PREPID", root);
if ( boot_img ) {
/* adds El-Torito boot info. Tunned for isolinux */
struct el_torito_boot_image *bootimg;
struct iso_tree_node_dir *boot = (struct iso_tree_node_dir *)
iso_tree_volume_path_to_node(volume, "isolinux");
struct iso_tree_node *img = iso_tree_volume_path_to_node(volume, boot_img);
if (!img) {
err(1, "boot image patch is not valid");
}
struct el_torito_boot_image *bootimg =
iso_volume_create_boot_catalog(volume, img, ELTORITO_NO_EMUL,
boot, "boot.cat");
bootimg = iso_volume_set_boot_image(volume, img, ELTORITO_NO_EMUL,
boot, "boot.cat");
el_torito_set_load_size(bootimg, 4);
el_torito_set_write_boot_info(bootimg);
el_torito_patch_isolinux_image(bootimg);
/* Or just this for hidden img
* iso_volume_set_boot_image_hidden(volume, boot_img, ELTORITO_NO_EMUL);
*/
}
volset = iso_volset_new( volume, "VOLSETID" );
@ -123,12 +141,16 @@ int main(int argc, char **argv)
iso_volume_set_application_id(volume, "Libburnia");
iso_volume_set_copyright_file_id(volume, "LICENSE");
int constraints = ECMA119_OMIT_VERSION_NUMBERS |
constraints = ECMA119_OMIT_VERSION_NUMBERS |
ECMA119_37_CHAR_FILENAMES | ECMA119_NO_DIR_REALOCATION |
ECMA119_RELAXED_FILENAMES;
struct ecma119_source_opts opts = {0, level, flags, constraints, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, "UTF-8", "UTF-8"};
memset(&opts, 0, sizeof(struct ecma119_source_opts));
opts.level = level;
opts.flags = flags;
opts.relaxed_constraints = 0;
opts.input_charset = NULL;
opts.ouput_charset = "UTF-8";
src = iso_source_new_ecma119(volset, &opts);
@ -137,5 +159,6 @@ int main(int argc, char **argv)
}
fclose(fd);
iso_finish();
return 0;
}

157
test/iso_add.c Normal file
View File

@ -0,0 +1,157 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set ts=8 sts=8 sw=8 noet : */
/*
* Little program that appends a dir to an existing image
*/
#define _GNU_SOURCE
#include "libisofs.h"
#include "libburn/libburn.h"
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <err.h>
#define SECSIZE 2048
const char * const optstring = "JRL:h";
extern char *optarg;
extern int optind;
void usage()
{
printf("test [OPTIONS] IMAGE DIRECTORY OUTPUT\n");
}
void help()
{
printf(
"Options:\n"
" -J Add Joliet support\n"
" -R Add Rock Ridge support\n"
" -L <num> Set the ISO level (1 or 2)\n"
" -h Print this message\n"
);
}
int main(int argc, char **argv)
{
struct ecma119_source_opts wopts;
struct ecma119_read_opts ropts;
struct data_source *rsrc;
struct iso_volset *volset;
struct iso_tree_node_dir *root;
struct burn_source *wsrc;
unsigned char buf[2048];
FILE *fd;
int c;
int constraints;
struct iso_tree_radd_dir_behavior behav = {0,0,0};
int level=1, flags=0;
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
case 'h':
usage();
help();
exit(0);
break;
case 'J':
flags |= ECMA119_JOLIET;
break;
case 'R':
flags |= ECMA119_ROCKRIDGE;
break;
case 'L':
level = atoi(optarg);
break;
case '?':
usage();
exit(1);
break;
}
}
if (argc < optind + 1) {
printf ("Please supply old image file\n");
usage();
return 1;
}
if (argc < optind + 2) {
printf ("Please supply directory to add to image\n");
usage();
return 1;
}
if (argc < optind + 3) {
printf ("Please supply output file\n");
usage();
return 1;
}
if (!iso_init()) {
err(1, "Can't init libisofs");
}
iso_msgs_set_severities("NEVER", "ALL", "");
rsrc = data_source_from_file(argv[optind]);
if (rsrc == NULL) {
printf ("Can't open device\n");
return 1;
}
fd = fopen(argv[optind+2], "w");
if (!fd) {
err(1, "error opening output file");
}
ropts.block = 0;
ropts.norock = 0;
ropts.nojoliet = 0;
ropts.preferjoliet = 0;
ropts.mode = 0555;
ropts.uid = 0;
ropts.gid = 0;
volset = iso_volset_read(rsrc, &ropts);
if (volset == NULL) {
printf ("Error reading image\n");
return 1;
}
root = iso_volume_get_root(iso_volset_get_volume(volset, 0));
iso_tree_radd_dir(root, argv[optind+1], &behav);
constraints = ECMA119_OMIT_VERSION_NUMBERS |
ECMA119_37_CHAR_FILENAMES | ECMA119_NO_DIR_REALOCATION |
ECMA119_RELAXED_FILENAMES;
memset(&wopts, 0, sizeof(struct ecma119_source_opts));
wopts.level = level;
wopts.flags = flags;
wopts.relaxed_constraints = 0;//constraints;
wopts.input_charset = "UTF-8";
wopts.ouput_charset = "UTF-8";
wopts.ms_block = 0;
wopts.src = rsrc;
wsrc = iso_source_new_ecma119(volset, &wopts);
while (wsrc->read(wsrc, buf, 2048) == 2048) {
fwrite(buf, 1, 2048, fd);
}
fclose(fd);
iso_finish();
return 0;
}

302
test/iso_grow.c Normal file
View File

@ -0,0 +1,302 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set ts=8 sts=8 sw=8 noet : */
#define _GNU_SOURCE
#include "libisofs.h"
#include "libburn/libburn.h"
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <err.h>
#define SECSIZE 2048
const char * const optstring = "JRL:h";
extern char *optarg;
extern int optind;
static struct data_source *libburn_data_source_new(struct burn_drive *d);
void usage()
{
printf("test [OPTIONS] DISC DIRECTORY\n");
}
void help()
{
printf(
"Options:\n"
" -J Add Joliet support\n"
" -R Add Rock Ridge support\n"
" -L <num> Set the ISO level (1 or 2)\n"
" -h Print this message\n"
);
}
int main(int argc, char **argv)
{
struct burn_drive_info *drives;
struct burn_drive *drive;
struct ecma119_source_opts wopts;
struct ecma119_read_opts ropts;
struct data_source *rsrc;
struct iso_volset *volset;
struct iso_tree_node_dir *root;
struct burn_source *wsrc;
int c;
struct iso_tree_radd_dir_behavior behav = {0,0,0};
int level=1, flags=0;
int ret = 0;
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
case 'h':
usage();
help();
exit(0);
break;
case 'J':
flags |= ECMA119_JOLIET;
break;
case 'R':
flags |= ECMA119_ROCKRIDGE;
break;
case 'L':
level = atoi(optarg);
break;
case '?':
usage();
exit(1);
break;
}
}
if (argc < optind + 1) {
printf ("Please supply device name\n");
usage();
return 1;
}
if (argc < optind + 2) {
printf ("Please supply directory to add to disc\n");
usage();
return 1;
}
if (!iso_init()) {
err(1, "Can't init libisofs");
}
if (!burn_initialize()) {
err(1, "Can't init libburn");
}
iso_msgs_set_severities("NEVER", "ALL", "");
burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
printf("Reading from %s\n", argv[optind]);
if (burn_drive_scan_and_grab(&drives, argv[optind], 0) != 1) {
err(1, "Can't open device. Are you sure it is a valid drive?\n");
}
drive = drives[0].drive;
{
/* 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;
}
}
rsrc = libburn_data_source_new(drive);
if (rsrc == NULL) {
printf ("Can't create data source.\n");
ret = 1;
goto exit_cleanup;
}
ropts.block = 0; /* image always start on first block */
ropts.norock = 0;
ropts.nojoliet = 0;
ropts.preferjoliet = 0;
ropts.mode = 0555;
ropts.uid = 0;
ropts.gid = 0;
volset = iso_volset_read(rsrc, &ropts);
if (volset == NULL) {
printf ("Error reading image\n");
ret = 1;
goto exit_cleanup;
}
printf("Image size: %d blocks.\n", ropts.size);
/* close source, no more needed */
data_source_free(rsrc);
root = iso_volume_get_root(iso_volset_get_volume(volset, 0));
/* add a new dir */
iso_tree_radd_dir(root, argv[optind+1], &behav);
memset(&wopts, 0, sizeof(struct ecma119_source_opts));
wopts.level = level;
wopts.flags = flags;
wopts.relaxed_constraints = 0;
wopts.input_charset = "UTF-8";
wopts.ouput_charset = "UTF-8";
/* round up to 32kb aligment = 16 block*/
wopts.ms_block = ((ropts.size + 15) / 16 ) * 16;
wopts.overwrite = calloc(32, 2048);
wsrc = iso_source_new_ecma119(volset, &wopts);
/* 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, wsrc);
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, wopts.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");
if ( burn_random_access_write(drive, 0, wopts.overwrite, 32*2048, 0) != 1) {
printf("Ups, new vol desc write failed\n");
}
free(wopts.overwrite);
iso_volset_free(volset);
exit_cleanup:;
burn_drive_release(drives[0].drive, 0);
burn_finish();
iso_finish();
exit(ret);
}
struct disc_data_src {
struct burn_drive *d;
int nblocks;
};
static int
libburn_ds_read_block(struct data_source *src, int lba, unsigned char *buffer)
{
struct disc_data_src *data;
off_t data_count;
assert(src && buffer);
data = (struct disc_data_src*)src->data;
/* if (lba >= data->nblocks)
* return BLOCK_OUT_OF_FILE;
*/
if ( burn_read_data(data->d, (off_t) lba * (off_t) 2048, buffer, 2048,
&data_count, 0) < 0 ) {
return -1; //error
}
return 0;
}
static int
libburn_ds_get_size(struct data_source *src)
{
struct disc_data_src *data;
assert(src);
data = (struct disc_data_src*)src->data;
return data->nblocks;
}
static void
libburn_ds_free_data(struct data_source *src)
{
free(src->data);
}
static struct data_source *
libburn_data_source_new(struct burn_drive *d)
{
struct disc_data_src *data;
struct data_source *ret;
assert(d);
data = malloc(sizeof(struct disc_data_src));
data->d = d;
//should be filled with the size of disc (or track?)
data->nblocks = 0;
ret = malloc(sizeof(struct data_source));
ret->refcount = 1;
ret->read_block = libburn_ds_read_block;
ret->get_size = libburn_ds_get_size;
ret->free_data = libburn_ds_free_data;
ret->data = data;
return ret;
}

159
test/iso_ms.c Normal file
View File

@ -0,0 +1,159 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set ts=8 sts=8 sw=8 noet : */
#define _GNU_SOURCE
#include "libisofs.h"
#include "libburn/libburn.h"
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <err.h>
#define SECSIZE 2048
const char * const optstring = "JRL:h";
extern char *optarg;
extern int optind;
void usage()
{
printf("test [OPTIONS] LSS NWA DISC DIRECTORY OUTPUT\n");
}
void help()
{
printf(
"Options:\n"
" -J Add Joliet support\n"
" -R Add Rock Ridge support\n"
" -L <num> Set the ISO level (1 or 2)\n"
" -h Print this message\n"
);
}
int main(int argc, char **argv)
{
struct ecma119_source_opts wopts;
struct ecma119_read_opts ropts;
struct data_source *rsrc;
struct iso_volset *volset;
struct iso_volume *volume;
struct iso_tree_node_dir *root;
struct burn_source *wsrc;
unsigned char buf[2048];
FILE *fd;
int c;
int constraints;
struct iso_tree_radd_dir_behavior behav = {0,0,0};
int level=1, flags=0;
char *boot_img = NULL;
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
case 'h':
usage();
help();
exit(0);
break;
case 'J':
flags |= ECMA119_JOLIET;
break;
case 'R':
flags |= ECMA119_ROCKRIDGE;
break;
case 'L':
level = atoi(optarg);
break;
case '?':
usage();
exit(1);
break;
}
}
if (argc < optind + 2) {
printf ("Please supply last_sess_start next_sess_start\n");
usage();
return 1;
}
if (argc < optind + 3) {
printf ("Please supply device name\n");
usage();
return 1;
}
if (argc < optind + 4) {
printf ("Please supply directory to add to disc\n");
usage();
return 1;
}
if (argc < optind + 5) {
printf ("Please supply output file\n");
usage();
return 1;
}
if (!iso_init()) {
err(1, "Can't init libisofs");
}
iso_msgs_set_severities("NEVER", "ALL", "");
rsrc = data_source_from_file(argv[optind+2]);
if (rsrc == NULL) {
printf ("Can't open device\n");
return 1;
}
fd = fopen(argv[optind+4], "w");
if (!fd) {
err(1, "error opening output file");
}
ropts.block = atoi(argv[optind]);
ropts.norock = 0;
ropts.nojoliet = 0;
ropts.preferjoliet = 0;
ropts.mode = 0555;
ropts.uid = 0;
ropts.gid = 0;
volset = iso_volset_read(rsrc, &ropts);
if (volset == NULL) {
printf ("Error reading image\n");
return 1;
}
root = iso_volume_get_root(iso_volset_get_volume(volset, 0));
iso_tree_radd_dir(root, argv[optind+3], &behav);
constraints = ECMA119_OMIT_VERSION_NUMBERS |
ECMA119_37_CHAR_FILENAMES | ECMA119_NO_DIR_REALOCATION |
ECMA119_RELAXED_FILENAMES;
memset(&wopts, 0, sizeof(struct ecma119_source_opts));
wopts.level = level;
wopts.flags = flags;
wopts.relaxed_constraints = 0;//constraints;
wopts.input_charset = "UTF-8";
wopts.ouput_charset = "UTF-8";
wopts.ms_block = atoi(argv[optind+1]);
wsrc = iso_source_new_ecma119(volset, &wopts);
while (wsrc->read(wsrc, buf, 2048) == 2048) {
fwrite(buf, 1, 2048, fd);
}
fclose(fd);
iso_finish();
return 0;
}

163
test/iso_read.c Normal file
View File

@ -0,0 +1,163 @@
/*
* Little program that reads an existing ISO image and prints its
* contents to stdout.
*/
#include "libisofs.h"
#include <stdio.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(struct iso_tree_node_dir *dir, int level)
{
int i;
struct iso_tree_iter *iter;
struct iso_tree_node *node;
char sp[level * 2 + 1];
for (i = 0; i < level * 2; i += 2) {
sp[i] = '|';
sp[i+1] = ' ';
}
sp[level * 2-1] = '-';
sp[level * 2] = '\0';
iter = iso_tree_node_children(dir);
while ( (node = iso_tree_iter_next(iter)) != NULL ) {
if (LIBISO_ISDIR(node)) {
printf("%s+[D] ", sp);
print_permissions(iso_tree_node_get_permissions(node));
printf(" %s\n", iso_tree_node_get_name(node) );
print_dir((struct iso_tree_node_dir*)node, level+1);
} else if (LIBISO_ISREG(node)) {
printf("%s-[F] ", sp);
print_permissions(iso_tree_node_get_permissions(node));
printf(" %s\n", iso_tree_node_get_name(node) );
} else if (LIBISO_ISLNK(node)) {
printf("%s-[L] ", sp);
print_permissions(iso_tree_node_get_permissions(node));
printf(" %s -> %s \n", iso_tree_node_get_name(node),
iso_tree_node_symlink_get_dest((struct iso_tree_node_symlink*)node) );
} else {
/* boot catalog */
printf("%s-[C] ", sp);
print_permissions(iso_tree_node_get_permissions(node));
printf(" %s\n", iso_tree_node_get_name(node) );
}
}
iso_tree_iter_free(iter);
}
static void
check_el_torito(struct iso_volume *volume)
{
struct iso_tree_node *cat, *img;
if (iso_volume_get_boot_image(volume, &img, &cat)) {
printf("\nEL-TORITO INFORMATION\n");
printf("=====================\n\n");
printf("Catalog: %s\n", iso_tree_node_get_name(cat) );
printf("Image: %s\n", iso_tree_node_get_name(img) );
}
}
int main(int argc, char **argv)
{
struct ecma119_read_opts opts;
struct data_source *src;
struct iso_volset *volset;
struct iso_volume *volume;
if (argc != 2) {
printf ("You need to specify a valid ISO image\n");
return 1;
}
if (!iso_init()) {
err(1, "Can't init libisofs");
}
iso_msgs_set_severities("NEVER", "ALL", "");
src = data_source_from_file(argv[1]);
if (src == NULL) {
printf ("Can't open image\n");
return 1;
}
opts.block = 0;
opts.norock = 0;
opts.nojoliet = 0;
opts.preferjoliet = 1;
opts.mode = 0555;
opts.uid = 0;
opts.gid = 0;
volset = iso_volset_read(src, &opts);
if (volset == NULL) {
printf ("Error reading image\n");
return 1;
}
volume = iso_volset_get_volume(volset, 0);
printf("\nVOLUME INFORMATION\n");
printf("==================\n\n");
printf("Vol. id: %s\n", iso_volume_get_volume_id(volume));
printf("Publisher: %s\n", iso_volume_get_publisher_id(volume));
printf("Data preparer: %s\n", iso_volume_get_data_preparer_id(volume));
printf("System: %s\n", iso_volume_get_system_id(volume));
printf("Application: %s\n", iso_volume_get_application_id(volume));
printf("Copyright: %s\n", iso_volume_get_copyright_file_id(volume));
printf("Abstract: %s\n", iso_volume_get_abstract_file_id(volume));
printf("Biblio: %s\n", iso_volume_get_biblio_file_id(volume));
if (opts.hasRR)
printf("Rock Ridge Extensions are available.\n");
if (opts.hasJoliet)
printf("Joliet Extensions are available.\n");
printf("\nDIRECTORY TREE\n");
printf("==============\n");
print_dir(iso_volume_get_root(volume), 0);
check_el_torito(volume);
printf("\n\n");
data_source_free(src);
iso_volset_free(volset);
iso_finish();
return 0;
}

View File

@ -8,6 +8,8 @@ static void create_test_suite()
add_file_hashtable_suite();
add_ecma119_tree_suite();
add_volume_suite();
add_data_source_suite();
add_isoread_suite();
}
int main(int argc, char **argv)

View File

@ -21,4 +21,8 @@ void add_ecma119_tree_suite();
void add_volume_suite();
void add_data_source_suite();
void add_isoread_suite();
#endif /*TEST_H_*/

75
test/test_data_source.c Normal file
View File

@ -0,0 +1,75 @@
/*
* Unit test for data_source implementation
*/
#include "test.h"
#include "libisofs.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void test_data_source_from_file()
{
int res;
struct data_source *ds;
unsigned char buffer[2048];
unsigned char rbuff[2048];
char filename[] = "/tmp/temp.iso.XXXXXX";
int fd = mkstemp(filename);
/* actually a failure here means that we couldn't test */
CU_ASSERT_NOT_EQUAL(fd, -1);
memset(buffer, 0x35, 2048);
write(fd, buffer, 2048);
memset(buffer, 0x20, 2048);
write(fd, buffer, 2048);
memset(buffer, 0xF2, 2048);
write(fd, buffer, 2048);
memset(buffer, 0x11, 2048);
write(fd, buffer, 2048);
memset(buffer, 0xAB, 2048);
write(fd, buffer, 2048);
close(fd);
ds = data_source_from_file(filename);
CU_ASSERT_PTR_NOT_NULL(ds);
/* check correct size reported */
CU_ASSERT_EQUAL(ds->get_size(ds), 5);
/* check reading */
res = ds->read_block(ds, 4, rbuff);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_NSTRING_EQUAL(rbuff, buffer, 2048);
res = ds->read_block(ds, 1, rbuff);
CU_ASSERT_EQUAL(res, 0);
memset(buffer, 0x20, 2048);
CU_ASSERT_NSTRING_EQUAL(rbuff, buffer, 2048);
res = ds->read_block(ds, 0, rbuff);
CU_ASSERT_EQUAL(res, 0);
memset(buffer, 0x35, 2048);
CU_ASSERT_NSTRING_EQUAL(rbuff, buffer, 2048);
res = ds->read_block(ds, 3, rbuff);
CU_ASSERT_EQUAL(res, 0);
memset(buffer, 0x11, 2048);
CU_ASSERT_NSTRING_EQUAL(rbuff, buffer, 2048);
/* and a block outside file */
res = ds->read_block(ds, 5, rbuff);
CU_ASSERT_TRUE(res < 0);
data_source_free(ds);
unlink(filename);
}
void add_data_source_suite()
{
CU_pSuite pSuite = CU_add_suite("DataSourceSuite", NULL, NULL);
CU_add_test(pSuite, "test of data_source_from_file()", test_data_source_from_file);
}

View File

@ -1,17 +1,12 @@
/*
* Unit test for ecma119_tree.h
*/
//FIXME not implemented yet!!
#include "libisofs.h"
#include "tree.h"
#include "test.h"
//#include "ecma119_tree.h"
/*
* Also including C file, testing internal functions
*/
//#include "ecma119_tree.c"
#include "ecma119.h"
#include "ecma119_tree.h"
#include <assert.h>
#include <stdio.h>
@ -19,16 +14,109 @@
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
static void test_calc_dirent_len()
struct ecma119_write_target t;
static void reset_write_target()
{
/* inititalize t with default values */
t.root = NULL;
t.joliet_root = NULL;
t.volset = NULL;
t.volnum = time(NULL);
t.now;
t.total_size = 0;
t.vol_space_size = 0;
t.rockridge = 0;
t.joliet = 0;
t.iso_level = 1;
t.eltorito = 0;
t.relaxed_constraints = 0;
t.catalog = NULL;
t.replace_mode = 0;
t.dir_mode = 0777;
t.file_mode = 0777;
t.gid = 0;
t.uid = 0;
t.input_charset = "UTF-8";
t.ouput_charset = "UTF-8";
t.cache_inodes = 0;
t.sort_files = 0;
t.ino = 0;
t.curblock = 0;
t.block_size = 2048;
t.path_table_size = 0;
t.path_table_size_joliet = 0;
t.l_path_table_pos = 0;
t.m_path_table_pos = 0;
t.l_path_table_pos_joliet = 0;
t.m_path_table_pos_joliet = 0;
t.total_dir_size = 0;
t.total_dir_size_joliet = 0;
t.dirlist = NULL;
t.pathlist = NULL;
t.dirlist_len = 0;
t.file_table = NULL;
t.filelist = NULL;
t.filelist_len = 0;
t.curfile = 0;
t.dirlist_joliet = NULL;
t.pathlist_joliet = NULL;
t.dirlist_len_joliet = 0;
t.state = ECMA119_WRITE_SYSTEM_AREA;
}
void test_create_tree_only_root()
{
struct iso_tree_node *root;
struct ecma119_tree_node *node;
reset_write_target();
root = (struct iso_tree_node*) iso_tree_new_root();
node = ecma119_tree_create(&t, root);
CU_ASSERT_PTR_NOT_NULL(node);
/* root has no name */
CU_ASSERT_PTR_NULL(node->iso_name);
CU_ASSERT_PTR_NULL(node->full_name);
/* target root has been set */
CU_ASSERT_PTR_EQUAL(t.root, node);
CU_ASSERT_PTR_EQUAL(node->target, &t);
CU_ASSERT_PTR_NULL(node->parent);
CU_ASSERT_EQUAL(node->attrib.st_mode, root->attrib.st_mode);
CU_ASSERT_EQUAL(node->attrib.st_uid, root->attrib.st_uid);
CU_ASSERT_EQUAL(node->attrib.st_gid, root->attrib.st_gid);
/* the node is a directory */
CU_ASSERT_EQUAL(node->type, ECMA119_DIR);
CU_ASSERT_EQUAL(node->info.dir.nchildren, 0);
iso_tree_free((struct iso_tree_node *)root);
ecma119_tree_free(node);
}
void add_ecma119_tree_suite()
{
CU_pSuite pSuite = CU_add_suite("Ecma119TreeSuite", NULL, NULL);
//CU_add_test(pSuite, "test of calc_dirent_len()", test_calc_dirent_len);
CU_add_test(pSuite, "test of ecma119_tree_create() with only root dir", test_create_tree_only_root);
//CU_add_test(pSuite, "test of create_dir()", test_create_dir);
}

View File

@ -21,7 +21,7 @@ static void test_iso_file_new()
file->node.attrib.st_size = 12;
file->node.attrib.st_dev = 15;
file->node.attrib.st_ino = 204;
file->path = "/tmp/filename";
file->loc.path = "/tmp/filename";
file->sort_weight = 1;
iso = iso_file_new(file);
@ -56,7 +56,7 @@ static void test_add_lookup()
file1->node.name = "fileName";
file1->node.attrib.st_dev = 15;
file1->node.attrib.st_ino = 204;
file1->path = "/tmp/filename";
file1->loc.path = "/tmp/filename";
iso1 = iso_file_new(file1);
@ -72,7 +72,7 @@ static void test_add_lookup()
file2->node.name = "fileName2";
file2->node.attrib.st_dev = 152;
file2->node.attrib.st_ino = 2042;
file2->path = "/tmp/filename2";
file2->loc.path = "/tmp/filename2";
iso3 = iso_file_new(file2);
r = iso_file_table_add_file(table, iso3);
@ -128,7 +128,7 @@ static void test_cache_inodes()
file1->node.name = "fileName";
file1->node.attrib.st_dev = 15;
file1->node.attrib.st_ino = 204;
file1->path = "/tmp/filename";
file1->loc.path = "/tmp/filename";
iso1 = iso_file_new(file1);
@ -140,7 +140,7 @@ static void test_cache_inodes()
file2->node.name = "another file";
file2->node.attrib.st_dev = 15;
file2->node.attrib.st_ino = 204;
file2->path = "/tmp/another";
file2->loc.path = "/tmp/another";
iso2 = iso_file_new(file2);
/* ensure it's not added again... */
@ -159,7 +159,7 @@ static void test_cache_inodes()
file2->node.name = "different file";
file2->node.attrib.st_dev = 16; /* different dev id */
file2->node.attrib.st_ino = 204;
file2->path = "/tmp/different";
file2->loc.path = "/tmp/different";
iso2 = iso_file_new(file2);
r = iso_file_table_add_file(table, iso2);
@ -195,7 +195,7 @@ static void test_no_cache_inodes()
file1->node.name = "fileName";
file1->node.attrib.st_dev = 15;
file1->node.attrib.st_ino = 204;
file1->path = "/tmp/filename";
file1->loc.path = "/tmp/filename";
iso1 = iso_file_new(file1);
@ -207,7 +207,7 @@ static void test_no_cache_inodes()
file2->node.name = "another file";
file2->node.attrib.st_dev = 15;
file2->node.attrib.st_ino = 204;
file2->path = "/tmp/another";
file2->loc.path = "/tmp/another";
iso2 = iso_file_new(file2);
/* ensure is added */
@ -222,7 +222,7 @@ static void test_no_cache_inodes()
file3->node.name = "different file";
file3->node.attrib.st_dev = 15;
file3->node.attrib.st_ino = 204;
file3->path = "/tmp/filename";
file3->loc.path = "/tmp/filename";
iso3 = iso_file_new(file3);
r = iso_file_table_add_file(table, iso3);
@ -237,12 +237,78 @@ static void test_no_cache_inodes()
free(table);
}
static void test_prev_img_files()
{
struct iso_file_table *table;
struct iso_tree_node_file *file1;
struct iso_tree_node_file *file2;
struct iso_tree_node_file *file3;
struct iso_file *iso1;
struct iso_file *iso2;
struct iso_file *iso3;
int r;
table = iso_file_table_new(0);
CU_ASSERT_PTR_NOT_NULL( table );
CU_ASSERT_FALSE( table->cache_inodes );
CU_ASSERT_EQUAL(table->count, 0);
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
file1->node.name = "fileName";
file1->node.procedence = LIBISO_PREVIMG;
file1->node.attrib.st_dev = 0;
file1->node.attrib.st_ino = 204;
file1->loc.block = 567;
iso1 = iso_file_new(file1);
r = iso_file_table_add_file(table, iso1);
CU_ASSERT_EQUAL(r, 1);
/* another file, different but with the same inode id */
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
file2->node.name = "another file";
file2->node.procedence = LIBISO_PREVIMG;
file2->node.attrib.st_dev = 0;
file2->node.attrib.st_ino = 204;
file2->loc.block = 567;
iso2 = iso_file_new(file2);
/* ensure is not added */
r = iso_file_table_add_file(table, iso2);
CU_ASSERT_EQUAL(r, 0);
iso3 = iso_file_table_lookup(table, file2);
CU_ASSERT_PTR_EQUAL(iso3, iso1);
/* and now a file added new */
file3 = calloc(1, sizeof(struct iso_tree_node_file) );
file3->node.name = "different file";
file3->node.attrib.st_dev = 0;
file3->node.attrib.st_ino = 204;
file3->loc.path = "/tmp/filename";
iso3 = iso_file_new(file3);
/* assert it's added */
r = iso_file_table_add_file(table, iso3);
CU_ASSERT_EQUAL(r, 1);
iso1 = iso_file_table_lookup(table, file3);
CU_ASSERT_PTR_EQUAL(iso1, iso3);
iso_file_table_clear(table);
free(file1);
free(file2);
free(file3);
free(table);
}
void add_file_hashtable_suite()
{
CU_pSuite pSuite = CU_add_suite("FileHashtableSuite", NULL, NULL);
CU_add_test(pSuite, "test of iso_file_new()", test_iso_file_new);
CU_add_test(pSuite, "test of add and lookup", test_add_lookup);
CU_add_test(pSuite, "test with cache_inodes", test_cache_inodes);
CU_add_test(pSuite, "test without cache_inodes", test_no_cache_inodes);
CU_add_test(pSuite, "iso_file_new()", test_iso_file_new);
CU_add_test(pSuite, "add and lookup", test_add_lookup);
CU_add_test(pSuite, "with cache_inodes", test_cache_inodes);
CU_add_test(pSuite, "with files from previous img", test_prev_img_files);
}

57
test/test_read.c Normal file
View File

@ -0,0 +1,57 @@
/*
* Unit test iso reading functions
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "test.h"
#include "ecma119_read_rr.h"
#include "util.h"
static void
test_read_rr_PX()
{
struct iso_read_info info;
struct susp_sys_user_entry px;
struct stat atts;
int res;
info.src = NULL; /* data source is not needed */
info.error = 0;
info.ino = 0;
memset(&atts, 0, sizeof(atts));
/* fill px struct */
px.sig[0] = 'P';
px.sig[1] = 'X';
px.version[0] = 1;
iso_bb(px.data.PX.uid, 33, 4);
iso_bb(px.data.PX.gid, 22, 4);
iso_bb(px.data.PX.links, 7, 4);
iso_bb(px.data.PX.mode, S_IFREG | 0555, 4);
/* a) test with RRIP 1.12 */
info.rr = RR_EXT_112;
px.len_sue[0] = 44;
iso_bb(px.data.PX.serial, 678, 4);
res = read_rr_PX(&info, &px, &atts);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(atts.st_uid, 33);
CU_ASSERT_EQUAL(atts.st_gid, 22);
CU_ASSERT_EQUAL(atts.st_mode, (mode_t) S_IFREG | 0555);
CU_ASSERT_EQUAL(atts.st_nlink, 7);
CU_ASSERT_EQUAL(atts.st_ino, 678);
//TODO
}
void add_isoread_suite()
{
CU_pSuite pSuite = CU_add_suite("IsoReadSuite", NULL, NULL);
CU_add_test(pSuite, "test of read_rr_PX()", test_read_rr_PX);
}

View File

@ -2,7 +2,6 @@
* Unit test for tree.h
*/
#include "libisofs.h"
#include "tree.h"
#include "test.h"
@ -56,7 +55,7 @@ static void test_add_file() {
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_PTR_EQUAL(root->children[0], (struct iso_tree_node *)file);
CU_ASSERT_STRING_EQUAL( file->node.name, "README" );
CU_ASSERT_STRING_EQUAL( file->path, "/tmp/libisofs_test/README" );
CU_ASSERT_STRING_EQUAL( file->loc.path, "/tmp/libisofs_test/README" );
CU_ASSERT( S_ISREG(file->node.attrib.st_mode) );
iso_tree_free((struct iso_tree_node *)root);
}
@ -116,7 +115,7 @@ static void test_add_node() {
CU_ASSERT( S_ISREG(node->attrib.st_mode) );
CU_ASSERT( ISO_ISREG(node) );
CU_ASSERT_STRING_EQUAL( node->name, "README" );
CU_ASSERT_STRING_EQUAL( ((struct iso_tree_node_file *) node)->path,
CU_ASSERT_STRING_EQUAL( ((struct iso_tree_node_file *) node)->loc.path,
"/tmp/libisofs_test/README" );
/* test no exiting file */
@ -140,38 +139,6 @@ static void test_add_node() {
iso_tree_free((struct iso_tree_node *)root);
}
static void test_radd_dir() {
struct iso_tree_node_dir *root;
struct iso_tree_node_dir *child;
struct iso_tree_node_file *file;
struct iso_tree_radd_dir_behavior behavior = {0,0,0};
//TODO write really full test
root = iso_tree_new_root();
CU_ASSERT_PTR_NOT_NULL(root);
iso_tree_radd_dir(root, "/tmp/libisofs_test", &behavior);
/* test _root_ children */
/*
child = (struct iso_tree_node_dir *)root->children[0];
CU_ASSERT( S_ISDIR(child->node.attrib.st_mode) );
CU_ASSERT_EQUAL( child->nchildren, 2);
CU_ASSERT_STRING_EQUAL( child->node.name, "dir1" );
child = (struct iso_tree_node_dir *)root->children[1];
CU_ASSERT( S_ISDIR(child->node.attrib.st_mode) );
CU_ASSERT_EQUAL( child->nchildren, 0);
CU_ASSERT_STRING_EQUAL( child->node.name, "dir2" );
file = (struct iso_tree_node_file *)root->children[2];
CU_ASSERT( S_ISREG(file->node.attrib.st_mode) );
CU_ASSERT_STRING_EQUAL( file->node.name, "README" );
*/
//iso_tree_print( (struct iso_tree_node *)root, 4 );
}
static void test_set_name() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
@ -202,6 +169,33 @@ static void test_set_name() {
iso_tree_free((struct iso_tree_node *)root);
}
static void test_get_name() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_STRING_EQUAL( iso_tree_node_get_name(node), "dir1");
iso_tree_node_set_name(node, "newname");
CU_ASSERT_STRING_EQUAL( iso_tree_node_get_name(node), "newname");
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_STRING_EQUAL( iso_tree_node_get_name(node), "link to readme");
iso_tree_node_set_name(node, "new link name");
CU_ASSERT_STRING_EQUAL( iso_tree_node_get_name(node), "new link name");
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_STRING_EQUAL( iso_tree_node_get_name(node), "README" );
iso_tree_node_set_name(node, "new file name");
CU_ASSERT_STRING_EQUAL( iso_tree_node_get_name(node), "new file name");
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_hidden() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
@ -244,6 +238,45 @@ static void test_set_hidden() {
iso_tree_free((struct iso_tree_node *)root);
}
static void test_is_hidden() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_FALSE(iso_tree_node_is_hidden(node));
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_RR);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_JOLIET);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_FALSE(iso_tree_node_is_hidden(node));
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_RR);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_JOLIET);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_FALSE(iso_tree_node_is_hidden(node));
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_RR);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_JOLIET);
iso_tree_node_set_hidden(node, LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
CU_ASSERT_EQUAL(iso_tree_node_is_hidden(node), LIBISO_HIDE_ON_RR|LIBISO_HIDE_ON_JOLIET);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_gid() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
@ -275,6 +308,34 @@ static void test_set_gid() {
iso_tree_free((struct iso_tree_node *)root);
}
static void test_get_gid() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
gid_t mygid = getgid();
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_EQUAL(iso_tree_node_get_gid(node), mygid);
iso_tree_node_set_gid(node, 1234);
CU_ASSERT_EQUAL(iso_tree_node_get_gid(node), 1234);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_EQUAL(iso_tree_node_get_gid(node), mygid);
iso_tree_node_set_gid(node, 1234);
CU_ASSERT_EQUAL(iso_tree_node_get_gid(node), 1234);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_EQUAL(iso_tree_node_get_gid(node), mygid);
iso_tree_node_set_gid(node, 1234);
CU_ASSERT_EQUAL(iso_tree_node_get_gid(node), 1234);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_uid() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
@ -308,6 +369,34 @@ static void test_set_uid() {
iso_tree_free((struct iso_tree_node *)root);
}
static void test_get_uid() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
uid_t myuid = getuid();
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_EQUAL(iso_tree_node_get_uid(node), myuid);
iso_tree_node_set_uid(node, 1234);
CU_ASSERT_EQUAL(iso_tree_node_get_uid(node), 1234);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_EQUAL(iso_tree_node_get_uid(node), myuid);
iso_tree_node_set_uid(node, 1234);
CU_ASSERT_EQUAL(iso_tree_node_get_uid(node), 1234);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_EQUAL(iso_tree_node_get_uid(node), myuid);
iso_tree_node_set_uid(node, 1234);
CU_ASSERT_EQUAL(iso_tree_node_get_uid(node), 1234);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_permissions() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
@ -350,6 +439,45 @@ static void test_set_permissions() {
iso_tree_free((struct iso_tree_node *)root);
}
static void test_get_permissions() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0755);
iso_tree_node_set_permissions(node, 0777);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0777);
iso_tree_node_set_permissions(node, 0744);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0744);
iso_tree_node_set_permissions(node, 0411);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0411);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0777);
iso_tree_node_set_permissions(node, 0555);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0555);
iso_tree_node_set_permissions(node, 0744);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0744);
iso_tree_node_set_permissions(node, 0411);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0411);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0555);
iso_tree_node_set_permissions(node, 0777);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0777);
iso_tree_node_set_permissions(node, 0744);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0744);
iso_tree_node_set_permissions(node, 0411);
CU_ASSERT_EQUAL(iso_tree_node_get_permissions(node), 0411);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_sort_weight() {
struct iso_tree_node_dir *root;
struct iso_tree_node_dir *dir;
@ -375,6 +503,519 @@ static void test_set_sort_weight() {
iso_tree_free((struct iso_tree_node *)root);
}
static void test_set_dest() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
struct iso_tree_node_symlink *link;
root = iso_tree_new_root();
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
link = (struct iso_tree_node_symlink *) node;
CU_ASSERT_STRING_EQUAL( link->dest, "/tmp/libisofs_test/README");
iso_tree_node_symlink_set_dest(link, "/tmp/inexistent");
CU_ASSERT_STRING_EQUAL( link->dest, "/tmp/inexistent");
iso_tree_free((struct iso_tree_node *)root);
}
static void test_get_dest() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
struct iso_tree_node_symlink *link;
root = iso_tree_new_root();
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
link = (struct iso_tree_node_symlink *) node;
CU_ASSERT_STRING_EQUAL( iso_tree_node_symlink_get_dest(link), "/tmp/libisofs_test/README");
iso_tree_node_symlink_set_dest(link, "/tmp/inexistent");
CU_ASSERT_STRING_EQUAL( iso_tree_node_symlink_get_dest(link), "/tmp/inexistent");
iso_tree_free((struct iso_tree_node *)root);
}
static void test_get_node_type() {
struct iso_tree_node_dir *root;
struct iso_tree_node *node;
root = iso_tree_new_root();
/* test on a dir */
node = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
CU_ASSERT_EQUAL(iso_tree_node_get_type(node), LIBISO_NODE_DIR);
/* test on a link */
node = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
CU_ASSERT_EQUAL(iso_tree_node_get_type(node), LIBISO_NODE_SYMLINK);
/* test on a file */
node = iso_tree_add_node(root, "/tmp/libisofs_test/README");
CU_ASSERT_EQUAL(iso_tree_node_get_type(node), LIBISO_NODE_FILE);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_children_iter() {
struct iso_tree_node_dir *root;
struct iso_tree_iter *iter;
struct iso_tree_node *child;
struct iso_tree_node *node1, *node2, *node3;
root = iso_tree_new_root();
node1 = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
node2 = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
node3 = iso_tree_add_node(root, "/tmp/libisofs_test/README");
/* get the iterator */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
/* test correct iteration */
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node2);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
/* and NULL when no more children */
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
/* now an iter on a empty dir */
iter = iso_tree_node_children((struct iso_tree_node_dir *)node1);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_free((struct iso_tree_node *)root);
}
static void test_tree_node_take() {
int res;
struct iso_tree_node_dir *root;
struct iso_tree_iter *iter;
struct iso_tree_node *child;
struct iso_tree_node *node1, *node2, *node3;
root = iso_tree_new_root();
node1 = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
node2 = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
node3 = iso_tree_add_node(root, "/tmp/libisofs_test/README");
/* we take a ref to each node to test current reference behavior */
iso_tree_node_ref(node1);
iso_tree_node_ref(node2);
iso_tree_node_ref(node3);
/* remove node2 */
res = iso_tree_node_take(root, node2);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 2);
CU_ASSERT_PTR_NULL(node2->parent);
/* node2 should keep both refs */
CU_ASSERT_EQUAL(node2->refcount, 2);
/* test iteration */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
/* try to remove again node2 */
res = iso_tree_node_take(root, node2);
CU_ASSERT_EQUAL(res, -1);
CU_ASSERT_EQUAL(root->nchildren, 2);
iso_tree_free(node2);
/* ok, now remove node1, and then node3 */
res = iso_tree_node_take(root, node1);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_EQUAL(node1->refcount, 2);
CU_ASSERT_PTR_NULL(node1->parent);
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
res = iso_tree_node_take(root, node3);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 0);
CU_ASSERT_EQUAL(node3->refcount, 2);
CU_ASSERT_PTR_NULL(node3->parent);
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
/* and try to remove on an empty dir */
res = iso_tree_node_take(root, node3);
CU_ASSERT_EQUAL(res, -1);
iso_tree_free(node1);
iso_tree_free(node3);
iso_tree_free((struct iso_tree_node *)root);
iso_tree_free(node1);
iso_tree_free(node2);
iso_tree_free(node3);
}
static void test_tree_node_remove() {
int res;
struct iso_tree_node_dir *root;
struct iso_tree_iter *iter;
struct iso_tree_node *child;
struct iso_tree_node *node1, *node2, *node3;
root = iso_tree_new_root();
node1 = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
node2 = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
node3 = iso_tree_add_node(root, "/tmp/libisofs_test/README");
/* we take a ref to each node to test current reference behavior */
iso_tree_node_ref(node1);
iso_tree_node_ref(node2);
iso_tree_node_ref(node3);
/* remove node2 */
res = iso_tree_node_remove(root, node2);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 2);
CU_ASSERT_PTR_NULL(node2->parent);
/* node2 should be unref */
CU_ASSERT_EQUAL(node2->refcount, 1);
/* test iteration */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
/* try to remove again node2 */
res = iso_tree_node_remove(root, node2);
CU_ASSERT_EQUAL(res, -1);
CU_ASSERT_EQUAL(root->nchildren, 2);
CU_ASSERT_EQUAL(node2->refcount, 1);
/* ok, now remove node1, and then node3 */
res = iso_tree_node_remove(root, node1);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_EQUAL(node1->refcount, 1);
CU_ASSERT_PTR_NULL(node1->parent);
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
res = iso_tree_node_remove(root, node3);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 0);
CU_ASSERT_EQUAL(node3->refcount, 1);
CU_ASSERT_PTR_NULL(node3->parent);
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
/* and try to remove on an empty dir */
res = iso_tree_node_remove(root, node3);
CU_ASSERT_EQUAL(res, -1);
CU_ASSERT_EQUAL(node3->refcount, 1);
iso_tree_free((struct iso_tree_node *)root);
iso_tree_free(node1);
iso_tree_free(node2);
iso_tree_free(node3);
}
static void test_tree_node_take_iter() {
int res;
struct iso_tree_node_dir *root;
struct iso_tree_iter *iter;
struct iso_tree_node *child;
struct iso_tree_node *node1, *node2, *node3;
root = iso_tree_new_root();
node1 = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
node2 = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
node3 = iso_tree_add_node(root, "/tmp/libisofs_test/README");
/* we take a ref to each node to test current reference behavior */
iso_tree_node_ref(node1);
iso_tree_node_ref(node2);
iso_tree_node_ref(node3);
/* begin iteration */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node2);
/* ok, take node 2 */
res = iso_tree_node_take_iter(iter);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 2);
CU_ASSERT_EQUAL(node2->refcount, 2);
CU_ASSERT_PTR_NULL(node2->parent);
/* the iter have to work after remove */
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
/* ok, now remove before the begining */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
res = iso_tree_node_take_iter(iter);
CU_ASSERT_TRUE(res < 0);
/* and the iter still works */
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
/* and now try to remove at the end */
res = iso_tree_node_take_iter(iter);
CU_ASSERT_TRUE(res < 0);
iso_tree_iter_free(iter);
/* ok, now remove all during iteration */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
res = iso_tree_node_take_iter(iter);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_EQUAL(node1->refcount, 2);
CU_ASSERT_PTR_NULL(node1->parent);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
res = iso_tree_node_take_iter(iter);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 0);
CU_ASSERT_EQUAL(node3->refcount, 2);
CU_ASSERT_PTR_NULL(node3->parent);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
iso_tree_free(node1);
iso_tree_free(node2);
iso_tree_free(node3);
iso_tree_free((struct iso_tree_node *)root);
iso_tree_free(node1);
iso_tree_free(node2);
iso_tree_free(node3);
}
static void test_tree_node_remove_iter() {
int res;
struct iso_tree_node_dir *root;
struct iso_tree_iter *iter;
struct iso_tree_node *child;
struct iso_tree_node *node1, *node2, *node3;
root = iso_tree_new_root();
node1 = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
node2 = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
node3 = iso_tree_add_node(root, "/tmp/libisofs_test/README");
/* we take a ref to each node to test current reference behavior */
iso_tree_node_ref(node1);
iso_tree_node_ref(node2);
iso_tree_node_ref(node3);
/* begin iteration */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node2);
/* ok, remove node 2 */
res = iso_tree_node_remove_iter(iter);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 2);
CU_ASSERT_EQUAL(node2->refcount, 1);
CU_ASSERT_PTR_NULL(node2->parent);
/* the iter have to work after remove */
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
/* ok, now remove before the begining */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
res = iso_tree_node_remove_iter(iter);
CU_ASSERT_TRUE(res < 0);
/* and the iter still works */
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
/* and now try to remove at the end */
res = iso_tree_node_remove_iter(iter);
CU_ASSERT_TRUE(res < 0);
iso_tree_iter_free(iter);
/* ok, now remove all during iteration */
iter = iso_tree_node_children(root);
CU_ASSERT_PTR_NOT_NULL(iter);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node1);
res = iso_tree_node_remove_iter(iter);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 1);
CU_ASSERT_EQUAL(node1->refcount, 1);
CU_ASSERT_PTR_NULL(node1->parent);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NOT_NULL(child);
CU_ASSERT_PTR_EQUAL(child, node3);
res = iso_tree_node_remove_iter(iter);
CU_ASSERT_EQUAL(res, 0);
CU_ASSERT_EQUAL(root->nchildren, 0);
CU_ASSERT_EQUAL(node3->refcount, 1);
CU_ASSERT_PTR_NULL(node3->parent);
child = iso_tree_iter_next(iter);
CU_ASSERT_PTR_NULL(child);
iso_tree_iter_free(iter);
iso_tree_free((struct iso_tree_node *)root);
iso_tree_free(node1);
iso_tree_free(node2);
iso_tree_free(node3);
}
static void test_tree_node_get_parent() {
struct iso_tree_node_dir *root;
struct iso_tree_node_dir *parent;
struct iso_tree_node *node1, *node2, *node3;
root = iso_tree_new_root();
node1 = iso_tree_add_node(root, "/tmp/libisofs_test/dir1");
node2 = iso_tree_add_node(root, "/tmp/libisofs_test/link to readme");
node3 = iso_tree_add_node( (struct iso_tree_node_dir*)node1,
"/tmp/libisofs_test/README");
parent = iso_tree_node_get_parent((struct iso_tree_node *)root);
CU_ASSERT_PTR_NULL(parent);
parent = iso_tree_node_get_parent(node1);
CU_ASSERT_PTR_NOT_NULL(parent);
CU_ASSERT_PTR_EQUAL(parent, root);
parent = iso_tree_node_get_parent(node2);
CU_ASSERT_PTR_NOT_NULL(parent);
CU_ASSERT_PTR_EQUAL(parent, root);
parent = iso_tree_node_get_parent(node3);
CU_ASSERT_PTR_NOT_NULL(parent);
CU_ASSERT_PTR_EQUAL(parent, node1);
iso_tree_node_take(root, node1);
parent = iso_tree_node_get_parent(node1);
CU_ASSERT_PTR_NULL(parent);
iso_tree_free((struct iso_tree_node *)root);
iso_tree_free(node1);
}
void add_tree_suite()
{
CU_pSuite pSuite = CU_add_suite("TreeSuite", NULL, NULL);
@ -384,12 +1025,27 @@ void add_tree_suite()
CU_add_test(pSuite, "test of iso_tree_add_file()", test_add_file);
CU_add_test(pSuite, "test of iso_tree_add_symlink()", test_add_symlink);
CU_add_test(pSuite, "test of iso_tree_add_node()", test_add_node);
CU_add_test(pSuite, "test of iso_tree_radd_dir()", test_radd_dir);
CU_add_test(pSuite, "test of iso_tree_node_set_name()", test_set_name);
CU_add_test(pSuite, "test of iso_tree_node_get_name()", test_get_name);
CU_add_test(pSuite, "test of iso_tree_node_set_hidden()", test_set_hidden);
CU_add_test(pSuite, "test of iso_tree_node_is_hidden()", test_is_hidden);
CU_add_test(pSuite, "test of iso_tree_node_set_gid()", test_set_gid);
CU_add_test(pSuite, "test of iso_tree_node_get_gid()", test_get_gid);
CU_add_test(pSuite, "test of iso_tree_node_set_uid()", test_set_uid);
CU_add_test(pSuite, "test of iso_tree_node_get_uid()", test_get_uid);
CU_add_test(pSuite, "test of iso_tree_node_set_permissions()", test_set_permissions);
CU_add_test(pSuite, "test of iso_tree_node_get_permissions()", test_get_permissions);
CU_add_test(pSuite, "test of iso_tree_node_set_sort_weight()", test_set_sort_weight);
CU_add_test(pSuite, "test of iso_tree_node_symlink_set_dest()", test_set_dest);
CU_add_test(pSuite, "test of iso_tree_node_symlink_get_dest()", test_get_dest);
CU_add_test(pSuite, "test of iso_tree_node_get_type()", test_get_node_type);
CU_add_test(pSuite, "test of children iteration", test_children_iter);
CU_add_test(pSuite, "test of iso_tree_node_take()", test_tree_node_take);
CU_add_test(pSuite, "test of iso_tree_node_remove()", test_tree_node_remove);
CU_add_test(pSuite, "test of iso_tree_node_take_iter()", test_tree_node_take_iter);
CU_add_test(pSuite, "test of iso_tree_node_remove_iter()", test_tree_node_remove_iter);
CU_add_test(pSuite, "test of iso_tree_node_get_parent()", test_tree_node_get_parent);
}

View File

@ -4,8 +4,10 @@
* This test utiliy functions
*
*/
#include "test.h"
#include <time.h>
#include <locale.h>
#include "test.h"
#include "util.h"
static void test_div_up()
@ -56,6 +58,122 @@ static void test_iso_lsb_msb()
CU_ASSERT_EQUAL( buf[1], 0x04 );
}
static void test_iso_read_lsb_msb()
{
uint8_t buf[4];
uint32_t num;
buf[0] = 0x04;
buf[1] = 0x03;
buf[2] = 0x02;
buf[3] = 0x01;
num = iso_read_lsb(buf, 4);
CU_ASSERT_EQUAL(num, 0x01020304);
num = iso_read_msb(buf, 4);
CU_ASSERT_EQUAL(num, 0x04030201);
num = iso_read_lsb(buf, 2);
CU_ASSERT_EQUAL(num, 0x0304);
num = iso_read_msb(buf, 2);
CU_ASSERT_EQUAL(num, 0x0403);
}
static void test_iso_bb()
{
uint8_t buf[8];
uint32_t num;
num = 0x01020304;
iso_bb(buf, num, 4);
CU_ASSERT_EQUAL( buf[0], 0x04 );
CU_ASSERT_EQUAL( buf[1], 0x03 );
CU_ASSERT_EQUAL( buf[2], 0x02 );
CU_ASSERT_EQUAL( buf[3], 0x01 );
CU_ASSERT_EQUAL( buf[4], 0x01 );
CU_ASSERT_EQUAL( buf[5], 0x02 );
CU_ASSERT_EQUAL( buf[6], 0x03 );
CU_ASSERT_EQUAL( buf[7], 0x04 );
iso_bb(buf, num, 2);
CU_ASSERT_EQUAL( buf[0], 0x04 );
CU_ASSERT_EQUAL( buf[1], 0x03 );
CU_ASSERT_EQUAL( buf[2], 0x03 );
CU_ASSERT_EQUAL( buf[3], 0x04 );
}
static void test_iso_read_bb()
{
uint8_t buf[8];
uint32_t num;
int error = 0;
buf[0] = 0x04;
buf[1] = 0x03;
buf[2] = 0x02;
buf[3] = 0x01;
buf[4] = 0x01;
buf[5] = 0x02;
buf[6] = 0x03;
buf[7] = 0x04;
num = iso_read_bb(buf, 4, &error);
CU_ASSERT_EQUAL( num, 0x01020304 );
CU_ASSERT_FALSE(error);
num = iso_read_bb(buf, 4, NULL);
CU_ASSERT_EQUAL( num, 0x01020304 );
buf[2] = 3;
num = iso_read_bb(buf, 4, &error);
/* return the LSB */
CU_ASSERT_EQUAL( num, 0x01030304 );
CU_ASSERT_TRUE(error);
num = iso_read_bb(buf, 4, NULL);
/* return the LSB */
CU_ASSERT_EQUAL( num, 0x01030304 );
error = 0;
buf[3] = 0x04;
num = iso_read_bb(buf, 2, &error);
CU_ASSERT_EQUAL( num, 0x0304 );
CU_ASSERT_FALSE(error);
num = iso_read_bb(buf, 2, NULL);
CU_ASSERT_EQUAL( num, 0x0304 );
}
static void test_iso_datetime_7()
{
uint8_t buf[7];
time_t t, t2;
struct tm tp;
strptime("01-03-1976 13:27:45", "%d-%m-%Y %T", &tp);
t = mktime(&tp);
iso_datetime_7(buf, t);
CU_ASSERT_EQUAL( buf[0], 76 ); /* year since 1900 */
CU_ASSERT_EQUAL( buf[1], 3 ); /* month */
CU_ASSERT_EQUAL( buf[2], 1 ); /* day */
CU_ASSERT_EQUAL( buf[3], 13 ); /* hour */
CU_ASSERT_EQUAL( buf[4], 27 ); /* minute */
CU_ASSERT_EQUAL( buf[5], 45 ); /* second */
/* the offset depends on current timezone and it's not easy to test */
//CU_ASSERT_EQUAL( buf[6], 4 ); /* 15 min offset */
/* check that reading returns the same time */
t2 = iso_datetime_read_7(buf);
CU_ASSERT_EQUAL(t2, t);
//TODO check with differnt timezones for reading and writting
}
static void test_iso_1_dirid()
{
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dir1", "UTF-8"), "DIR1" );
@ -253,13 +371,17 @@ void add_util_suite()
{
CU_pSuite pSuite = CU_add_suite("UtilSuite", NULL, NULL);
CU_add_test(pSuite, "test of div_up()", test_div_up);
CU_add_test(pSuite, "test of round_up()", test_round_up);
CU_add_test(pSuite, "test of iso_lsb_msb()", test_iso_lsb_msb);
CU_add_test(pSuite, "test of iso_1_dirid()", test_iso_1_dirid);
CU_add_test(pSuite, "test of iso_2_dirid()", test_iso_2_dirid);
CU_add_test(pSuite, "test of iso_r_dirid()", test_iso_r_dirid);
CU_add_test(pSuite, "test of iso_1_fileid()", test_iso_1_fileid);
CU_add_test(pSuite, "test of iso_2_fileid()", test_iso_2_fileid);
CU_add_test(pSuite, "test of iso_r_fileid()", test_iso_r_fileid);
CU_add_test(pSuite, "div_up()", test_div_up);
CU_add_test(pSuite, "round_up()", test_round_up);
CU_add_test(pSuite, "iso_lsb() and iso_msb()", test_iso_lsb_msb);
CU_add_test(pSuite, "iso_read_lsb() and iso_read_msb()", test_iso_read_lsb_msb);
CU_add_test(pSuite, "iso_bb()", test_iso_bb);
CU_add_test(pSuite, "iso_read_bb()", test_iso_read_bb);
CU_add_test(pSuite, "iso_datetime_7()", test_iso_datetime_7);
CU_add_test(pSuite, "iso_1_dirid()", test_iso_1_dirid);
CU_add_test(pSuite, "iso_2_dirid()", test_iso_2_dirid);
CU_add_test(pSuite, "iso_r_dirid()", test_iso_r_dirid);
CU_add_test(pSuite, "iso_1_fileid()", test_iso_1_fileid);
CU_add_test(pSuite, "iso_2_fileid()", test_iso_2_fileid);
CU_add_test(pSuite, "iso_r_fileid()", test_iso_r_fileid);
}

View File

@ -105,6 +105,20 @@ static void test_iso_volume_set_volume_id()
iso_volume_free(volume);
}
static void test_iso_volume_get_volume_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_STRING_EQUAL( iso_volume_get_volume_id(volume), "volume_id" );
char *volid = "new volume id";
iso_volume_set_volume_id(volume, volid);
CU_ASSERT_STRING_EQUAL( iso_volume_get_volume_id(volume), "new volume id" );
iso_volume_free(volume);
}
static void test_iso_volume_set_publisher_id()
{
struct iso_volume *volume;
@ -121,6 +135,20 @@ static void test_iso_volume_set_publisher_id()
iso_volume_free(volume);
}
static void test_iso_volume_get_publisher_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_STRING_EQUAL( iso_volume_get_publisher_id(volume), "publisher_id" );
char *pubid = "new publisher id";
iso_volume_set_publisher_id(volume, pubid);
CU_ASSERT_STRING_EQUAL( iso_volume_get_publisher_id(volume), "new publisher id" );
iso_volume_free(volume);
}
static void test_iso_volume_set_data_preparer_id()
{
struct iso_volume *volume;
@ -137,6 +165,20 @@ static void test_iso_volume_set_data_preparer_id()
iso_volume_free(volume);
}
static void test_iso_volume_get_data_preparer_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_STRING_EQUAL( iso_volume_get_data_preparer_id(volume), "data_preparer_id" );
char *dpid = "new data preparer id";
iso_volume_set_data_preparer_id(volume, dpid);
CU_ASSERT_STRING_EQUAL( iso_volume_get_data_preparer_id(volume), "new data preparer id" );
iso_volume_free(volume);
}
static void test_iso_volume_set_system_id()
{
struct iso_volume *volume;
@ -153,6 +195,20 @@ static void test_iso_volume_set_system_id()
iso_volume_free(volume);
}
static void test_iso_volume_get_system_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(iso_volume_get_system_id(volume));
char *sysid = "new system id";
iso_volume_set_system_id(volume, sysid);
CU_ASSERT_STRING_EQUAL( iso_volume_get_system_id(volume), "new system id" );
iso_volume_free(volume);
}
static void test_iso_volume_set_application_id()
{
struct iso_volume *volume;
@ -169,6 +225,50 @@ static void test_iso_volume_set_application_id()
iso_volume_free(volume);
}
static void test_iso_volume_get_application_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(iso_volume_get_application_id(volume));
char *appid = "new application id";
iso_volume_set_application_id(volume, appid);
CU_ASSERT_STRING_EQUAL( iso_volume_get_application_id(volume), "new application id" );
iso_volume_free(volume);
}
static void test_iso_volume_set_copyright_file_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(volume->copyright_file_id);
char *copid = "new copyright id";
iso_volume_set_copyright_file_id(volume, copid);
CU_ASSERT_STRING_EQUAL( volume->copyright_file_id, "new copyright id" );
/* check string was strdup'ed */
CU_ASSERT_PTR_NOT_EQUAL( volume->copyright_file_id, copid );
iso_volume_free(volume);
}
static void test_iso_volume_get_copyright_file_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(iso_volume_get_copyright_file_id(volume));
char *copid = "new copyright id";
iso_volume_set_copyright_file_id(volume, copid);
CU_ASSERT_STRING_EQUAL( iso_volume_get_copyright_file_id(volume), "new copyright id" );
iso_volume_free(volume);
}
static void test_iso_volume_set_abstract_file_id()
{
struct iso_volume *volume;
@ -185,6 +285,20 @@ static void test_iso_volume_set_abstract_file_id()
iso_volume_free(volume);
}
static void test_iso_volume_get_abstract_file_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(iso_volume_get_abstract_file_id(volume));
char *absid = "new abstract id";
iso_volume_set_abstract_file_id(volume, absid);
CU_ASSERT_STRING_EQUAL(iso_volume_get_abstract_file_id(volume), "new abstract id");
iso_volume_free(volume);
}
static void test_iso_volume_set_biblio_file_id()
{
struct iso_volume *volume;
@ -201,6 +315,20 @@ static void test_iso_volume_set_biblio_file_id()
iso_volume_free(volume);
}
static void test_iso_volume_get_biblio_file_id()
{
struct iso_volume *volume;
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
CU_ASSERT_PTR_NULL(iso_volume_get_biblio_file_id(volume));
char *bibid = "new biblio id";
iso_volume_set_biblio_file_id(volume, bibid);
CU_ASSERT_STRING_EQUAL(iso_volume_get_biblio_file_id(volume), "new biblio id");
iso_volume_free(volume);
}
static void test_iso_volset_new()
{
struct iso_volume *volume;
@ -228,11 +356,20 @@ void add_volume_suite()
CU_add_test(pSuite, "test of iso_volume_new_with_root()", test_iso_volume_new_with_root);
CU_add_test(pSuite, "test of iso_volume_get_root()", test_iso_volume_get_root);
CU_add_test(pSuite, "test of iso_volume_set_volume_id()", test_iso_volume_set_volume_id);
CU_add_test(pSuite, "test of iso_volume_get_volume_id()", test_iso_volume_get_volume_id);
CU_add_test(pSuite, "test of iso_volume_set_publisher_id()", test_iso_volume_set_publisher_id);
CU_add_test(pSuite, "test of iso_volume_get_publisher_id()", test_iso_volume_get_publisher_id);
CU_add_test(pSuite, "test of iso_volume_set_data_preparer_id()", test_iso_volume_set_data_preparer_id);
CU_add_test(pSuite, "test of iso_volume_get_data_preparer_id()", test_iso_volume_get_data_preparer_id);
CU_add_test(pSuite, "test of iso_volume_set_system_id()", test_iso_volume_set_system_id);
CU_add_test(pSuite, "test of iso_volume_get_system_id()", test_iso_volume_get_system_id);
CU_add_test(pSuite, "test of iso_volume_set_application_id()", test_iso_volume_set_application_id);
CU_add_test(pSuite, "test of iso_volume_get_application_id()", test_iso_volume_get_application_id);
CU_add_test(pSuite, "test of iso_volume_set_copyright_file_id()", test_iso_volume_set_copyright_file_id);
CU_add_test(pSuite, "test of iso_volume_get_copyright_file_id()", test_iso_volume_get_copyright_file_id);
CU_add_test(pSuite, "test of iso_volume_set_abstract_file_id()", test_iso_volume_set_abstract_file_id);
CU_add_test(pSuite, "test of iso_volume_get_abstract_file_id()", test_iso_volume_get_abstract_file_id);
CU_add_test(pSuite, "test of iso_volume_set_biblio_file_id()", test_iso_volume_set_biblio_file_id);
CU_add_test(pSuite, "test of iso_volume_get_biblio_file_id()", test_iso_volume_get_biblio_file_id);
CU_add_test(pSuite, "test of iso_volset_new()", test_iso_volset_new);
}