Compare commits
64 Commits
ZeroTwoFou
...
master
Author | SHA1 | Date | |
---|---|---|---|
c6136416c3 | |||
|
de3cf8e385 | ||
|
3028015ab8 | ||
|
7b9834a315 | ||
|
63f2cfd673 | ||
|
2b92fbc31a | ||
|
b9c4f7ad1d | ||
|
485607ce7b | ||
|
08c53aa997 | ||
|
0224ad402d | ||
|
6546f1a197 | ||
|
f4ad1c630b | ||
b1966abe45 | |||
|
f5e31470bd | ||
|
f811234b8f | ||
|
8de9d35873 | ||
|
ead523ff27 | ||
|
0071d733fd | ||
|
9639d45b35 | ||
|
370fac83c1 | ||
|
d41a020cea | ||
|
33ad67ee2c | ||
|
2629a25d4e | ||
|
5c82fc5108 | ||
|
d60193e2d5 | ||
|
0746d622e4 | ||
|
139fb6496c | ||
|
df04ee014e | ||
|
a4e0041128 | ||
|
a28e699d9b | ||
|
4354e9598d | ||
|
0fece11399 | ||
|
170dfe21bf | ||
|
3ea44305b4 | ||
|
1b7fec7751 | ||
|
0b1a9c5565 | ||
|
2e073c258c | ||
|
b7573134cb | ||
|
9d08c115fd | ||
|
3fd2309025 | ||
|
6da923c16e | ||
|
acf402c75d | ||
|
14605541c9 | ||
|
7faf1635a0 | ||
|
9746b5b273 | ||
|
44b504640f | ||
|
89f291f412 | ||
|
8390f85e1f | ||
|
22c02b9b2f | ||
|
3e29f914fd | ||
|
0281fcb717 | ||
|
a97e96c604 | ||
|
d54045fb42 | ||
|
802476a0c6 | ||
|
0ae442220a | ||
|
24730f52d1 | ||
|
7ea76d34d7 | ||
|
bbd286f7e1 | ||
|
5a64e11df5 | ||
|
ef56dc8f4f | ||
|
b46f805756 | ||
|
71270599b8 | ||
|
e8c4da784f | ||
|
fe66983e82 |
|
@ -1,2 +1,4 @@
|
|||
Joe Neeman
|
||||
Philippe Rouquier
|
||||
Suriyan Laohaprapanon
|
||||
Vreixo Formoso Lopes
|
||||
|
|
14
ChangeLog
14
ChangeLog
|
@ -1 +1,13 @@
|
|||
nothing here now
|
||||
|
||||
Development
|
||||
===========
|
||||
|
||||
- Support for reading of plain iso images.
|
||||
- Support for reading RR extensions
|
||||
|
||||
|
||||
|
||||
Version 0.2.8
|
||||
=============
|
||||
|
||||
TODO
|
62
Makefile.am
62
Makefile.am
|
@ -29,7 +29,22 @@ libisofs_libisofs_la_SOURCES = \
|
|||
libisofs/exclude.c \
|
||||
libisofs/exclude.h \
|
||||
libisofs/hash.h \
|
||||
libisofs/hash.c
|
||||
libisofs/hash.c \
|
||||
libisofs/file.h \
|
||||
libisofs/file.c \
|
||||
libisofs/file_src.h \
|
||||
libisofs/file_src.c \
|
||||
libisofs/eltorito.h \
|
||||
libisofs/eltorito.c \
|
||||
libisofs/data_source.c \
|
||||
libisofs/ecma119_read.h \
|
||||
libisofs/ecma119_read.c \
|
||||
libisofs/ecma119_read_rr.h \
|
||||
libisofs/ecma119_read_rr.c \
|
||||
libisofs/libiso_msgs.h \
|
||||
libisofs/libiso_msgs.c \
|
||||
libisofs/messages.h \
|
||||
libisofs/messages.c
|
||||
|
||||
libinclude_HEADERS = \
|
||||
libisofs/libisofs.h
|
||||
|
@ -38,12 +53,51 @@ 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 = \
|
||||
test/test
|
||||
|
||||
test_test_CPPFLAGS = -Ilibisofs
|
||||
test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) -lcunit
|
||||
test_test_LDFLAGS = -L.. -lm
|
||||
|
||||
test_test_SOURCES = \
|
||||
test/test_exclude.c \
|
||||
test/test_tree.c \
|
||||
test/test_ecma119_tree.c \
|
||||
test/test_file_hashtable.c \
|
||||
test/test_util.c \
|
||||
test/test_volume.c \
|
||||
test/test_data_source.c \
|
||||
test/test_read.c \
|
||||
test/test.c
|
||||
|
||||
## ========================================================================= ##
|
||||
|
||||
|
@ -95,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
77
README
|
@ -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
|
||||
|
|
64
TODO
Normal file
64
TODO
Normal file
|
@ -0,0 +1,64 @@
|
|||
GENERAL
|
||||
=======
|
||||
|
||||
Improve documentation
|
||||
Build system improvements
|
||||
Clarify licencing (GPL2 only (!) with exception)
|
||||
|
||||
FEATURES
|
||||
========
|
||||
|
||||
El-Torito
|
||||
Support for multiple images
|
||||
HFS/HFS+
|
||||
CD reading
|
||||
[ok] plain iso
|
||||
[ok] Rock Ridge
|
||||
[ok] Joliet
|
||||
Merge RR and Joliet trees
|
||||
[ok] User options to customize reading
|
||||
[ok] Read El-Torito info
|
||||
[ok] Multisession
|
||||
[ok] DVD+RW image growing
|
||||
El-Torito images from previous session
|
||||
Add new el-torito image from prev. session file
|
||||
Path for isolinux from prev. session
|
||||
UDF
|
||||
[ok] ISO relaxed contraints
|
||||
ISO 9660:1998
|
||||
|
||||
Support for special files (only dirs, reg. files and symlinks are supported).
|
||||
Modification of timestamps attribs on nodes
|
||||
|
||||
TESTS
|
||||
=====
|
||||
|
||||
[several done]
|
||||
Test all util.h functions, especially date-related ones
|
||||
Test for RR read functions
|
||||
For all
|
||||
|
||||
IMPLEMENTATION
|
||||
==============
|
||||
|
||||
a way to return NULL sources meaning a failure!!
|
||||
[ok] Error message queue
|
||||
Better charset support
|
||||
[ok] default input charset to locale one, no always UTF-8
|
||||
add charset management on image reading
|
||||
use iso-8859-1 instead of UTF-8 on RR?
|
||||
[ok] Improve date handling
|
||||
for DVD+RW, the VD to be written at the beginning of disc must be
|
||||
returned as 32KB block
|
||||
Sources to write file contents
|
||||
encyrption/compression of files
|
||||
auto cut of files to 2gb limit
|
||||
|
||||
BUGS
|
||||
====
|
||||
|
||||
Joliet names need ";1" at the end
|
||||
RR Continuation Areas can't be in Directory Record block
|
||||
[ok] Fix mangle names when iso relaxed constraints
|
||||
|
||||
|
|
@ -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])
|
||||
|
||||
|
@ -25,7 +25,7 @@ dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
|
|||
dnl
|
||||
BURN_MAJOR_VERSION=0
|
||||
BURN_MINOR_VERSION=2
|
||||
BURN_MICRO_VERSION=3
|
||||
BURN_MICRO_VERSION=4
|
||||
BURN_INTERFACE_AGE=0
|
||||
BURN_BINARY_AGE=0
|
||||
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
|
||||
|
@ -112,6 +112,6 @@ AC_CONFIG_FILES([
|
|||
Makefile
|
||||
doc/doxygen.conf
|
||||
version.h
|
||||
libisofs-1.pc
|
||||
libisofs-5.pc
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
|
1176
doc/doxygen.conf.in
1176
doc/doxygen.conf.in
File diff suppressed because it is too large
Load Diff
0
libisofs/Makefile
Executable file → Normal file
0
libisofs/Makefile
Executable file → Normal file
|
@ -1,49 +0,0 @@
|
|||
pkgconfigdir=$(libdir)/pkgconfig
|
||||
libincludedir=$(includedir)/libburn
|
||||
|
||||
##bin_PROGRAMS = test
|
||||
|
||||
lib_LTLIBRARIES = libisofs.la
|
||||
|
||||
libisofs_la_SOURCES = \
|
||||
tree.h \
|
||||
tree.c \
|
||||
volume.h \
|
||||
volume.c \
|
||||
util.h \
|
||||
util.c \
|
||||
ecma119.c \
|
||||
ecma119.h \
|
||||
ecma119_tree.c \
|
||||
ecma119_tree.h \
|
||||
susp.h \
|
||||
susp.c \
|
||||
rockridge.h \
|
||||
rockridge.c \
|
||||
joliet.c \
|
||||
joliet.h
|
||||
|
||||
libinclude_HEADERS = libisofs.h
|
||||
|
||||
##test_SOURCES = test.c
|
||||
##test_LDADD = libisofs.la
|
||||
|
||||
##noinst_PROGRAMS = test
|
||||
##test_SOURCES = test.c
|
||||
##test_LDADD = $(libisofs_la_OBJECTS)
|
||||
|
||||
##INCLUDES = -I../burn/libburn
|
||||
|
||||
## ========================================================================= ##
|
||||
indent_files = $(libisofs_la_SOURCES)
|
||||
|
||||
indent: $(indent_files)
|
||||
indent -bad -bap -nbbb -nbbo -nbc -bli0 -br -bls \
|
||||
-cdw -ce -cli0 -ncs -nbfda -i8 -l79 -lc79 \
|
||||
-lp -saf -sai -nprs -npsl -saw -sob -ss -ut \
|
||||
-sbi0 -nsc -ts8 -npcs -ncdb -fca \
|
||||
$^
|
||||
|
||||
.PHONY: indent
|
||||
|
||||
## ========================================================================= ##
|
107
libisofs/data_source.c
Normal file
107
libisofs/data_source.c
Normal 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);
|
||||
}
|
||||
}
|
600
libisofs/ecma119.c
Executable file → Normal file
600
libisofs/ecma119.c
Executable file → Normal 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"
|
||||
|
@ -16,8 +19,12 @@
|
|||
#include "volume.h"
|
||||
#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
|
||||
|
@ -77,6 +84,7 @@ static const write_fn writers[] =
|
|||
NULL,
|
||||
wr_system_area,
|
||||
wr_pri_vol_desc,
|
||||
el_torito_wr_boot_vol_desc,
|
||||
joliet_wr_sup_vol_desc,
|
||||
wr_vol_desc_term,
|
||||
wr_l_path_table,
|
||||
|
@ -85,6 +93,7 @@ static const write_fn writers[] =
|
|||
joliet_wr_m_path_table,
|
||||
wr_dir_records,
|
||||
joliet_wr_dir_records,
|
||||
el_torito_wr_catalog,
|
||||
wr_files
|
||||
};
|
||||
|
||||
|
@ -101,30 +110,35 @@ add_susp_fields_rec(struct ecma119_write_target *t,
|
|||
{
|
||||
size_t i;
|
||||
|
||||
if (!node->iso_self)
|
||||
return;
|
||||
|
||||
rrip_add_PX(t, node);
|
||||
rrip_add_NM(t, node);
|
||||
rrip_add_TF(t, node);
|
||||
if (node->iso_self->attrib.st_rdev)
|
||||
rrip_add_PN(t, node);
|
||||
if (S_ISLNK(node->iso_self->attrib.st_mode))
|
||||
rrip_add_SL(t, node);
|
||||
if (node->type == ECMA119_FILE && node->file.real_me)
|
||||
rrip_add_CL(t, node);
|
||||
if (node->type == ECMA119_DIR
|
||||
&& node->dir.real_parent != node->parent) {
|
||||
rrip_add_RE(t, node);
|
||||
rrip_add_PL(t, node);
|
||||
|
||||
switch (node->type) {
|
||||
case ECMA119_FILE:
|
||||
break;
|
||||
case ECMA119_SYMLINK:
|
||||
rrip_add_SL(t, node);
|
||||
break;
|
||||
case ECMA119_DIR:
|
||||
if (node->info.dir.real_parent != node->parent) {
|
||||
rrip_add_RE(t, node);
|
||||
rrip_add_PL(t, node);
|
||||
}
|
||||
for (i = 0; i < node->info.dir.nchildren; i++) {
|
||||
add_susp_fields_rec(t, node->info.dir.children[i]);
|
||||
}
|
||||
break;
|
||||
case ECMA119_PLACEHOLDER:
|
||||
rrip_add_CL(t, node);
|
||||
break;
|
||||
default:
|
||||
// FIXME support for device blocks by uncommenting this
|
||||
//if (node->iso_self->attrib.st_rdev)
|
||||
// rrip_add_PN(t, node);
|
||||
break;
|
||||
}
|
||||
susp_add_CE(t, node);
|
||||
|
||||
if (node->type == ECMA119_DIR) {
|
||||
for (i = 0; i < node->dir.nchildren; i++) {
|
||||
add_susp_fields_rec(t, node->dir.children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -146,32 +160,33 @@ calc_dir_size(struct ecma119_write_target *t,
|
|||
struct ecma119_tree_node *dir)
|
||||
{
|
||||
size_t i;
|
||||
size_t newlen;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
t->dirlist_len++;
|
||||
dir->dir.len = 34 + dir->dir.self_susp.non_CE_len
|
||||
+ 34 + dir->dir.parent_susp.non_CE_len;
|
||||
dir->dir.CE_len = dir->dir.self_susp.CE_len
|
||||
+ dir->dir.parent_susp.CE_len;
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||
dir->info.dir.len = 34 + dir->info.dir.self_susp.non_CE_len
|
||||
+ 34 + dir->info.dir.parent_susp.non_CE_len;
|
||||
dir->info.dir.CE_len = dir->info.dir.self_susp.CE_len
|
||||
+ dir->info.dir.parent_susp.CE_len;
|
||||
for (i = 0; i < dir->info.dir.nchildren; ++i) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
|
||||
dir->dir.len += ch->dirent_len + ch->susp.non_CE_len;
|
||||
dir->dir.CE_len += ch->susp.CE_len;
|
||||
newlen = dir->info.dir.len + ch->dirent_len + ch->susp.non_CE_len;
|
||||
if ((newlen % 2048) < (dir->info.dir.len % 2048)) {
|
||||
dir->info.dir.len = newlen + (2048 - (dir->info.dir.len % 2048));
|
||||
} else {
|
||||
dir->info.dir.len += ch->dirent_len + ch->susp.non_CE_len;
|
||||
}
|
||||
dir->info.dir.CE_len += ch->susp.CE_len;
|
||||
}
|
||||
t->total_dir_size += round_up(dir->dir.len + dir->dir.CE_len,
|
||||
t->total_dir_size += round_up(dir->info.dir.len + dir->info.dir.CE_len,
|
||||
t->block_size);
|
||||
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||
struct iso_tree_node *iso = ch->iso_self;
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
if (ch->type == ECMA119_DIR) {
|
||||
calc_dir_size(t, ch);
|
||||
} else if (iso && iso->attrib.st_size
|
||||
&& iso->loc.type == LIBISO_FILESYS
|
||||
&& iso->loc.path) {
|
||||
t->filelist_len++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,97 +203,165 @@ calc_dir_pos(struct ecma119_write_target *t,
|
|||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
/* we don't need to set iso_self->block since each tree writes
|
||||
* its own directories */
|
||||
dir->block = t->curblock;
|
||||
t->curblock += div_up(dir->dir.len + dir->dir.CE_len, t->block_size);
|
||||
dir->info.dir.block = t->curblock;
|
||||
t->curblock += div_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size);
|
||||
t->dirlist[t->curfile++] = dir;
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
if (ch->type == ECMA119_DIR)
|
||||
calc_dir_pos(t, ch);
|
||||
}
|
||||
}
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
if (!dir->parent) {
|
||||
t->curfile = 0;
|
||||
}
|
||||
static int
|
||||
cmp_file(const void *f1, const void *f2)
|
||||
{
|
||||
struct iso_file *f = *((struct iso_file**)f1);
|
||||
struct iso_file *g = *((struct iso_file**)f2);
|
||||
/* higher weighted first */
|
||||
return g->sort_weight - f->sort_weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill out the block field for each ecma119_tree_node that is a file and fill
|
||||
* out t->filelist.
|
||||
* 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);
|
||||
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||
if (ch->type == ECMA119_FILE && ch->iso_self) {
|
||||
struct iso_tree_node *iso = ch->iso_self;
|
||||
off_t size = iso->attrib.st_size;
|
||||
for (i = 0; i < FILE_HASH_NODES; ++i) {
|
||||
|
||||
struct iso_file_hash_node *node;
|
||||
|
||||
iso->block = ch->block = t->curblock;
|
||||
t->curblock += div_up(size, t->block_size);
|
||||
if (size && iso->loc.type == LIBISO_FILESYS
|
||||
&& iso->loc.path)
|
||||
t->filelist[t->curfile++] = ch;
|
||||
}
|
||||
node = t->file_table->table[i];
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
do {
|
||||
struct iso_file *file = node->file;
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||
if (ch->type == ECMA119_DIR)
|
||||
calc_file_pos(t, ch);
|
||||
|
||||
t->filelist_len = t->curfile;
|
||||
|
||||
/* sort */
|
||||
if ( t->sort_files )
|
||||
qsort(t->filelist, t->filelist_len, sizeof(void*), cmp_file);
|
||||
|
||||
/* fill block value */
|
||||
for ( i = 0; i < t->filelist_len; ++i) {
|
||||
struct iso_file *file = t->filelist[i];
|
||||
file->block = t->curblock;
|
||||
t->curblock += div_up(file->size, t->block_size);
|
||||
}
|
||||
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
if (!dir->parent) {
|
||||
t->curfile = 0;
|
||||
}
|
||||
t->curfile = 0;
|
||||
}
|
||||
|
||||
struct ecma119_write_target*
|
||||
|
||||
/**
|
||||
* Create a new ecma119_write_target from the given volume number of the
|
||||
* given volume set.
|
||||
*
|
||||
* \pre \p volnum is less than \p volset-\>volset_size.
|
||||
* \post For each node in the tree, writer_data has been allocated.
|
||||
* \post The directory heirarchy has been reorganised to be ecma119-compatible.
|
||||
*/
|
||||
static struct ecma119_write_target*
|
||||
ecma119_target_new(struct iso_volset *volset,
|
||||
int volnum,
|
||||
int level,
|
||||
int flags)
|
||||
struct ecma119_source_opts *opts)
|
||||
{
|
||||
struct ecma119_write_target *t =
|
||||
calloc(1, sizeof(struct ecma119_write_target));
|
||||
size_t i, j, cur;
|
||||
struct iso_tree_node *iso_root = volset->volume[volnum]->root;
|
||||
struct iso_tree_node *iso_root =
|
||||
(struct iso_tree_node*) volset->volume[opts->volnum]->root;
|
||||
|
||||
t->cache_inodes = opts->no_cache_inodes ? 0 : 1;
|
||||
t->replace_mode = opts->default_mode ? 0 : 1;
|
||||
if ( opts->replace_dir_mode )
|
||||
t->replace_mode |= 0x02;
|
||||
if ( opts->replace_file_mode )
|
||||
t->replace_mode |= 0x04;
|
||||
if ( opts->replace_gid )
|
||||
t->replace_mode |= 0x08;
|
||||
if ( opts->replace_uid )
|
||||
t->replace_mode |= 0x10;
|
||||
t->dir_mode = opts->dir_mode;
|
||||
t->file_mode = opts->file_mode;
|
||||
t->gid = opts->gid;
|
||||
t->uid = opts->uid;
|
||||
|
||||
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++;
|
||||
t->iso_level = opts->level;
|
||||
t->block_size = 2048;
|
||||
t->relaxed_constraints = opts->relaxed_constraints;
|
||||
|
||||
t->rockridge = (opts->flags & ECMA119_ROCKRIDGE) ? 1 : 0;
|
||||
t->joliet = (opts->flags & ECMA119_JOLIET) ? 1 : 0;
|
||||
|
||||
t->catalog = volset->volume[opts->volnum]->bootcat;
|
||||
t->eltorito = t->catalog ? 1 : 0;
|
||||
t->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);
|
||||
t->joliet = (flags & ECMA119_JOLIET) ? 1 : 0;
|
||||
if (t->joliet)
|
||||
t->joliet_root = joliet_tree_create(t, iso_root);
|
||||
t->volset = volset;
|
||||
t->volnum = volnum;
|
||||
t->volnum = opts->volnum;
|
||||
t->now = time(NULL);
|
||||
|
||||
t->rockridge = (flags & ECMA119_ROCKRIDGE) ? 1 : 0;
|
||||
t->iso_level = level;
|
||||
t->block_size = 2048;
|
||||
|
||||
if (t->rockridge)
|
||||
add_susp_fields(t);
|
||||
|
||||
calc_dir_size(t, t->root);
|
||||
if (t->joliet) {
|
||||
joliet_calc_dir_size(t, t->joliet_root);
|
||||
t->pathlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len);
|
||||
t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len);
|
||||
t->pathlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len_joliet);
|
||||
t->dirlist_joliet = calloc(1, sizeof(void*) * t->dirlist_len_joliet);
|
||||
}
|
||||
|
||||
t->dirlist = calloc(1, sizeof(void*) * t->dirlist_len);
|
||||
t->pathlist = calloc(1, sizeof(void*) * t->dirlist_len);
|
||||
t->filelist = calloc(1, sizeof(void*) * t->filelist_len);
|
||||
|
||||
/* fill out the pathlist */
|
||||
t->pathlist[0] = t->root;
|
||||
|
@ -286,20 +369,23 @@ ecma119_target_new(struct iso_volset *volset,
|
|||
cur = 1;
|
||||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
struct ecma119_tree_node *dir = t->pathlist[i];
|
||||
for (j = 0; j < dir->dir.nchildren; j++) {
|
||||
struct ecma119_tree_node *ch = dir->dir.children[j];
|
||||
for (j = 0; j < dir->info.dir.nchildren; j++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[j];
|
||||
if (ch->type == ECMA119_DIR) {
|
||||
size_t len = 8 + strlen(ch->name);
|
||||
size_t len = 8 + strlen(ch->iso_name);
|
||||
t->pathlist[cur++] = ch;
|
||||
t->path_table_size += len + len % 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t->curblock = 16 /* system area */
|
||||
+ 1 /* volume desc */
|
||||
+ 1; /* volume desc terminator */
|
||||
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 */
|
||||
if (t->joliet) /* supplementary vol desc */
|
||||
t->curblock += div_up (2048, t->block_size);
|
||||
|
||||
|
@ -316,23 +402,84 @@ ecma119_target_new(struct iso_volset *volset,
|
|||
}
|
||||
|
||||
calc_dir_pos(t, t->root);
|
||||
if (t->joliet)
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
t->curfile = 0;
|
||||
if (t->joliet) {
|
||||
|
||||
joliet_calc_dir_pos(t, t->joliet_root);
|
||||
calc_file_pos(t, t->root);
|
||||
if (t->joliet)
|
||||
joliet_update_file_pos (t, t->joliet_root);
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
t->curfile = 0;
|
||||
}
|
||||
|
||||
/* el-torito? */
|
||||
if (t->eltorito) {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -346,14 +493,25 @@ is_joliet_state(enum ecma119_write_state state)
|
|||
|| state == ECMA119_WRITE_DIR_RECORDS_JOLIET;
|
||||
}
|
||||
|
||||
static int
|
||||
is_eltorito_state(enum ecma119_write_state state)
|
||||
{
|
||||
return state == ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC
|
||||
|| state == ECMA119_WRITE_ELTORITO_CATALOG;
|
||||
}
|
||||
|
||||
static void
|
||||
next_state(struct ecma119_write_target *t)
|
||||
{
|
||||
char msg[42];
|
||||
t->state++;
|
||||
while (!t->joliet && is_joliet_state(t->state))
|
||||
while ( (!t->joliet && is_joliet_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
|
||||
|
@ -397,29 +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 ecma119_tree_node *f = t->filelist[f_st->file];
|
||||
const char *path = f->iso_self->loc.path;
|
||||
struct iso_file *f = t->filelist[f_st->file];
|
||||
|
||||
if (!f_st->fd) {
|
||||
f_st->data_len = f->iso_self->attrib.st_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);
|
||||
|
@ -431,15 +593,25 @@ write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
|||
{
|
||||
struct ecma119_pri_vol_desc *vol = (struct ecma119_pri_vol_desc*)buf;
|
||||
struct iso_volume *volume = t->volset->volume[t->volnum];
|
||||
char *vol_id = str2ascii(volume->volume_id);
|
||||
char *pub_id = str2ascii(volume->publisher_id);
|
||||
char *data_id = str2ascii(volume->data_preparer_id);
|
||||
char *volset_id = str2ascii(t->volset->volset_id);
|
||||
|
||||
char *vol_id = str2d_char(volume->volume_id, t->input_charset);
|
||||
char *pub_id = str2a_char(volume->publisher_id, t->input_charset);
|
||||
char *data_id = str2a_char(volume->data_preparer_id, t->input_charset);
|
||||
char *volset_id = str2d_char(t->volset->volset_id, t->input_charset);
|
||||
|
||||
char *system_id = str2a_char(volume->system_id, t->input_charset);
|
||||
char *application_id = str2a_char(volume->application_id, t->input_charset);
|
||||
char *copyright_file_id = str2d_char(volume->copyright_file_id, t->input_charset);
|
||||
char *abstract_file_id = str2d_char(volume->abstract_file_id, t->input_charset);
|
||||
char *biblio_file_id = str2d_char(volume->biblio_file_id, t->input_charset);
|
||||
|
||||
vol->vol_desc_type[0] = 1;
|
||||
memcpy(vol->std_identifier, "CD001", 5);
|
||||
vol->vol_desc_version[0] = 1;
|
||||
memcpy(vol->system_id, "SYSID", 5);
|
||||
if (system_id)
|
||||
strncpy((char*)vol->system_id, system_id, 32);
|
||||
else
|
||||
/* put linux by default? */
|
||||
memcpy(vol->system_id, "LINUX", 5);
|
||||
if (vol_id)
|
||||
strncpy((char*)vol->volume_id, vol_id, 32);
|
||||
iso_bb(vol->vol_space_size, t->vol_space_size, 4);
|
||||
|
@ -452,10 +624,19 @@ write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
|||
|
||||
write_one_dir_record(t, t->root, 3, vol->root_dir_record);
|
||||
|
||||
/* mmm, why not check for null? */
|
||||
strncpy((char*)vol->vol_set_id, volset_id, 128);
|
||||
strncpy((char*)vol->publisher_id, pub_id, 128);
|
||||
strncpy((char*)vol->data_prep_id, data_id, 128);
|
||||
strncpy((char*)vol->application_id, "APPID", 128);
|
||||
|
||||
if (application_id)
|
||||
strncpy((char*)vol->application_id, application_id, 128);
|
||||
if (copyright_file_id)
|
||||
strncpy((char*)vol->copyright_file_id, copyright_file_id, 37);
|
||||
if (abstract_file_id)
|
||||
strncpy((char*)vol->abstract_file_id, abstract_file_id, 37);
|
||||
if (biblio_file_id)
|
||||
strncpy((char*)vol->bibliographic_file_id, biblio_file_id, 37);
|
||||
|
||||
iso_datetime_17(vol->vol_creation_time, t->now);
|
||||
iso_datetime_17(vol->vol_modification_time, t->now);
|
||||
|
@ -466,6 +647,11 @@ write_pri_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
|||
free(volset_id);
|
||||
free(pub_id);
|
||||
free(data_id);
|
||||
free(system_id);
|
||||
free(application_id);
|
||||
free(copyright_file_id);
|
||||
free(abstract_file_id);
|
||||
free(biblio_file_id);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -491,17 +677,18 @@ write_path_table(struct ecma119_write_target *t, int l_type, uint8_t *buf)
|
|||
|
||||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
dir = t->pathlist[i];
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
while ((i) && t->pathlist[parent] != dir->parent)
|
||||
parent++;
|
||||
assert(parent < i || i == 0);
|
||||
|
||||
rec = (struct ecma119_path_table_record*) buf;
|
||||
rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->name) : 1;
|
||||
rec->len_di[0] = dir->parent ? (uint8_t) strlen(dir->iso_name) : 1;
|
||||
rec->len_xa[0] = 0;
|
||||
write_int(rec->block, dir->block, 4);
|
||||
write_int(rec->block, dir->info.dir.block, 4);
|
||||
write_int(rec->parent, parent + 1, 2);
|
||||
if (dir->parent)
|
||||
memcpy(rec->dir_id, dir->name, rec->len_di[0]);
|
||||
memcpy(rec->dir_id, dir->iso_name, rec->len_di[0]);
|
||||
buf += 8 + rec->len_di[0] + (rec->len_di[0] % 2);
|
||||
}
|
||||
}
|
||||
|
@ -527,22 +714,46 @@ write_one_dir_record(struct ecma119_write_target *t,
|
|||
int file_id,
|
||||
uint8_t *buf)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t block;
|
||||
uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len;
|
||||
uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->name);
|
||||
uint8_t len_fi = (file_id >= 0) ? 1 : strlen(node->iso_name);
|
||||
uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id);
|
||||
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name;
|
||||
uint32_t len = (node->type == ECMA119_DIR) ? node->dir.len
|
||||
: node->file.real_me ? 0 : node->iso_self->attrib.st_size;
|
||||
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->iso_name;
|
||||
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
|
||||
|
||||
|
||||
if (node->type == ECMA119_DIR) {
|
||||
len = node->info.dir.len;
|
||||
block = node->info.dir.block;
|
||||
} else if (node->type == ECMA119_FILE) {
|
||||
len = node->info.file->size;
|
||||
block = node->info.file->block;
|
||||
} else 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;
|
||||
block = 0;
|
||||
}
|
||||
|
||||
/* we don't write out susp fields for the root node */
|
||||
if (t->rockridge) {
|
||||
if (file_id == 0) {
|
||||
susp_write(t, &node->dir.self_susp, &buf[len_dr]);
|
||||
len_dr += node->dir.self_susp.non_CE_len;
|
||||
assert(node->type == ECMA119_DIR);
|
||||
susp_write(t, &node->info.dir.self_susp, &buf[len_dr]);
|
||||
len_dr += node->info.dir.self_susp.non_CE_len;
|
||||
} else if (file_id == 1) {
|
||||
susp_write(t, &node->dir.parent_susp, &buf[len_dr]);
|
||||
len_dr += node->dir.parent_susp.non_CE_len;
|
||||
assert(node->type == ECMA119_DIR);
|
||||
susp_write(t, &node->info.dir.parent_susp, &buf[len_dr]);
|
||||
len_dr += node->info.dir.parent_susp.non_CE_len;
|
||||
} else if (file_id < 0) {
|
||||
susp_write(t, &node->susp, &buf[len_dr]);
|
||||
len_dr += node->susp.non_CE_len;
|
||||
|
@ -552,7 +763,7 @@ write_one_dir_record(struct ecma119_write_target *t,
|
|||
node = node->parent;
|
||||
|
||||
rec->len_dr[0] = len_dr;
|
||||
iso_bb(rec->block, node->block, 4);
|
||||
iso_bb(rec->block, block, 4);
|
||||
iso_bb(rec->length, len, 4);
|
||||
iso_datetime_7(rec->recording_time, t->now);
|
||||
rec->flags[0] = (node->type == ECMA119_DIR) ? 2 : 0;
|
||||
|
@ -567,7 +778,10 @@ write_one_dir(struct ecma119_write_target *t,
|
|||
uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
int j;
|
||||
size_t len;
|
||||
uint8_t *orig_buf = buf;
|
||||
uint8_t *prior_buf = buf;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
/* write the "." and ".." entries first */
|
||||
|
@ -577,23 +791,34 @@ write_one_dir(struct ecma119_write_target *t,
|
|||
write_one_dir_record(t, dir, 1, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
write_one_dir_record(t, dir->dir.children[i], -1, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
write_one_dir_record(t, dir->info.dir.children[i], -1, buf);
|
||||
len = ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
if ((buf + len - prior_buf) >= 2048) {
|
||||
for (j = len - 1; j >= 0; j--) {
|
||||
prior_buf[2048 + j] = buf[j];
|
||||
buf[j] = 0;
|
||||
}
|
||||
prior_buf += 2048;
|
||||
buf = prior_buf + len;
|
||||
}
|
||||
else {
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
}
|
||||
}
|
||||
|
||||
/* write the susp continuation areas */
|
||||
if (t->rockridge) {
|
||||
susp_write_CE(t, &dir->dir.self_susp, buf);
|
||||
buf += dir->dir.self_susp.CE_len;
|
||||
susp_write_CE(t, &dir->dir.parent_susp, buf);
|
||||
buf += dir->dir.parent_susp.CE_len;
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
susp_write_CE(t, &dir->dir.children[i]->susp, buf);
|
||||
buf += dir->dir.children[i]->susp.CE_len;
|
||||
susp_write_CE(t, &dir->info.dir.self_susp, buf);
|
||||
buf += dir->info.dir.self_susp.CE_len;
|
||||
susp_write_CE(t, &dir->info.dir.parent_susp, buf);
|
||||
buf += dir->info.dir.parent_susp.CE_len;
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
susp_write_CE(t, &dir->info.dir.children[i]->susp, buf);
|
||||
buf += dir->info.dir.children[i]->susp.CE_len;
|
||||
}
|
||||
}
|
||||
assert (buf - orig_buf == dir->dir.len + dir->dir.CE_len);
|
||||
assert (buf - orig_buf == dir->info.dir.len + dir->info.dir.CE_len);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -604,7 +829,7 @@ write_dirs(struct ecma119_write_target *t, uint8_t *buf)
|
|||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
dir = t->dirlist[i];
|
||||
write_one_dir(t, dir, buf);
|
||||
buf += round_up(dir->dir.len + dir->dir.CE_len, t->block_size);
|
||||
buf += round_up(dir->info.dir.len + dir->info.dir.CE_len, t->block_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,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
|
||||
|
@ -669,26 +929,38 @@ bs_free_data(struct burn_source *bs)
|
|||
{
|
||||
struct ecma119_write_target *t = (struct ecma119_write_target*)bs->data;
|
||||
ecma119_tree_free(t->root);
|
||||
iso_file_table_clear(t->file_table);
|
||||
|
||||
free(t->dirlist);
|
||||
free(t->pathlist);
|
||||
free(t->dirlist_joliet);
|
||||
free(t->pathlist_joliet);
|
||||
free(t->filelist);
|
||||
free(t->state_data);
|
||||
if (t->state_files.fd)
|
||||
fclose(t->state_files.fd);
|
||||
if (t->joliet)
|
||||
joliet_tree_free(t->joliet_root);
|
||||
|
||||
// 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,
|
||||
int volnum,
|
||||
int level,
|
||||
int flags)
|
||||
struct ecma119_source_opts *opts)
|
||||
{
|
||||
struct burn_source *ret = calloc(1, sizeof(struct burn_source));
|
||||
ret->refcount = 1;
|
||||
ret->read = bs_read;
|
||||
ret->get_size = bs_get_size;
|
||||
ret->set_size = bs_set_size;
|
||||
ret->free_data = bs_free_data;
|
||||
ret->data = ecma119_target_new(volset, volnum, level, flags);
|
||||
ret->data = ecma119_target_new(volset, opts);
|
||||
return ret;
|
||||
}
|
||||
|
|
99
libisofs/ecma119.h
Executable file → Normal file
99
libisofs/ecma119.h
Executable file → Normal file
|
@ -29,6 +29,7 @@ enum ecma119_write_state
|
|||
|
||||
ECMA119_WRITE_SYSTEM_AREA,
|
||||
ECMA119_WRITE_PRI_VOL_DESC,
|
||||
ECMA119_WRITE_ELTORITO_BOOT_VOL_DESC,
|
||||
ECMA119_WRITE_SUP_VOL_DESC_JOLIET,
|
||||
ECMA119_WRITE_VOL_DESC_TERMINATOR,
|
||||
ECMA119_WRITE_L_PATH_TABLE,
|
||||
|
@ -37,6 +38,7 @@ enum ecma119_write_state
|
|||
ECMA119_WRITE_M_PATH_TABLE_JOLIET,
|
||||
ECMA119_WRITE_DIR_RECORDS,
|
||||
ECMA119_WRITE_DIR_RECORDS_JOLIET,
|
||||
ECMA119_WRITE_ELTORITO_CATALOG,
|
||||
ECMA119_WRITE_FILES,
|
||||
|
||||
ECMA119_WRITE_DONE
|
||||
|
@ -61,7 +63,57 @@ struct ecma119_write_target
|
|||
unsigned int rockridge:1;
|
||||
unsigned int joliet:1;
|
||||
unsigned int iso_level:2;
|
||||
unsigned int eltorito:1;
|
||||
|
||||
unsigned int write_eltorito:1;
|
||||
/**<
|
||||
* In multisession discs, select whether to copy el-torito catalog
|
||||
* and boot image. Copy is needed for isolinux images, that need to
|
||||
* be patched. However, it can lead to problems when the image is
|
||||
* not present in the iso filesystem, because we can't figure out
|
||||
* its size. In those cases, we only copy 1 block of data.
|
||||
* When modifying images, we always need to copy data. Thus, this is
|
||||
* always 1 for both new and modified images.
|
||||
*/
|
||||
|
||||
struct el_torito_boot_catalog *catalog;
|
||||
uint32_t catblock; /**< location of the boot catalog in the new image */
|
||||
uint32_t imgblock; /**< location of the boot image in the new image */
|
||||
|
||||
int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */
|
||||
|
||||
int replace_mode; /**< Replace ownership and modes of files
|
||||
*
|
||||
* 0. filesystem values
|
||||
* 1. useful values
|
||||
* bits 1-4 bitmask:
|
||||
* 2 - replace dir
|
||||
* 3 - replace file
|
||||
* 4 - replace gid
|
||||
* 5 - replace uid
|
||||
*/
|
||||
mode_t dir_mode;
|
||||
mode_t file_mode;
|
||||
gid_t gid;
|
||||
uid_t uid;
|
||||
|
||||
char *input_charset;
|
||||
char *ouput_charset;
|
||||
|
||||
int cache_inodes;
|
||||
|
||||
int sort_files; /**< if sort files or not. Sorting is based of
|
||||
* the weight of each file */
|
||||
|
||||
/**
|
||||
* In the CD, each file must have an unique inode number. So each
|
||||
* time we add a new file, this is incremented.
|
||||
*/
|
||||
ino_t ino;
|
||||
|
||||
uint32_t ms_block; /**< if != 0, nwa for multisession */
|
||||
struct data_source* src;
|
||||
|
||||
int curblock;
|
||||
uint16_t block_size;
|
||||
uint32_t path_table_size;
|
||||
|
@ -86,10 +138,13 @@ struct ecma119_write_target
|
|||
size_t dirlist_len; /**< The length of the previous 2 lists.
|
||||
*/
|
||||
|
||||
struct ecma119_tree_node **filelist;
|
||||
/**< A pre-order list of files with
|
||||
* non-NULL paths and non-zero sizes.
|
||||
|
||||
struct iso_file_table *file_table;
|
||||
/**<
|
||||
* A hash table with info about all files
|
||||
*/
|
||||
|
||||
struct iso_file **filelist; /**< A pre-order list of files.*/
|
||||
size_t filelist_len; /* Length of the previous list. */
|
||||
|
||||
int curfile; /**< Used as a helper field for writing
|
||||
|
@ -101,6 +156,8 @@ struct ecma119_write_target
|
|||
*/
|
||||
struct joliet_tree_node **dirlist_joliet;
|
||||
struct joliet_tree_node **pathlist_joliet;
|
||||
|
||||
size_t dirlist_len_joliet;
|
||||
|
||||
enum ecma119_write_state state; /* The current state of the writer. */
|
||||
|
||||
|
@ -117,30 +174,15 @@ 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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ecma119_write_target from the given volume number of the
|
||||
* given volume set.
|
||||
*
|
||||
* \pre \p volnum is less than \p volset-\>volset_size.
|
||||
* \post For each node in the tree, writer_data has been allocated.
|
||||
* \post The directory heirarchy has been reorganised to be ecma119-compatible.
|
||||
*/
|
||||
struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset,
|
||||
int volnum,
|
||||
int level,
|
||||
int flags);
|
||||
/* temp buffer for read functions */
|
||||
uint8_t buffer[2048];
|
||||
int bytes_read;
|
||||
};
|
||||
|
||||
#define BP(a,b) [(b) - (a) + 1]
|
||||
|
||||
|
@ -218,6 +260,17 @@ struct ecma119_sup_vol_desc
|
|||
uint8_t reserved2 BP(1396, 2048);
|
||||
};
|
||||
|
||||
struct ecma119_boot_rec_vol_desc
|
||||
{
|
||||
uint8_t vol_desc_type BP(1, 1);
|
||||
uint8_t std_identifier BP(2, 6);
|
||||
uint8_t vol_desc_version BP(7, 7);
|
||||
uint8_t boot_sys_id BP(8, 39);
|
||||
uint8_t boot_id BP(40, 71);
|
||||
uint8_t boot_catalog BP(72, 75);
|
||||
uint8_t unused BP(76, 2048);
|
||||
};
|
||||
|
||||
struct ecma119_vol_desc_terminator
|
||||
{
|
||||
uint8_t vol_desc_type BP(1, 1);
|
||||
|
|
888
libisofs/ecma119_read.c
Normal file
888
libisofs/ecma119_read.c
Normal 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
76
libisofs/ecma119_read.h
Normal 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
316
libisofs/ecma119_read_rr.c
Normal 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
144
libisofs/ecma119_read_rr.h
Normal 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_*/
|
|
@ -9,74 +9,339 @@
|
|||
#include "ecma119_tree.h"
|
||||
#include "tree.h"
|
||||
#include "util.h"
|
||||
#include "eltorito.h"
|
||||
|
||||
static size_t calc_dirent_len(struct ecma119_tree_node *n)
|
||||
{
|
||||
int ret = n->name ? strlen(n->name) + 33 : 34;
|
||||
int ret = n->iso_name ? strlen(n->iso_name) + 33 : 34;
|
||||
if (ret % 2) ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the file permissions and user/group id of an ECMA-119 node.
|
||||
* This is used when a replace mode is selected, i.e., when we want to
|
||||
* create a disc where the mode of each file or directory will be
|
||||
* different than the mode in the original source.
|
||||
*/
|
||||
static void
|
||||
replace_node_mode(struct ecma119_write_target *t, struct stat *st)
|
||||
{
|
||||
if ( S_ISDIR(st->st_mode) ) {
|
||||
if ( t->replace_mode & 0x02 ) {
|
||||
/* replace dir mode with specific */
|
||||
st->st_mode &= S_IFMT;
|
||||
st->st_mode |= t->dir_mode;
|
||||
} else if (t->replace_mode & 0x01) {
|
||||
/* replace dir mode with default */
|
||||
/* read perm */
|
||||
mode_t new_mode = (st->st_mode & S_IFMT) | 0444;
|
||||
/* search bit if any */
|
||||
if ( st->st_mode & 0111)
|
||||
new_mode |= 0111;
|
||||
st->st_mode = new_mode;
|
||||
}
|
||||
} else {
|
||||
if ( t->replace_mode & 0x04 ) {
|
||||
/* replace file mode with specific */
|
||||
st->st_mode &= S_IFMT;
|
||||
st->st_mode |= t->file_mode;
|
||||
} else if (t->replace_mode & 0x01) {
|
||||
/* replace file mode with default */
|
||||
/* read perm */
|
||||
mode_t new_mode = (st->st_mode & S_IFMT) | 0444;
|
||||
/* execute bit if any */
|
||||
if ( st->st_mode & 0111)
|
||||
new_mode |= 0111;
|
||||
st->st_mode = new_mode;
|
||||
}
|
||||
|
||||
}
|
||||
if ( t->replace_mode & 0x08 ) {
|
||||
/* replace gid mode with specific */
|
||||
st->st_gid = t->gid;
|
||||
} else if (t->replace_mode & 0x01) {
|
||||
st->st_gid = 0;
|
||||
}
|
||||
if ( t->replace_mode & 0x10 ) {
|
||||
/* replace gid mode with specific */
|
||||
st->st_uid = t->uid;
|
||||
} else if (t->replace_mode & 0x01) {
|
||||
st->st_uid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ECMA-119 node from the given iso tree node, and initializes
|
||||
* the fields that are common to all kind of nodes (dir, reg file, symlink...).
|
||||
*
|
||||
* @param t
|
||||
* The options for the ECMA-119 tree that is being created
|
||||
* @param parent
|
||||
* The parent of the node, or NULL if it's the root.
|
||||
* @param iso
|
||||
* The node from which this function creates a ECMA-119 node
|
||||
* @return
|
||||
* The created node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_ecma119_node(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
char *(*iso_name)(const char *, const char *) = ISO_ISDIR(iso) ?
|
||||
((t->iso_level == 1) ? iso_1_dirid : iso_2_dirid)
|
||||
: ((t->iso_level == 1) ? iso_1_fileid : iso_2_fileid);
|
||||
char *(*iso_r_name)(const char *, const char *, int) =
|
||||
ISO_ISDIR(iso) ? iso_r_dirid : iso_r_fileid;
|
||||
|
||||
assert(t && (!parent || parent->type == ECMA119_DIR) && iso );
|
||||
|
||||
ret = calloc(1, sizeof(struct ecma119_tree_node));
|
||||
|
||||
/*
|
||||
* If selected one ISO relaxed constraints other than NO_DIR_REALOCATION,
|
||||
* we use the function that computes the relaxed name, otherwise normal
|
||||
* function for specified level is used.
|
||||
*/
|
||||
ret->iso_name = iso->name ?
|
||||
( t->relaxed_constraints & ~ECMA119_NO_DIR_REALOCATION ?
|
||||
iso_r_name(iso->name, t->input_charset, t->relaxed_constraints) :
|
||||
iso_name(iso->name, t->input_charset)
|
||||
) : NULL;
|
||||
ret->dirent_len = calc_dirent_len(ret);
|
||||
|
||||
/* iso node keeps the same file attribs as the original file. */
|
||||
ret->attrib = iso->attrib;
|
||||
|
||||
/*
|
||||
* When using RR extension and replace mode, we will replace the
|
||||
* permissions and uid/gid of each file with those previously selected
|
||||
* by the user.
|
||||
*/
|
||||
if ( t->rockridge && t->replace_mode )
|
||||
replace_node_mode(t, &ret->attrib);
|
||||
|
||||
if (!iso->name)
|
||||
ret->full_name = NULL;
|
||||
else if ( strcmp(t->input_charset,t->ouput_charset) )
|
||||
/* convert the file name charset */
|
||||
ret->full_name = convert_str(iso->name, t->input_charset,
|
||||
t->ouput_charset);
|
||||
else
|
||||
ret->full_name = strdup(iso->name);
|
||||
ret->target = t;
|
||||
ret->parent = parent;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a directory from a iso directory
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_dir(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node *iso)
|
||||
struct iso_tree_node_dir *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
|
||||
assert(t && (!parent || parent->type == ECMA119_DIR)
|
||||
&& iso && S_ISDIR(iso->attrib.st_mode));
|
||||
&& iso && S_ISDIR(iso->node.attrib.st_mode));
|
||||
|
||||
ret = calloc(1, sizeof(struct ecma119_tree_node));
|
||||
ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_dirid(iso->name)
|
||||
: iso_2_dirid(iso->name))
|
||||
: NULL;
|
||||
ret->dirent_len = calc_dirent_len(ret);
|
||||
ret->iso_self = iso;
|
||||
ret->target = t;
|
||||
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
|
||||
ret->type = ECMA119_DIR;
|
||||
ret->parent = ret->dir.real_parent = parent;
|
||||
ret->dir.depth = parent ? parent->dir.depth + 1 : 1;
|
||||
ret->dir.nchildren = iso->nchildren;
|
||||
ret->dir.children = calloc(1, sizeof(void*) * iso->nchildren);
|
||||
ret->info.dir.real_parent = parent;
|
||||
ret->info.dir.depth = parent ? parent->info.dir.depth + 1 : 1;
|
||||
ret->info.dir.nchildren = 0;
|
||||
ret->info.dir.children = calloc(1, sizeof(void*) * iso->nchildren);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a regular file from a iso file
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_file(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node *iso)
|
||||
struct iso_tree_node_file *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
struct iso_file *file;
|
||||
|
||||
assert(t && iso && parent && parent->type == ECMA119_DIR);
|
||||
|
||||
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
|
||||
ret->type = ECMA119_FILE;
|
||||
|
||||
/* get iso_file struct */
|
||||
file = iso_file_table_lookup(t->file_table, iso);
|
||||
if ( file == NULL ) {
|
||||
/*
|
||||
* If the file is not already added to the disc, we add it now
|
||||
* to the file table, and get a new inode number for it.
|
||||
*/
|
||||
file = iso_file_new(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 {
|
||||
/* increment number of hard-links */
|
||||
file->nlink++;
|
||||
}
|
||||
|
||||
ret->attrib.st_nlink = file->nlink;
|
||||
ret->attrib.st_ino = file->ino;
|
||||
ret->info.file = file;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a placeholder for a relocated
|
||||
* dir.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5 for details
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_placeholder(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct ecma119_tree_node *real)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
|
||||
assert(t && real && real->type == ECMA119_DIR
|
||||
&& parent && parent->type == ECMA119_DIR);
|
||||
|
||||
ret = calloc(1, sizeof(struct ecma119_tree_node));
|
||||
ret->iso_name = real->iso_name; /* TODO strdup? */
|
||||
/* FIXME
|
||||
* if we strdup above, if name changes in mangle_all,
|
||||
* this probably keeps as original.
|
||||
* if not, both change, but we need to update dirent_len.
|
||||
* I think that attributes of a placeholder must be taken from
|
||||
* real_me, not keept here.
|
||||
* FIXME
|
||||
* Another question is that real is a dir, while placeholder is
|
||||
* a file, and ISO name restricctions are different, what to do?
|
||||
*/
|
||||
ret->dirent_len = real->dirent_len;
|
||||
ret->attrib = real->attrib;
|
||||
ret->full_name = strdup(real->full_name);
|
||||
ret->target = t;
|
||||
ret->parent = parent;
|
||||
ret->type = ECMA119_PLACEHOLDER;
|
||||
ret->info.real_me = real;
|
||||
ret->attrib.st_nlink = 1;
|
||||
ret->attrib.st_ino = ++t->ino;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a symbolic link from a iso symlink
|
||||
* node.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_symlink(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node_symlink *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
|
||||
assert(t && iso && parent && parent->type == ECMA119_DIR);
|
||||
|
||||
ret = calloc(1, sizeof(struct ecma119_tree_node));
|
||||
ret->name = iso->name ? ((t->iso_level == 1) ? iso_1_fileid(iso->name)
|
||||
: iso_2_fileid(iso->name))
|
||||
: NULL;
|
||||
ret->dirent_len = calc_dirent_len(ret);
|
||||
ret->parent = parent;
|
||||
ret->iso_self = iso;
|
||||
ret->target = t;
|
||||
ret->type = ECMA119_FILE;
|
||||
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
|
||||
ret->type = ECMA119_SYMLINK;
|
||||
ret->info.dest = iso->dest; /* TODO strdup? */
|
||||
ret->attrib.st_nlink = 1;
|
||||
ret->attrib.st_ino = ++t->ino;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node representing a boot catalog 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(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node_boot *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
|
||||
assert(t && iso && parent && parent->type == ECMA119_DIR);
|
||||
|
||||
ret = create_ecma119_node(t, parent, (struct iso_tree_node*) iso);
|
||||
ret->type = ECMA119_BOOT;
|
||||
|
||||
ret->info.boot_img = iso->img;
|
||||
|
||||
ret->attrib.st_nlink = 1;
|
||||
ret->attrib.st_ino = ++t->ino;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ECMA-119 node that corresponds to the given iso tree node.
|
||||
* If that node is a dir, this function recurses over all their children,
|
||||
* thus creating a ECMA-119 tree whose root is the given iso dir.
|
||||
*/
|
||||
static struct ecma119_tree_node*
|
||||
create_tree(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *parent,
|
||||
struct iso_tree_node *iso)
|
||||
{
|
||||
struct ecma119_tree_node *ret;
|
||||
size_t i;
|
||||
struct ecma119_tree_node *ret = NULL;
|
||||
|
||||
assert(t && iso);
|
||||
|
||||
ret = (S_ISDIR(iso->attrib.st_mode) ? create_dir : create_file)
|
||||
(t, parent, iso);
|
||||
for (i = 0; i < iso->nchildren; i++) {
|
||||
ret->dir.children[i] = create_tree(t, ret, iso->children[i]);
|
||||
|
||||
if ( iso->hide_flags & LIBISO_HIDE_ON_RR )
|
||||
return NULL;
|
||||
|
||||
switch ( iso->type ) {
|
||||
case LIBISO_NODE_FILE:
|
||||
ret = create_file(t, parent, (struct iso_tree_node_file*)iso);
|
||||
break;
|
||||
case LIBISO_NODE_SYMLINK:
|
||||
if ( !t->rockridge )
|
||||
printf("Can't add symlinks to a non ISO tree. Skipping %s \n",
|
||||
iso->name);
|
||||
else
|
||||
ret = create_symlink(t, parent, (struct iso_tree_node_symlink*)iso);
|
||||
break;
|
||||
case LIBISO_NODE_DIR:
|
||||
{
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir = (struct iso_tree_node_dir*)iso;
|
||||
ret = create_dir(t, parent, dir);
|
||||
for (i = 0; i < dir->nchildren; i++) {
|
||||
struct ecma119_tree_node *child;
|
||||
child = create_tree(t, ret, dir->children[i]);
|
||||
if (child)
|
||||
ret->info.dir.children[ret->info.dir.nchildren++] = child;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LIBISO_NODE_BOOT:
|
||||
ret = create_boot(t, parent, (struct iso_tree_node_boot*)iso);
|
||||
break;
|
||||
default:
|
||||
/* should never happen */
|
||||
assert( 0 );
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -87,12 +352,13 @@ ecma119_tree_free(struct ecma119_tree_node *root)
|
|||
size_t i;
|
||||
|
||||
if (root->type == ECMA119_DIR) {
|
||||
for (i=0; i < root->dir.nchildren; i++) {
|
||||
ecma119_tree_free(root->dir.children[i]);
|
||||
for (i=0; i < root->info.dir.nchildren; i++) {
|
||||
ecma119_tree_free(root->info.dir.children[i]);
|
||||
}
|
||||
free(root->dir.children);
|
||||
free(root->info.dir.children);
|
||||
}
|
||||
free(root->name);
|
||||
free(root->iso_name);
|
||||
free(root->full_name);
|
||||
free(root);
|
||||
}
|
||||
|
||||
|
@ -102,13 +368,19 @@ max_child_name_len(struct ecma119_tree_node *root)
|
|||
size_t ret = 0, i;
|
||||
|
||||
assert(root->type == ECMA119_DIR);
|
||||
for (i=0; i < root->dir.nchildren; i++) {
|
||||
size_t len = strlen(root->dir.children[i]->name);
|
||||
for (i=0; i < root->info.dir.nchildren; i++) {
|
||||
size_t len = strlen(root->info.dir.children[i]->iso_name);
|
||||
ret = MAX(ret, len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Relocates a directory, as specified in Rock Ridge Specification
|
||||
* (see IEEE P1282, section 4.1.5). This is needed when the number of levels
|
||||
* on a directory hierarchy exceeds 8, or the length of a path is higher
|
||||
* than 255 characters, as specified in ECMA-119, section 6.8.2.1
|
||||
*/
|
||||
static void
|
||||
reparent(struct ecma119_tree_node *child,
|
||||
struct ecma119_tree_node *parent)
|
||||
|
@ -120,13 +392,11 @@ reparent(struct ecma119_tree_node *child,
|
|||
assert(child && parent && parent->type == ECMA119_DIR && child->parent);
|
||||
|
||||
/* replace the child in the original parent with a placeholder */
|
||||
for (i=0; i < child->parent->dir.nchildren; i++) {
|
||||
if (child->parent->dir.children[i] == child) {
|
||||
placeholder = create_file(child->target,
|
||||
child->parent,
|
||||
child->iso_self);
|
||||
placeholder->file.real_me = child;
|
||||
child->parent->dir.children[i] = placeholder;
|
||||
for (i=0; i < child->parent->info.dir.nchildren; i++) {
|
||||
if (child->parent->info.dir.children[i] == child) {
|
||||
placeholder = create_placeholder(child->target,
|
||||
child->parent, child);
|
||||
child->parent->info.dir.children[i] = placeholder;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -135,52 +405,83 @@ reparent(struct ecma119_tree_node *child,
|
|||
|
||||
/* add the child to its new parent */
|
||||
child->parent = parent;
|
||||
parent->dir.nchildren++;
|
||||
parent->dir.children = realloc( parent->dir.children,
|
||||
sizeof(void*) * parent->dir.nchildren );
|
||||
parent->dir.children[parent->dir.nchildren-1] = child;
|
||||
parent->info.dir.nchildren++;
|
||||
parent->info.dir.children = realloc( parent->info.dir.children,
|
||||
sizeof(void*) * parent->info.dir.nchildren );
|
||||
parent->info.dir.children[parent->info.dir.nchildren-1] = child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the tree, if necessary, to ensure that
|
||||
* - the depth is at most 8
|
||||
* - each path length is at most 255 characters
|
||||
* This restriction is imposed by ECMA-119 specification (see ECMA-119,
|
||||
* 6.8.2.1).
|
||||
*/
|
||||
static void
|
||||
reorder_tree(struct ecma119_tree_node *root,
|
||||
reorder_tree(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *root,
|
||||
struct ecma119_tree_node *cur)
|
||||
{
|
||||
size_t max_path;
|
||||
|
||||
assert(root && cur && cur->type == ECMA119_DIR);
|
||||
|
||||
cur->dir.depth = cur->parent ? cur->parent->dir.depth + 1 : 1;
|
||||
cur->dir.path_len = cur->parent ? cur->parent->dir.path_len
|
||||
+ strlen(cur->name) : 0;
|
||||
max_path = cur->dir.path_len + cur->dir.depth + max_child_name_len(cur);
|
||||
cur->info.dir.depth = cur->parent ? cur->parent->info.dir.depth + 1 : 1;
|
||||
cur->info.dir.path_len = cur->parent ? cur->parent->info.dir.path_len
|
||||
+ strlen(cur->iso_name) : 0;
|
||||
max_path = cur->info.dir.path_len + cur->info.dir.depth
|
||||
+ max_child_name_len(cur);
|
||||
|
||||
if (cur->dir.depth > 8 || max_path > 255) {
|
||||
reparent(cur, root);
|
||||
/* we are appended to the root's children now, so there is no
|
||||
* need to recurse (the root will hit us again) */
|
||||
if (cur->info.dir.depth > 8 || max_path > 255) {
|
||||
|
||||
if (t->rockridge) {
|
||||
reparent(cur, root);
|
||||
/* we are appended to the root's children now, so there is no
|
||||
* need to recurse (the root will hit us again) */
|
||||
} else {
|
||||
/* we need to delete cur */
|
||||
size_t i,j;
|
||||
struct ecma119_tree_node *parent = cur->parent;
|
||||
|
||||
printf("Can't dirs deeper than 8 without RR. Skipping %s\n",
|
||||
cur->full_name);
|
||||
for (i=0; i < parent->info.dir.nchildren; ++i) {
|
||||
if (parent->info.dir.children[i] == cur) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert ( i < parent->info.dir.nchildren);
|
||||
for ( j = i; j < parent->info.dir.nchildren - 1; ++j)
|
||||
parent->info.dir.children[j] = parent->info.dir.children[j+1];
|
||||
parent->info.dir.nchildren--;
|
||||
ecma119_tree_free(cur);
|
||||
}
|
||||
} else {
|
||||
size_t i;
|
||||
|
||||
for (i=0; i < cur->dir.nchildren; i++) {
|
||||
if (cur->dir.children[i]->type == ECMA119_DIR)
|
||||
reorder_tree(root, cur->dir.children[i]);
|
||||
for (i=0; i < cur->info.dir.nchildren; i++) {
|
||||
if (cur->info.dir.children[i]->type == ECMA119_DIR)
|
||||
reorder_tree(t, root, cur->info.dir.children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the iso name of two ECMA-119 nodes
|
||||
*/
|
||||
static int
|
||||
cmp_node(const void *f1, const void *f2)
|
||||
{
|
||||
struct ecma119_tree_node *f = *((struct ecma119_tree_node**)f1);
|
||||
struct ecma119_tree_node *g = *((struct ecma119_tree_node**)f2);
|
||||
return strcmp(f->name, g->name);
|
||||
return strcmp(f->iso_name, g->iso_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts a the children of each directory in the ECMA-119 tree represented
|
||||
* by \p root, acording to the order specified in ECMA-119, section 9.3.
|
||||
*/
|
||||
static void
|
||||
sort_tree(struct ecma119_tree_node *root)
|
||||
{
|
||||
|
@ -188,10 +489,11 @@ sort_tree(struct ecma119_tree_node *root)
|
|||
|
||||
assert(root && root->type == ECMA119_DIR);
|
||||
|
||||
qsort(root->dir.children, root->dir.nchildren, sizeof(void*), cmp_node);
|
||||
for (i=0; i < root->dir.nchildren; i++) {
|
||||
if (root->dir.children[i]->type == ECMA119_DIR)
|
||||
sort_tree(root->dir.children[i]);
|
||||
qsort(root->info.dir.children, root->info.dir.nchildren,
|
||||
sizeof(void*), cmp_node);
|
||||
for (i=0; i < root->info.dir.nchildren; i++) {
|
||||
if (root->info.dir.children[i]->type == ECMA119_DIR)
|
||||
sort_tree(root->info.dir.children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,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, ';');
|
||||
|
@ -219,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);
|
||||
|
@ -231,44 +551,61 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the ISO name of each children of the given dir is unique,
|
||||
* changing some of them if needed.
|
||||
*/
|
||||
static void
|
||||
mangle_all(struct ecma119_tree_node *dir)
|
||||
{
|
||||
size_t i, j, k;
|
||||
struct ecma119_dir_info d = dir->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++) {
|
||||
/* find the number of consecutive equal names */
|
||||
j = 1;
|
||||
while ( i+j < d.nchildren &&
|
||||
!strcmp(d.children[i]->name,
|
||||
d.children[i+j]->name) )
|
||||
!strcmp(d.children[i]->iso_name,
|
||||
d.children[i+j]->iso_name) )
|
||||
j++;
|
||||
if (j == 1) continue;
|
||||
|
||||
/* mangle the names */
|
||||
changed = 1;
|
||||
n_change = j / 10 + 1;
|
||||
n_change = j / 10 + digits;
|
||||
for (k=0; k < j; k++) {
|
||||
mangle_name(&(d.children[i+k]->name),
|
||||
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]);
|
||||
|
@ -277,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++) {
|
||||
|
@ -290,7 +633,8 @@ ecma119_tree_create(struct ecma119_write_target *t,
|
|||
struct iso_tree_node *iso_root)
|
||||
{
|
||||
t->root = create_tree(t, NULL, iso_root);
|
||||
reorder_tree(t->root, t->root);
|
||||
if ( !(t->relaxed_constraints & ECMA119_NO_DIR_REALOCATION) )
|
||||
reorder_tree(t, t->root, t->root);
|
||||
sort_tree(t->root);
|
||||
mangle_all(t->root);
|
||||
return t->root;
|
||||
|
@ -305,8 +649,8 @@ ecma119_tree_print(struct ecma119_tree_node *root, int spaces)
|
|||
memset(sp, ' ', spaces);
|
||||
sp[spaces] = '\0';
|
||||
|
||||
printf("%s%s\n", sp, root->name);
|
||||
printf("%s%s\n", sp, root->iso_name);
|
||||
if (root->type == ECMA119_DIR)
|
||||
for (i=0; i < root->dir.nchildren; i++)
|
||||
ecma119_tree_print(root->dir.children[i], spaces+2);
|
||||
for (i=0; i < root->info.dir.nchildren; i++)
|
||||
ecma119_tree_print(root->info.dir.children[i], spaces+2);
|
||||
}
|
||||
|
|
|
@ -10,11 +10,19 @@
|
|||
#ifndef LIBISO_ECMA119_TREE_H
|
||||
#define LIBISO_ECMA119_TREE_H
|
||||
|
||||
struct ecma119_write_target;
|
||||
#include <sys/stat.h>
|
||||
|
||||
enum {
|
||||
#include "file.h"
|
||||
|
||||
struct ecma119_write_target;
|
||||
struct iso_tree_node;
|
||||
|
||||
enum ecma119_node_type {
|
||||
ECMA119_FILE,
|
||||
ECMA119_DIR
|
||||
ECMA119_SYMLINK,
|
||||
ECMA119_DIR,
|
||||
ECMA119_PLACEHOLDER, /**< placeholder for a relocated dir. */
|
||||
ECMA119_BOOT
|
||||
};
|
||||
|
||||
struct ecma119_dir_info {
|
||||
|
@ -25,6 +33,7 @@ struct ecma119_dir_info {
|
|||
* Directory Records (including SU) */
|
||||
size_t CE_len; /**< sum of the lengths of children's
|
||||
* SUSP CE areas */
|
||||
size_t block;
|
||||
|
||||
int depth;
|
||||
size_t path_len; /**< The length of a path up to, and
|
||||
|
@ -37,39 +46,38 @@ struct ecma119_dir_info {
|
|||
/**< The parent before relocation */
|
||||
};
|
||||
|
||||
struct ecma119_file_info
|
||||
{
|
||||
struct ecma119_tree_node *real_me;
|
||||
/**< If this is non-NULL, the file is
|
||||
* a placeholder for a relocated
|
||||
* directory and this field points to
|
||||
* that relocated directory.
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* A node for a tree containing all the information necessary for writing
|
||||
* an ISO9660 volume.
|
||||
*/
|
||||
struct ecma119_tree_node
|
||||
{
|
||||
char *name; /**< in ASCII, conforming to the
|
||||
* current ISO level. */
|
||||
char *iso_name; /**< in ASCII, conforming to the
|
||||
* current ISO level. */
|
||||
char *full_name; /**< full name, in current locale */
|
||||
size_t dirent_len; /**< Length of the directory record,
|
||||
* not including SU. */
|
||||
size_t block;
|
||||
* not including SU. */
|
||||
|
||||
struct ecma119_tree_node *parent;
|
||||
struct iso_tree_node *iso_self;
|
||||
struct ecma119_write_target *target;
|
||||
|
||||
struct stat attrib;
|
||||
|
||||
struct susp_info susp;
|
||||
|
||||
int type; /**< file or directory */
|
||||
/* union {*/
|
||||
enum ecma119_node_type type; /**< file, symlink, directory or placeholder */
|
||||
union {
|
||||
struct iso_file *file;
|
||||
char *dest;
|
||||
struct ecma119_dir_info dir;
|
||||
struct ecma119_file_info file;
|
||||
/* };*/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
619
libisofs/eltorito.c
Normal file
619
libisofs/eltorito.c
Normal file
|
@ -0,0 +1,619 @@
|
|||
#include "libisofs.h"
|
||||
|
||||
#include "eltorito.h"
|
||||
#include "volume.h"
|
||||
#include "util.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
/**
|
||||
* This table should be written with accuracy values at offset
|
||||
* 8 of boot image, when used ISOLINUX boot loader
|
||||
*/
|
||||
struct boot_info_table {
|
||||
uint8_t bi_pvd BP(1, 4); /* LBA of primary volume descriptor */
|
||||
uint8_t bi_file BP(5, 8); /* LBA of boot file */
|
||||
uint8_t bi_length BP(9, 12); /* Length of boot file */
|
||||
uint8_t bi_csum BP(13, 16); /* Checksum of boot file */
|
||||
uint8_t bi_reserved BP(17, 56); /* Reserved */
|
||||
};
|
||||
|
||||
struct partition_desc {
|
||||
uint8_t boot_ind;
|
||||
uint8_t begin_chs[3];
|
||||
uint8_t type;
|
||||
uint8_t end_chs[3];
|
||||
uint8_t start[4];
|
||||
uint8_t size[4];
|
||||
};
|
||||
|
||||
struct hard_disc_mbr {
|
||||
uint8_t code_area[440];
|
||||
uint8_t opt_disk_sg[4];
|
||||
uint8_t pad[2];
|
||||
struct partition_desc partition[4];
|
||||
uint8_t sign1;
|
||||
uint8_t sign2;
|
||||
};
|
||||
|
||||
static 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(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 (attrib.st_size) {
|
||||
case 1200 * 1024:
|
||||
boot_media_type = 1; /* 1.2 meg diskette */
|
||||
break;
|
||||
case 1440 * 1024:
|
||||
boot_media_type = 2; /* 1.44 meg diskette */
|
||||
break;
|
||||
case 2880 * 1024:
|
||||
boot_media_type = 3; /* 2.88 meg diskette */
|
||||
break;
|
||||
default:
|
||||
{
|
||||
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
|
||||
* a single sector (512b) */
|
||||
load_sectors = 1;
|
||||
break;
|
||||
case ELTORITO_HARD_DISC_EMUL:
|
||||
{
|
||||
size_t i;
|
||||
int fd;
|
||||
struct hard_disc_mbr mbr;
|
||||
int used_partition;
|
||||
|
||||
/* read the MBR on disc and get the type of the partition */
|
||||
fd = open(path, O_RDONLY);
|
||||
if ( fd == -1 ) {
|
||||
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)) ) {
|
||||
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
|
||||
"Can't read MBR from image file.");
|
||||
libisofs_errno = ELTORITO_WRONG_IMAGE;
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
/* check valid MBR signature */
|
||||
if ( mbr.sign1 != 0x55 || mbr.sign2 != 0xAA ) {
|
||||
iso_msg_sorry(LIBISO_EL_TORITO_WRONG_IMG,
|
||||
"Invalid MBR. Wrong signature.");
|
||||
libisofs_errno = ELTORITO_WRONG_IMAGE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ensure single partition */
|
||||
used_partition = -1;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (mbr.partition[i].type != 0) {
|
||||
/* it's an used partition */
|
||||
if (used_partition != -1) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
partition_type = mbr.partition[used_partition].type;
|
||||
}
|
||||
boot_media_type = 4;
|
||||
|
||||
/* only load the MBR */
|
||||
load_sectors = 1;
|
||||
break;
|
||||
case ELTORITO_NO_EMUL:
|
||||
boot_media_type = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
boot = calloc(1, sizeof(struct el_torito_boot_image));
|
||||
boot->bootable = 1;
|
||||
boot->type = boot_media_type;
|
||||
boot->load_size = load_sectors;
|
||||
boot->partition_type = partition_type;
|
||||
return boot;
|
||||
}
|
||||
|
||||
/* 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 *boot;
|
||||
|
||||
assert( (parent && name) || (!parent && !name) );
|
||||
|
||||
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.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_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 *cat_node;
|
||||
struct el_torito_boot_catalog *catalog;
|
||||
struct iso_tree_node_file *imgfile;
|
||||
|
||||
assert(volume && !volume->bootcat);
|
||||
assert(image && ISO_ISREG(image));
|
||||
assert(dir && name);
|
||||
|
||||
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));
|
||||
if (!catalog) {
|
||||
el_torito_image_free(boot_image);
|
||||
return NULL;
|
||||
}
|
||||
catalog->image = boot_image;
|
||||
|
||||
/* add catalog file */
|
||||
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)
|
||||
{
|
||||
if (bootimg->type != ELTORITO_NO_EMUL)
|
||||
return;
|
||||
bootimg->load_seg = segment;
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_set_load_size(struct el_torito_boot_image *bootimg, int sectors)
|
||||
{
|
||||
if (bootimg->type != ELTORITO_NO_EMUL)
|
||||
return;
|
||||
bootimg->load_size = sectors;
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_set_no_bootable(struct el_torito_boot_image *bootimg)
|
||||
{
|
||||
bootimg->bootable = 0;
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_patch_isolinux_image(struct el_torito_boot_image *bootimg)
|
||||
{
|
||||
bootimg->isolinux = 1;
|
||||
}
|
||||
|
||||
void el_torito_boot_catalog_free(struct el_torito_boot_catalog *cat)
|
||||
{
|
||||
assert(cat);
|
||||
|
||||
el_torito_image_free(cat->image);
|
||||
iso_tree_free((struct iso_tree_node*)cat->node);
|
||||
free(cat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the Boot Record Volume Descriptor
|
||||
*/
|
||||
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 =
|
||||
(struct ecma119_boot_rec_vol_desc*)buf;
|
||||
|
||||
assert(cat);
|
||||
|
||||
vol->vol_desc_type[0] = 0;
|
||||
memcpy(vol->std_identifier, "CD001", 5);
|
||||
vol->vol_desc_version[0] = 1;
|
||||
memcpy(vol->boot_sys_id, "EL TORITO SPECIFICATION", 23);
|
||||
iso_lsb(vol->boot_catalog, t->catblock, 4);
|
||||
}
|
||||
|
||||
static void
|
||||
write_validation_entry(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
int checksum;
|
||||
|
||||
struct el_torito_validation_entry *ve =
|
||||
(struct el_torito_validation_entry*)buf;
|
||||
ve->header_id[0] = 1;
|
||||
ve->platform_id[0] = 0; /* 0: 80x86, 1: PowerPC, 2: Mac */
|
||||
ve->key_byte1[0] = 0x55;
|
||||
ve->key_byte2[0] = 0xAA;
|
||||
|
||||
/* calculate the checksum, to ensure sum of all words is 0 */
|
||||
checksum = 0;
|
||||
for (i = 0; i < sizeof(struct el_torito_validation_entry); i += 2) {
|
||||
checksum -= buf[i];
|
||||
checksum -= (buf[i] << 8);
|
||||
}
|
||||
iso_lsb(ve->checksum, checksum, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
patch_boot_image(uint8_t *buf, struct ecma119_write_target *t, ssize_t imgsize)
|
||||
{
|
||||
struct boot_info_table *info;
|
||||
uint32_t checksum;
|
||||
ssize_t offset;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
/* compute checksum, as the the sum of all 32 bit words in boot image
|
||||
* from offset 64 */
|
||||
checksum = 0;
|
||||
offset = (ssize_t) 64;
|
||||
|
||||
while (offset < imgsize) {
|
||||
checksum += iso_read_lsb(buf + offset, 4);
|
||||
offset += 4;
|
||||
}
|
||||
if (offset != imgsize) {
|
||||
/* file length not multiple of 4 */
|
||||
iso_msg_warn(LIBISO_ISOLINUX_CANT_PATCH,
|
||||
"Unexpected isolinux image length. Patch might not work.");
|
||||
}
|
||||
|
||||
/* patch boot info table */
|
||||
info = (struct boot_info_table*)(buf + 8);
|
||||
memset(info, 0, sizeof(struct boot_info_table));
|
||||
iso_lsb(info->bi_pvd, t->ms_block + 16, 4);
|
||||
iso_lsb(info->bi_file, t->imgblock, 4);
|
||||
iso_lsb(info->bi_length, imgsize, 4);
|
||||
iso_lsb(info->bi_csum, checksum, 4);
|
||||
}
|
||||
|
||||
static void
|
||||
write_boot_image(uint8_t *buf, struct ecma119_write_target *t)
|
||||
{
|
||||
ssize_t imgsize;
|
||||
struct el_torito_boot_image *image;
|
||||
|
||||
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 only for default image (the only supported just now)
|
||||
*/
|
||||
static void
|
||||
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] = img->partition_type;
|
||||
iso_lsb(se->sec_count, img->load_size, 2);
|
||||
iso_lsb(se->block, t->imgblock, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->image);
|
||||
|
||||
write_validation_entry(t, buf);
|
||||
|
||||
/* write default entry */
|
||||
write_section_entry(buf + 32, t);
|
||||
|
||||
write_boot_image(buf + 2048, t);
|
||||
}
|
||||
|
||||
void
|
||||
el_torito_wr_boot_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
||||
{
|
||||
assert(t->catalog);
|
||||
ecma119_start_chunking(t,
|
||||
el_torito_write_boot_vol_desc,
|
||||
2048,
|
||||
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,
|
||||
size,
|
||||
buf);
|
||||
}
|
83
libisofs/eltorito.h
Normal file
83
libisofs/eltorito.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
#ifndef ELTORITO_H_
|
||||
#define ELTORITO_H_
|
||||
|
||||
#include "tree.h"
|
||||
#include "file.h"
|
||||
#include "ecma119.h"
|
||||
|
||||
struct el_torito_boot_catalog {
|
||||
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 {
|
||||
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 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);
|
||||
|
||||
/**
|
||||
* Write the Boot Record Volume Descriptor
|
||||
*/
|
||||
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);
|
||||
|
||||
#endif /*ELTORITO_H_*/
|
|
@ -1,42 +1,29 @@
|
|||
#include "hash.h"
|
||||
#include "exclude.h"
|
||||
|
||||
static struct iso_hash_node *table[HASH_NODES]={0,};
|
||||
static int num=0;
|
||||
|
||||
void
|
||||
iso_exclude_add_path(const char *path)
|
||||
iso_exclude_add_path(struct iso_hash_table *table, const char *path)
|
||||
{
|
||||
if (!path)
|
||||
return;
|
||||
|
||||
num += iso_hash_insert(table, path);
|
||||
table->num += iso_hash_insert(table->table, path);
|
||||
}
|
||||
|
||||
void
|
||||
iso_exclude_remove_path(const char *path)
|
||||
iso_exclude_empty(struct iso_hash_table *table)
|
||||
{
|
||||
if (!num || !path)
|
||||
if (!table->num)
|
||||
return;
|
||||
|
||||
num -= iso_hash_remove(table, path);
|
||||
}
|
||||
|
||||
void
|
||||
iso_exclude_empty(void)
|
||||
{
|
||||
if (!num)
|
||||
return;
|
||||
|
||||
iso_hash_empty(table);
|
||||
num=0;
|
||||
iso_hash_empty(table->table);
|
||||
table->num=0;
|
||||
}
|
||||
|
||||
int
|
||||
iso_exclude_lookup(const char *path)
|
||||
iso_exclude_lookup(struct iso_hash_table *table, const char *path)
|
||||
{
|
||||
if (!num || !path)
|
||||
if (!table->num || !path)
|
||||
return 0;
|
||||
|
||||
return iso_hash_lookup(table, path);
|
||||
return iso_hash_lookup(table->table, path);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,30 @@
|
|||
#ifndef ISO_EXCLUDE_H
|
||||
#define ISO_EXCLUDE_H
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
struct iso_hash_table {
|
||||
struct iso_hash_node *table[HASH_NODES];
|
||||
int num;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a path to ignore when adding a directory recursively.
|
||||
*
|
||||
* \param path The path, on the local filesystem, of the file.
|
||||
*/
|
||||
int
|
||||
iso_exclude_lookup(const char *path);
|
||||
int iso_exclude_lookup(struct iso_hash_table *table, const char *path);
|
||||
|
||||
/**
|
||||
* Add the path of a file or directory to ignore when adding a directory recursively.
|
||||
*
|
||||
* \param path The path, on the local filesystem, of the file.
|
||||
*/
|
||||
void iso_exclude_add_path(struct iso_hash_table *table, const char *path);
|
||||
|
||||
/**
|
||||
* Remove all paths that were set to be ignored when adding a directory recusively.
|
||||
*/
|
||||
void iso_exclude_empty(struct iso_hash_table *table);
|
||||
|
||||
#endif /* ISO_EXCLUDE */
|
||||
|
|
254
libisofs/file.c
Normal file
254
libisofs/file.c
Normal file
|
@ -0,0 +1,254 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "file.h"
|
||||
#include "tree.h"
|
||||
#include "file_src.h"
|
||||
#include "messages.h"
|
||||
#include "ecma119.h"
|
||||
|
||||
//TODO: refactor both hash and this hash table into a single one??
|
||||
|
||||
struct iso_file *
|
||||
iso_file_new(struct ecma119_write_target *t, struct iso_tree_node_file *f)
|
||||
{
|
||||
struct iso_file *file = calloc(1, sizeof(struct iso_file));
|
||||
if (!file)
|
||||
return NULL;
|
||||
if (f->node.procedence == LIBISO_NEW) {
|
||||
file->path = f->loc.path; /*TODO strdup? it needs to be free on clear then */
|
||||
file->real_dev = f->node.attrib.st_dev;
|
||||
file->real_ino = f->node.attrib.st_ino;
|
||||
file->src = iso_file_src_from_path(file->path);
|
||||
} else {
|
||||
file->block = f->loc.block;
|
||||
file->prev_img = 1;
|
||||
file->real_dev = 0; /* we use 0 as dev for prev. session files */
|
||||
/* don't take care about inode number read from RR TX, block
|
||||
* number is good enouht for this. Moreover, when we are modifying
|
||||
* an image, we will modify file->block with the block where the
|
||||
* file needs to be written in the new image. So, we store the block
|
||||
* in original image here */
|
||||
file->real_ino = f->loc.block;
|
||||
file->src = iso_file_src_from_prev_img(t->src, f->loc.block,
|
||||
f->node.attrib.st_size);
|
||||
}
|
||||
if (!file->src)
|
||||
goto creation_error;
|
||||
file->size = file->src->get_size(file->src);
|
||||
|
||||
if (file->size != f->node.attrib.st_size) {
|
||||
char msg[PATH_MAX + 32];
|
||||
/* can only happen on path files */
|
||||
assert(f->node.procedence == LIBISO_NEW);
|
||||
sprintf(msg, "Size of file %s has changed\n", file->path);
|
||||
iso_msg_sorry(LIBISO_CANT_READ_FILE, msg);
|
||||
}
|
||||
file->nlink = 1;
|
||||
file->sort_weight = f->sort_weight;
|
||||
return file;
|
||||
creation_error:;
|
||||
free(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
iso_file_table_hash(const char *path)
|
||||
{
|
||||
unsigned int hash_num=0;
|
||||
const char *c;
|
||||
|
||||
c=path;
|
||||
while(*c)
|
||||
hash_num = (hash_num << 15) + (hash_num << 3) + (hash_num >> 3) + *c++;
|
||||
|
||||
return hash_num % FILE_HASH_NODES;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
iso_file_table_hash_inode(dev_t dev, ino_t ino)
|
||||
{
|
||||
return (dev ^ ino) % FILE_HASH_NODES;
|
||||
}
|
||||
|
||||
struct iso_file_table*
|
||||
iso_file_table_new(int cache_inodes)
|
||||
{
|
||||
struct iso_file_table *table = calloc(1, sizeof(struct iso_file_table));
|
||||
table->cache_inodes = cache_inodes;
|
||||
return table;
|
||||
}
|
||||
|
||||
static struct iso_file_hash_node *
|
||||
iso_file_table_node_new(struct iso_file *file)
|
||||
{
|
||||
struct iso_file_hash_node *node;
|
||||
node = calloc(1, sizeof(struct iso_file_hash_node) );
|
||||
node->file = file;
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
iso_file_table_node_free(struct iso_file_hash_node *node)
|
||||
{
|
||||
iso_file_src_free(node->file->src);
|
||||
free(node->file);
|
||||
free(node);
|
||||
}
|
||||
|
||||
void
|
||||
iso_file_table_clear(struct iso_file_table *ft)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < FILE_HASH_NODES; i++) {
|
||||
struct iso_file_hash_node *node;
|
||||
|
||||
node=ft->table[i];
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
ft->table[i] = NULL;
|
||||
|
||||
do {
|
||||
struct iso_file_hash_node *next;
|
||||
|
||||
next = node->next;
|
||||
iso_file_table_node_free(node);
|
||||
node = next;
|
||||
} while (node);
|
||||
}
|
||||
ft->count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* return 0 if equal, != 0 if not
|
||||
*/
|
||||
static int
|
||||
iso_table_compare_files(struct iso_file_table *ft,
|
||||
struct iso_file *f1, struct iso_file *f2)
|
||||
{
|
||||
assert(ft && f1 && f2);
|
||||
if (f1->prev_img || f2->prev_img) {
|
||||
if (f1->prev_img && f2->prev_img)
|
||||
return f1->real_ino != f2->real_ino;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
if (ft->cache_inodes) {
|
||||
return (f1->real_dev != f2->real_dev) || (f1->real_ino != f2->real_ino);
|
||||
} else {
|
||||
return strcmp(f1->path, f2->path);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f)
|
||||
{
|
||||
struct iso_file_hash_node *node;
|
||||
unsigned int hash_num;
|
||||
|
||||
assert(ft && f);
|
||||
|
||||
/* find the hash number */
|
||||
if (f->prev_img)
|
||||
hash_num = f->real_ino % FILE_HASH_NODES;
|
||||
else if (ft->cache_inodes)
|
||||
hash_num = iso_file_table_hash_inode(f->real_dev, f->real_ino);
|
||||
else
|
||||
hash_num = iso_file_table_hash(f->path);
|
||||
|
||||
/* insert it */
|
||||
node = ft->table[hash_num];
|
||||
|
||||
/* unfortunately, we can't safely consider that a file
|
||||
* won't be twice in the hash table so make sure it
|
||||
* doesn't already exists */
|
||||
if (!node) {
|
||||
ft->table[hash_num]=iso_file_table_node_new(f);
|
||||
ft->count++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* if it's already in, we don't do anything */
|
||||
if (!iso_table_compare_files(ft, f, node->file))
|
||||
return 0;
|
||||
|
||||
while (node->next) {
|
||||
node = node->next;
|
||||
|
||||
/* if it's already in, we don't do anything */
|
||||
if (!iso_table_compare_files(ft, f, node->file))
|
||||
return 0;
|
||||
}
|
||||
|
||||
node->next = iso_file_table_node_new(f);
|
||||
ft->count++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** 0 on equal, != 0 otherwise */
|
||||
static int
|
||||
iso_table_compare_node_file(struct iso_file_table *ft,
|
||||
struct iso_tree_node_file *f1, struct iso_file *f2)
|
||||
{
|
||||
assert(ft && f1 && f2);
|
||||
|
||||
if (f1->node.procedence || f2->prev_img) {
|
||||
if (f1->node.procedence && f2->prev_img)
|
||||
return f1->loc.block != f2->real_ino;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
if (ft->cache_inodes) {
|
||||
return (f1->node.attrib.st_dev != f2->real_dev)
|
||||
|| (f1->node.attrib.st_ino != f2->real_ino);
|
||||
} else {
|
||||
return strcmp(f1->loc.path, f2->path);
|
||||
}
|
||||
}
|
||||
|
||||
struct iso_file *
|
||||
iso_file_table_lookup(struct iso_file_table *ft, struct iso_tree_node_file *f)
|
||||
{
|
||||
struct iso_file_hash_node *node;
|
||||
unsigned int hash_num;
|
||||
int equal;
|
||||
|
||||
assert(ft && f);
|
||||
|
||||
/* find the hash number */
|
||||
if (f->node.procedence == LIBISO_PREVIMG)
|
||||
hash_num = f->loc.block % FILE_HASH_NODES;
|
||||
else if ( ft->cache_inodes )
|
||||
hash_num = iso_file_table_hash_inode(f->node.attrib.st_dev,
|
||||
f->node.attrib.st_ino);
|
||||
else
|
||||
hash_num = iso_file_table_hash(f->loc.path);
|
||||
|
||||
node = ft->table[hash_num];
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
equal = !iso_table_compare_node_file(ft, f, node->file);
|
||||
if (equal)
|
||||
return node->file;
|
||||
|
||||
while (node->next) {
|
||||
node = node->next;
|
||||
|
||||
equal = !iso_table_compare_node_file(ft, f, node->file);
|
||||
if (equal)
|
||||
return node->file;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
74
libisofs/file.h
Normal file
74
libisofs/file.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/**
|
||||
* \file file.h
|
||||
*
|
||||
* Declare the structs to keep track of the files to be written into image.
|
||||
* These files are stored in a hash table. Two modes of operation are supported:
|
||||
* when cache inodes is enabled, the files are indexed into the table by the
|
||||
* device and inode id in the local filesystem. This way, two different files
|
||||
* with same inode and device id are treated as if they were a single file.
|
||||
* This is usually the correct behavior, as a different file with same inode
|
||||
* and device used to be a hard link.
|
||||
* When cache inode is disabled, indexing is done by path on local filesystem.
|
||||
*/
|
||||
|
||||
#ifndef FILE_H_
|
||||
#define FILE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#define FILE_HASH_NODES 2048
|
||||
|
||||
struct iso_file {
|
||||
unsigned int prev_img:1; /**< if the file comes from a previous image */
|
||||
char *path; /**< Path of the file on local filesystem */
|
||||
off_t size; /**< size of this file */
|
||||
ino_t ino; /**< This will be the inode number on CD of the file (RR) */
|
||||
nlink_t nlink; /**< Number of hard links of the file on CD (RR) */
|
||||
uint32_t block; /**< Block where this file is to be written on image */
|
||||
dev_t real_dev;
|
||||
ino_t real_ino; /**< for lookup by inode caching */
|
||||
int sort_weight;
|
||||
struct iso_file_src *src;
|
||||
};
|
||||
|
||||
struct iso_file_hash_node {
|
||||
struct iso_file_hash_node *next;
|
||||
struct iso_file *file;
|
||||
};
|
||||
|
||||
struct iso_file_table {
|
||||
struct iso_file_hash_node *table[FILE_HASH_NODES];
|
||||
size_t count;
|
||||
int cache_inodes; /**< 1 to index by inode number */
|
||||
};
|
||||
|
||||
struct iso_tree_node_file;
|
||||
struct ecma119_write_target;
|
||||
|
||||
/**
|
||||
* Create a struct that represents the specified iso_tree_node_file,
|
||||
* suitable to be stored into the table,
|
||||
*/
|
||||
struct iso_file *iso_file_new(struct ecma119_write_target *t,
|
||||
struct iso_tree_node_file*);
|
||||
|
||||
struct iso_file_table *iso_file_table_new(int cache_inodes);
|
||||
|
||||
/**
|
||||
* Clear a hash table. All iso_file structs stored will also be freed,
|
||||
* but not the path of each iso_file
|
||||
*/
|
||||
void iso_file_table_clear(struct iso_file_table *ft);
|
||||
|
||||
/**
|
||||
* Add a new file to the table.
|
||||
* \return 1 if the file is added, 0 if the file already exist on table
|
||||
*/
|
||||
int iso_file_table_add_file(struct iso_file_table *ft, struct iso_file *f);
|
||||
|
||||
struct iso_file *iso_file_table_lookup(struct iso_file_table *ft,
|
||||
struct iso_tree_node_file *f);
|
||||
|
||||
#endif /*FILE_H_*/
|
306
libisofs/file_src.c
Normal file
306
libisofs/file_src.c
Normal 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
94
libisofs/file_src.h
Normal 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_*/
|
|
@ -7,6 +7,8 @@
|
|||
#include "tree.h"
|
||||
#include "util.h"
|
||||
#include "volume.h"
|
||||
#include "eltorito.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
@ -19,33 +21,88 @@ create_node(struct ecma119_write_target *t,
|
|||
struct joliet_tree_node *ret =
|
||||
calloc(1, sizeof(struct joliet_tree_node));
|
||||
|
||||
ret->name = iso_j_id(iso->name);
|
||||
ret->name = iso_j_id(iso->name, t->input_charset);
|
||||
ret->dirent_len = 34 + (ret->name ? ucslen(ret->name) * 2 : 0);
|
||||
ret->len = iso->attrib.st_size; /* for dirs, we'll change this */
|
||||
ret->block = iso->block; /* only actually for files, not dirs */
|
||||
ret->parent = parent;
|
||||
ret->iso_self = iso;
|
||||
ret->target = t;
|
||||
ret->nchildren = iso->nchildren;
|
||||
if (ret->nchildren)
|
||||
ret->children = calloc(sizeof(void*), ret->nchildren);
|
||||
|
||||
if ( ISO_ISDIR(iso) ) {
|
||||
struct iso_tree_node_dir *dir = (struct iso_tree_node_dir *) iso;
|
||||
ret->info.dir.children = calloc(sizeof(void*), dir->nchildren);
|
||||
ret->type = JOLIET_DIR;
|
||||
} else if (ISO_ISREG(iso)) {
|
||||
/* it's a file */
|
||||
struct iso_tree_node_file *iso_f = (struct iso_tree_node_file *) iso;
|
||||
struct iso_file *file;
|
||||
file = iso_file_table_lookup(t->file_table, iso_f);
|
||||
if ( file == NULL ) {
|
||||
file = iso_file_new(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 if (ISO_ISBOOT(iso)) {
|
||||
/* it's boot catalog info */
|
||||
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;
|
||||
}
|
||||
|
||||
static struct joliet_tree_node*
|
||||
create_tree(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *parent,
|
||||
struct iso_tree_node *iso_root)
|
||||
{
|
||||
struct joliet_tree_node *root = create_node(t, parent, iso_root);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < root->nchildren; i++) {
|
||||
struct iso_tree_node *iso_ch = iso_root->children[i];
|
||||
if (ISO_ISDIR(iso_ch))
|
||||
root->children[i] = create_tree(t, root, iso_ch);
|
||||
else
|
||||
root->children[i] = create_node(t, root, iso_ch);
|
||||
struct iso_tree_node *iso)
|
||||
{
|
||||
struct joliet_tree_node *root;
|
||||
assert(t && iso);
|
||||
|
||||
if ( iso->hide_flags & LIBISO_HIDE_ON_JOLIET )
|
||||
return NULL;
|
||||
|
||||
switch (iso->type) {
|
||||
case LIBISO_NODE_FILE:
|
||||
case LIBISO_NODE_BOOT:
|
||||
root = create_node(t, parent, iso);
|
||||
break;
|
||||
case LIBISO_NODE_DIR:
|
||||
{
|
||||
size_t i;
|
||||
struct joliet_tree_node *node;
|
||||
struct iso_tree_node_dir *dir;
|
||||
root = create_node(t, parent, iso);
|
||||
dir = (struct iso_tree_node_dir*)iso;
|
||||
for (i = 0; i < dir->nchildren; ++i) {
|
||||
node = create_tree(t, root, dir->children[i]);
|
||||
if ( node != NULL ) {
|
||||
root->info.dir.children[root->info.dir.nchildren++] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -63,12 +120,15 @@ sort_tree(struct joliet_tree_node *root)
|
|||
{
|
||||
size_t i;
|
||||
|
||||
assert(root && ISO_ISDIR(root->iso_self));
|
||||
assert(root && (root->type == JOLIET_DIR));
|
||||
|
||||
qsort(root->children, root->nchildren, sizeof(void*), cmp_node);
|
||||
for (i = 0; i < root->nchildren; i++)
|
||||
if (ISO_ISDIR(root->children[i]->iso_self))
|
||||
sort_tree(root->children[i]);
|
||||
qsort(root->info.dir.children, root->info.dir.nchildren,
|
||||
sizeof(void*), cmp_node);
|
||||
for (i = 0; i < root->info.dir.nchildren; i++) {
|
||||
struct joliet_tree_node *child = root->info.dir.children[i];
|
||||
if ( child->type == JOLIET_DIR )
|
||||
sort_tree(child);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -80,11 +140,11 @@ joliet_prepare_path_tables(struct ecma119_write_target *t)
|
|||
t->path_table_size_joliet = 10; /* root directory record */
|
||||
cur = 1;
|
||||
|
||||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
for (i = 0; i < t->dirlist_len_joliet; i++) {
|
||||
struct joliet_tree_node *dir = t->pathlist_joliet[i];
|
||||
for (j = 0; j < dir->nchildren; j++) {
|
||||
struct joliet_tree_node *ch = dir->children[j];
|
||||
if (ISO_ISDIR(ch->iso_self)) {
|
||||
for (j = 0; j < dir->info.dir.nchildren; j++) {
|
||||
struct joliet_tree_node *ch = dir->info.dir.children[j];
|
||||
if (ch->type == JOLIET_DIR) {
|
||||
size_t len = 8 + ucslen(ch->name)*2;
|
||||
t->pathlist_joliet[cur++] = ch;
|
||||
t->path_table_size_joliet += len;
|
||||
|
@ -101,18 +161,25 @@ joliet_calc_dir_size(struct ecma119_write_target *t,
|
|||
struct joliet_tree_node *root)
|
||||
{
|
||||
size_t i;
|
||||
size_t newlen;
|
||||
struct joliet_tree_node *ch;
|
||||
|
||||
assert(root && ISO_ISDIR(root->iso_self));
|
||||
assert(root && (root->type == JOLIET_DIR) );
|
||||
|
||||
root->len = 68; /* for "." and ".." entries */
|
||||
for (i = 0; i < root->nchildren; i++) {
|
||||
ch = root->children[i];
|
||||
root->len += ch->dirent_len;
|
||||
if (ISO_ISDIR(ch->iso_self))
|
||||
t->dirlist_len_joliet++;
|
||||
root->info.dir.len = 68; /* for "." and ".." entries */
|
||||
for (i = 0; i < root->info.dir.nchildren; ++i) {
|
||||
ch = root->info.dir.children[i];
|
||||
newlen = root->info.dir.len + ch->dirent_len;
|
||||
if ((newlen % 2048) < (root->info.dir.len % 2048)) {
|
||||
root->info.dir.len = newlen + (2048 - (root->info.dir.len % 2048));
|
||||
} else {
|
||||
root->info.dir.len += ch->dirent_len;
|
||||
}
|
||||
if (ch->type == JOLIET_DIR)
|
||||
joliet_calc_dir_size(t, ch);
|
||||
}
|
||||
t->total_dir_size_joliet += round_up (root->len, t->block_size);
|
||||
t->total_dir_size_joliet += round_up (root->info.dir.len, t->block_size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,45 +192,17 @@ joliet_calc_dir_pos(struct ecma119_write_target *t,
|
|||
size_t i;
|
||||
struct joliet_tree_node *ch;
|
||||
|
||||
assert(root && ISO_ISDIR(root->iso_self));
|
||||
assert(root && (root->type == JOLIET_DIR));
|
||||
|
||||
root->block = t->curblock;
|
||||
t->curblock += div_up(root->len, t->block_size);
|
||||
root->info.dir.block = t->curblock;
|
||||
t->curblock += div_up(root->info.dir.len, t->block_size);
|
||||
|
||||
t->dirlist_joliet[t->curfile++] = root;
|
||||
for (i = 0; i < root->nchildren; i++) {
|
||||
ch = root->children[i];
|
||||
if (ISO_ISDIR(ch->iso_self))
|
||||
for (i = 0; i < root->info.dir.nchildren; i++) {
|
||||
ch = root->info.dir.children[i];
|
||||
if (ch->type == JOLIET_DIR)
|
||||
joliet_calc_dir_pos(t, ch);
|
||||
}
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
if (!root->parent)
|
||||
t->curfile = 0;
|
||||
}
|
||||
|
||||
void
|
||||
joliet_update_file_pos(struct ecma119_write_target *t,
|
||||
struct joliet_tree_node *dir)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
assert(dir && ISO_ISDIR(dir->iso_self));
|
||||
for (i = 0; i < dir->nchildren; i++) {
|
||||
struct joliet_tree_node *ch;
|
||||
ch = dir->children[i];
|
||||
|
||||
if (!ISO_ISDIR (ch->iso_self)) {
|
||||
struct iso_tree_node *iso = ch->iso_self;
|
||||
ch->block = iso->block;
|
||||
}
|
||||
else
|
||||
joliet_update_file_pos(t, ch);
|
||||
}
|
||||
|
||||
/* reset curfile when we're finished */
|
||||
if (!dir->parent)
|
||||
t->curfile = 0;
|
||||
}
|
||||
|
||||
struct joliet_tree_node*
|
||||
|
@ -176,6 +215,21 @@ joliet_tree_create(struct ecma119_write_target *t,
|
|||
return root;
|
||||
}
|
||||
|
||||
void
|
||||
joliet_tree_free(struct joliet_tree_node *root)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (root->type == JOLIET_DIR) {
|
||||
for (i=0; i < root->info.dir.nchildren; i++) {
|
||||
joliet_tree_free(root->info.dir.children[i]);
|
||||
}
|
||||
free(root->info.dir.children);
|
||||
}
|
||||
free(root->name);
|
||||
free(root);
|
||||
}
|
||||
|
||||
/* ugh. this is mostly C&P */
|
||||
static void
|
||||
write_path_table(struct ecma119_write_target *t,
|
||||
|
@ -185,7 +239,7 @@ write_path_table(struct ecma119_write_target *t,
|
|||
void (*write_int)(uint8_t*, uint32_t, int) = l_type ?
|
||||
iso_lsb : iso_msb;
|
||||
|
||||
size_t i;
|
||||
size_t i;
|
||||
struct ecma119_path_table_record *rec;
|
||||
struct joliet_tree_node *dir;
|
||||
int parent = 0;
|
||||
|
@ -202,7 +256,7 @@ write_path_table(struct ecma119_write_target *t,
|
|||
rec->len_di[0] = dir->parent ?
|
||||
(uint8_t) ucslen(dir->name) * 2 : 1;
|
||||
rec->len_xa[0] = 0;
|
||||
write_int(rec->block, dir->block, 4);
|
||||
write_int(rec->block, dir->info.dir.block, 4);
|
||||
write_int(rec->parent, parent + 1, 2);
|
||||
if (dir->parent)
|
||||
memcpy(rec->dir_id, dir->name, rec->len_di[0]);
|
||||
|
@ -220,20 +274,42 @@ write_one_dir_record(struct ecma119_write_target *t,
|
|||
int file_id,
|
||||
uint8_t *buf)
|
||||
{
|
||||
uint32_t len;
|
||||
uint32_t block;
|
||||
uint8_t len_dr = (file_id >= 0) ? 34 : node->dirent_len;
|
||||
uint8_t len_fi = (file_id >= 0) ? 1 : ucslen(node->name) * 2;
|
||||
uint8_t f_id = (uint8_t) ((file_id == 3) ? 0 : file_id);
|
||||
uint8_t *name = (file_id >= 0) ? &f_id : (uint8_t*)node->name;
|
||||
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
|
||||
|
||||
if (node->type == JOLIET_DIR) {
|
||||
len = node->info.dir.len;
|
||||
block = node->info.dir.block;
|
||||
} else 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;
|
||||
}
|
||||
|
||||
if (file_id == 1 && node->parent)
|
||||
node = node->parent;
|
||||
|
||||
rec->len_dr[0] = len_dr;
|
||||
iso_bb(rec->block, node->block, 4);
|
||||
iso_bb(rec->length, node->len, 4);
|
||||
iso_bb(rec->block, block, 4);
|
||||
iso_bb(rec->length, len, 4);
|
||||
iso_datetime_7(rec->recording_time, t->now);
|
||||
rec->flags[0] = ISO_ISDIR(node->iso_self) ? 2 : 0;
|
||||
rec->flags[0] = (node->type == JOLIET_DIR) ? 2 : 0;
|
||||
iso_bb(rec->vol_seq_number, t->volnum + 1, 2);
|
||||
rec->len_fi[0] = len_fi;
|
||||
memcpy(rec->file_id, name, len_fi);
|
||||
|
@ -251,24 +327,34 @@ 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];
|
||||
uint16_t *vol_id = str2ucs(volume->volume_id);
|
||||
uint16_t *pub_id = str2ucs(volume->publisher_id);
|
||||
uint16_t *data_id = str2ucs(volume->data_preparer_id);
|
||||
uint16_t *volset_id = str2ucs(t->volset->volset_id);
|
||||
uint16_t *vol_id = str2ucs(volume->volume_id, t->input_charset);
|
||||
uint16_t *pub_id = str2ucs(volume->publisher_id, t->input_charset);
|
||||
uint16_t *data_id = str2ucs(volume->data_preparer_id, t->input_charset);
|
||||
uint16_t *volset_id = str2ucs(t->volset->volset_id, t->input_charset);
|
||||
int vol_id_len = MIN(32, ucslen(vol_id) * 2);
|
||||
int pub_id_len = MIN(128, ucslen(pub_id) * 2);
|
||||
int data_id_len = MIN(128, ucslen(data_id) * 2);
|
||||
int volset_id_len = MIN(128, ucslen(volset_id) * 2);
|
||||
|
||||
uint16_t *system_id = str2ucs(volume->system_id, t->input_charset);
|
||||
uint16_t *application_id = str2ucs(volume->application_id, t->input_charset);
|
||||
uint16_t *copyright_file_id = str2ucs(volume->copyright_file_id, t->input_charset);
|
||||
uint16_t *abstract_file_id = str2ucs(volume->abstract_file_id, t->input_charset);
|
||||
uint16_t *biblio_file_id = str2ucs(volume->biblio_file_id, t->input_charset);
|
||||
int system_id_len = MIN(32, ucslen(system_id) * 2);
|
||||
int application_id_len = MIN(128, ucslen(application_id) * 2);
|
||||
int copyright_file_id_len = MIN(37, ucslen(copyright_file_id) * 2);
|
||||
int abstract_file_id_len = MIN(37, ucslen(abstract_file_id) * 2);
|
||||
int biblio_file_id_len = MIN(37, ucslen(biblio_file_id) * 2);
|
||||
|
||||
vol->vol_desc_type[0] = 2;
|
||||
memcpy(vol->std_identifier, "CD001", 5);
|
||||
vol->vol_desc_version[0] = 1;
|
||||
memcpy(vol->system_id, "SYSID", 5);
|
||||
if (vol_id)
|
||||
memcpy(vol->volume_id, vol_id, vol_id_len);
|
||||
memcpy(vol->esc_sequences, "%/E", 3);
|
||||
|
@ -285,8 +371,13 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
|||
memcpy(vol->vol_set_id, volset_id, volset_id_len);
|
||||
memcpy(vol->publisher_id, pub_id, pub_id_len);
|
||||
memcpy(vol->data_prep_id, data_id, data_id_len);
|
||||
/*memcpy(vol->application_id, "APPID", app_id_len);*/
|
||||
|
||||
|
||||
memcpy(vol->system_id, system_id, system_id_len);
|
||||
memcpy(vol->application_id, "APPID", application_id_len);
|
||||
memcpy(vol->copyright_file_id, copyright_file_id, copyright_file_id_len);
|
||||
memcpy(vol->abstract_file_id, abstract_file_id, abstract_file_id_len);
|
||||
memcpy(vol->bibliographic_file_id, biblio_file_id, biblio_file_id_len);
|
||||
|
||||
iso_datetime_17(vol->vol_creation_time, t->now);
|
||||
iso_datetime_17(vol->vol_modification_time, t->now);
|
||||
iso_datetime_17(vol->vol_effective_time, t->now);
|
||||
|
@ -296,6 +387,11 @@ write_sup_vol_desc(struct ecma119_write_target *t, uint8_t *buf)
|
|||
free(volset_id);
|
||||
free(pub_id);
|
||||
free(data_id);
|
||||
free(system_id);
|
||||
free(application_id);
|
||||
free(copyright_file_id);
|
||||
free(abstract_file_id);
|
||||
free(biblio_file_id);
|
||||
|
||||
}
|
||||
|
||||
|
@ -305,9 +401,12 @@ write_one_dir(struct ecma119_write_target *t,
|
|||
uint8_t *buf)
|
||||
{
|
||||
size_t i;
|
||||
int j;
|
||||
size_t len;
|
||||
uint8_t *orig_buf = buf;
|
||||
uint8_t *prior_buf = buf;
|
||||
|
||||
assert(ISO_ISDIR (dir->iso_self));
|
||||
assert(dir->type == JOLIET_DIR);
|
||||
/* write the "." and ".." entries first */
|
||||
write_one_dir_record(t, dir, 0, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
|
@ -315,12 +414,23 @@ write_one_dir(struct ecma119_write_target *t,
|
|||
write_one_dir_record(t, dir, 1, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
|
||||
for (i = 0; i < dir->nchildren; i++) {
|
||||
write_one_dir_record(t, dir->children[i], -1, buf);
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
write_one_dir_record(t, dir->info.dir.children[i], -1, buf);
|
||||
len = ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
if ((buf + len - prior_buf) >= 2048) {
|
||||
for (j = len - 1; j >= 0; j--) {
|
||||
prior_buf[2048 + j] = buf[j];
|
||||
buf[j] = 0;
|
||||
}
|
||||
prior_buf += 2048;
|
||||
buf = prior_buf + len;
|
||||
}
|
||||
else {
|
||||
buf += ((struct ecma119_dir_record*) buf)->len_dr[0];
|
||||
}
|
||||
}
|
||||
|
||||
assert (buf - orig_buf == dir->len);
|
||||
assert (buf - orig_buf == dir->info.dir.len);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -329,11 +439,11 @@ 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]->block);
|
||||
for (i = 0; i < t->dirlist_len; i++) {
|
||||
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);
|
||||
buf += round_up(dir->len, t->block_size);
|
||||
buf += round_up(dir->info.dir.len, t->block_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,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);
|
||||
}
|
||||
|
|
|
@ -17,19 +17,36 @@
|
|||
struct ecma119_write_target;
|
||||
struct iso_tree_node;
|
||||
|
||||
enum joliet_node_type {
|
||||
JOLIET_FILE,
|
||||
JOLIET_DIR,
|
||||
JOLIET_BOOT
|
||||
};
|
||||
|
||||
struct joliet_dir_info {
|
||||
struct joliet_tree_node **children;
|
||||
size_t nchildren;
|
||||
size_t len;
|
||||
size_t block;
|
||||
};
|
||||
|
||||
struct joliet_tree_node
|
||||
{
|
||||
uint16_t *name; /**< In UCS-2BE. */
|
||||
size_t dirent_len;
|
||||
size_t len;
|
||||
size_t block;
|
||||
|
||||
struct joliet_tree_node *parent;
|
||||
struct iso_tree_node *iso_self;
|
||||
struct ecma119_write_target *target;
|
||||
|
||||
struct joliet_tree_node **children;
|
||||
size_t nchildren;
|
||||
|
||||
enum joliet_node_type type;
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -52,13 +69,6 @@ joliet_calc_dir_size(struct ecma119_write_target *t, struct joliet_tree_node*);
|
|||
void
|
||||
joliet_calc_dir_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
|
||||
|
||||
/**
|
||||
* Update the position of each file in the joliet hierarchy (to be called
|
||||
* AFTER the file positions in the iso tree have been set).
|
||||
*/
|
||||
void
|
||||
joliet_update_file_pos(struct ecma119_write_target *t, struct joliet_tree_node*);
|
||||
|
||||
/**
|
||||
* Calculate the size of the joliet path table and fill in the list of
|
||||
* directories.
|
||||
|
@ -69,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
404
libisofs/libiso_msgs.c
Normal 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
454
libisofs/libiso_msgs.h
Normal 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 */
|
1052
libisofs/libisofs.h
Executable file → Normal file
1052
libisofs/libisofs.h
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
160
libisofs/messages.c
Normal file
160
libisofs/messages.c
Normal 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
67
libisofs/messages.h
Normal 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_*/
|
95
libisofs/rockridge.c
Executable file → Normal file
95
libisofs/rockridge.c
Executable file → Normal file
|
@ -14,6 +14,30 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/** See IEEE P1281 Draft Version 1.12/5.5 */
|
||||
void
|
||||
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||
{
|
||||
unsigned char *ER = malloc(182);
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
ER[0] = 'E';
|
||||
ER[1] = 'R';
|
||||
ER[2] = 182;
|
||||
ER[3] = 1;
|
||||
ER[4] = 9;
|
||||
ER[5] = 72;
|
||||
ER[6] = 93;
|
||||
ER[7] = 1;
|
||||
memcpy(&ER[8], "IEEE_1282", 9);
|
||||
memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
|
||||
"FILE SYSTEM SEMANTICS.", 72);
|
||||
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
|
||||
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
|
||||
susp_append(t, &dir->info.dir.self_susp, ER);
|
||||
}
|
||||
|
||||
/* create a PX field from the permissions on the current node. */
|
||||
uint8_t *rrip_make_PX(struct ecma119_write_target *t,
|
||||
struct ecma119_tree_node *node)
|
||||
|
@ -24,11 +48,11 @@ uint8_t *rrip_make_PX(struct ecma119_write_target *t,
|
|||
PX[1] = 'X';
|
||||
PX[2] = 44;
|
||||
PX[3] = 1;
|
||||
iso_bb(&PX[4], node->iso_self->attrib.st_mode, 4);
|
||||
iso_bb(&PX[12], node->iso_self->attrib.st_nlink, 4);
|
||||
iso_bb(&PX[20], node->iso_self->attrib.st_uid, 4);
|
||||
iso_bb(&PX[28], node->iso_self->attrib.st_gid, 4);
|
||||
iso_bb(&PX[36], node->iso_self->attrib.st_ino, 4);
|
||||
iso_bb(&PX[4], node->attrib.st_mode, 4);
|
||||
iso_bb(&PX[12], node->attrib.st_nlink, 4);
|
||||
iso_bb(&PX[20], node->attrib.st_uid, 4);
|
||||
iso_bb(&PX[28], node->attrib.st_gid, 4);
|
||||
iso_bb(&PX[36], node->attrib.st_ino, 4);
|
||||
return PX;
|
||||
}
|
||||
|
||||
|
@ -37,8 +61,8 @@ void rrip_add_PX(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
{
|
||||
susp_append(t, &node->susp, rrip_make_PX(t, node));
|
||||
if (node->type == ECMA119_DIR) {
|
||||
susp_append(t, &node->dir.self_susp, rrip_make_PX(t, node));
|
||||
susp_append(t, &node->dir.parent_susp, rrip_make_PX(t, node));
|
||||
susp_append(t, &node->info.dir.self_susp, rrip_make_PX(t, node));
|
||||
susp_append(t, &node->info.dir.parent_susp, rrip_make_PX(t, node));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,8 +74,8 @@ void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
PN[1] = 'N';
|
||||
PN[2] = 20;
|
||||
PN[3] = 1;
|
||||
iso_bb(&PN[4], node->iso_self->attrib.st_dev >> 32, 4);
|
||||
iso_bb(&PN[12], node->iso_self->attrib.st_dev & 0xffffffff, 4);
|
||||
iso_bb(&PN[4], node->attrib.st_dev >> 32, 4);
|
||||
iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4);
|
||||
susp_append(t, &node->susp, PN);
|
||||
}
|
||||
|
||||
|
@ -102,7 +126,7 @@ static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
|
|||
|
||||
void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
int ret, pathsize = 0;
|
||||
int path_size;
|
||||
char *path = NULL, *cur, *prev;
|
||||
int i, j;
|
||||
|
||||
|
@ -113,19 +137,9 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
|
||||
uint8_t *SL;
|
||||
|
||||
do {
|
||||
pathsize += 128;
|
||||
path = realloc(path, pathsize);
|
||||
/* FIXME: what if the file is not on the local fs? */
|
||||
ret = readlink(node->iso_self->loc.path, path, pathsize);
|
||||
} while (ret == pathsize);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Error: couldn't read symlink: %s\n",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
path[ret] = '\0';
|
||||
|
||||
path = node->info.dest;
|
||||
path_size = strlen(path);
|
||||
|
||||
prev = path;
|
||||
for (cur = strchr(path, '/'); cur && *cur; cur = strchr(cur, '/')) {
|
||||
rrip_SL_add_component(prev, cur, &n_comp, &comp);
|
||||
|
@ -134,8 +148,8 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
}
|
||||
|
||||
/* if there was no trailing '/', we need to add the last component. */
|
||||
if (prev == path || prev != &path[ret - 1]) {
|
||||
rrip_SL_add_component(prev, &path[ret], &n_comp, &comp);
|
||||
if (prev == path || prev != &path[path_size - 1]) {
|
||||
rrip_SL_add_component(prev, &path[path_size], &n_comp, &comp);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_comp; i++) {
|
||||
|
@ -172,7 +186,6 @@ void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
}
|
||||
susp_append(t, &node->susp, SL);
|
||||
|
||||
free(path);
|
||||
/* free the components */
|
||||
for (i = 0; i < n_comp; i++) {
|
||||
free(comp[i]);
|
||||
|
@ -200,7 +213,7 @@ static void rrip_add_NM_single(struct ecma119_write_target *t,
|
|||
void
|
||||
rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||
{
|
||||
char *name = iso_p_fileid(node->iso_self->name);
|
||||
char *name = node->full_name;
|
||||
int len = name ? strlen(name) : 0;
|
||||
char *pos = name;
|
||||
|
||||
|
@ -208,8 +221,8 @@ rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
return;
|
||||
|
||||
if (node->type == ECMA119_DIR) {
|
||||
rrip_add_NM_single(t, &node->dir.self_susp, pos, 0, 1 << 1);
|
||||
rrip_add_NM_single(t, &node->dir.parent_susp, pos, 0, 1 << 2);
|
||||
rrip_add_NM_single(t, &node->info.dir.self_susp, pos, 0, 1 << 1);
|
||||
rrip_add_NM_single(t, &node->info.dir.parent_susp, pos, 0, 1 << 2);
|
||||
}
|
||||
|
||||
while (len > 250) {
|
||||
|
@ -240,7 +253,7 @@ rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
PL[1] = 'L';
|
||||
PL[2] = 12;
|
||||
PL[3] = 1;
|
||||
susp_append(t, &node->dir.parent_susp, PL);
|
||||
susp_append(t, &node->info.dir.parent_susp, PL);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -264,10 +277,10 @@ rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
TF[1] = 'F';
|
||||
TF[2] = 5 + 3 * 7;
|
||||
TF[3] = 1;
|
||||
TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7);
|
||||
iso_datetime_7(&TF[5], node->iso_self->attrib.st_mtime);
|
||||
iso_datetime_7(&TF[12], node->iso_self->attrib.st_atime);
|
||||
iso_datetime_7(&TF[19], node->iso_self->attrib.st_ctime);
|
||||
TF[4] = (1 << 1) | (1 << 2) | (1 << 3);
|
||||
iso_datetime_7(&TF[5], node->attrib.st_mtime);
|
||||
iso_datetime_7(&TF[12], node->attrib.st_atime);
|
||||
iso_datetime_7(&TF[19], node->attrib.st_ctime);
|
||||
susp_append(t, &node->susp, TF);
|
||||
}
|
||||
|
||||
|
@ -278,21 +291,21 @@ rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
|||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
if (dir->parent != dir->dir.real_parent) {
|
||||
uint8_t *PL = susp_find(&dir->dir.parent_susp, "PL");
|
||||
if (dir->parent != dir->info.dir.real_parent) {
|
||||
uint8_t *PL = susp_find(&dir->info.dir.parent_susp, "PL");
|
||||
|
||||
assert(PL);
|
||||
iso_bb(&PL[4], dir->dir.real_parent->block, 4);
|
||||
iso_bb(&PL[4], dir->info.dir.real_parent->info.dir.block, 4);
|
||||
}
|
||||
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
|
||||
if (ch->type == ECMA119_FILE && ch->file.real_me) {
|
||||
if (ch->type == ECMA119_PLACEHOLDER) {
|
||||
uint8_t *CL = susp_find(&ch->susp, "CL");
|
||||
|
||||
assert(CL);
|
||||
iso_bb(&CL[4], ch->file.real_me->block, 4);
|
||||
iso_bb(&CL[4], ch->info.real_me->info.dir.block, 4);
|
||||
} else if (ch->type == ECMA119_DIR) {
|
||||
rrip_finalize(t, ch);
|
||||
}
|
||||
|
|
96
libisofs/rockridge.h
Executable file → Normal file
96
libisofs/rockridge.h
Executable file → Normal file
|
@ -1,6 +1,11 @@
|
|||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/** Functions and structures used for Rock Ridge support. */
|
||||
/**
|
||||
* Functions and structures used for Rock Ridge support.
|
||||
*
|
||||
* See IEEE P1282, Rock Ridge Interchange Protocol, Draft Standard version
|
||||
* 1.12 for further details.
|
||||
*/
|
||||
|
||||
#ifndef ISO_ROCKRIDGE_H
|
||||
#define ISO_ROCKRIDGE_H
|
||||
|
@ -8,18 +13,99 @@
|
|||
struct ecma119_write_target;
|
||||
struct ecma119_tree_node;
|
||||
|
||||
/**
|
||||
* Add a SUSP "ER" System Use Entry to identify the Rock Ridge specification.
|
||||
*
|
||||
* The "ER" System Use Entry is used to uniquely identify a specification
|
||||
* compliant with SUSP. This method adds to the given tree node "." entry
|
||||
* the "ER" corresponding to the RR protocol.
|
||||
*
|
||||
* See IEEE P1281, section 5.5 and IEEE P1282, section 4.3 for more details.
|
||||
*/
|
||||
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PX System Use Entry to the given tree node and, if that node is
|
||||
* a directory, to its "." and ".." entries. The PX System Use Entry is
|
||||
* used to add POSIX file attributes, such as access permissions or user and
|
||||
* group id, to a ECMA 119 directory record.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.1 for more details.
|
||||
*/
|
||||
void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PN System Use Entry to the given tree node.
|
||||
* The PN System Use Entry is used to store the device number, and it's
|
||||
* mandatory if the tree node corresponds to a character or block device.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.2 for more details.
|
||||
*/
|
||||
void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a SL System Use Entry to the given tree node. This is used to store
|
||||
* the content of a symbolic link, and is mandatory if the tree node
|
||||
* indicates a symbolic link.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.3 for more details.
|
||||
*/
|
||||
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a NM System Use Entry to the given tree node. The purpose of this
|
||||
* System Use Entry is to store the content of an Alternate Name to support
|
||||
* POSIX-style or other names.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.4 for more details.
|
||||
*/
|
||||
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/*
|
||||
* The next 3 System Use Entries are used to handle Deep Directory
|
||||
* Hierarchies, i.e., hierarchies where the number of directory levels
|
||||
* exceed the eight limit of ECMA-119.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add to the given tree node a CL System Use Entry, that is used to record
|
||||
* the new location of a directory which has been relocated.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.1 for more details.
|
||||
*/
|
||||
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a PL System Use Entry, used to record the location of the original
|
||||
* parent directory of a directory which has been relocated.
|
||||
*
|
||||
* This is special because it doesn't modify the susp fields of the directory
|
||||
* that gets passed to it; it modifies the susp fields of the ".." entry in
|
||||
* that directory.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.2 for more details.
|
||||
*/
|
||||
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add a RE System Use Entry to the given tree node. The purpose of the
|
||||
* this System Use Entry is to indicate to an RRIP-compliant receiving
|
||||
* system that the Directory Record in which an "RE" System Use Entry is
|
||||
* recorded has been relocated from another position in the original
|
||||
* Directory Hierarchy.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.5.3 for more details.
|
||||
*/
|
||||
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/**
|
||||
* Add to the given tree node a TF System Use Entry, used to record some
|
||||
* time stamps related to the file.
|
||||
*
|
||||
* See IEEE P1282, section 4.1.6 for more details.
|
||||
*/
|
||||
void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/* This is special because it doesn't modify the susp fields of the directory
|
||||
* that gets passed to it; it modifies the susp fields of the ".." entry in
|
||||
* that directory. */
|
||||
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
|
|
62
libisofs/susp.c
Executable file → Normal file
62
libisofs/susp.c
Executable file → Normal file
|
@ -117,8 +117,8 @@ susp_add_CE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
|||
{
|
||||
try_add_CE(t, &node->susp, node->dirent_len);
|
||||
if (node->type == ECMA119_DIR) {
|
||||
try_add_CE(t, &node->dir.self_susp, 34);
|
||||
try_add_CE(t, &node->dir.parent_susp, 34);
|
||||
try_add_CE(t, &node->info.dir.self_susp, 34);
|
||||
try_add_CE(t, &node->info.dir.parent_susp, 34);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
|||
SP[4] = 0xbe;
|
||||
SP[5] = 0xef;
|
||||
SP[6] = 0;
|
||||
susp_append(t, &dir->dir.self_susp, SP);
|
||||
susp_append(t, &dir->info.dir.self_susp, SP);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@ -155,38 +155,14 @@ static void susp_add_ST(struct ecma119_write_target *t,
|
|||
}
|
||||
#endif
|
||||
|
||||
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
|
||||
void
|
||||
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||
{
|
||||
unsigned char *ER = malloc(182);
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
ER[0] = 'E';
|
||||
ER[1] = 'R';
|
||||
ER[2] = 182;
|
||||
ER[3] = 1;
|
||||
ER[4] = 9;
|
||||
ER[5] = 72;
|
||||
ER[6] = 93;
|
||||
ER[7] = 1;
|
||||
memcpy(&ER[8], "IEEE_1282", 9);
|
||||
memcpy(&ER[17], "THE IEEE 1282 PROTOCOL PROVIDES SUPPORT FOR POSIX "
|
||||
"FILE SYSTEM SEMANTICS.", 72);
|
||||
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
|
||||
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
|
||||
susp_append(t, &dir->dir.self_susp, ER);
|
||||
}
|
||||
|
||||
/* calculate the location of the CE areas. Since CE areas don't need to be
|
||||
* aligned to a block boundary, we contatenate all CE areas from a single
|
||||
* directory and dump them immediately after all the directory records.
|
||||
*
|
||||
* Requires that the following be known:
|
||||
* - position of the current directory (dir->block)
|
||||
* - length of the current directory (dir->dir.len)
|
||||
* - sum of the children's CE lengths (dir->dir.CE_len)
|
||||
* - position of the current directory (dir->info.dir.block)
|
||||
* - length of the current directory (dir->info.dir.len)
|
||||
* - sum of the children's CE lengths (dir->info.dir.CE_len)
|
||||
*/
|
||||
static void
|
||||
susp_fin_1_CE(struct ecma119_write_target *t,
|
||||
|
@ -208,18 +184,18 @@ static void susp_fin_CE(struct ecma119_write_target *t,
|
|||
struct ecma119_tree_node *dir)
|
||||
{
|
||||
int i;
|
||||
size_t CE_offset = dir->dir.len;
|
||||
size_t CE_offset = dir->info.dir.len;
|
||||
|
||||
assert(dir->type == ECMA119_DIR);
|
||||
|
||||
susp_fin_1_CE(t, &dir->dir.self_susp, dir->block, &CE_offset);
|
||||
susp_fin_1_CE(t, &dir->dir.parent_susp, dir->block, &CE_offset);
|
||||
susp_fin_1_CE(t, &dir->info.dir.self_susp, dir->info.dir.block, &CE_offset);
|
||||
susp_fin_1_CE(t, &dir->info.dir.parent_susp, dir->info.dir.block, &CE_offset);
|
||||
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||
susp_fin_1_CE(t, &ch->susp, dir->block, &CE_offset);
|
||||
for (i = 0; i < dir->info.dir.nchildren; i++) {
|
||||
struct ecma119_tree_node *ch = dir->info.dir.children[i];
|
||||
susp_fin_1_CE(t, &ch->susp, dir->info.dir.block, &CE_offset);
|
||||
}
|
||||
assert(CE_offset == dir->dir.len + dir->dir.CE_len);
|
||||
assert(CE_offset == dir->info.dir.len + dir->info.dir.CE_len);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -229,13 +205,11 @@ susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
|||
|
||||
assert(dir->type = ECMA119_DIR);
|
||||
|
||||
if (dir->dir.depth != 1) {
|
||||
susp_fin_CE(t, dir);
|
||||
}
|
||||
|
||||
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||
if (dir->dir.children[i]->type == ECMA119_DIR)
|
||||
susp_finalize(t, dir->dir.children[i]);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
24
libisofs/susp.h
Executable file → Normal file
24
libisofs/susp.h
Executable file → Normal file
|
@ -1,6 +1,10 @@
|
|||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||
|
||||
/** Functions and structures used for SUSP (IEEE 1281).
|
||||
/**
|
||||
* Functions and structures used for SUSP (IEEE 1281).
|
||||
*
|
||||
* Please refer to IEEE P1281 System Use Sharing Protocol, draft standard
|
||||
* version 1.12 for more details.
|
||||
*/
|
||||
|
||||
#ifndef __ISO_SUSP
|
||||
|
@ -28,13 +32,23 @@ struct susp_info
|
|||
* will go in a CE area. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a CE System Use Entry to the given tree node. A "CE" is used to add
|
||||
* a continuation area, where additional System Use Entry can be written.
|
||||
* See IEEE P1281, section 5.1.
|
||||
*/
|
||||
void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/* these next 2 are special because they don't modify the susp fields of the
|
||||
* directory; they modify the susp fields of the
|
||||
* "." entry in the directory. */
|
||||
/**
|
||||
* Add a SP System Use Entry to the "." entry of the directory. The SP provide
|
||||
* an identifier that the SUSP is used within the volume. The SP shall be
|
||||
* recorded in the "." entry of the root directory.
|
||||
* See IEEE P1281, section 5.3 for more details.
|
||||
*
|
||||
* this is special because it doesn't modify the susp fields of the
|
||||
* directory; it modifies the susp fields of the "." entry in the directory.
|
||||
*/
|
||||
void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||
|
||||
/** Once all the directories and files are laid out, recurse through the tree
|
||||
* and finalize all SUSP CE entries. */
|
||||
|
|
679
libisofs/tree.c
Executable file → Normal file
679
libisofs/tree.c
Executable file → Normal file
|
@ -20,8 +20,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "tree.h"
|
||||
#include "util.h"
|
||||
#include "volume.h"
|
||||
#include "exclude.h"
|
||||
|
||||
static void
|
||||
|
@ -30,171 +28,613 @@ set_default_stat(struct stat *s)
|
|||
time_t now = time(NULL);
|
||||
|
||||
memset(s, 0, sizeof(struct stat));
|
||||
s->st_mode = 0777 | S_IFREG;
|
||||
s->st_mode = 0555;
|
||||
s->st_atime = s->st_mtime = s->st_ctime = now;
|
||||
}
|
||||
|
||||
static struct stat
|
||||
get_attrib(const struct iso_tree_node *node)
|
||||
void
|
||||
iso_tree_add_child(struct iso_tree_node_dir *parent,
|
||||
struct iso_tree_node *child)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (node) {
|
||||
return node->attrib;
|
||||
}
|
||||
set_default_stat(&st);
|
||||
return st;
|
||||
}
|
||||
|
||||
static void
|
||||
append_node(struct iso_tree_node *parent,
|
||||
struct iso_tree_node *child)
|
||||
{
|
||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child);
|
||||
if (!parent)
|
||||
return;
|
||||
|
||||
assert(parent && child);
|
||||
assert(!child->parent);
|
||||
|
||||
parent->nchildren++;
|
||||
parent->children =
|
||||
realloc(parent->children, parent->nchildren * sizeof(void*));
|
||||
parent->children[parent->nchildren-1] = child;
|
||||
child->parent = parent;
|
||||
}
|
||||
|
||||
struct iso_tree_node_dir*
|
||||
iso_tree_new_root()
|
||||
{
|
||||
struct iso_tree_node_dir *root;
|
||||
|
||||
root = calloc(1, sizeof(struct iso_tree_node_dir));
|
||||
|
||||
set_default_stat(&root->node.attrib);
|
||||
root->node.refcount = 1;
|
||||
root->node.attrib.st_mode = S_IFDIR | 0777;
|
||||
root->node.type = LIBISO_NODE_DIR;
|
||||
return root;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_new_root(struct iso_volume *vol)
|
||||
{
|
||||
assert(vol);
|
||||
|
||||
if (vol->root) {
|
||||
iso_tree_free(vol->root);
|
||||
}
|
||||
|
||||
vol->root = calloc(1, sizeof(struct iso_tree_node));
|
||||
vol->root->volume = vol;
|
||||
set_default_stat(&vol->root->attrib);
|
||||
vol->root->attrib.st_mode = S_IFDIR | 0777;
|
||||
vol->root->loc.type = LIBISO_NONE;
|
||||
return vol->root;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_new_file(struct iso_tree_node *parent, const char *name)
|
||||
{
|
||||
struct iso_tree_node *f = calloc(1, sizeof(struct iso_tree_node));
|
||||
|
||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
|
||||
|
||||
f->volume = parent ? parent->volume : NULL;
|
||||
f->parent = parent;
|
||||
f->name = parent ? strdup(name) : NULL;
|
||||
f->attrib = get_attrib(parent);
|
||||
f->attrib.st_mode = 0777 | S_IFREG;
|
||||
f->loc.type = LIBISO_NONE;
|
||||
append_node(parent, f);
|
||||
return f;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_new_dir(struct iso_tree_node *parent, const char *name)
|
||||
{
|
||||
struct iso_tree_node *d = iso_tree_add_new_file(parent, name);
|
||||
|
||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
|
||||
|
||||
d->attrib.st_mode = (d->attrib.st_mode & ~S_IFMT) | S_IFDIR;
|
||||
return d;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_add_node(struct iso_tree_node *parent, const char *path)
|
||||
iso_tree_add_file(struct iso_tree_node_dir *parent, const char *path)
|
||||
{
|
||||
struct iso_tree_node_file *f;
|
||||
char *p;
|
||||
struct stat st;
|
||||
struct iso_tree_node *ret;
|
||||
|
||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
|
||||
|
||||
if (lstat(path, &st) == -1)
|
||||
|
||||
assert( parent && path);
|
||||
|
||||
if (lstat(path, &st) == -1) {
|
||||
libisofs_errno = NO_FILE;
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
if ( !S_ISREG(st.st_mode) ) {
|
||||
libisofs_errno = UNEXPECTED_FILE_TYPE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( access(path, R_OK) ) {
|
||||
libisofs_errno = NO_READ_ACCESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f = calloc(1, sizeof(struct iso_tree_node_file));
|
||||
|
||||
/* fill fields */
|
||||
f->node.refcount = 1;
|
||||
f->node.attrib = st;
|
||||
f->loc.path = strdup(path);
|
||||
f->node.type = LIBISO_NODE_FILE;
|
||||
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
|
||||
/* it doesn't matter if we add a file or directory since we modify
|
||||
* attrib anyway. */
|
||||
ret = iso_tree_add_new_file(parent, basename(p));
|
||||
ret->attrib = st;
|
||||
ret->loc.type = LIBISO_FILESYS;
|
||||
ret->loc.path = strdup(path);
|
||||
f->node.name = strdup( basename(p) );
|
||||
free(p);
|
||||
|
||||
return ret;
|
||||
|
||||
/* add to parent (this also sets f->node->parent) */
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) f);
|
||||
|
||||
return (struct iso_tree_node*) f;
|
||||
}
|
||||
|
||||
struct iso_tree_node*
|
||||
iso_tree_radd_dir (struct iso_tree_node *parent, const char *path)
|
||||
iso_tree_add_symlink(struct iso_tree_node_dir *parent,
|
||||
const char *name, const char *dest)
|
||||
{
|
||||
struct iso_tree_node_symlink *link;
|
||||
|
||||
assert( parent && name && dest);
|
||||
|
||||
link = calloc(1, sizeof(struct iso_tree_node_symlink));
|
||||
|
||||
/* fill fields */
|
||||
set_default_stat(&link->node.attrib);
|
||||
link->node.refcount = 1;
|
||||
link->node.attrib.st_mode |= S_IFLNK;
|
||||
link->node.name = strdup(name);
|
||||
link->node.type = LIBISO_NODE_SYMLINK;
|
||||
link->dest = strdup(dest);
|
||||
|
||||
/* add to parent (this also sets link->node->parent) */
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) link);
|
||||
|
||||
return (struct iso_tree_node*) link;
|
||||
}
|
||||
|
||||
struct iso_tree_node_dir*
|
||||
iso_tree_add_dir(struct iso_tree_node_dir *parent,
|
||||
const char *name)
|
||||
{
|
||||
struct iso_tree_node_dir *dir;
|
||||
|
||||
assert( parent && name );
|
||||
|
||||
dir = calloc(1, sizeof(struct iso_tree_node_dir));
|
||||
|
||||
dir->node.refcount = 1;
|
||||
dir->node.attrib = parent->node.attrib;
|
||||
dir->node.type = LIBISO_NODE_DIR;
|
||||
dir->node.name = strdup(name);
|
||||
|
||||
iso_tree_add_child(parent, (struct iso_tree_node*) dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
free(node->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)
|
||||
{
|
||||
assert(node);
|
||||
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)
|
||||
{
|
||||
assert(node);
|
||||
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)
|
||||
{
|
||||
assert(node);
|
||||
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)
|
||||
{
|
||||
assert(node);
|
||||
node->attrib.st_mode = (node->attrib.st_mode & S_IFMT) |
|
||||
(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)
|
||||
{
|
||||
assert(node);
|
||||
if ( ISO_ISDIR(node) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir;
|
||||
dir = (struct iso_tree_node_dir *) node;
|
||||
for (i=0; i < dir->nchildren; i++) {
|
||||
iso_tree_node_set_sort_weight(dir->children[i], w);
|
||||
}
|
||||
} else if ( ISO_ISREG(node) ) {
|
||||
struct iso_tree_node_file *file;
|
||||
file = (struct iso_tree_node_file *) node;
|
||||
file->sort_weight = w;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct stat st;
|
||||
struct iso_tree_node *node;
|
||||
|
||||
assert( parent && path);
|
||||
|
||||
if (lstat(path, &st) == -1) {
|
||||
libisofs_errno = NO_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( access(path, R_OK) ) {
|
||||
libisofs_errno = NO_READ_ACCESS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (st.st_mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
/* regular file */
|
||||
node = iso_tree_add_file(parent, path);
|
||||
break;
|
||||
case S_IFLNK:
|
||||
/* symlink */
|
||||
{
|
||||
char dest[PATH_MAX];
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
n = readlink(path, dest, PATH_MAX);
|
||||
if ( n == -1 ) {
|
||||
libisofs_errno = INTERNAL_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
dest[n] = '\0';
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
node = iso_tree_add_symlink(parent, basename(p), dest);
|
||||
free(p);
|
||||
node->attrib = st;
|
||||
}
|
||||
break;
|
||||
case S_IFDIR:
|
||||
/* directory */
|
||||
{
|
||||
char *p;
|
||||
p = strdup(path); /* because basename() might modify its arg */
|
||||
node = (struct iso_tree_node*) iso_tree_add_dir(parent, basename(p));
|
||||
free(p);
|
||||
node->attrib = st;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
libisofs_errno = UNEXPECTED_FILE_TYPE;
|
||||
node = NULL;
|
||||
break;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
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 (!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(root->name);
|
||||
free(root);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iso_tree_radd_dir_aux(struct iso_tree_node_dir *parent, const char *path,
|
||||
struct iso_tree_radd_dir_behavior *behavior,
|
||||
struct iso_hash_table *excludes)
|
||||
{
|
||||
struct iso_tree_node *new;
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
|
||||
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
|
||||
|
||||
new = iso_tree_add_node(parent, path);
|
||||
if (!new || !S_ISDIR(new->attrib.st_mode)) {
|
||||
return new;
|
||||
}
|
||||
|
||||
dir = opendir(path);
|
||||
if (!dir) {
|
||||
warn("couldn't open directory %s: %s\n", path, strerror(errno));
|
||||
return new;
|
||||
return;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
char child[strlen(ent->d_name) + strlen(path) + 2];
|
||||
|
||||
if (behavior->stop_on_error & behavior->error)
|
||||
break;
|
||||
|
||||
if (strcmp(ent->d_name, ".") == 0 ||
|
||||
strcmp(ent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
//TODO check if path already finished in '/'
|
||||
sprintf(child, "%s/%s", path, ent->d_name);
|
||||
|
||||
/* see if this child is excluded. */
|
||||
if (iso_exclude_lookup(child))
|
||||
if (iso_exclude_lookup(excludes, child))
|
||||
continue;
|
||||
|
||||
iso_tree_radd_dir(new, child);
|
||||
new = iso_tree_add_node(parent, child);
|
||||
if (!new || !ISO_ISDIR(new)) {
|
||||
if (!new)
|
||||
behavior->error = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
iso_tree_radd_dir_aux( (struct iso_tree_node_dir *) new, child,
|
||||
behavior, excludes);
|
||||
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return new;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_free(struct iso_tree_node *root)
|
||||
void
|
||||
iso_tree_radd_dir(struct iso_tree_node_dir *parent, const char *path,
|
||||
struct iso_tree_radd_dir_behavior *behavior)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i=0; i < root->nchildren; i++) {
|
||||
iso_tree_free(root->children[i]);
|
||||
struct iso_tree_node_dir *dir;
|
||||
struct iso_hash_table table = { {0,}, 0};
|
||||
|
||||
assert ( parent && path );
|
||||
|
||||
behavior->error = 0;
|
||||
|
||||
/* initialize exclude hash_table */
|
||||
if ( behavior->excludes ) {
|
||||
char *exclude;
|
||||
int i = 0;
|
||||
while ( (exclude = behavior->excludes[i++]) ) {
|
||||
iso_exclude_add_path(&table, exclude);
|
||||
}
|
||||
}
|
||||
free(root->name);
|
||||
free(root->children);
|
||||
free(root);
|
||||
|
||||
/* recurse into dir */
|
||||
iso_tree_radd_dir_aux(parent, path, behavior, &table);
|
||||
|
||||
/* clear hashtable */
|
||||
iso_exclude_empty(&table);
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_print(const struct iso_tree_node *root, int spaces)
|
||||
{
|
||||
size_t i;
|
||||
char sp[spaces+1];
|
||||
|
||||
memset(sp, ' ', spaces);
|
||||
sp[spaces] = '\0';
|
||||
|
||||
printf("%s%sn", sp, root->name);
|
||||
for (i=0; i < root->nchildren; i++) {
|
||||
iso_tree_print(root->children[i], spaces+2);
|
||||
printf("%s%s\n", sp, root->name);
|
||||
|
||||
if ( ISO_ISDIR(root) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir;
|
||||
|
||||
dir = (struct iso_tree_node_dir *) root;
|
||||
for (i=0; i < dir->nchildren; i++) {
|
||||
iso_tree_print(dir->children[i], spaces+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,19 +645,18 @@ iso_tree_print_verbose(const struct iso_tree_node *root,
|
|||
void *callback_data,
|
||||
int spaces)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
(S_ISDIR(root->attrib.st_mode) ? dir : file)
|
||||
(ISO_ISDIR(root) ? dir : file)
|
||||
(root, callback_data, spaces);
|
||||
for (i=0; i < root->nchildren; i++) {
|
||||
iso_tree_print_verbose(root->children[i], dir,
|
||||
file, callback_data, spaces+2);
|
||||
|
||||
if ( ISO_ISDIR(root) ) {
|
||||
size_t i;
|
||||
struct iso_tree_node_dir *dir_node;
|
||||
|
||||
dir_node = (struct iso_tree_node_dir *) root;
|
||||
for (i=0; i < dir_node->nchildren; i++) {
|
||||
iso_tree_print_verbose(dir_node->children[i], dir,
|
||||
file, callback_data, spaces+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
iso_tree_node_set_name(struct iso_tree_node *file, const char *name)
|
||||
{
|
||||
free(file->name);
|
||||
file->name = strdup(name);
|
||||
}
|
||||
|
|
149
libisofs/tree.h
Executable file → Normal file
149
libisofs/tree.h
Executable file → Normal 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,95 +20,103 @@
|
|||
#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;
|
||||
/* };*/
|
||||
};
|
||||
|
||||
/**
|
||||
* A node in the filesystem tree.
|
||||
*/
|
||||
struct iso_tree_node
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
struct iso_tree_node *parent;
|
||||
/*
|
||||
* 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
|
||||
* documented in "man 2 stat". */
|
||||
struct iso_file_location loc;
|
||||
/**< Only used for regular files and symbolic
|
||||
* links (ie. files for which we might have to
|
||||
* copy data). */
|
||||
|
||||
int hide_flags; /**< If the node is to be hidden in RR/ISO or
|
||||
* Joilet tree */
|
||||
enum tree_node_from procedence; /**< Procedence of the node. */
|
||||
enum iso_tree_node_type type; /**< Type of the node. */
|
||||
};
|
||||
|
||||
/**
|
||||
* A node in the filesystem tree that represents a regular file
|
||||
*/
|
||||
struct iso_tree_node_file
|
||||
{
|
||||
struct iso_tree_node node;
|
||||
|
||||
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 */
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* A node in the filesystem tree that represents a symbolic link
|
||||
*/
|
||||
struct iso_tree_node_symlink
|
||||
{
|
||||
struct iso_tree_node node;
|
||||
|
||||
char *dest; /**< Destination of the link */
|
||||
};
|
||||
|
||||
/**
|
||||
* A directory on the filesystem tree
|
||||
*/
|
||||
struct iso_tree_node_dir
|
||||
{
|
||||
struct iso_tree_node node;
|
||||
|
||||
size_t nchildren; /**< The number of children of this
|
||||
* directory (if this is a directory). */
|
||||
struct iso_tree_node **children;
|
||||
|
||||
size_t block; /**< The block at which this file will
|
||||
* reside on disk. We store this here as
|
||||
* well as in the various mangled trees
|
||||
* because many different trees might point
|
||||
* to the same file and they need to share the
|
||||
* block location. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new root directory for a volume.
|
||||
*
|
||||
* \param vol The volume for which to create a new root directory.
|
||||
*
|
||||
* \pre \p vol is non-NULL.
|
||||
* \post \p vol has a non-NULL, empty root directory with permissions 777.
|
||||
* \return \p vol's new non-NULL, empty root directory.
|
||||
* Tree node that corresponds to some El-Torito artifact.
|
||||
* This can be either the boot catalog or a bootable image.
|
||||
*/
|
||||
struct iso_tree_node *iso_tree_new_root(struct iso_volume *vol);
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new, empty, file.
|
||||
*
|
||||
* \param parent The parent directory of the new file. If this is null, create
|
||||
* and return a new file node without adding it to any tree.
|
||||
* \param name The name of the new file, encoded in the current locale.
|
||||
* \pre \p name is non-NULL and it does not match any other file or directory
|
||||
* name in \p parent.
|
||||
* \post \p parent (if non-NULL) contains a file with the following properties:
|
||||
* - the file's name is \p name (converted to wchar_t)
|
||||
* - the file's POSIX permissions are the same as \p parent's
|
||||
* - the file is a regular file
|
||||
* - the file is empty
|
||||
*
|
||||
* \return \p parent's newly created file.
|
||||
* An iterator for directory children.
|
||||
*/
|
||||
struct iso_tree_node *iso_tree_add_new_file(struct iso_tree_node *parent,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
struct iso_tree_iter
|
||||
{
|
||||
struct iso_tree_node_dir *dir;
|
||||
int index;
|
||||
};
|
||||
|
||||
/**
|
||||
* A function that prints verbose information about a directory.
|
||||
|
@ -154,6 +162,9 @@ void iso_tree_print_verbose(const struct iso_tree_node *root,
|
|||
void *callback_data,
|
||||
int spaces);
|
||||
|
||||
#define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode)
|
||||
#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 */
|
||||
|
|
424
libisofs/util.c
Executable file → Normal file
424
libisofs/util.c
Executable file → Normal file
|
@ -16,9 +16,12 @@
|
|||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
#include <locale.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "libisofs.h"
|
||||
|
||||
/* avoids warning and names in iso, joliet and rockridge can't be > 255 bytes
|
||||
* anyway. There are at most 31 characters in iso level 1, 255 for rockridge,
|
||||
|
@ -35,32 +38,141 @@ int round_up(int n, int mul)
|
|||
return div_up(n, mul) * mul;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a string between charsets.
|
||||
* This assumes '\0' means end-of-string, what is not necessarily true,
|
||||
* but given there are lots of strdup around there, it will fail in other
|
||||
* places anyway...
|
||||
*/
|
||||
char *
|
||||
convert_str(const char *str, const char *icharset, const char *ocharset)
|
||||
{
|
||||
char *ret;
|
||||
size_t inbytes;
|
||||
size_t outbytes;
|
||||
|
||||
inbytes = strlen(str);
|
||||
outbytes = (inbytes+1) * MB_LEN_MAX;
|
||||
{
|
||||
/* ensure enought space */
|
||||
char out[outbytes];
|
||||
char *src;
|
||||
size_t n;
|
||||
|
||||
iconv_t conv = iconv_open(ocharset, icharset);
|
||||
if (conv == (iconv_t)(-1)) {
|
||||
printf("Can't convert from %s to %s\n", icharset, ocharset);
|
||||
return NULL;
|
||||
}
|
||||
src = (char *)str;
|
||||
ret = (char *)out;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
if (n == -1) {
|
||||
/* error just return input stream */
|
||||
perror("Convert error.");
|
||||
printf("Maybe string %s is not encoded in %s\n", str, icharset);
|
||||
|
||||
iconv_close(conv);
|
||||
return strdup(str);
|
||||
}
|
||||
iconv_close(conv);
|
||||
*ret = '\0';
|
||||
|
||||
ret = strdup(out);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a str in a specified codeset to WCHAR_T.
|
||||
* The result must be free() when no more needed
|
||||
*/
|
||||
static wchar_t *str2wchar(const char *str, const char *codeset)
|
||||
{
|
||||
iconv_t conv;
|
||||
size_t inbytes;
|
||||
size_t outbytes;
|
||||
char *ret;
|
||||
char *src;
|
||||
wchar_t *wstr;
|
||||
size_t n;
|
||||
|
||||
conv = iconv_open("WCHAR_T", codeset);
|
||||
if (conv == (iconv_t)-1) {
|
||||
perror("Invalid encodings\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inbytes = strlen(str);
|
||||
outbytes = (inbytes + 1) * sizeof(wchar_t);
|
||||
|
||||
/* we are sure that numchars <= inbytes */
|
||||
wstr = malloc(outbytes);
|
||||
ret = (char *)wstr;
|
||||
src = (char *)str;
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
while (n == -1) {
|
||||
|
||||
if( errno != EINVAL ) {
|
||||
/* error, should never occur */
|
||||
iconv_close(conv);
|
||||
perror("Convert error\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* invalid input string charset, just log and ignore */
|
||||
printf("String %s is not encoded in %s\n", str, codeset);
|
||||
inbytes--;
|
||||
|
||||
if(!inbytes)
|
||||
break;
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
}
|
||||
iconv_close(conv);
|
||||
|
||||
*( (wchar_t *)ret )='\0';
|
||||
return wstr;
|
||||
}
|
||||
|
||||
/* this function must always return a name
|
||||
* since the caller never checks if a NULL
|
||||
* is returned. It also avoids some warnings. */
|
||||
char *str2ascii(const char *src_arg)
|
||||
char *str2ascii(const char *src_arg, const char *icharset)
|
||||
{
|
||||
wchar_t wsrc_[NAME_BUFFER_SIZE];
|
||||
char *src = (char*)wsrc_;
|
||||
char *ret_;
|
||||
wchar_t *wsrc_;
|
||||
char *ret;
|
||||
mbstate_t state;
|
||||
char *ret_;
|
||||
char *src;
|
||||
iconv_t conv;
|
||||
size_t numchars;
|
||||
size_t outbytes;
|
||||
size_t inbytes;
|
||||
size_t n;
|
||||
|
||||
assert(icharset);
|
||||
|
||||
if (!src_arg)
|
||||
return NULL;
|
||||
|
||||
/* convert the string to a wide character string. Note: outbytes
|
||||
* is in fact the number of characters in the string and doesn't
|
||||
* include the last NULL character. */
|
||||
memset(&state, 0, sizeof(state));
|
||||
numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state);
|
||||
if (numchars < 0)
|
||||
* include the last NULL character.
|
||||
*
|
||||
* For now, just assume input to be in UTF-8, we can change
|
||||
* this later.
|
||||
*/
|
||||
|
||||
wsrc_ = str2wchar(src_arg, icharset);
|
||||
|
||||
if (!wsrc_)
|
||||
return NULL;
|
||||
|
||||
src = (char *)wsrc_;
|
||||
numchars = wcslen(wsrc_);
|
||||
|
||||
|
||||
inbytes = numchars * sizeof(wchar_t);
|
||||
|
||||
|
@ -70,8 +182,10 @@ char *str2ascii(const char *src_arg)
|
|||
|
||||
/* initialize iconv */
|
||||
conv = iconv_open("ASCII", "WCHAR_T");
|
||||
if (conv == (iconv_t)-1)
|
||||
if (conv == (iconv_t)-1) {
|
||||
free(wsrc_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||
while(n == -1) {
|
||||
|
@ -109,17 +223,18 @@ char *str2ascii(const char *src_arg)
|
|||
iconv_close(conv);
|
||||
|
||||
*ret='\0';
|
||||
free(wsrc_);
|
||||
|
||||
return ret_;
|
||||
}
|
||||
|
||||
/* FIXME: C&P */
|
||||
uint16_t *str2ucs(const char *src_arg)
|
||||
uint16_t *str2ucs(const char *src_arg, const char *icharset)
|
||||
{
|
||||
wchar_t wsrc_[NAME_BUFFER_SIZE];
|
||||
char *src = (char*)wsrc_;
|
||||
wchar_t *wsrc_;
|
||||
char *src;
|
||||
char *ret_;
|
||||
char *ret;
|
||||
mbstate_t state;
|
||||
iconv_t conv;
|
||||
size_t outbytes;
|
||||
size_t numchars;
|
||||
|
@ -129,13 +244,17 @@ uint16_t *str2ucs(const char *src_arg)
|
|||
if (!src_arg)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
|
||||
|
||||
/* convert the string to a wide character string. Note: outbytes
|
||||
* is in fact the number of characters in the string and doesn't
|
||||
* include the last NULL character. */
|
||||
memset(&state, 0, sizeof(state));
|
||||
numchars = mbsrtowcs(wsrc_, &src_arg, NAME_BUFFER_SIZE-1, &state);
|
||||
if (numchars < 0)
|
||||
* include the last NULL character.
|
||||
*/
|
||||
|
||||
wsrc_ = str2wchar(src_arg, icharset);
|
||||
if (!wsrc_)
|
||||
return calloc(2, 1); /* empty UCS string */
|
||||
src = (char*)wsrc_;
|
||||
numchars = wcslen(wsrc_);
|
||||
|
||||
inbytes = numchars * sizeof(wchar_t);
|
||||
|
||||
|
@ -190,7 +309,6 @@ uint16_t *str2ucs(const char *src_arg)
|
|||
return (uint16_t*)ret_;
|
||||
}
|
||||
|
||||
|
||||
static int valid_d_char(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
|
||||
|
@ -218,9 +336,45 @@ static int valid_p_char(char c)
|
|||
|| (c == '.') || (c == '_') || (c == '-');
|
||||
}
|
||||
|
||||
static char *iso_dirid(const char *src, int size)
|
||||
char *str2d_char(const char *str, const char *icharset) {
|
||||
char *ret;
|
||||
size_t len, i;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
ret = str2ascii(str, icharset);
|
||||
len = strlen(ret);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
char c = toupper(ret[i]);
|
||||
ret[i] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *str2a_char(const char *str, const char *icharset) {
|
||||
char *ret;
|
||||
size_t len, i;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
|
||||
ret = str2ascii(str, icharset);
|
||||
len = strlen(ret);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
char c = toupper(ret[i]);
|
||||
ret[i] = valid_a_char(c) ? c : '_';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *iso_dirid(const char *src, int size, const char *icharset)
|
||||
{
|
||||
char *ret = str2ascii(src);
|
||||
char *ret = str2ascii(src, icharset);
|
||||
size_t len, i;
|
||||
|
||||
if (!ret)
|
||||
|
@ -239,19 +393,46 @@ static char *iso_dirid(const char *src, int size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
char *iso_1_dirid(const char *src)
|
||||
char *iso_1_dirid(const char *src, const char *icharset)
|
||||
{
|
||||
return iso_dirid(src, 8);
|
||||
return iso_dirid(src, 8, icharset);
|
||||
}
|
||||
|
||||
char *iso_2_dirid(const char *src)
|
||||
char *iso_2_dirid(const char *src, const char *icharset)
|
||||
{
|
||||
return iso_dirid(src, 31);
|
||||
return iso_dirid(src, 31, icharset);
|
||||
}
|
||||
|
||||
char *iso_1_fileid(const char *src_arg)
|
||||
char *iso_r_dirid(const char *src, const char *icharset, int flags)
|
||||
{
|
||||
char *src = str2ascii(src_arg);
|
||||
char *ret = str2ascii(src, icharset);
|
||||
size_t size, len, i;
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
size = flags & ECMA119_37_CHAR_FILENAMES ? 37 : 31;
|
||||
|
||||
len = strlen(ret);
|
||||
if (len > size) {
|
||||
ret[size] = '\0';
|
||||
len = size;
|
||||
}
|
||||
|
||||
if (flags & ECMA119_RELAXED_FILENAMES)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
char c = toupper(ret[i]);
|
||||
ret[i] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *iso_1_fileid(const char *src_arg, const char *icharset)
|
||||
{
|
||||
char *src = str2ascii(src_arg, icharset);
|
||||
char *dest;
|
||||
char *dot; /* Position of the last dot in the
|
||||
filename, will be used to calculate
|
||||
|
@ -300,9 +481,9 @@ char *iso_1_fileid(const char *src_arg)
|
|||
return dest;
|
||||
}
|
||||
|
||||
char *iso_2_fileid(const char *src_arg)
|
||||
char *iso_2_fileid(const char *src_arg, const char *icharset)
|
||||
{
|
||||
char *src = str2ascii(src_arg);
|
||||
char *src = str2ascii(src_arg, icharset);
|
||||
char *dest;
|
||||
char *dot;
|
||||
int lname, lext, lnname, lnext, pos, i;
|
||||
|
@ -318,7 +499,7 @@ char *iso_2_fileid(const char *src_arg)
|
|||
extension, we need to calculate their new lengths (lnname and
|
||||
lnext). If the original filename is too long, we start by trimming
|
||||
the extension, but keep a minimum extension length of 3. */
|
||||
if (dot == NULL || dot == src || *(dot + 1) == '\0') {
|
||||
if (dot == NULL || *(dot + 1) == '\0') {
|
||||
lname = strlen(src);
|
||||
lnname = (lname > 30) ? 30 : lname;
|
||||
lext = lnext = 0;
|
||||
|
@ -360,9 +541,89 @@ char *iso_2_fileid(const char *src_arg)
|
|||
}
|
||||
|
||||
char *
|
||||
iso_p_fileid(const char *src)
|
||||
iso_r_fileid(const char *src_arg, const char *icharset, int flag)
|
||||
{
|
||||
char *ret = str2ascii(src);
|
||||
char *src = str2ascii(src_arg, icharset);
|
||||
char *dest;
|
||||
char *dot;
|
||||
int lname, lext, lnname, lnext, pos, i;
|
||||
size_t max;
|
||||
|
||||
size_t size = flag & (1<<1) ? 37 : 33;
|
||||
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
dest = malloc(size+1);
|
||||
|
||||
if (flag & ECMA119_RELAXED_FILENAMES) {
|
||||
strncpy(dest, src, size);
|
||||
dest[size] = '\0'; /* ensure 37 / 33 max length */
|
||||
pos = strlen(dest);
|
||||
pos = pos < (size == 37 ? 37 : 31) ? pos : (size == 37 ? 37 : 31);
|
||||
if ( !(flag & ECMA119_OMIT_VERSION_NUMBERS) ) {
|
||||
dest[pos++] = ';';
|
||||
dest[pos++] = '1';
|
||||
}
|
||||
dest[pos] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* no relaxed filenames */
|
||||
dot = strrchr(src, '.');
|
||||
|
||||
max = (size == 37 ? 36 : 30);
|
||||
/* Since the maximum length can be divided freely over the name and
|
||||
extension, we need to calculate their new lengths (lnname and
|
||||
lnext). If the original filename is too long, we start by trimming
|
||||
the extension, but keep a minimum extension length of 3. */
|
||||
if (dot == NULL || *(dot + 1) == '\0') {
|
||||
lname = strlen(src);
|
||||
lnname = (lname > max) ? max : lname;
|
||||
lext = lnext = 0;
|
||||
} else {
|
||||
lext = strlen(dot + 1);
|
||||
lname = strlen(src) - lext - 1;
|
||||
lnext = (strlen(src) > max + 1 && lext > 3)
|
||||
? (lname < max - 3 ? max - lname : 3) : lext;
|
||||
lnname = (strlen(src) > max +1) ? max - lnext : lname;
|
||||
}
|
||||
|
||||
if (lnname == 0 && lnext == 0) {
|
||||
free(src);
|
||||
free(dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
/* Convert up to lnname characters of the filename. */
|
||||
for (i = 0; i < lnname; i++) {
|
||||
char c = toupper(src[i]);
|
||||
|
||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
dest[pos++] = '.';
|
||||
/* Convert up to lnext characters of the extension, if any. */
|
||||
for (i = 0; i < lnext; i++) {
|
||||
char c = toupper(src[lname + 1 + i]);
|
||||
|
||||
dest[pos++] = valid_d_char(c) ? c : '_';
|
||||
}
|
||||
if ( !(flag & ECMA119_OMIT_VERSION_NUMBERS) ) {
|
||||
dest[pos++] = ';';
|
||||
dest[pos++] = '1';
|
||||
}
|
||||
dest[pos] = '\0';
|
||||
dest = (char *)realloc(dest, pos + 1);
|
||||
|
||||
free(src);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *
|
||||
iso_p_fileid(const char *src, const char *icharset)
|
||||
{
|
||||
char *ret = str2ascii(src, icharset);
|
||||
size_t i, len;
|
||||
|
||||
if (!ret)
|
||||
|
@ -377,9 +638,9 @@ iso_p_fileid(const char *src)
|
|||
}
|
||||
|
||||
uint16_t *
|
||||
iso_j_id(const char *src_arg)
|
||||
iso_j_id(const char *src_arg, const char *icharset)
|
||||
{
|
||||
uint16_t *j_str = str2ucs(src_arg);
|
||||
uint16_t *j_str = str2ucs(src_arg, icharset);
|
||||
size_t len = ucslen(j_str);
|
||||
size_t n;
|
||||
|
||||
|
@ -420,7 +681,6 @@ void iso_bb(uint8_t *buf, uint32_t num, int bytes)
|
|||
iso_msb(buf+bytes, num, bytes);
|
||||
}
|
||||
|
||||
|
||||
void iso_datetime_7(unsigned char *buf, time_t t)
|
||||
{
|
||||
static int tzsetup = 0;
|
||||
|
@ -441,12 +701,12 @@ void iso_datetime_7(unsigned char *buf, time_t t)
|
|||
buf[4] = tm.tm_min;
|
||||
buf[5] = tm.tm_sec;
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
tzoffset = -tm.tm_gmtoff / 60 / 15;
|
||||
tzoffset = tm.tm_gmtoff / 60 / 15;
|
||||
#else
|
||||
tzoffset = -timezone / 60 / 15;
|
||||
tzoffset = timezone / 60 / 15;
|
||||
#endif
|
||||
if (tzoffset < -48)
|
||||
tzoffset += 101;
|
||||
if (tzoffset > 52)
|
||||
tzoffset -= 101;
|
||||
buf[6] = tzoffset;
|
||||
}
|
||||
|
||||
|
@ -455,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)
|
||||
|
@ -490,12 +749,12 @@ void iso_datetime_17(unsigned char *buf, time_t t)
|
|||
sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
|
||||
memcpy(&buf[14], "00", 2);
|
||||
#ifdef HAVE_TM_GMTOFF
|
||||
tzoffset = -tm.tm_gmtoff / 60 / 15;
|
||||
tzoffset = tm.tm_gmtoff / 60 / 15;
|
||||
#else
|
||||
tzoffset = -timezone / 60 / 15;
|
||||
tzoffset = timezone / 60 / 15;
|
||||
#endif
|
||||
if (tzoffset < -48)
|
||||
tzoffset += 101;
|
||||
if (tzoffset > 52)
|
||||
tzoffset -= 101;
|
||||
buf[16] = tzoffset;
|
||||
}
|
||||
}
|
||||
|
@ -513,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)
|
||||
|
@ -574,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;
|
||||
}
|
||||
|
|
50
libisofs/util.h
Executable file → Normal file
50
libisofs/util.h
Executable file → Normal file
|
@ -30,19 +30,29 @@ extern inline int round_up(int n, int mul)
|
|||
return div_up(n, mul) * mul;
|
||||
}
|
||||
|
||||
char *convert_str(const char *str, const char *icharset, const char *ocharset);
|
||||
|
||||
wchar_t *towcs(const char *);
|
||||
char *str2ascii(const char*);
|
||||
uint16_t *str2ucs(const char*);
|
||||
char *str2ascii(const char*, const char *);
|
||||
uint16_t *str2ucs(const char *, const char *);
|
||||
|
||||
char *str2d_char(const char*, const char *);
|
||||
char *str2a_char(const char*, const char *);
|
||||
|
||||
/**
|
||||
* Create a level 1 directory identifier.
|
||||
*/
|
||||
char *iso_1_dirid(const char *src);
|
||||
char *iso_1_dirid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a level 2 directory identifier.
|
||||
*/
|
||||
char *iso_2_dirid(const char *src);
|
||||
char *iso_2_dirid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a directory identifier with relaxed constraints
|
||||
*/
|
||||
char *iso_r_dirid(const char *src, const char *icharset, int flags);
|
||||
|
||||
/**
|
||||
* Create a level 1 file identifier that consists of a name, extension and
|
||||
|
@ -51,7 +61,7 @@ char *iso_2_dirid(const char *src);
|
|||
* length 3, followed by a separator (;) and a version number (digit 1).
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_1_fileid(const char *src);
|
||||
char *iso_1_fileid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a level 2 file identifier that consists of a name, extension and
|
||||
|
@ -60,7 +70,12 @@ char *iso_1_fileid(const char *src);
|
|||
* followed by a separator (;) and a version number (digit 1).
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_2_fileid(const char *src);
|
||||
char *iso_2_fileid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a file identifier with relaxed constraints.
|
||||
*/
|
||||
char *iso_r_fileid(const char *src, const char *icharset, int flags);
|
||||
|
||||
/**
|
||||
* Create a Joliet file or directory identifier that consists of a name,
|
||||
|
@ -73,7 +88,7 @@ char *iso_2_fileid(const char *src);
|
|||
* @param size will be set to the size (in bytes) of the identifier.
|
||||
* @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available.
|
||||
*/
|
||||
uint16_t *iso_j_id(const char *src);
|
||||
uint16_t *iso_j_id(const char *src, const char *icharset);
|
||||
|
||||
/**
|
||||
* FIXME: what are the requirements for these next two? Is this for RR?
|
||||
|
@ -82,7 +97,7 @@ uint16_t *iso_j_id(const char *src);
|
|||
* The resulting file name will not exceed 250 characters.
|
||||
* @return NULL if the original name and extension both are of length 0.
|
||||
*/
|
||||
char *iso_p_fileid(const char *src);
|
||||
char *iso_p_fileid(const char *src, const char *);
|
||||
|
||||
/**
|
||||
* Create a POSIX portable directory name.
|
||||
|
@ -97,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);
|
||||
|
@ -118,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 */
|
||||
|
|
277
libisofs/volume.c
Executable file → Normal file
277
libisofs/volume.c
Executable file → Normal 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>
|
||||
|
@ -9,6 +10,7 @@
|
|||
#include "tree.h"
|
||||
#include "util.h"
|
||||
#include "volume.h"
|
||||
#include "eltorito.h"
|
||||
|
||||
struct iso_volset*
|
||||
iso_volset_new(struct iso_volume *vol, const char *id)
|
||||
|
@ -20,11 +22,15 @@ iso_volset_new(struct iso_volume *vol, const char *id)
|
|||
volset->volume = malloc(sizeof(void *));
|
||||
volset->volume[0] = vol;
|
||||
volset->volset_id = strdup(id);
|
||||
|
||||
vol->refcount++;
|
||||
return volset;
|
||||
}
|
||||
|
||||
void
|
||||
iso_volset_ref(struct iso_volset *volset)
|
||||
{
|
||||
++volset->refcount;
|
||||
}
|
||||
|
||||
void
|
||||
iso_volset_free(struct iso_volset *volset)
|
||||
{
|
||||
|
@ -35,9 +41,20 @@ iso_volset_free(struct iso_volset *volset)
|
|||
}
|
||||
free(volset->volume);
|
||||
free(volset->volset_id);
|
||||
free(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,
|
||||
|
@ -53,14 +70,14 @@ struct iso_volume*
|
|||
iso_volume_new_with_root(const char *volume_id,
|
||||
const char *publisher_id,
|
||||
const char *data_preparer_id,
|
||||
struct iso_tree_node *root)
|
||||
struct iso_tree_node_dir *root)
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = calloc(1, sizeof(struct iso_volume));
|
||||
volume->refcount = 1;
|
||||
|
||||
volume->root = root ? root : iso_tree_new_root(volume);
|
||||
volume->root = root ? root : iso_tree_new_root();
|
||||
|
||||
if (volume_id != NULL)
|
||||
volume->volume_id = strdup(volume_id);
|
||||
|
@ -76,39 +93,166 @@ iso_volume_free(struct iso_volume *volume)
|
|||
{
|
||||
/* Only free if no references are in use. */
|
||||
if (--volume->refcount < 1) {
|
||||
iso_tree_free(volume->root);
|
||||
iso_tree_free( (struct iso_tree_node*) volume->root);
|
||||
|
||||
free(volume->volume_id);
|
||||
free(volume->publisher_id);
|
||||
free(volume->data_preparer_id);
|
||||
|
||||
free(volume->system_id);
|
||||
free(volume->application_id);
|
||||
free(volume->copyright_file_id);
|
||||
free(volume->abstract_file_id);
|
||||
free(volume->biblio_file_id);
|
||||
if (volume->bootcat)
|
||||
el_torito_boot_catalog_free(volume->bootcat);
|
||||
free(volume);
|
||||
}
|
||||
}
|
||||
|
||||
struct iso_tree_node *
|
||||
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)
|
||||
{
|
||||
struct iso_tree_node *node;
|
||||
struct iso_tree_node_dir *dir;
|
||||
char *ptr, *brk_info, *component;
|
||||
|
||||
/* get the first child at the root of the volume
|
||||
* that is "/" */
|
||||
node=iso_volume_get_root(volume);
|
||||
if (!strcmp (path, "/"))
|
||||
dir = iso_volume_get_root(volume);
|
||||
node = (struct iso_tree_node *)dir;
|
||||
if (!strcmp(path, "/"))
|
||||
return node;
|
||||
|
||||
if (!node->nchildren)
|
||||
if (!dir->nchildren)
|
||||
return NULL;
|
||||
|
||||
/* the name of the nodes is in wide characters so first convert path
|
||||
* into wide characters. */
|
||||
ptr = strdup(path);
|
||||
|
||||
/* get the first component of the path */
|
||||
|
@ -116,12 +260,18 @@ iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
|
|||
while (component) {
|
||||
size_t max;
|
||||
size_t i;
|
||||
|
||||
if ( !ISO_ISDIR(node) ) {
|
||||
node=NULL;
|
||||
break;
|
||||
}
|
||||
dir = (struct iso_tree_node_dir *)node;
|
||||
|
||||
/* search among all the children of this directory if this path component exists */
|
||||
max=node->nchildren;
|
||||
max=dir->nchildren;
|
||||
for (i=0; i < max; i++) {
|
||||
if (!strcmp(component, node->children[i]->name)) {
|
||||
node=node->children[i];
|
||||
if (!strcmp(component, dir->children[i]->name)) {
|
||||
node=dir->children[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -136,54 +286,55 @@ iso_tree_volume_path_to_node(struct iso_volume *volume, const char *path)
|
|||
}
|
||||
|
||||
free(ptr);
|
||||
return node;
|
||||
}
|
||||
|
||||
struct iso_tree_node *
|
||||
iso_tree_volume_add_path(struct iso_volume *volume,
|
||||
const char *disc_path,
|
||||
const char *path)
|
||||
{
|
||||
char *tmp;
|
||||
struct iso_tree_node *node;
|
||||
struct iso_tree_node *parent_node;
|
||||
|
||||
tmp=strdup(disc_path);
|
||||
parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
|
||||
free(tmp);
|
||||
|
||||
if (!parent_node)
|
||||
return NULL;
|
||||
|
||||
node = iso_tree_radd_dir(parent_node, path);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
tmp=strdup(disc_path);
|
||||
iso_tree_node_set_name(node, basename(tmp));
|
||||
free(tmp);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
struct iso_tree_node *
|
||||
iso_tree_volume_add_new_dir(struct iso_volume *volume,
|
||||
const char *disc_path)
|
||||
{
|
||||
char *tmp;
|
||||
struct iso_tree_node *node;
|
||||
struct iso_tree_node *parent_node;
|
||||
|
||||
tmp=strdup(disc_path);
|
||||
parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
|
||||
free(tmp);
|
||||
|
||||
if (!parent_node)
|
||||
return NULL;
|
||||
|
||||
tmp=strdup(disc_path);
|
||||
node = iso_tree_add_new_dir(parent_node, basename(tmp));
|
||||
free(tmp);
|
||||
|
||||
return node;
|
||||
}
|
||||
//
|
||||
//struct iso_tree_node *
|
||||
//iso_tree_volume_add_path(struct iso_volume *volume,
|
||||
// const char *disc_path,
|
||||
// const char *path)
|
||||
//{
|
||||
// char *tmp;
|
||||
// struct iso_tree_node *node;
|
||||
// struct iso_tree_node *parent_node;
|
||||
//
|
||||
// tmp=strdup(disc_path);
|
||||
// parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
|
||||
// free(tmp);
|
||||
//
|
||||
// if (!parent_node)
|
||||
// return NULL;
|
||||
//
|
||||
// node = iso_tree_radd_dir(parent_node, path);
|
||||
// if (!node)
|
||||
// return NULL;
|
||||
//
|
||||
// tmp=strdup(disc_path);
|
||||
// iso_tree_node_set_name(node, basename(tmp));
|
||||
// free(tmp);
|
||||
//
|
||||
// return node;
|
||||
//}
|
||||
//
|
||||
//struct iso_tree_node *
|
||||
//iso_tree_volume_add_new_dir(struct iso_volume *volume,
|
||||
// const char *disc_path)
|
||||
//{
|
||||
// char *tmp;
|
||||
// struct iso_tree_node *node;
|
||||
// struct iso_tree_node *parent_node;
|
||||
//
|
||||
// tmp=strdup(disc_path);
|
||||
// parent_node = iso_tree_volume_path_to_node(volume, dirname(tmp));
|
||||
// free(tmp);
|
||||
//
|
||||
// if (!parent_node)
|
||||
// return NULL;
|
||||
//
|
||||
// tmp=strdup(disc_path);
|
||||
// node = iso_tree_add_new_dir(parent_node, basename(tmp));
|
||||
// free(tmp);
|
||||
//
|
||||
// return node;
|
||||
//}
|
||||
|
|
10
libisofs/volume.h
Executable file → Normal file
10
libisofs/volume.h
Executable file → Normal file
|
@ -18,12 +18,20 @@ struct iso_volume
|
|||
int refcount; /**< Number of used references to this
|
||||
volume. */
|
||||
|
||||
struct iso_tree_node *root; /**< Root of the directory tree for the
|
||||
struct iso_tree_node_dir *root; /**< Root of the directory tree for the
|
||||
volume. */
|
||||
|
||||
char *volume_id; /**< Volume identifier. */
|
||||
char *publisher_id; /**< Volume publisher. */
|
||||
char *data_preparer_id; /**< Volume data preparer. */
|
||||
|
||||
char *system_id; /**< Volume system identifier. */
|
||||
char *application_id; /**< Volume application id */
|
||||
char *copyright_file_id;
|
||||
char *abstract_file_id;
|
||||
char *biblio_file_id;
|
||||
|
||||
struct el_torito_boot_catalog *bootcat; /**< El-Torito boot catalog */
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
33
test.sh
Normal file
33
test.sh
Normal file
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
|
||||
TEST_ROOT=/tmp/libisofs_test
|
||||
|
||||
rm -rf $TEST_ROOT
|
||||
|
||||
#create test folders
|
||||
mkdir -p $TEST_ROOT
|
||||
mkdir -p $TEST_ROOT/dir1/dir11
|
||||
chmod 755 $TEST_ROOT/dir1
|
||||
chmod 755 $TEST_ROOT/dir1/dir11
|
||||
|
||||
touch $TEST_ROOT/dir1/dir11/a
|
||||
echo "This file is to check correct file permissions. set them to 754" > $TEST_ROOT/dir1/permtest
|
||||
chmod 754 $TEST_ROOT/dir1/permtest
|
||||
|
||||
mkdir -p $TEST_ROOT/dir2
|
||||
ln -s $TEST_ROOT/dir1 "$TEST_ROOT/link to dir1"
|
||||
|
||||
echo "README file" > $TEST_ROOT/README
|
||||
chmod 555 $TEST_ROOT/README
|
||||
ln -s $TEST_ROOT/README "$TEST_ROOT/link to readme"
|
||||
|
||||
echo "No read file" > $TEST_ROOT/no_read
|
||||
chmod 000 $TEST_ROOT/no_read
|
||||
|
||||
if ! make check
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test/test
|
||||
|
87
test/iso.c
87
test/iso.c
|
@ -20,41 +20,49 @@
|
|||
|
||||
#define SECSIZE 2048
|
||||
|
||||
const char * const optstring = "JRL: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"
|
||||
" -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 *root;
|
||||
struct iso_tree_node_dir *root;
|
||||
struct burn_source *src;
|
||||
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;
|
||||
|
@ -67,8 +75,14 @@ int main(int argc, char **argv)
|
|||
case 'L':
|
||||
level = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
boot_img = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
volid = optarg;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
usage(argv);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
|
@ -76,32 +90,75 @@ 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");
|
||||
}
|
||||
|
||||
root = iso_tree_radd_dir(NULL, argv[optind]);
|
||||
root = iso_tree_new_root();
|
||||
iso_tree_radd_dir(root, argv[optind], &behav);
|
||||
if (!root) {
|
||||
err(1, "error opening input directory");
|
||||
}
|
||||
volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root );
|
||||
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");
|
||||
}
|
||||
bootimg = iso_volume_set_boot_image(volume, img, ELTORITO_NO_EMUL,
|
||||
boot, "boot.cat");
|
||||
el_torito_set_load_size(bootimg, 4);
|
||||
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" );
|
||||
|
||||
/* some tests */
|
||||
iso_volume_set_application_id(volume, "Libburnia");
|
||||
iso_volume_set_copyright_file_id(volume, "LICENSE");
|
||||
|
||||
src = iso_source_new_ecma119(volset, 0, level, flags);
|
||||
constraints = ECMA119_OMIT_VERSION_NUMBERS |
|
||||
ECMA119_37_CHAR_FILENAMES | ECMA119_NO_DIR_REALOCATION |
|
||||
ECMA119_RELAXED_FILENAMES;
|
||||
|
||||
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);
|
||||
|
||||
while (src->read(src, buf, 2048) == 2048) {
|
||||
fwrite(buf, 1, 2048, fd);
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
iso_finish();
|
||||
return 0;
|
||||
}
|
||||
|
|
157
test/iso_add.c
Normal file
157
test/iso_add.c
Normal 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
302
test/iso_grow.c
Normal 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
159
test/iso_ms.c
Normal 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
163
test/iso_read.c
Normal 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;
|
||||
}
|
30
test/test.c
Normal file
30
test/test.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "test.h"
|
||||
|
||||
static void create_test_suite()
|
||||
{
|
||||
add_util_suite();
|
||||
add_tree_suite();
|
||||
add_exclude_suite();
|
||||
add_file_hashtable_suite();
|
||||
add_ecma119_tree_suite();
|
||||
add_volume_suite();
|
||||
add_data_source_suite();
|
||||
add_isoread_suite();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CU_pSuite pSuite = NULL;
|
||||
|
||||
/* initialize the CUnit test registry */
|
||||
if (CUE_SUCCESS != CU_initialize_registry())
|
||||
return CU_get_error();
|
||||
|
||||
create_test_suite();
|
||||
|
||||
/* Run all tests using the console interface */
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
28
test/test.h
Normal file
28
test/test.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef TEST_H_
|
||||
#define TEST_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <CUnit/Basic.h>
|
||||
|
||||
#include "libisofs.h"
|
||||
|
||||
void add_tree_suite();
|
||||
|
||||
void add_exclude_suite();
|
||||
|
||||
void add_file_hashtable_suite();
|
||||
|
||||
void add_util_suite();
|
||||
|
||||
void add_ecma119_tree_suite();
|
||||
|
||||
void add_volume_suite();
|
||||
|
||||
void add_data_source_suite();
|
||||
|
||||
void add_isoread_suite();
|
||||
|
||||
#endif /*TEST_H_*/
|
75
test/test_data_source.c
Normal file
75
test/test_data_source.c
Normal 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);
|
||||
}
|
122
test/test_ecma119_tree.c
Normal file
122
test/test_ecma119_tree.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Unit test for ecma119_tree.h
|
||||
*/
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "tree.h"
|
||||
#include "test.h"
|
||||
#include "ecma119.h"
|
||||
#include "ecma119_tree.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
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 ecma119_tree_create() with only root dir", test_create_tree_only_root);
|
||||
//CU_add_test(pSuite, "test of create_dir()", test_create_dir);
|
||||
}
|
33
test/test_exclude.c
Normal file
33
test/test_exclude.c
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Unit test for exclude.h
|
||||
*/
|
||||
|
||||
|
||||
#include "exclude.h"
|
||||
#include "test.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void test_exclude()
|
||||
{
|
||||
struct iso_hash_table table = { {0,}, 0};
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/otherdir") );
|
||||
iso_exclude_add_path(&table, "/otherdir");
|
||||
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/otherdir") );
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
|
||||
iso_exclude_add_path(&table, "/dir");
|
||||
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/otherdir") );
|
||||
CU_ASSERT_TRUE( iso_exclude_lookup(&table, "/dir") );
|
||||
iso_exclude_empty(&table);
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/dir") );
|
||||
CU_ASSERT_FALSE( iso_exclude_lookup(&table, "/otherdir") );
|
||||
}
|
||||
|
||||
void add_exclude_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("ExcludeSuite", NULL, NULL);
|
||||
|
||||
CU_add_test(pSuite, "test of exclude", test_exclude);
|
||||
}
|
314
test/test_file_hashtable.c
Normal file
314
test/test_file_hashtable.c
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* Unit test for file.h
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "file.h"
|
||||
#include "tree.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void test_iso_file_new()
|
||||
{
|
||||
struct iso_tree_node_file *file;
|
||||
struct iso_file *iso;
|
||||
|
||||
file = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file->node.name = "fileName";
|
||||
file->node.attrib.st_size = 12;
|
||||
file->node.attrib.st_dev = 15;
|
||||
file->node.attrib.st_ino = 204;
|
||||
file->loc.path = "/tmp/filename";
|
||||
file->sort_weight = 1;
|
||||
|
||||
iso = iso_file_new(file);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(iso);
|
||||
CU_ASSERT_STRING_EQUAL(iso->path, "/tmp/filename");
|
||||
CU_ASSERT_EQUAL(iso->size, 12);
|
||||
CU_ASSERT_EQUAL(iso->ino, 0);
|
||||
CU_ASSERT_EQUAL(iso->nlink, 1);
|
||||
CU_ASSERT_EQUAL(iso->sort_weight, 1);
|
||||
CU_ASSERT_EQUAL(iso->real_dev, 15);
|
||||
CU_ASSERT_EQUAL(iso->real_ino, 204);
|
||||
}
|
||||
|
||||
static void test_add_lookup()
|
||||
{
|
||||
struct iso_file_table *table;
|
||||
struct iso_tree_node_file *file1;
|
||||
struct iso_tree_node_file *file2;
|
||||
struct iso_file *iso1;
|
||||
struct iso_file *iso2;
|
||||
struct iso_file *iso3;
|
||||
int r;
|
||||
|
||||
table = iso_file_table_new(1);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL( table );
|
||||
CU_ASSERT_TRUE( table->cache_inodes );
|
||||
CU_ASSERT_EQUAL(table->count, 0);
|
||||
|
||||
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file1->node.name = "fileName";
|
||||
file1->node.attrib.st_dev = 15;
|
||||
file1->node.attrib.st_ino = 204;
|
||||
file1->loc.path = "/tmp/filename";
|
||||
|
||||
iso1 = iso_file_new(file1);
|
||||
|
||||
r = iso_file_table_add_file(table, iso1);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
CU_ASSERT_EQUAL(table->count, 1);
|
||||
|
||||
iso2 = iso_file_table_lookup(table, file1);
|
||||
CU_ASSERT_PTR_NOT_NULL(iso2);
|
||||
CU_ASSERT_PTR_EQUAL(iso2, iso1);
|
||||
|
||||
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file2->node.name = "fileName2";
|
||||
file2->node.attrib.st_dev = 152;
|
||||
file2->node.attrib.st_ino = 2042;
|
||||
file2->loc.path = "/tmp/filename2";
|
||||
|
||||
iso3 = iso_file_new(file2);
|
||||
r = iso_file_table_add_file(table, iso3);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
CU_ASSERT_EQUAL(table->count, 2);
|
||||
|
||||
/* treat to add the same file again */
|
||||
r = iso_file_table_add_file(table, iso3);
|
||||
CU_ASSERT_EQUAL(r, 0);
|
||||
CU_ASSERT_EQUAL(table->count, 2);
|
||||
|
||||
iso2 = iso_file_table_lookup(table, file1);
|
||||
CU_ASSERT_PTR_NOT_NULL(iso2);
|
||||
CU_ASSERT_PTR_EQUAL(iso2, iso1);
|
||||
|
||||
iso2 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_NOT_NULL(iso2);
|
||||
CU_ASSERT_PTR_EQUAL(iso2, iso3);
|
||||
|
||||
iso3 = iso_file_new(file2);
|
||||
r = iso_file_table_add_file(table, iso3);
|
||||
CU_ASSERT_EQUAL(r, 0);
|
||||
CU_ASSERT_EQUAL(table->count, 2);
|
||||
|
||||
iso_file_table_clear(table);
|
||||
CU_ASSERT_EQUAL(table->count, 0);
|
||||
|
||||
iso2 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_NULL(iso2);
|
||||
|
||||
free( file1 );
|
||||
free( file2 );
|
||||
free( table );
|
||||
}
|
||||
|
||||
static void test_cache_inodes()
|
||||
{
|
||||
struct iso_file_table *table;
|
||||
struct iso_tree_node_file *file1;
|
||||
struct iso_tree_node_file *file2;
|
||||
struct iso_file *iso1;
|
||||
struct iso_file *iso2;
|
||||
struct iso_file *iso3;
|
||||
int r;
|
||||
|
||||
table = iso_file_table_new(1);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL( table );
|
||||
CU_ASSERT_TRUE( table->cache_inodes );
|
||||
CU_ASSERT_EQUAL(table->count, 0);
|
||||
|
||||
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file1->node.name = "fileName";
|
||||
file1->node.attrib.st_dev = 15;
|
||||
file1->node.attrib.st_ino = 204;
|
||||
file1->loc.path = "/tmp/filename";
|
||||
|
||||
iso1 = iso_file_new(file1);
|
||||
|
||||
r = iso_file_table_add_file(table, iso1);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
|
||||
/* another file, different but with the same inode id */
|
||||
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file2->node.name = "another file";
|
||||
file2->node.attrib.st_dev = 15;
|
||||
file2->node.attrib.st_ino = 204;
|
||||
file2->loc.path = "/tmp/another";
|
||||
iso2 = iso_file_new(file2);
|
||||
|
||||
/* ensure it's not added again... */
|
||||
r = iso_file_table_add_file(table, iso2);
|
||||
CU_ASSERT_EQUAL(r, 0);
|
||||
|
||||
/* ...and the lookup returns the first */
|
||||
iso3 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_EQUAL(iso1, iso3);
|
||||
|
||||
free(iso2);
|
||||
free(file2);
|
||||
|
||||
/* and now a file with same inode but different device */
|
||||
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file2->node.name = "different file";
|
||||
file2->node.attrib.st_dev = 16; /* different dev id */
|
||||
file2->node.attrib.st_ino = 204;
|
||||
file2->loc.path = "/tmp/different";
|
||||
iso2 = iso_file_new(file2);
|
||||
|
||||
r = iso_file_table_add_file(table, iso2);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
iso3 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_NOT_EQUAL(iso3, iso1);
|
||||
CU_ASSERT_PTR_EQUAL(iso3, iso2);
|
||||
|
||||
iso_file_table_clear(table);
|
||||
free( file1 );
|
||||
free( file2 );
|
||||
free( table );
|
||||
}
|
||||
|
||||
static void test_no_cache_inodes()
|
||||
{
|
||||
struct iso_file_table *table;
|
||||
struct iso_tree_node_file *file1;
|
||||
struct iso_tree_node_file *file2;
|
||||
struct iso_tree_node_file *file3;
|
||||
struct iso_file *iso1;
|
||||
struct iso_file *iso2;
|
||||
struct iso_file *iso3;
|
||||
int r;
|
||||
|
||||
table = iso_file_table_new(0);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL( table );
|
||||
CU_ASSERT_FALSE( table->cache_inodes );
|
||||
CU_ASSERT_EQUAL(table->count, 0);
|
||||
|
||||
file1 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file1->node.name = "fileName";
|
||||
file1->node.attrib.st_dev = 15;
|
||||
file1->node.attrib.st_ino = 204;
|
||||
file1->loc.path = "/tmp/filename";
|
||||
|
||||
iso1 = iso_file_new(file1);
|
||||
|
||||
r = iso_file_table_add_file(table, iso1);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
|
||||
/* another file, different but with the same inode id */
|
||||
file2 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file2->node.name = "another file";
|
||||
file2->node.attrib.st_dev = 15;
|
||||
file2->node.attrib.st_ino = 204;
|
||||
file2->loc.path = "/tmp/another";
|
||||
iso2 = iso_file_new(file2);
|
||||
|
||||
/* ensure is added */
|
||||
r = iso_file_table_add_file(table, iso2);
|
||||
CU_ASSERT_EQUAL(r, 1);
|
||||
|
||||
iso3 = iso_file_table_lookup(table, file2);
|
||||
CU_ASSERT_PTR_EQUAL(iso3, iso2);
|
||||
|
||||
/* and now a file with same inode and path */
|
||||
file3 = calloc(1, sizeof(struct iso_tree_node_file) );
|
||||
file3->node.name = "different file";
|
||||
file3->node.attrib.st_dev = 15;
|
||||
file3->node.attrib.st_ino = 204;
|
||||
file3->loc.path = "/tmp/filename";
|
||||
iso3 = iso_file_new(file3);
|
||||
|
||||
r = iso_file_table_add_file(table, iso3);
|
||||
CU_ASSERT_EQUAL(r, 0);
|
||||
iso3 = iso_file_table_lookup(table, file3);
|
||||
CU_ASSERT_PTR_EQUAL(iso3, iso1);
|
||||
|
||||
iso_file_table_clear(table);
|
||||
free(file1);
|
||||
free(file2);
|
||||
free(file3);
|
||||
free(table);
|
||||
}
|
||||
|
||||
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, "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
57
test/test_read.c
Normal 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);
|
||||
}
|
1051
test/test_tree.c
Normal file
1051
test/test_tree.c
Normal file
File diff suppressed because it is too large
Load Diff
387
test/test_util.c
Normal file
387
test/test_util.c
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Unit test for util.h
|
||||
*
|
||||
* This test utiliy functions
|
||||
*
|
||||
*/
|
||||
#include <time.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "test.h"
|
||||
#include "util.h"
|
||||
|
||||
static void test_div_up()
|
||||
{
|
||||
CU_ASSERT_EQUAL( div_up(1, 2), 1 );
|
||||
CU_ASSERT_EQUAL( div_up(2, 2), 1 );
|
||||
CU_ASSERT_EQUAL( div_up(0, 2), 0 );
|
||||
CU_ASSERT_EQUAL( div_up(-1, 2), 0 );
|
||||
CU_ASSERT_EQUAL( div_up(3, 2), 2 );
|
||||
}
|
||||
|
||||
static void test_round_up()
|
||||
{
|
||||
CU_ASSERT_EQUAL( round_up(1, 2), 2 );
|
||||
CU_ASSERT_EQUAL( round_up(2, 2), 2 );
|
||||
CU_ASSERT_EQUAL( round_up(0, 2), 0 );
|
||||
CU_ASSERT_EQUAL( round_up(-1, 2), 0 );
|
||||
CU_ASSERT_EQUAL( round_up(3, 2), 4 );
|
||||
CU_ASSERT_EQUAL( round_up(15, 7), 21 );
|
||||
CU_ASSERT_EQUAL( round_up(13, 7), 14 );
|
||||
CU_ASSERT_EQUAL( round_up(14, 7), 14 );
|
||||
}
|
||||
|
||||
static void test_iso_lsb_msb()
|
||||
{
|
||||
uint8_t buf[4];
|
||||
uint32_t num;
|
||||
|
||||
num = 0x01020304;
|
||||
iso_lsb(buf, num, 4);
|
||||
CU_ASSERT_EQUAL( buf[0], 0x04 );
|
||||
CU_ASSERT_EQUAL( buf[1], 0x03 );
|
||||
CU_ASSERT_EQUAL( buf[2], 0x02 );
|
||||
CU_ASSERT_EQUAL( buf[3], 0x01 );
|
||||
|
||||
iso_msb(buf, num, 4);
|
||||
CU_ASSERT_EQUAL( buf[0], 0x01 );
|
||||
CU_ASSERT_EQUAL( buf[1], 0x02 );
|
||||
CU_ASSERT_EQUAL( buf[2], 0x03 );
|
||||
CU_ASSERT_EQUAL( buf[3], 0x04 );
|
||||
|
||||
iso_lsb(buf, num, 2);
|
||||
CU_ASSERT_EQUAL( buf[0], 0x04 );
|
||||
CU_ASSERT_EQUAL( buf[1], 0x03 );
|
||||
|
||||
iso_msb(buf, num, 2);
|
||||
CU_ASSERT_EQUAL( buf[0], 0x03 );
|
||||
CU_ASSERT_EQUAL( buf[1], 0x04 );
|
||||
}
|
||||
|
||||
static void test_iso_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" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dIR1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("DIR1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dirwithbigname", "UTF-8"), "DIRWITHB");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dirwith8", "UTF-8"), "DIRWITH8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("dir.1", "UTF-8"), "DIR_1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_dirid("4f<0KmM::xcvf", "UTF-8"), "4F_0KMM_");
|
||||
}
|
||||
|
||||
static void test_iso_2_dirid()
|
||||
{
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dir1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dIR1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("DIR1", "UTF-8"), "DIR1" );
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dirwithbigname", "UTF-8"), "DIRWITHBIGNAME");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dirwith8", "UTF-8"), "DIRWITH8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("dir.1", "UTF-8"), "DIR_1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("4f<0KmM::xcvf", "UTF-8"), "4F_0KMM__XCVF");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("directory with 31 characters ok", "UTF-8"), "DIRECTORY_WITH_31_CHARACTERS_OK");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_dirid("directory with more than 31 characters", "UTF-8"), "DIRECTORY_WITH_MORE_THAN_31_CHA");
|
||||
}
|
||||
|
||||
static void test_iso_r_dirid()
|
||||
{
|
||||
int flag;
|
||||
|
||||
/* 1. only ECMA119_37_CHAR_FILENAMES */
|
||||
flag = ECMA119_37_CHAR_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "DIRWITHBIGNAME");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "DIRWITH8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "DIR_1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4F_0KMM__XCVF");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "DIRECTORY_WITH_31_CHARACTERS_OK");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "DIRECTORY_WITH_MORE_THAN_37_CHARACTER");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "DIRECTORY_WITH_JUST_37_CHARACTERS__OK");
|
||||
|
||||
/* 2. only ECMA119_RELAXED_FILENAMES */
|
||||
flag = ECMA119_RELAXED_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "dir1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "dIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "dirwithbigname");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "dirwith8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "dir.1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4f<0KmM::xcvf");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "directory with 31 characters ok");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "directory with more than 37 cha");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "directory with just 37 characte");
|
||||
|
||||
/* 3. both ECMA119_RELAXED_FILENAMES and ECMA119_37_CHAR_FILENAMES */
|
||||
flag = ECMA119_RELAXED_FILENAMES | ECMA119_37_CHAR_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir1", "UTF-8", flag), "dir1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dIR1", "UTF-8", flag), "dIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("DIR1", "UTF-8", flag), "DIR1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwithbigname", "UTF-8", flag), "dirwithbigname");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dirwith8", "UTF-8", flag), "dirwith8");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("dir.1", "UTF-8", flag), "dir.1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("4f<0KmM::xcvf", "UTF-8", flag), "4f<0KmM::xcvf");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with 31 characters ok", "UTF-8", flag), "directory with 31 characters ok");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with more than 37 characters", "UTF-8", flag), "directory with more than 37 character");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_dirid("directory with just 37 characters ok", "UTF-8", flag), "directory with just 37 characters ok");
|
||||
}
|
||||
|
||||
static void test_iso_1_fileid()
|
||||
{
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fILe1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("FILE1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid(".EXT", "UTF-8"), ".EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ext", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fiLE.ext", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.EXt", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("FILE.EXT", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename", "UTF-8"), "BIGFILEN.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.ext", "UTF-8"), "BIGFILEN.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.e", "UTF-8"), "BIGFILEN.E;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.bigext", "UTF-8"), "FILE.BIG;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid(".bigext", "UTF-8"), ".BIG;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("bigfilename.bigext", "UTF-8"), "BIGFILEN.BIG;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file<:a.ext", "UTF-8"), "FILE__A.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.<:a", "UTF-8"), "FILE.__A;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file<:a.--a", "UTF-8"), "FILE__A.__A;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ex1.ex2", "UTF-8"), "FILE_EX1.EX2;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("file.ex1.ex2.ex3", "UTF-8"), "FILE_EX1.EX3;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_1_fileid("fil.ex1.ex2.ex3", "UTF-8"), "FIL_EX1_.EX3;1");
|
||||
}
|
||||
|
||||
static void test_iso_2_fileid()
|
||||
{
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fILe1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("FILE1", "UTF-8"), "FILE1.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".EXT", "UTF-8"), ".EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ext", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fiLE.ext", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.EXt", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("FILE.EXT", "UTF-8"), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename", "UTF-8"), "BIGFILENAME.;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.ext", "UTF-8"), "BIGFILENAME.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.e", "UTF-8"), "BIGFILENAME.E;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("31 characters filename.extensio", "UTF-8"), "31_CHARACTERS_FILENAME.EXTENSIO;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("32 characters filename.extension", "UTF-8"), "32_CHARACTERS_FILENAME.EXTENSIO;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("more than 30 characters filename.extension", "UTF-8"), "MORE_THAN_30_CHARACTERS_FIL.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.bigext", "UTF-8"), "FILE.BIGEXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".bigext", "UTF-8"), ".BIGEXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("bigfilename.bigext", "UTF-8"), "BIGFILENAME.BIGEXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file<:a.ext", "UTF-8"), "FILE__A.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.<:a", "UTF-8"), "FILE.__A;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file<:a.--a", "UTF-8"), "FILE__A.__A;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ex1.ex2", "UTF-8"), "FILE_EX1.EX2;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("file.ex1.ex2.ex3", "UTF-8"), "FILE_EX1_EX2.EX3;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid("fil.ex1.ex2.ex3", "UTF-8"), "FIL_EX1_EX2.EX3;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_2_fileid(".file.bigext", "UTF-8"), "_FILE.BIGEXT;1");
|
||||
}
|
||||
|
||||
static void test_iso_r_fileid()
|
||||
{
|
||||
int flag;
|
||||
|
||||
/* 1. only ECMA119_OMIT_VERSION_NUMBERS */
|
||||
flag = ECMA119_OMIT_VERSION_NUMBERS;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31_CHARACTERS_FILENAME.EXTENSIO");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "IT_S_37_CHARACTERS_FILENAME.EXT");
|
||||
|
||||
/* 2. only ECMA119_37_CHAR_FILENAMES */
|
||||
flag = ECMA119_37_CHAR_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "BIGFILENAME.");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "BIGFILENAME.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "BIGFILENAME.E");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "FILE.BIGEXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31_CHARACTERS_FILENAME.EXTENSIO");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "IT_S_37_CHARACTERS_FILENAME.EXTENSION");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("more than 37 characters filename.extension", "UTF-8", flag), "MORE_THAN_37_CHARACTERS_FILENAME.EXTE");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "FILE.THIS_IS_A_37_CHARS_LEN_EXTENSION");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a very very big extension", "UTF-8", flag), "FILE.THIS_IS_A_VERY_VERY_BIG_EXTENSIO");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "FIL_EX1_EX2.EX3");
|
||||
|
||||
/* 3. only ECMA119_RELAXED_FILENAMES */
|
||||
flag = ECMA119_RELAXED_FILENAMES;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "file1;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "fILe1;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "file.ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "fiLE.ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "file.EXt;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "bigfilename;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "bigfilename.ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "bigfilename.e;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "file.bigext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31 characters filename.extensio;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "it's 37 characters filename.ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "file.this is a 37 chars len ext;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "fil.ex1.ex2.ex3;1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.<:a", "UTF-8", flag), "file.<:a;1");
|
||||
|
||||
/* 3. ECMA119_RELAXED_FILENAMES and ECMA119_OMIT_VERSION_NUMBERS*/
|
||||
flag = ECMA119_RELAXED_FILENAMES | ECMA119_OMIT_VERSION_NUMBERS;
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file1", "UTF-8", flag), "file1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fILe1", "UTF-8", flag), "fILe1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE1", "UTF-8", flag), "FILE1");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid(".EXT", "UTF-8", flag), ".EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.ext", "UTF-8", flag), "file.ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fiLE.ext", "UTF-8", flag), "fiLE.ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.EXt", "UTF-8", flag), "file.EXt");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("FILE.EXT", "UTF-8", flag), "FILE.EXT");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename", "UTF-8", flag), "bigfilename");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.ext", "UTF-8", flag), "bigfilename.ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("bigfilename.e", "UTF-8", flag), "bigfilename.e");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.bigext", "UTF-8", flag), "file.bigext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("31 characters filename.extensio", "UTF-8", flag), "31 characters filename.extensio");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("it's 37 characters filename.extension", "UTF-8", flag), "it's 37 characters filename.ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.this is a 37 chars len extension", "UTF-8", flag), "file.this is a 37 chars len ext");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("fil.ex1.ex2.ex3", "UTF-8", flag), "fil.ex1.ex2.ex3");
|
||||
CU_ASSERT_STRING_EQUAL( iso_r_fileid("file.<:a", "UTF-8", flag), "file.<:a");
|
||||
}
|
||||
|
||||
void add_util_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("UtilSuite", NULL, NULL);
|
||||
|
||||
CU_add_test(pSuite, "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);
|
||||
}
|
375
test/test_volume.c
Normal file
375
test/test_volume.c
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* Unit test for volume.h
|
||||
*/
|
||||
|
||||
|
||||
#include "libisofs.h"
|
||||
#include "tree.h"
|
||||
#include "test.h"
|
||||
#include "volume.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static void test_iso_volume_new()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NOT_NULL(volume);
|
||||
CU_ASSERT_EQUAL(volume->refcount, 1);
|
||||
/* a new root must be created */
|
||||
CU_ASSERT_PTR_NOT_NULL(volume->root);
|
||||
|
||||
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
|
||||
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
|
||||
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
|
||||
|
||||
CU_ASSERT_PTR_NULL(volume->system_id);
|
||||
CU_ASSERT_PTR_NULL(volume->application_id);
|
||||
CU_ASSERT_PTR_NULL(volume->copyright_file_id);
|
||||
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
|
||||
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
|
||||
|
||||
CU_ASSERT_PTR_NULL(volume->bootcat);
|
||||
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_new_with_root()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
struct iso_tree_node_dir *root;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
volume = iso_volume_new_with_root("volume_id", "publisher_id",
|
||||
"data_preparer_id", root);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(volume);
|
||||
CU_ASSERT_EQUAL(volume->refcount, 1);
|
||||
CU_ASSERT_PTR_NOT_NULL(volume->root);
|
||||
CU_ASSERT_PTR_EQUAL(volume->root, root);
|
||||
|
||||
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
|
||||
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
|
||||
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
|
||||
|
||||
CU_ASSERT_PTR_NULL(volume->system_id);
|
||||
CU_ASSERT_PTR_NULL(volume->application_id);
|
||||
CU_ASSERT_PTR_NULL(volume->copyright_file_id);
|
||||
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
|
||||
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
|
||||
|
||||
CU_ASSERT_PTR_NULL(volume->bootcat);
|
||||
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_get_root()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
struct iso_tree_node_dir *root;
|
||||
struct iso_tree_node_dir *root2;
|
||||
|
||||
root = iso_tree_new_root();
|
||||
volume = iso_volume_new_with_root("volume_id", "publisher_id",
|
||||
"data_preparer_id", root);
|
||||
|
||||
root2 = iso_volume_get_root(volume);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(root2);
|
||||
CU_ASSERT_PTR_EQUAL(root2, volume->root);
|
||||
CU_ASSERT_PTR_EQUAL(root2, root);
|
||||
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_set_volume_id()
|
||||
{
|
||||
struct iso_volume *volume;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_STRING_EQUAL( volume->volume_id, "volume_id" );
|
||||
|
||||
char *volid = "new volume id";
|
||||
iso_volume_set_volume_id(volume, volid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->volume_id, "new volume id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->volume_id, volid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_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;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "publisher_id" );
|
||||
|
||||
char *pubid = "new publisher id";
|
||||
iso_volume_set_publisher_id(volume, pubid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->publisher_id, "new publisher id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->publisher_id, pubid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_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;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "data_preparer_id" );
|
||||
|
||||
char *dpid = "new data preparer id";
|
||||
iso_volume_set_data_preparer_id(volume, dpid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->data_preparer_id, "new data preparer id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->data_preparer_id, dpid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_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;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NULL(volume->system_id);
|
||||
|
||||
char *sysid = "new system id";
|
||||
iso_volume_set_system_id(volume, sysid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->system_id, "new system id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->system_id, sysid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_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;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NULL(volume->application_id);
|
||||
|
||||
char *appid = "new application id";
|
||||
iso_volume_set_application_id(volume, appid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->application_id, "new application id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->application_id, appid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_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;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NULL(volume->abstract_file_id);
|
||||
|
||||
char *absid = "new abstract id";
|
||||
iso_volume_set_abstract_file_id(volume, absid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->abstract_file_id, "new abstract id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->abstract_file_id, absid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_volume_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;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
CU_ASSERT_PTR_NULL(volume->biblio_file_id);
|
||||
|
||||
char *bibid = "new biblio id";
|
||||
iso_volume_set_biblio_file_id(volume, bibid);
|
||||
CU_ASSERT_STRING_EQUAL( volume->biblio_file_id, "new biblio id" );
|
||||
|
||||
/* check string was strdup'ed */
|
||||
CU_ASSERT_PTR_NOT_EQUAL( volume->biblio_file_id, bibid );
|
||||
iso_volume_free(volume);
|
||||
}
|
||||
|
||||
static void test_iso_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;
|
||||
struct iso_volset *volset;
|
||||
|
||||
volume = iso_volume_new("volume_id", "publisher_id", "data_preparer_id");
|
||||
|
||||
volset = iso_volset_new(volume, "volset_id");
|
||||
CU_ASSERT_PTR_NOT_NULL(volset);
|
||||
CU_ASSERT_EQUAL(volset->refcount, 1);
|
||||
CU_ASSERT_EQUAL(volset->volset_size, 1);
|
||||
CU_ASSERT_PTR_NOT_NULL(volset->volume);
|
||||
CU_ASSERT_PTR_NOT_NULL(volset->volume[0]);
|
||||
CU_ASSERT_PTR_EQUAL(volset->volume[0], volume);
|
||||
CU_ASSERT_STRING_EQUAL( volset->volset_id, "volset_id" );
|
||||
|
||||
iso_volset_free(volset);
|
||||
}
|
||||
|
||||
void add_volume_suite()
|
||||
{
|
||||
CU_pSuite pSuite = CU_add_suite("VolumeSuite", NULL, NULL);
|
||||
|
||||
CU_add_test(pSuite, "test of iso_volume_new()", test_iso_volume_new);
|
||||
CU_add_test(pSuite, "test of iso_volume_new_with_root()", test_iso_volume_new_with_root);
|
||||
CU_add_test(pSuite, "test of iso_volume_get_root()", test_iso_volume_get_root);
|
||||
CU_add_test(pSuite, "test of iso_volume_set_volume_id()", test_iso_volume_set_volume_id);
|
||||
CU_add_test(pSuite, "test of iso_volume_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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user