Compare commits

...

78 Commits

Author SHA1 Message Date
Thomas Schmitt c6136416c3 Marked libisofs SVN copy as outdated (use bzr on lp) 2010-02-08 11:10:47 +00:00
Mario Danic de3cf8e385 Moved libisofs trunk to attic, due to libisofs-ng 2008-02-02 18:56:45 +00:00
Vreixo Formoso Lopes 3028015ab8 Add setter and getters for atime and ctime on tree_node. 2007-10-22 09:30:43 +00:00
Vreixo Formoso Lopes 7b9834a315 Added getter and setter for mtime on tree_node. 2007-10-22 08:44:33 +00:00
Vreixo Formoso Lopes 63f2cfd673 Add get_size() method to tree_node. 2007-10-22 08:39:22 +00:00
Vreixo Formoso Lopes 2b92fbc31a Guard against a message retrieval before library initialization. 2007-10-19 07:36:14 +00:00
Vreixo Formoso Lopes b9c4f7ad1d Added iso_volset_ref(). 2007-10-18 07:32:37 +00:00
Vreixo Formoso Lopes 485607ce7b Fix bug in mangle_all. 2007-10-08 16:07:10 +00:00
Vreixo Formoso Lopes 08c53aa997 Return 0 on EOF in burn_source. 2007-10-08 07:57:23 +00:00
Vreixo Formoso Lopes 0224ad402d Some fixes in burn_source implementation 2007-10-03 16:32:09 +00:00
Vreixo Formoso Lopes 6546f1a197 Change burn_source implementation to fit libburn requirements. 2007-10-02 16:47:19 +00:00
Vreixo Formoso Lopes f4ad1c630b Add a set_size function to burn_source to fix sigsegv. 2007-10-02 07:16:50 +00:00
Thomas Schmitt b1966abe45 Removed apostrophes which my compiler does not like 2007-09-28 16:04:09 +00:00
Vreixo Formoso Lopes f5e31470bd Some new taks added to TODO file 2007-09-26 11:44:48 +00:00
Vreixo Formoso Lopes f811234b8f Migration to iso_file_src in file writing function. 2007-09-26 07:47:45 +00:00
Vreixo Formoso Lopes 8de9d35873 Add iso_file_src default implementation.
This will be the base class for file content writting, with support for 
on-the-file file modification, useful for things like compression or 
encryption.
2007-09-25 10:17:29 +00:00
Vreixo Formoso Lopes ead523ff27 update makefile to propertly deal with new file names. 2007-09-24 11:54:43 +00:00
Vreixo Formoso Lopes 0071d733fd Rename libdax_* message system to libiso_* 2007-09-24 11:53:22 +00:00
Mario Danic 9639d45b35 Updated doxygen.conf.in 2007-09-14 09:02:21 +00:00
Mario Danic 370fac83c1 Added licence reminder to TODO 2007-09-14 04:30:12 +00:00
Mario Danic d41a020cea Minor cleanup of authors file 2007-09-14 04:28:06 +00:00
Mario Danic 33ad67ee2c Added general tasks to TODO 2007-09-14 04:25:46 +00:00
Mario Danic 2629a25d4e Made minor changes to libisofs iso.c 2007-09-14 04:03:42 +00:00
Vreixo Formoso Lopes 5c82fc5108 Add -V option to test/iso.c little testing app. 2007-09-06 15:15:09 +00:00
Mario Danic d60193e2d5 Implemented support for eltorito on MS discs 2007-09-01 20:35:53 +00:00
Mario Danic 0746d622e4 Provide better support for overwriteable media 2007-08-30 21:55:36 +00:00
Mario Danic 139fb6496c Finally commited the patch :P 2007-08-28 10:29:55 +00:00
Mario Danic df04ee014e Done major changes to libisofs, including multisession and reading support 2007-08-27 22:51:48 +00:00
Mario Danic a4e0041128 Done some changes to configure.ac 2007-08-10 20:37:25 +00:00
Mario Danic a28e699d9b Fixed build system of libburn and libisofs in respect to .pc files 2007-08-10 11:41:18 +00:00
Mario Danic 4354e9598d Temporary usage of libburn readme 2007-08-10 09:55:17 +00:00
Mario Danic 0fece11399 Corrected pc-in file according to our sonumber 2007-08-10 09:45:55 +00:00
Mario Danic 170dfe21bf Added tests as part of MS patch 2007-08-10 09:37:39 +00:00
Mario Danic 3ea44305b4 Removed bindings, removed svn:executable properties 2007-08-10 09:37:16 +00:00
Mario Danic 1b7fec7751 Added files - part of MS patch 2007-08-10 09:36:34 +00:00
Mario Danic 0b1a9c5565 Implemented numeber of multisession options, reading, modifying tree, and a number of improvements 2007-08-10 09:35:10 +00:00
Mario Danic 2e073c258c Fixed relaxed constraints patch 2007-08-10 09:30:26 +00:00
Mario Danic b7573134cb Fixed broken SUSP handling 2007-08-02 19:10:08 +00:00
Mario Danic 9d08c115fd Improved docs, and created 0.3.8 branch 2007-07-31 07:32:26 +00:00
Mario Danic 3fd2309025 Commited unit tests 2007-07-12 14:25:29 +00:00
Mario Danic 6da923c16e Started documenting libisofs, implemented more unit tests 2007-07-12 14:24:46 +00:00
Mario Danic acf402c75d Implemented advanced unit tests and trivial fixes 2007-06-25 05:42:29 +00:00
Mario Danic 14605541c9 Implemented relaxed iso constraints & Cunit based unit-tests 2007-06-21 11:19:11 +00:00
Mario Danic 7faf1635a0 Implemented basic eltorito 2007-06-05 22:01:26 +00:00
Mario Danic 9746b5b273 Fixed obsolete lines, free joliet tree, added public functions 2007-06-02 08:24:58 +00:00
Mario Danic 44b504640f Implemented basic unit tests 2007-06-01 12:57:09 +00:00
Mario Danic 89f291f412 Implemented simple unit tests 2007-06-01 07:08:16 +00:00
Mario Danic 8390f85e1f Added Vreixo to contributors 2007-06-01 07:03:11 +00:00
Mario Danic 22c02b9b2f Commited second part of major changes 2007-06-01 07:02:15 +00:00
Mario Danic 3e29f914fd Changed tree, re-implemented and fixed a lot of problematic areas 2007-05-31 04:25:39 +00:00
Mario Danic 0281fcb717 Implemented ECMA constraints on PVD 2007-05-15 10:35:42 +00:00
Mario Danic a97e96c604 Implemented complete iso PVM and workaround charset problems 2007-05-12 00:30:04 +00:00
Dave d54045fb42 Add the basics for a high level IsoFS class. I have no proof that it currently
works correctly.
2007-04-13 20:45:03 +00:00
Dave 802476a0c6 Fix a typo in the libisofs printing function. 2007-04-13 20:38:38 +00:00
Dave 0ae442220a Add the beginnings of a high level API to isofs. Currently only does
initialization and getting/setting volume attributes.
2007-04-13 04:56:31 +00:00
Dave 24730f52d1 Manually unbreak the core binding. The pyglet code generator generates
one structure def per function call, which means the structs can't be 
passed between functions (!!). It's fixed manually for now, but the 
pyglet generator should be fixed.
2007-04-13 04:53:45 +00:00
Dave 7ea76d34d7 Initial structure and core internal module for the libisofs python
bindings.
2007-04-13 03:00:51 +00:00
Dave bbd286f7e1 Implement the three setters declared in the public API but lacking an
implementation. The python bindings generated code complains about them 
being missing, and they seemed simple enough to write.
2007-04-13 02:59:16 +00:00
Mario Danic 5a64e11df5 Added Suriyan as contributor 2007-04-06 02:17:31 +00:00
Mario Danic ef56dc8f4f Implemented potential fix to obey ECMA 2007-03-20 09:41:52 +00:00
Mario Danic b46f805756 Reverted to r720 - for real 2007-03-20 09:41:05 +00:00
Alexander Nedotsukov 71270599b8 - Fixed reference counting in iso_volset_new().
- Plugged memory leak in iso_volset_free().
2007-01-25 15:46:45 +00:00
Mario Danic e8c4da784f Changed micro version to affect 0.2.4 2007-01-03 19:17:44 +00:00
Mario Danic fe66983e82 Deleted obsolete Makefile.am 2007-01-03 16:06:39 +00:00
Mario Danic 3da1c7682a Fixed broken libisofs-1.pc.iin 2007-01-03 16:01:14 +00:00
Mario Danic fbaee3aab8 Patched libisofs tree to respect autoreconf 2006-12-10 17:12:14 +00:00
Mario Danic e28999196a Modified libisofs authors 2006-12-04 23:18:39 +00:00
Mario Danic 530f34c9a6 Fixed build system autoconf-related bug 2006-12-04 22:01:21 +00:00
Mario Danic 2d46772be3 Clarified libisofs docs 2006-12-04 19:34:57 +00:00
Mario Danic fda4857184 Synced readme file 2006-12-03 19:54:49 +00:00
Mario Danic b5b3c3704b Rendered iso.c more friendly 2006-12-03 11:14:07 +00:00
Mario Danic 30aa4f6d4c Removed binary file/s 2006-12-03 11:12:00 +00:00
Mario Danic 2d667f1d00 Fixed broken libisofs build system 2006-12-02 17:11:45 +00:00
Mario Danic 4ebd10179b Adapted svn version of libisofs 2006-11-14 01:25:39 +00:00
Mario Danic b860f2599f Adapted libisofs build system to separate tree 2006-11-14 01:24:10 +00:00
Mario Danic 3a05fb4e87 Started cleaning libisofs tree 2006-11-14 00:58:21 +00:00
Mario Danic 58bb4389b3 Introduced libisofs as separated development unit 2006-11-13 00:15:17 +00:00
Mario Danic 8927e3df9f Started logical separation of libisofs and libburn 2006-11-13 00:13:21 +00:00
143 changed files with 12049 additions and 25532 deletions

View File

@ -1,5 +1,2 @@
Developers:
Mario Danic
Thomas Schmitt
Lorenzo Taylor

View File

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

13
ChangeLog Normal file
View File

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

234
INSTALL Normal file
View File

@ -0,0 +1,234 @@
Installation Instructions
*************************
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
2006 Free Software Foundation, Inc.
This file is free documentation; the Free Software Foundation gives
unlimited permission to copy, distribute and modify it.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package.
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that the
`configure' script does not know about. Run `./configure --help' for
details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX'.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Optional Features
=================
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Specifying the System Type
==========================
There may be some features `configure' cannot figure out automatically,
but needs to determine by the type of machine the package will run on.
Usually, assuming the package is built to be run on the _same_
architectures, `configure' can figure that out, but if it prints a
message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share, you
can create a site shell script called `config.site' that gives default
values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it operates.
`--help'
`-h'
Print a summary of the options to `configure', and exit.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

@ -1,68 +1,11 @@
pkgconfigdir=$(libdir)/pkgconfig
libincludedir=$(includedir)/libburn
libincludedir=$(includedir)/libisofs
lib_LTLIBRARIES = libburn/libburn.la libisofs/libisofs.la
lib_LTLIBRARIES = libisofs/libisofs.la
## ========================================================================= ##
# Build libraries
libburn_libburn_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
libburn_libburn_la_LIBADD = $(LIBBURN_ARCH_LIBS) $(THREAD_LIBS)
libburn_libburn_la_SOURCES = \
libburn/async.c \
libburn/async.h \
libburn/back_hacks.h \
libburn/cleanup.c \
libburn/cleanup.h \
libburn/crc.c \
libburn/crc.h \
libburn/debug.c \
libburn/debug.h \
libburn/drive.c \
libburn/drive.h \
libburn/error.h \
libburn/file.c \
libburn/file.h \
libburn/init.c \
libburn/init.h \
libburn/lec.c \
libburn/lec.h \
libburn/libburn.h \
libburn/libdax_audioxtr.h \
libburn/libdax_audioxtr.c \
libburn/libdax_msgs.h \
libburn/libdax_msgs.c \
libburn/mmc.c \
libburn/mmc.h \
libburn/null.c \
libburn/null.h \
libburn/options.c \
libburn/options.h \
libburn/read.c \
libburn/read.h \
libburn/sbc.c \
libburn/sbc.h \
libburn/sector.c \
libburn/sector.h \
libburn/sg.c \
libburn/sg.h \
libburn/source.h \
libburn/source.c \
libburn/spc.c \
libburn/spc.h \
libburn/structure.c \
libburn/structure.h \
libburn/toc.c \
libburn/toc.h \
libburn/transport.h \
libburn/util.c \
libburn/util.h \
libburn/write.c \
libburn/write.h \
version.h
## libburn/sg-@ARCH@.c \
libisofs_libisofs_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
@ -86,60 +29,75 @@ 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 = \
libburn/libburn.h \
libisofs/libisofs.h
## ========================================================================= ##
## Build test applications
noinst_PROGRAMS = \
test/libburner \
test/dewav \
test/fake_au \
test/iso \
test/poll \
test/toc \
test/structest
test/isoread \
test/isoms \
test/isoadd \
test/isogrow
bin_PROGRAMS = \
cdrskin/cdrskin
test_libburner_CPPFLAGS = -Ilibburn
test_libburner_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
test_libburner_SOURCES = test/libburner.c
test_dewav_CPPFLAGS = -Ilibburn
test_dewav_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
test_dewav_SOURCES = test/dewav.c
test_fake_au_CPPFLAGS =
test_fake_au_LDADD =
test_fake_au_SOURCES = test/fake_au.c
test_poll_CPPFLAGS = -Ilibburn
test_poll_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
test_poll_SOURCES = test/poll.c
test_toc_CPPFLAGS = -Ilibburn
test_toc_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
test_toc_SOURCES = test/toc.c
test_structest_CPPFLAGS = -Ilibburn
test_structest_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
test_structest_SOURCES = test/structest.c
test_iso_CPPFLAGS = -Ilibisofs
test_iso_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS)
test_iso_SOURCES = test/iso.c
## cdrskin construction site - ts A60816
cdrskin_cdrskin_CPPFLAGS = -Ilibburn
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_2_3
cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cdrskin_timestamp.h
## cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cleanup.c cdrskin/cleanup.h cdrskin/cdrskin_timestamp.h
##
## Open questions: how to compute $timestamp and express -DX="$timestamp"
##
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
## ========================================================================= ##
@ -175,11 +133,6 @@ uninstall-local:
# Indent source files
indent_files = \
$(libisofs_libisofs_la_SOURCES) \
$(libburn_libburn_la_SOURCES) \
$(test_libburner_SOURCES) \
$(test_poll_SOURCES) \
$(test_toc_SOURCES) \
$(test_structest_SOURCES) \
$(test_iso_SOURCES)
@ -196,12 +149,10 @@ indent: $(indent_files)
# Extra things
nodist_pkgconfig_DATA = \
libburn-1.pc \
libisofs-1.pc
libisofs-5.pc
EXTRA_DIST = \
libburn-1.pc.in \
libisofs-1.pc.in \
libisofs-5.pc.in \
version.h.in \
doc/comments \
doc/doxygen.conf.in \
@ -209,15 +160,8 @@ EXTRA_DIST = \
AUTHORS \
CONTRIBUTORS \
COPYRIGHT \
cdrskin/README \
cdrskin/cdrecord_spy.sh \
cdrskin/compile_cdrskin.sh \
cdrskin/changelog.txt \
cdrskin/cdrskin_eng.html \
cdrskin/wiki_plain.txt \
cdrskin/cleanup.h \
cdrskin/cleanup.c \
libburn/sg-freebsd.c \
libburn/sg-linux.c \
COPYING
COPYING \
NEWS \
INSTALL \
ChangeLog

1
NEWS Normal file
View File

@ -0,0 +1 @@
nothing here now

111
README
View File

@ -1,25 +1,25 @@
------------------------------------------------------------------------------
libburn.pykix.org
libburnia-project.org
------------------------------------------------------------------------------
This all is under GPL.
(See GPL reference, our clarification and commitment at the end of this text)
------------------------------------------------------------------------------
libburn.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 libburn.pykix.org-copyright
holders and then libburn.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 libburn.pykix.org toplevel README (C) 2006 Thomas Schmitt
This libburnia-project.org toplevel README (C) 2006-2007 Thomas Schmitt
------------------------------------------------------------------------------
Build and Installation
@ -27,43 +27,51 @@ This libburn.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://libburn-svn.pykix.org/trunk 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 libburn.pykix.org and its subprojects 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
make install
The other half of the project, libisofs, is hosted in the libburnia SVN, too:
svn co http://svn.libburnia-project.org/libisofs/trunk libisofs
See README file there.
------------------------------------------------------------------------------
Overview of libburn.pykix.org
libburn.pykix.org is an open-source library for reading, mastering and writing
optical discs. For now this means only CD-R and CD-RW.
Overview of libburnia-project.org
libburnia-project.org is an open-source software project for reading, mastering
and writing optical discs.
For now this means only CD media and all single layer DVD media except DVD+R.
The project comprises of several more or less interdependent parts which
together strive to be a usable foundation for application development.
These are libraries, language bindings, and middleware binaries which emulate
classical (and valuable) Linux tools.
Our scope is currently Linux 2.4 and 2.6 and we will have a hard time to widen
this for now, because of our history. The project could need advise from or
membership of skilled kernel people and people who know how to talk CD/DVD
drives into doing things.
Our scope is currently Linux 2.4 and 2.6 only. For ports to other systems
we would need : login on a development machine resp. a live OS on CD or DVD,
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
volunteers for testing of realistic use cases.
We do have a workable code base for burning data CDs, though. The burn API is
quite comprehensively documented and can be used to build a presentable
application.
We do have a functional binary which emulates parts of cdrecord in order to
prove that usability, and in order to allow you to explore libburn's scope
We have a workable code base for burning CD and most single layer DVD.
The burn API is quite comprehensively documented and can be used to build a
presentable application.
We have a functional binary which emulates parts of cdrecord in order to
prove that usability, and in order to allow you to explore libburnia's scope
by help of existing cdrecord frontends.
The project components (list subject to growth, hopefully):
@ -71,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
@ -114,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.
@ -158,13 +171,45 @@ Project history as far as known to me:
This version of cdrskin is much more cdrecord compatible in repect
to drive addressing and audio features.
- 30th October 2006 release of cdrskin-0.2.4 .
- 13th November 2006 splitting releases of libburn+cdrskin from libisofs.
- 24th November 2006 release of libburn-0.2.6 and cdrskin-0.2.6 . cdrskin has
become suitable for unaware frontends as long as they perform only the core
of cdrecord use cases (including open-ended input streams, audio, and
multi-session).
- 28th November 2006 the umbrella project which encloses both, libisofs and
libburn, is now called libburnia. For the origin of this name, see
http://en.wikipedia.org/wiki/Liburnians .
- 16th January 2007 release of libburn-0.3.0 and cdrskin-0.3.0 . Now the scope
is widened to a first class of DVD media: overwriteable single layer types
DVD-RAM, DVD+RW, DVD-RW. This is not a cdrecord emulation but rather inspired
by dvd+rw-tools' "poor man" writing facility for this class of media.
Taking a bow towards Andy Polyakov.
- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
multi-session and with DAO.
- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
yet.
- 23th April 2007 version 0.3.6 follows the unanimous opinion of Linux kernel
people that one should not use /dev/sg on kernel 2.6.
- 31st July 2007 version 0.3.8 marks the first anniversary of libburn revival.
We look back on improved stability, a substantially extended list of media
and write modes, and better protection against typical user mishaps.
------------------------------------------------------------------------------
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
@ -177,9 +222,9 @@ Project history as far as known to me:
------------------------------------------------------------------------------
Clarification in my name and in the name of Mario Danic, upcoming copyright
holders on toplevel of libburn. To be fully in effect after the remaining other
copyrighted code has been replaced by ours and by copyright-free contributions
of our friends:
holders on toplevel of libburnia. To be fully in effect after the remaining
other copyrighted code has been replaced by ours and by copyright-free
contributions of our friends:
------------------------------------------------------------------------------
We, the copyright holders, agree on the interpretation that

64
TODO Normal file
View 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

View File

@ -1,433 +0,0 @@
------------------------------------------------------------------------------
libburn.pykix.org scdbackup.sourceforge.net/cdrskin_eng.html
------------------------------------------------------------------------------
Installation instructions at about line 60. First the legal stuff:
------------------------------------------------------------------------------
This all is under GPL.
(See GPL reference, our clarification and commitment at the end of this text)
------------------------------------------------------------------------------
Based on and sub project of:
libburn.pykix.org
By Mario Danic <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
Copyright (C) 2006 Mario Danic, Thomas Schmitt
libburn.pykix.org is inspired by and in other components 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
See toplevel README for an overview of the current copyright situation in
libburn.pykix.org.
------------------------------------------------------------------------------
My thanks to the above authors (except myself, of course) for making the
following possible.
cdrskin. By Thomas Schmitt <scdbackup@gmx.net>
Integrated sub project of libburn.pykix.org but also published via:
http://scdbackup.sourceforge.net/cdrskin_eng.html
http://scdbackup.sourceforge.net/cdrskin-0.2.5.tar.gz
Copyright (C) 2006 Thomas Schmitt
------------------------------------------------------------------------------
On top of libburn there is implemented cdrskin 0.2.5, a limited cdrecord
compatibility wrapper which allows to use some libburn features from
the command line.
Interested users of cdrecord are invited to participate in the development
of cdrskin. Contact: scdbackup@gmx.net or libburn-hackers@pykix.org .
We will keep copyright narrow but will of course acknowledge valuable
contributions in a due way.
Important :
This software is provided as is. There is no warranty implied and no
protection against possible damages. You use this on your own risk.
Don't blame me or other authors of libburn if anything goes wrong.
I used it on my own risk with :
SuSE 7.2, kernel 2.4.4, ide-scsi emulation, LITE-ON LTR48125S CD burner, 2002
SuSE 9.0, kernel 2.4.21, ide-scsi emulation, LG GSA-4082B CD/DVD burner, 2004
NEC ND-4570A CD/DVD burner, 2006
RIP-14.4, kernel 2.6.14, no ide-scsi, with all above burners
It fails to compile or run on SuSE 6.4 (kernel 2.2.14).
It does not find the IDE CD burner on SuSE 7.2 without ide-scsi.
Other people sucessfully tested cdrskin on several kernel 2.6 based x86 Linux
systems, including 64 bit systems. (Further reports are welcome.)
Compilation, First Glimpse, Installation
Obtain cdrskin-0.2.5.tar.gz , take it to a directory of your choice and do:
tar xzf cdrskin-0.2.5.tar.gz
cd cdrskin-0.2.5
Or obtain a libburn.pykix.org SVN snapshot,
go into the toplevel directory of the snapshot (e.g. cd libburn_pykix ),
and execute the autotools script ./bootstrap . Use autools version >= 1.7 .
Within that toplevel directory of either cdrskin-0.2.5 or libburn then execute:
./configure
make
(Note: there are next-level directories "libburn" and "cdrskin". Those
would be the wrong ones. Meant is the highest directory of tarball resp.
SVN download. Among others containing files "AUTHORS", "configure",
"Makefile.am", as well as directories "libburn" and "cdrskin".)
This will already produce a cdrskin binary. But it might be necessary to
install libburn in order to use this binary. Installation of libburn is
beyond the scope of cdrskin. For this, see included libburn docs.
In order to surely get a standalone binary, execute
cdrskin/compile_cdrskin.sh
Version identification and help texts available afterwards:
cdrskin/cdrskin -version
cdrskin/cdrskin --help
cdrskin/cdrskin -help
Install (eventually as superuser) cdrskin to a directory where it can be found:
If cdrskin was already installed by a previous version, or by "make install"
in the course of this installation, then find out where:
which cdrskin
Copy your standalone binary to exactly the address which you get as reply
cp cdrskin/cdrskin /usr/bin/cdrskin
Check the version timestamps of the globally installed binary
cdrskin -version
It is not necessary for the standalone cdrskin binary to have libburn
installed, since it incorporates the necessary libburn parts at compile time.
It will not collide with an installed version of libburn either.
But libpthread must be installed on the system and glibc has to match. (See
below for a way to create a statically linked binary.)
Usage
The user of cdrskin needs rw-permission for the CD burner device.
A list of rw-accessible drives can be obtained by
cdrskin --devices
CD devices which offer no rw-permission are invisible to normal users.
The superuser should be able to see any usable drive and then set the
permissions as needed. If this hangs then there is a drive with
unexpected problems (locked, busy, broken, whatever). You might have to
guess the address of your (non-broken) burner by other means, then.
On Linux 2.4 this would be some /dev/sgN and on 2.6. some /dev/hdX.
The output of cdrskin --devices might look like
0 dev='/dev/sg0' rwrwr- : '_NEC' 'DVD_RW ND-4570A'
1 dev='/dev/sg1' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
So full and insecure enabling of both for everybody would look like
chmod a+rw /dev/sg0 /dev/sg1
I strongly discourage to run cdrskin with setuid root or via sudo !
It is not checked for the necessary degree of hacker safety.
Usage examples
Get an overview of cdrecord style addresses of available devices
cdrskin -scanbus
cdrskin dev=ATA -scanbus
Note: Adresses reported with dev=ATA are to be used with prefix "ATA:". You may
well use device file addresses as reported with --devices. Examples:
dev=0,1,0 dev=/dev/sg1 dev=ATA:1,0,0 dev=/dev/hdc
See also "Drive Addressing".
Note: Address numbers have changed since cdrskin-0.2.2 in order to become
compatible with cdrecord numbers. To get the old number scheme, use
option --old_pseudo_scsi_adr . See also "Pseudo-SCSI Adresses".
Sorry for any inconvenience.
Obtain some info about the drive
cdrskin dev=0,1,0 -checkdrive
Obtain some info about the drive and the inserted media
cdrskin dev=0,1,0 -atip
Thoroughly blank a CD-RW
cdrskin -v dev=0,1,0 blank=all -eject
Blank CD-RW sufficiently for making it ready for overwrite
cdrskin -v dev=0,1,0 blank=fast -eject
Burn image file my_image.iso to CD
cdrskin -v dev=0,1,0 speed=12 fs=8m -sao driveropts=burnfree padsize=300k \
-eject my_image.iso
Burn a compressed afio archive to CD on-the-fly
find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 -tao \
driveropts=burnfree padsize=300k -
Burn 6 audio tracks from files with different formats to CD.
Anything except .wav or .au files has to be converted into raw format first.
See below "Audio CD" for specifications.
ogg123 -d raw -f track01.cd /path/to/track1.ogg
oggdec -R -o track02.cd /path/to/track2.ogg
lame --decode -t /path/to/track3.mp3 track03.cd
madplay -o raw:track04.cd /path/to/track4.mp3
mppdec --raw-le /path/to/track5.mpc track05.cd
cdrskin -v dev=0,1,0 blank=fast -eject speed=48 -sao \
-audio -swab track0[1-5].cd /path/to/track6.wav
Usage example with http://scdbackup.sourceforge.net
Address may be a cdrecord-style "scsibus,target,lun" as listed with
cdrskin -scanbus (and hopefully as listed with cdrecord -scanbus) :
export SCDBACKUP_SCSI_ADR="0,1,0"
or a device file address as listed by --devices with an accessible drive :
export SCDBACKUP_SCSI_ADR="/dev/sg1"
Set usage of cdrskin with appropriate options rather than cdrecord :
export SCDBACKUP_CDRECORD="cdrskin -v -v"
Run a backup :
scdbackup_home
Restrictions
The major restrictions are lifted now: audio, TAO, multi-session do work.
Many cdrecord options are still unsupported, though.
If you have use cases for them, please report your wishes and expectations.
Inspiration and Standard
For the original meaning of cdrecord options see :
man cdrecord
(http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html)
Do not bother Joerg Schilling with any cdrskin problems.
(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
this "don't bother Joerg" demand.)
cdrskin does not contain any bytes copied from cdrecord's sources. Many bytes
have been copied from the message output of cdrecord runs, though. I am
thankful to Joerg Schilling for every single one of them.
Actually i, Thomas Schmitt, am a devoted user of cdrecord via my project
scdbackup which still runs a bit better with cdrecord than with cdrskin. TAO.
I have the hope that Joerg feels more flattered than annoyed by cdrskin.
Drive Addressing
Drives get addressed either via their cdrecord-style addresses as listed
with option -scanbus (see below "Pseudo-SCSI Adresses") or via the paths
of device files.
Not only device files listed by --devices may be used but also device files
which via their major,minor numbers point to the same device driver as
a listed device file.
Helpful with Linux kernel 2.4 is a special SCSI feature:
It is possible to address a scsi(-emulated) drive via associated device files
which are not listed by option --devices but point to the same SCSI addresses
as listed device files. This addressing via e.g. /dev/sr0 or /dev/scd1 is
compatible with generic read programs like dd and with write program growisofs.
Pseudo-SCSI Adresses
cdrecord and cdrskin share the syntax of SCSI addresses but not necessarily
the meaning of the components. A cdrecord-style address for cdrskin
[prefix:]scsibus,target,lun
can be interpreted in two different modes.
Standard mode tries to be compatible to original cdrecord. This should be true
with (emulated) SCSI where the /dev/sgN with is looked up with matching
scsibus,target,lun as given by the operating system.
With dev=ATA: or dev=ATAPI: the translation to /dev/hdX is purely literal
but matches the cdrecord addresses on all systems tested so far:
X = 'a' + 2 * scsibus + target
where target only may have the values 0 or 1.
In this mode, option -scanbus will list only SCSI devices unless option
dev=ATA or dev=ATAPI are given, which will suppress SCSI devices and only
show IDE drives (i.e. /dev/hdX without ide-scsi emulation).
In mode --old_pseudo_scsi_adr there is a scsibus,target,lun representation
which has nothing to do with SCSI and thus is not compatible to cdrecord.
Each number triple corresponds either to a device file address or to a
libburn drive number.
Component "scsibus" indicates the translation method. Defined busses are:
0 target is the libburn drivenumber as listed with --devices
1 associated to device file /dev/sgN , target chooses N
2 associated to device file /dev/hdX , target 0='a', 1='b' ..., 25='z'
So "1,1,0" is /dev/sg1, "2,3,0" is /dev/hdd, "0,2,0" is libburn drive #2 at
some unspecified device file.
This scheme shall help to keep cdrecord-style addresses stable and exchangeable
between users without excluding drives with unexpected device addresses.
The numbering on bus 0 is prone to arbitrary changes caused by changes in
drive accessability.
Further busses may emerge as libburn evolves. "prefix" and "lun" may get
a meaning. To stay upward compatible, use addresses as printed by -scanbus.
User Defined Device Address Translation
Some programs or users have their own ideas about the address of their burner.
K3b 0.10 for example derives cdrecord addresses by own examination of the
devices and not by calling cdrecord -scanbus.
Standard mode will hopefully be fully compatible with their ideas.
Old frontends which do not know dev=ATA or dev=ATAPI and which do ask their
"cdrecord" via -scanbus may be well served with option --old_pseudo_scsi_adr .
To direct any remaining stubborn callers to the appropriate drives, cdrskin
allows to define device address aliases. Like
cdrskin dev_translation=+1,0,0+/dev/sg1 \
dev_translation=+ATA:1,0,0+/dev/sg1 \
dev_translation=-"cd+dvd"-0,1,0 \
...
Any of the addresses dev=1,0,0, dev=ATA:1,0,0, dev=cd+dvd will be mapped to
/dev/sg1 resp. to 0,1,0.
The first character after "dev_translation=" defines the character which
separates the two parts of the translation pair. (Above: "+" and "-".)
In K3b 0.10 it is possible to employ alternative writer programs by setting
their full path (e.g. /usr/bin/cdrskin) in menu
Settings:Configure K3b...:Programs:Search Path
and to make them default in menu
Settings:Configure K3b...:Programs:Programs:
A suitable setting for "cdrecord" in menu
Settings:Configure K3b...:Programs:User Parameters
would then probably be
-v dev_translation=+1,0,0+/dev/sg1
You will learn from button "Show Debugging Output" after a failed burn run
what cdrecord command was used with what address "dev=...". This address "..."
will be the right one to replace "1,0,0" in above example.
Startup Files
If not --no_rc is the first argument then cdrskin attempts on startup to read
arguments from the following three files:
/etc/defaults/cdrskin
/etc/opt/cdrskin/rc
$HOME/.cdrskinrc
The files are read in the sequence given above.
Each readable line is treated as one single argument. No extra blanks.
A first character '#' marks a comment, empty lines are ignored.
Example content of a startup file:
# This is the default device
dev=0,1,0
# To accomodate to eventual remnant cdrskin-0.2.2 addresses
dev_translation=+1,0,0+0,1,0
# Some more options
--fifo_start_empty
fs=16m
Audio CD
Lorenzo Taylor enabled option -audio in cdrskin (thanks !) and reports neat
results with audio data files which are :
headerless PCM (i.e. uncompressed)
44100 Hz sampling rate
16 bits per sample
stereo (2 channels)
little-endian byte order with option -swab, or big-endian without -swab
Files with name extension .wav get examined wether they are in Microsoft WAVE
format with above parameters and eventually get extracted by cdrskin itself.
In the same way files with name extension .au get examined wether they are
in SUN's audio format. For both formats, track format -audio and eventual
endianness option -swab are enabled automatically.
Any other formats are to be converted to format .wav with above parameters
or to be extracted as raw CD track data by commands like those given above
under "Usage examples". Those raw files need option -audio and in most cases
option -swab to mark them as little-endian/Intel/LSB-first 16-bit data.
Incorrect endianness setting results in random noise on CD.
I myself am not into audio. So libburn-hackers@pykix.org might be the
best address for suggestions, requests and bug reports.
Special compilation variations
You may get a (super fat) statically linked binary by :
cdrskin/compile_cdrskin.sh -static
if your system supports static linking, at all. This will not help with kernels
which do not properly support the necessary low-level interfaces chosen by
your compile-time libraries.
A size reduced but fully functional binary may be produced by
cdrskin/compile_cdrskin.sh -do_strip
An extra lean binary with reduced capabilities is created by
cdrskin/compile_cdrskin.sh -do_diet -do_strip
It will not read startup files, will abort on option dev_translation= ,
will not have a fifo buffer, and will not be able to put out help texts or
debugging messages.
------------------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
------------------------------------------------------------------------------
cdrskin is currently copyright Thomas Schmitt only.
It adopts the following commitment by the toplevel copyright holders:
------------------------------------------------------------------------------
We, the copyright holders, agree on the interpretation that
dynamical linking of our libraries constitutes "use of" and
not "derivation from" our work in the sense of GPL, provided
those libraries are compiled from our unaltered code.
Thus you may link our libraries dynamically with applications
which are not under GPL. You may distribute our libraries and
application tools in binary form, if you fulfill the usual
condition of GPL to offer a copy of the source code -altered
or unaltered- under GPL.
We ask you politely to use our work in open source spirit
and with the due reference to the entire open source community.
If there should really arise the case where above clarification
does not suffice to fulfill a clear and neat request in open source
spirit that would otherwise be declined for mere formal reasons,
only in that case we will duely consider to issue a special license
covering only that special case.
It is the open source idea of responsible freedom which will be
decisive and you will have to prove that you exhausted all own
means to qualify for GPL.
For now we are firmly committed to maintain one single license: GPL.
signed for cdrskin: Thomas Schmitt

View File

@ -1,203 +0,0 @@
#!/bin/sh
set -x
# This script documents how this cdrskin version was derived from
# a vanilla libburn version. It is not intended nor needed for any
# use of cdrskin but included here only to show the technical
# relationship between both projects - which are close friends
# and issue roughly the same software.
#
# Package maintainers are advised to cover rather libburn than
# cdrskin unless they put only emphasis on the cdrecord emulation
# provided by cdrskin. libburn contains cdrskin - cdrskin is an
# oscillating, friendly and coordinated fork of libburn.
#
# Script results are a source tarball and two binaries
# one dynamic and one static in respect to system libs.
# Both binaries are static in respect to libburn.
#
# The script is to be run in the directory above the toplevel
# directory of libburn resp. cdrskin development.
#
# libburn version used: http://libburn.pykix.org
# Downloaded by:
# $ svn co http://libburn-svn.pykix.org/trunk libburn_pykix
# packed up in a tarball just to save it from inadverted changes by
# $ tar czf libburn_svn.tgz libburn_pykix
original="./libburn_svn.tgz"
# Historic moments:
# original="./libburn_svn_A60815.tgz"
# original="./libburn_cdrskin_A60819.tgz"
# The top level directory in that snapshot is named
intermediate="./libburn_pykix"
# My changes are in libburn-0.2.3.ts.develop , mainly in ./cdrskin
changes="./libburn-0.2.3.ts.develop"
skin_rev="0.2.4"
# The result directory and the name of the result tarballs
target="./cdrskin-${skin_rev}"
cdrskin_tarball="./cdrskin-${skin_rev}.tar.gz"
cdrskin_tarball_svn="./cdrskin-${skin_rev}.svn.tar.gz"
# (This once earned me an embarrassingly blooping source tarball)
# compile_dir="$changes"
compile_dir="$target"
compile_cmd="./cdrskin/compile_cdrskin.sh"
compile_static_opts="-static"
compile_result="cdrskin/cdrskin"
bintarget_dynamic="cdrskin_${skin_rev}-x86-suse9_0"
bintarget_static="$bintarget_dynamic"-static
if test -d "$changes"
then
dummy=dummy
else
echo "$0 : FATAL : no directory $changes" >&2
exit 1
fi
for i in "$target" "$intermediate"
do
if test -e "$i"
then
echo "$0 : FATAL : already existing $i" >&2
exit 2
fi
done
if test -f "$original"
then
dummy=dummy
else
echo "$0 : FATAL : no file $original" >&2
exit 3
fi
# Unpack SVN snapshot.
tar xzf "$original"
# Rename the directory to the cdrskin name
mv "$intermediate" "$target"
# Copy the changes from the development tree
#
cdrskin_dir="$changes"/cdrskin
libburn_dir="$changes"/libburn
cdrskin_target="$target"/cdrskin
libburn_target="$target"/libburn
# Create version timestamp
timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
echo "$timestamp"
echo '#define Cdrskin_timestamP "'"$timestamp"'"' >"$cdrskin_dir"/cdrskin_timestamp.h
# Add the cdrskin files
if test -e "$cdrskin_target"
then
rm -rf "$cdrskin_target"
fi
cp -a "$cdrskin_dir" "$cdrskin_target"
# Remove copied binaries
rm "$cdrskin_target"/*.o
rm "$cdrskin_target"/cdrfifo
rm "$cdrskin_target"/cdrskin
rm "$cdrskin_target"/cleanup
for i in std new make old
do
if test -e "$cdrskin_target"/cdrskin_"$i"
then
rm "$cdrskin_target"/cdrskin_"$i"
fi
done
for i in .deps .dirstamp .libs
do
if test -e "$cdrskin_target"/"$i"
then
rm -rf "$cdrskin_target"/"$i"
fi
done
# Remove unwanted SVN stuff (TODO: avoid downloading it)
for i in "$target"/.svn "$target"/*/.svn
do
if test "$i" = "$target"'/*/.svn'
then
dummy=dummy
else
if test -e "$i"
then
rm -rf "$i"
fi
fi
done
## No more : Add own libburn-README in toplevel
# cp -a "$changes"/README "$target"
## No more : Add modified Makefile.am
# cp -a "$changes"/Makefile.am "$target"
# Make SVN state tarball for the libburn team
tar czf "$cdrskin_tarball_svn" "$target"
# Get over dependecy on autotools. Rely only on cc, make et. al.
# This is not the same as "make dist" but i can do it without
# having to evaluate the quality of said "make dist"
#
( cd "$target" ; ./bootstrap )
# Remove unwanted stuff after bootstrap
for i in "$target"/autom4te.cache
do
if echo "$i" | grep '\*' >/dev/null
then
dummy=dummy
else
if test -e "$i"
then
rm -rf "$i"
fi
fi
done
# Pack it up to the new libburn+cdrskin-tarball
tar czf "$cdrskin_tarball" "$target"
# Produce a static and a dynamic binary
(
cd "$compile_dir" || exit 1
./configure
make
$compile_cmd -do_strip
cp "$compile_result" "../$bintarget_dynamic"
if test -n "$compile_static_opts"
then
$compile_cmd $compile_static_opts -do_strip
cp "$compile_result" "../$bintarget_static"
fi
)
# Remove the build area
# Disable this for debugging the merge process
rm -rf "$target"
# Show the result
./"$bintarget_dynamic" -version
./"$bintarget_static" -version
ls -l "$cdrskin_tarball"
ls -l "$bintarget_dynamic"
ls -l "$bintarget_static"

View File

@ -1,203 +0,0 @@
#!/bin/sh
set -x
# This script documents how this cdrskin version was derived from
# a vanilla libburn version. It is not intended nor needed for any
# use of cdrskin but included here only to show the technical
# relationship between both projects - which are close friends
# and issue roughly the same software.
#
# Package maintainers are advised to cover rather libburn than
# cdrskin unless they put only emphasis on the cdrecord emulation
# provided by cdrskin. libburn contains cdrskin - cdrskin is an
# oscillating, friendly and coordinated fork of libburn.
#
# Script results are a source tarball and two binaries
# one dynamic and one static in respect to system libs.
# Both binaries are static in respect to libburn.
#
# The script is to be run in the directory above the toplevel
# directory of libburn resp. cdrskin development.
#
# libburn version used: http://libburn.pykix.org
# Downloaded by:
# $ svn co http://libburn-svn.pykix.org/trunk libburn_pykix
# packed up in a tarball just to save it from inadverted changes by
# $ tar czf libburn_svn.tgz libburn_pykix
original="./libburn_svn.tgz"
# Historic moments:
# original="./libburn_svn_A60815.tgz"
# original="./libburn_cdrskin_A60819.tgz"
# The top level directory in that snapshot is named
intermediate="./libburn_pykix"
# My changes are in libburn-0.2.3.ts.develop , mainly in ./cdrskin
changes="./libburn-0.2.3.ts.develop"
skin_rev="0.2.5"
# The result directory and the name of the result tarballs
target="./cdrskin-${skin_rev}"
cdrskin_tarball="./cdrskin-${skin_rev}.tar.gz"
cdrskin_tarball_svn="./cdrskin-${skin_rev}.svn.tar.gz"
# (This once earned me an embarrassingly blooping source tarball)
# compile_dir="$changes"
compile_dir="$target"
compile_cmd="./cdrskin/compile_cdrskin.sh"
compile_static_opts="-static"
compile_result="cdrskin/cdrskin"
bintarget_dynamic="cdrskin_${skin_rev}-x86-suse9_0"
bintarget_static="$bintarget_dynamic"-static
if test -d "$changes"
then
dummy=dummy
else
echo "$0 : FATAL : no directory $changes" >&2
exit 1
fi
for i in "$target" "$intermediate"
do
if test -e "$i"
then
echo "$0 : FATAL : already existing $i" >&2
exit 2
fi
done
if test -f "$original"
then
dummy=dummy
else
echo "$0 : FATAL : no file $original" >&2
exit 3
fi
# Unpack SVN snapshot.
tar xzf "$original"
# Rename the directory to the cdrskin name
mv "$intermediate" "$target"
# Copy the changes from the development tree
#
cdrskin_dir="$changes"/cdrskin
libburn_dir="$changes"/libburn
cdrskin_target="$target"/cdrskin
libburn_target="$target"/libburn
# Create version timestamp
timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
echo "$timestamp"
echo '#define Cdrskin_timestamP "'"$timestamp"'"' >"$cdrskin_dir"/cdrskin_timestamp.h
# Add the cdrskin files
if test -e "$cdrskin_target"
then
rm -rf "$cdrskin_target"
fi
cp -a "$cdrskin_dir" "$cdrskin_target"
# Remove copied binaries
rm "$cdrskin_target"/*.o
rm "$cdrskin_target"/cdrfifo
rm "$cdrskin_target"/cdrskin
rm "$cdrskin_target"/cleanup
for i in std new make old
do
if test -e "$cdrskin_target"/cdrskin_"$i"
then
rm "$cdrskin_target"/cdrskin_"$i"
fi
done
for i in .deps .dirstamp .libs
do
if test -e "$cdrskin_target"/"$i"
then
rm -rf "$cdrskin_target"/"$i"
fi
done
# Remove unwanted SVN stuff (TODO: avoid downloading it)
for i in "$target"/.svn "$target"/*/.svn
do
if test "$i" = "$target"'/*/.svn'
then
dummy=dummy
else
if test -e "$i"
then
rm -rf "$i"
fi
fi
done
## No more : Add own libburn-README in toplevel
# cp -a "$changes"/README "$target"
## No more : Add modified Makefile.am
# cp -a "$changes"/Makefile.am "$target"
# Make SVN state tarball for the libburn team
tar czf "$cdrskin_tarball_svn" "$target"
# Get over dependecy on autotools. Rely only on cc, make et. al.
# This is not the same as "make dist" but i can do it without
# having to evaluate the quality of said "make dist"
#
( cd "$target" ; ./bootstrap )
# Remove unwanted stuff after bootstrap
for i in "$target"/autom4te.cache
do
if echo "$i" | grep '\*' >/dev/null
then
dummy=dummy
else
if test -e "$i"
then
rm -rf "$i"
fi
fi
done
# Pack it up to the new libburn+cdrskin-tarball
tar czf "$cdrskin_tarball" "$target"
# Produce a static and a dynamic binary
(
cd "$compile_dir" || exit 1
./configure
make
$compile_cmd -do_strip
cp "$compile_result" "../$bintarget_dynamic"
if test -n "$compile_static_opts"
then
$compile_cmd $compile_static_opts -do_strip
cp "$compile_result" "../$bintarget_static"
fi
)
# Remove the build area
# Disable this for debugging the merge process
rm -rf "$target"
# Show the result
./"$bintarget_dynamic" -version
./"$bintarget_static" -version
ls -l "$cdrskin_tarball"
ls -l "$bintarget_dynamic"
ls -l "$bintarget_static"

View File

@ -1,37 +0,0 @@
#!/bin/sh
#
# Spying on the call to cdrecord.
#
# Move $(which cdrecord) to $(dirname $(which cdrecord))/real_cdrecord .
# Install this sript instead. (Do not forget to revoke this after the test.)
#
# The report target is set in variable rt.
# The default is this file :
rt=/tmp/cdrecord_spy_log
# To use a bystanding xterm as target i find out the pty address by
# executing in that terminal
# sleep 12345
# and then running in another terminal
# ps -ef | grep 'sleep 12345'
# which answers something like
# thomas 21303 30518 0 14:02 pts/23 00:00:00 sleep 12345
# thomas 21421 30523 0 14:02 pts/24 00:00:00 grep sleep 12345
# from which i learn that pts/23 is sleeping 12345. Now sleep can be aborted.
#
# rt=/dev/pts/23
echo '------------------------------------- cdrecord_spy 0.1.0 -------' >>"$rt"
date >>"$rt"
echo '----------------------------------------------------------------' >>"$rt"
echo "$0" >>"$rt"
for i in "$@"
do
echo "$i" >>"$rt"
done
echo '------------------------------------- cdrecord_spy 0.1.0 - end -' >>"$rt"
real_cdrecord "$@"

File diff suppressed because it is too large Load Diff

View File

@ -1,155 +0,0 @@
/*
cdrfifo.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
A fd-to-fd or fd-to-memory fifo to be used within cdrskin or independently.
By chaining of fifo objects, several fifos can be run simultaneously
in fd-to-fd mode. Modes are controlled by parameter flag of
Cdrfifo_try_to_work().
Provided under GPL license within cdrskin and under BSD license elsewise.
*/
#ifndef Cdrfifo_headerfile_includeD
#define Cdrfifo_headerfile_includeD
/** The fifo buffer which will smoothen the data stream from data provider
to data consumer. Although this is not a mandatory lifesaver for modern
burners any more, a fifo can speed up burning of data which is delivered
with varying bandwidths (e.g. compressed archives created on the fly
or mkisofs running at its speed limit.).
This structure is opaque to applications and may only be used via
the Cdrfifo*() methods described in cdrfifo.h .
*/
struct CdrfifO;
/** Create a fifo object.
@param ff Returns the address of the new object.
@param source_fd Filedescriptor opened to a readable data stream.
@param dest_fd Filedescriptor opened to a writable data stream.
To work with libburn, it needs to be attached to a
struct burn_source object.
@param chunk_size Size of buffer block for a single transaction (0=default)
@param buffer_size Size of fifo buffer
@param flag unused yet
@return 1 on success, <=0 on failure
*/
int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
int chunk_size, int buffer_size, int flag);
/** Release from memory a fifo object previously created by Cdrfifo_new().
@param ff The victim (gets returned as NULL, call can stand *ff==NULL)
@param flag Bitfield for control purposes:
bit0= do not close destination fd
*/
int Cdrfifo_destroy(struct CdrfifO **ff, int flag);
/** Close any output fds */
int Cdrfifo_close(struct CdrfifO *o, int flag);
/** Close any output fds of o and its chain peers */
int Cdrfifo_close_all(struct CdrfifO *o, int flag);
int Cdrfifo_get_sizes(struct CdrfifO *o, int *chunk_size, int *buffer_size,
int flag);
/** Set a speed limit for buffer output.
@param o The fifo object
@param bytes_per_second >0 catch up slowdowns over the whole run time
<0 catch up slowdowns only over one interval
=0 disable speed limit
*/
int Cdrfifo_set_speed_limit(struct CdrfifO *o, double bytes_per_second,
int flag);
/** Set a fixed size for input in order to cut off any unwanted tail
@param o The fifo object
@param idx index for fds attached via Cdrfifo_attach_follow_up_fds(),
first attached is 0, <0 directs limit to active fd limit
(i.e. first track is -1, second track is 0, third is 1, ...)
*/
int Cdrfifo_set_fd_in_limit(struct CdrfifO *o, double fd_in_limit, int idx,
int flag);
int Cdrfifo_set_fds(struct CdrfifO *o, int source_fd, int dest_fd, int flag);
int Cdrfifo_get_fds(struct CdrfifO *o, int *source_fd, int *dest_fd, int flag);
/** Attach a further pair of input and output fd which will use the same
fifo buffer when its predecessors are exhausted. Reading will start as
soon as reading of the predecessor encounters EOF. Writing will start
as soon as all pending predecessor data are written.
@return index number of new item + 1, <=0 indicates error
*/
int Cdrfifo_attach_follow_up_fds(struct CdrfifO *o, int source_fd, int dest_fd,
int flag);
/** Attach a further fifo which shall be processed simultaneously with this
one by Cdrfifo_try_to_work() in fd-to-fd mode.
*/
int Cdrfifo_attach_peer(struct CdrfifO *o, struct CdrfifO *next, int flag);
/** Obtain buffer state.
@param o The buffer object
@param fill Returns the number of pending payload bytes in the buffer
@param space Returns the number of unused buffer bytes
@param flag unused yet
@return -1=error , 0=inactive , 1=reading and writing ,
2=reading ended (but still writing)
*/
int Cdrfifo_get_buffer_state(struct CdrfifO *o,int *fill,int *space,int flag);
int Cdrfifo_get_counters(struct CdrfifO *o,
double *in_counter, double *out_counter, int flag);
/** reads min_fill and begins measurement interval for next min_fill */
int Cdrfifo_next_interval(struct CdrfifO *o, int *min_fill, int flag);
int Cdrfifo_get_min_fill(struct CdrfifO *o, int *total_min_fill,
int *interval_min_fill, int flag);
int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
double *put_counter, double *get_counter,
double *empty_counter, double *full_counter,
int flag);
/** Check for pending data at the fifo's source file descriptor and wether the
fifo is ready to take them. Simultaneously check the buffer for existing
data and the destination fd for readiness to accept some. If so, a small
chunk of data is transfered to and/or from the fifo.
This is done for the given fifo object and all members of its next-chain.
The check and transactions are repeated until a given timespan has elapsed.
libburn applications call this function in the burn loop instead of sleep().
It may also be used instead of read(). Then it returns as soon as an output
transaction would be performed. See flag:bit2.
@param o The fifo object
@param wait_usec The time in microseconds after which the function shall
return.
@param reply_buffer with bit2: Returns write-ready buffer chunk and must
be able to take at least chunk_size bytes
@param reply_count with bit2: Returns number of writeable bytes in reply_pt
@param flag Bitfield for control purposes:
bit0= Enable debug pacifier (same with Cdrfifo_debuG)
bit1= Do not write, just fill buffer
bit2= fd-to-memory mode (else fd-to-fd mode):
Rather than writing a chunk return it and its size.
No simultaneous processing of chained fifos.
bit3= With bit2: do not check destination fd for readiness
@return <0 = error , 0 = idle , 1 = did some work , 2 = all work is done
*/
int Cdrfifo_try_to_work(struct CdrfifO *o, int wait_usec,
char *reply_buffer, int *reply_count, int flag);
/** Fill the fifo as far as possible without writing to destination fd
@return 1 on success, <=0 on failure
*/
int Cdrfifo_fill(struct CdrfifO *o, int flag);
#endif /* Cdrfifo_headerfile_includeD */

File diff suppressed because it is too large Load Diff

View File

@ -1,437 +0,0 @@
<HTML>
<HEAD>
<META NAME="description" CONTENT="cdrskin, a limited cdrecord compatibility wrapper for libburn">
<META NAME="keywords" CONTENT="cdrskin, libburn, burn, CD, linux, CDR, CD-R, CDRW, CD-RW, cdrecord, compatible, scdbackup, burning">
<META NAME="robots" CONTENT="follow">
<TITLE>cdrskin homepage english</TITLE>
</HEAD>
<BODY BGCOLOR="#F5DEB3" TEXT=#000000 LINK=#0000A0 VLINK=#800000>
<FONT SIZE=+1>
<CENTER>
<P><H2>Homepage of</H2><H1><BR>cdrskin</H1><BR>
<!-- <FONT SIZE=+0><A HREF="cdrskin_ger.html">deutsch (german)</A></FONT> -->
<H2>Limited cdrecord compatibility wrapper for libburn</H2>
</CENTER>
<P>
<H2>Purpose:</H2>
<UL>
<LI>Burns preformatted data to CD-R or CD-RW</LI>
</UL>
</P>
<P>
<HR>
<P>
<H2>Hardware requirements:</H2>
A CD recorder suitable for
<A HREF="http://libburn.pykix.org">libburn.pykix.org</A>
(SCSI or IDE/ATAPI writers compliant to mmc standard).
<BR>
</P>
<P>
<H2>Software requirements :</H2>
<DL>
<DT>Linux kernel 2.4 or higher</DT>
<DD>With kernel 2.4 the drive has to be under ide-scsi emulation.</DD>
<DD>With kernel 2.6 the drive should not be under ide-scsi.</DD>
<DT>libpthread</DT>
<DD>is supposed to be a standard system component.</DD>
</DL>
</P>
<P>
<H2>
GPL software included:<BR>
</H2>
<DL>
<DT>libburn-0.2.3 stabilized SVN snapshot</DT>
<DD>(by Derek Foreman, Ben Jansens, and team of libburn.pykix.org)</DD>
<DD>transfers data to CD</DD>
</DL>
</P>
<P>
This program system has been tested on Intel/AMD Linux systems only.<BR>
Ports to other usable systems are appreciated. Reports are welcome.
</P>
<HR>
<P>
<H2>Special features:</H2>
<UL>
<LI>Source code is independent of
<A HREF="http://cdrecord.berlios.de/old/private/cdrecord.html">cdrecord</A>
</LI>
</UL>
</P>
<P>
<H2>Commands:</H2>
<DL>
<DT>The goal is to provide some of cdrecord's options in a compatible way.
This has been achieved quite sufficiently for the needs of backup tool
<A HREF="http://scdbackup.sourceforge.net/main_eng.html">scdbackup</A>
and for data CD projects of <A HREF="http://www.k3b.org">K3b</A>
(see <A HREF="#examples">examples</A>).
Suitability for audio CD frontends has been improved much and is now being
evaluated.<BR>
Further enhancements depend on people who can describe and discuss their
wishes as well as on the development of libburn.</DT>
<BR><BR>
<DT>Get an overview of drives:</DT>
<DD>$ cdrskin -scanbus</DD>
<DD>$ cdrskin dev=ATA -scanbus</DD>
<DD>$ cdrskin --devices</DD>
<DT>Get info about a particular drive or loaded media:</DT>
<DD>$ cdrskin dev=0,1,0 -checkdrive</DD>
<DD>$ cdrskin dev=ATA:1,0,0 -atip</DD>
<DD>$ cdrskin dev=/dev/hdc -toc</DD>
<DT>Make used CD-RW writable again:</DT>
<DD>$ cdrskin -v dev=/dev/sg1 blank=all -eject</DD>
<DD>$ cdrskin -v dev=/dev/dvd blank=fast -eject</DD>
<DT>Write ISO-9660 filesystem image:</DT>
<DD>$ cdrskin -v dev=/dev/hdc speed=12 fs=8m driveropts=burnfree -sao -eject padsize=300k my_image.iso</DD>
<DT>Write compressed afio archive on-the-fly via cdrskin-0.2.4 :</DT>
<DD>$ find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 driveropts=burnfree padsize=300k -sao tsize=650m -</DD>
<DT>Write compressed afio archive on-the-fly via cdrskin-0.2.5 :</DT>
<DD>$ find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 driveropts=burnfree padsize=300k -tao -</DD>
<DT>Write audio tracks:</DT>
<DD>$ cdrskin -v dev=ATA:1,0,0 speed=48 driveropts=burnfree -sao track1.wav track2.au -audio -swab track3.raw
<DD>
<BR>
<DT><A HREF="cdrskin_help">cdrskin -help</A></DT>
<DD>reports the cdrecord compatible options</DD>
<DT><A HREF="cdrskin__help">cdrskin --help</A></DT>
<DD>reports the non-cdrecord options</DD>
<DT><A HREF="http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html">man cdrecord</A></DT>
<DD>documents the standard for which cdrskin is striving.
<B>Do not bother Joerg Schilling with any cdrskin problems.</B>
(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
this "don't bother Joerg" demand.)
</DD>
</DL>
</P>
<P>
<H2>Known deficiencies:</H2>
<UL>
<DT></DT>
<LI>
Burns only a single closed session. No -multi option yet.
Note: Development version 0.2.5 offers multi-session now. See below.
</LI>
<LI>
No TAO mode in cdrskin-0.2.4 and therefore no writing on-the-fly without
a predefined source size.<BR>
Note: Development version 0.2.5 offers TAO now. See below.
</LI>
<LI>
cdrskin -scanbus or --devices hangs for quite a while if there is
a CD drive which does not work properly (e.g. because it has individual
problems with DMA).
So if the superuser gets no result with cdrskin --devices then one should
disable DMA with the problematic CD drives
(like: <KBD>hdparm -d0 /dev/hdd</KBD> )
and try again.<BR>
In severe cases it might be necessary to guess the device name /dev/sgN resp.
/dev/hdX of the non-ill burner if it cannot be found otherwise among its
ill peers. Alternatively one can guess the address of the ill device, remove
rw-permissions and retry the bus scan as non-superuser.
</UL>
</P>
<HR>
<P>
<DL>
<DT>Download as source code (see README):</DT>
<DD><A HREF="cdrskin-0.2.4.pl01.tar.gz">cdrskin-0.2.4.pl01.tar.gz</A>
(510 KB).
</DD>
<DD>
The "stable" cdrskin tarballs are source code identical with "stable"
libburn releases or with "stabilized" libburn SVN snapshots. They get
produced via a different procedure, though.<BR>
cdrskin is part of libburn - full libburn is provided with cdrskin releases.
</DD>
<DD>&nbsp;</DD>
<DT>Download as single x86 binaries (untar and move to /usr/bin/cdrskin):</DT>
<DD><A HREF="cdrskin_0.2.4.pl01-x86-suse9_0.tar.gz">
cdrskin_0.2.4.pl01-x86-suse9_0.tar.gz</A>, (60 KB),
<DL>
<DD>runs on SuSE 9.0 (2.4.21) , RIP-14.4 (2.6.14) ,
Gentoo (2.6.15 x86_64 Athlon).</DD>
</DL>
<DD><A HREF="cdrskin_0.2.4.pl01-x86-suse9_0-static.tar.gz">
cdrskin_0.2.4.pl01-x86-suse9_0-static.tar.gz</A>, (260 KB), -static compiled,
<DL>
<DD>runs on SuSE 7.2 (2.4.4), and on the systems above.</DD>
</DL>
</DD>
</DL>
<DL><DT>Documentation:</DT>
<DD><A HREF="README_cdrskin">README</A> a short introduction</DD>
<DD><A HREF="cdrskin__help">cdrskin --help</A> non-cdrecord options</DD>
<DD><A HREF="cdrskin_help">cdrskin -help</A> cdrecord compatible options</DD>
<DD>&nbsp;</DD>
</DL>
<DL><DT>Contact:</DT>
<DD>Thomas Schmitt, <A HREF="mailto:scdbackup@gmx.net">scdbackup@gmx.net</A></DD>
</DL>
<DL><DT>License:</DT>
<DD><A HREF="COPYING_cdrskin">GPL</A>, an <A HREF="http://www.opensource.org/">Open Source</A> approved license</DD>
<DD>&nbsp;</DD>
</DL>
</P>
<HR>
<P>
Enhancements towards previous stable version cdrskin-0.2.2:
<UL>
<LI>cdrecord compatibility with drive addresses of form [ATA:]Bus,Target,Lun.
<BR>(use option --old_pseudo_scsi_adr to get back the incompatible
Bus,Traget,Lun addressing of version 0.2.2)
</LI>
<LI>Drives adressable via links and device siblings (/dev/cdrom , /dev/scd0).
</LI>
<LI>Automatic -audio extraction with .wav files and .au files.
</LI>
<LI>Bug fix about failure to eject.</LI>
<LI>Comments and empty lines allowed in startup files.</LI>
<LI>Options -scanbus and --devices print SORRY messages about busy drives.
</LI>
<LI>Drive buffer fill indicator reports realistic percentage numbers.</LI>
<LI>Option -toc is supported, drive firmware revision gets displayed.</LI>
</UL>
</P>
<HR>
<P>
<DL>
<DT><H3>Development snapshot, version 0.2.5 :</H3></DT>
<DD>Enhancements towards stable version 0.2.4:
<UL>
<LI>Option <KBD><B>-tao</B></KBD> is fully enabled.
With single track or with undefined size from standard input,
default is -tao. With other multi-track sessions, default is -sao.
(The latter is an intentional deviation from cdrecord defaults.)
</LI>
<LI>Status report during blank, preparation and finalization improved.</LI>
<LI>Bug fixed: Trailing trash appended to .wav files caused error message
and, if exceeding fifo size, could even stall a burn.
(Workaround: disable fifo by <KBD><B>fs=0</B></KBD>)</LI>
<LI>Bug fixed: False speed with first pacifier cycle. Potential program
abort by floating point exception (NaN).</LI>
<LI>multi-session CDs: <KBD><B>-multi</B></KBD>, <KBD><B>-msinfo</B></KBD>,
writing to appendable CDs (for now restricted to write mode TAO).</LI>
</UL>
</DD>
<DD>&nbsp;</DD>
<DD><A HREF="README_cdrskin_devel">README 0.2.5</A>
<DD><A HREF="cdrskin__help_devel">cdrskin_0.2.5 --help</A></DD>
<DD><A HREF="cdrskin_help_devel">cdrskin_0.2.5 -help</A></DD>
<DD>&nbsp;</DD>
<DT>Maintainers of cdrskin unstable packages please use SVN of
<A HREF="http://libburn.pykix.org"> libburn.pykix.org</A></DT>
<DD>Download: <KBD><B>svn co http://libburn-svn.pykix.org/trunk libburn_pykix</B>
</KBD></DD>
<DD>Build: <KBD><B>cd libburn_pykix ; ./bootstrap ; ./configure ; make</B>
</KBD></DD>
<DD>Build of SVN versions needs <A HREF="http://sources.redhat.com/autobook/">
autotools</A> of at least version 1.7 installed.
But after the run of <KBD>./bootstrap</KBD>, only
vanilla tools like make and gcc are needed.</DD>
</DD>
<DD>&nbsp;</DD>
<DT>The following downloads are intended for adventurous end users or
admins with full system souvereignty.</DT>
<DD>Source (./bootstrap is already applied, build tested, for more see above
<A HREF="README_cdrskin_devel">upcoming README</A> ):
</DD>
<DD>
<A HREF="cdrskin-0.2.5.tar.gz">cdrskin-0.2.5.tar.gz</A>
(500 KB).
</DD>
<DD>Binary (untar and move to /usr/bin/cdrskin):</DD>
<DD><A HREF="cdrskin_0.2.5-x86-suse9_0.tar.gz">
cdrskin_0.2.5-x86-suse9_0.tar.gz</A>, (60 KB).
</DD>
<DD><A HREF="cdrskin_0.2.5-x86-suse9_0-static.tar.gz">
cdrskin_0.2.5-x86-suse9_0-static.tar.gz</A>, (260 KB)
</DD>
</DL>
</P>
<HR>
<P>
Many thanks to Joerg Schilling for cdrecord,
<BR>
and to Derek Foreman and Ben Jansens for creating libburn.
<BR>
Historic versions based on Derek's and Ben's
<A HREF="http://icculus.org/burn">icculus.org/burn</A> :<BR>
<A HREF="cdrskin-0.1.2.0.2.ts.tar.gz">cdrskin-0.1.2.0.2.ts.tar.gz</A><BR>
<A HREF="cdrskin-0.1.3.0.2.ts.tar.gz">cdrskin-0.1.3.0.2.ts.tar.gz</A>
</P>
<HR>
<A NAME="examples">
<P>
<DL>
<DT>Example for a setup of device permissions. To be done by the superuser:</DT>
<DT>(CD devices which offer no r-permission are invisible to normal users.)</DT>
<DT>(CD devices which offer no w-permission are not useable.)</DT>
<DD># <KBD><B>cdrskin --devices</B></KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>0&nbsp; dev='/dev/sg0'&nbsp; rwrwr- :&nbsp; 'TEAC' 'CD-ROM CD-532S'</KBD></DD>
<DD><KBD>1&nbsp; dev='/dev/hdc'&nbsp; rwrw-- :&nbsp; 'LITE-ON' 'LTR-48125S'</KBD></DD>
<DD># <KBD><B>chmod a+rw /dev/sg0 /dev/hdc</B></KBD></DD>
</DL>
</P>
<HR>
<A NAME="k3b">
<P>
<A HREF="k3b_on_cdrskin.html">
Example how to setup K3b to use cdrskin for burning data CD projects.
<A><BR>
(<A HREF="http://www.k3b.org">K3b</A>
is a GUI frontend which uses cdrecord for CD burning.)
</P>
<HR>
<A NAME="scdbackup">
<P>
<DL>
<DT>Example for a test session with a cdrecord based scdbackup installation:</DT>
<DD>$ <KBD><B>cdrskin -scanbus</B></KBD></DD>
<DD><KBD>...</KBD></DD>
</DL>
If your system is stricken with some ill CD device then this can stall
and you will have to press <KBD>Ctrl+C</KBD> to abort.
In this case, you may execute
<KBD>export SCDBACKUP_NO_SCANBUS=1</KBD>
and try again.
<DL>
<DT></DT>
<DD><KBD>&nbsp;&nbsp;&nbsp; 2,0,0 &nbsp;&nbsp; 0)&nbsp; 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
<DD>$ <KBD><B>cdrskin -scanbus dev=ATA</B></KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; 1,0,0 &nbsp;&nbsp; 1)&nbsp; 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
<DD>$ <KBD><B>export SCDBACKUP_SCSI_ADR="ATA:1,0,0"</B></KBD></DD>
<DD>$ <KBD><B>export SCDBACKUP_CDRECORD="cdrskin -v -v tao_to_sao_tsize=650m"</B></KBD></DD>
<DD>$ <KBD><B>scdbackup_home</B></KBD></DD>
</DL>
<DL>
<DT>Example for a permanent configuration of cdrskin based scdbackup</DT>
<DD>$ <KBD><B>cd scdbackup-0.8.6/inst</B></KBD></DD>
<DD>$ <KBD><B>export SCDBACKUP_USE_CDRSKIN=1</B></KBD></DD>
<DD>$ <KBD><B>./CONFIGURE_CD</B></KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>cdrskin 0.2.4 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD> ------------------- SCSI devices. To be used like &nbsp;&nbsp; 0,0,0</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; 2,0,0 &nbsp;&nbsp; 0)&nbsp; 'TEAC' 'CD-ROM CD-532S' '?' Removable CD-ROM</KBD></DD>
<DD><KBD> ------------------- end of SCSI device list</KBD></DD>
<DD><KBD> ------------------- ATA devices. To be used like ATA:0,0,0
<DD><KBD>&nbsp;&nbsp;&nbsp; 1,0,0 &nbsp;&nbsp; 1)&nbsp; 'LITE-ON' 'LTR-48125S' '?' Removable CD-ROM</KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>&nbsp;&nbsp;&nbsp; * Your cdrecord offers -driveropts=burnfree with your recorder.</KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>scdbackup for CD 0.8.6 : First stage of installation done.</KBD></DD>
<DD><KBD>...</KBD></DD>
<DD><KBD>Now give it a try. Run : scdbackup_home</KBD></DD>
<DD>$ <KBD><B>unset SCDBACKUP_USE_CDRSKIN</B></KBD></DD>
</DL>
<DL>
<DT>To get back to using cdrecord :</DT>
<DD>$ <KBD><B>cd scdbackup-0.8.6/inst</B></KBD></DD>
<DD>$ <KBD><B>export SCDBACKUP_USE_CDRSKIN=0</B></KBD></DD>
<DD>$ <KBD><B>./CONFIGURE_CD</B></KBD></DD>
<DD><KBD>...</KBD></DD>
<DD>$ <KBD><B>unset SCDBACKUP_USE_CDRSKIN</B></KBD></DD>
</DL>
</P>
<HR>
<A NAME="cdrecord">
<P>
<CENTER><H3>About the relationship of cdrecord and cdrskin</H3></CENTER>
First of all: this relationship is single sided, as cdrskin has to be aware of
cdrecord but not vice versa.
<BR>
<BR>
I am a long time user of cdrecord and it works fine for me.
Especially i do appreciate its write mode -tao which allows to pipe arbitrary
data on CD and CD-RW via stdin. cdrecord is reliable, versatile and well
maintained. So for me - there would be not problem with it.
<BR>
But the author of cdrecord and the Linux kernel people foster a very hostile
relationship. Ok, that's their business, not mine (or ours if you are with me).
One has to be aware, though, that this relationship might lead to a situation
where cdrecord is no longer available for certain Linux kernels.
<BR>
To have my own project prepared for such a time, i began to implement its
cdrecord gestures on top of libburn.
From now on i invite other interested users of cdrecord to teach cdrskin
the gestures necessary for their cdrecord applications.
Contact me. Let's see what we can achieve.
<BR>
<BR>
I am aware that libburn and cdrskin still have way to go until you can simply
install cdrskin as cdrecord and may expect any application to run with it.
Currently i do not encourage this approach, but of course such a replacement
opportunity is the long term goal of a cdrecord compatibility wrapper.
<BR>
<BR>
It is very important to me that this project is not perceived as hostile
towards Joerg Schilling and his ongoing work.
I owe him much. For cdrecord, for mkisofs, for star. Chapeau.
<BR>
</P>
<HR>
<CENTER><FONT SIZE=+0>
<!-- <A NAME="bottom" HREF="main_ger.html#bottom">deutsch (german)</A>
<BR><BR>
-->
<FONT SIZE=+0>Enjoying free Open Source hosting by <A HREF="http://www.webframe.org">www.webframe.org</A><BR>
<A HREF="http://www.webframe.org">
<IMG SRC="msfree.gif" ALT="100 % Microsoft free" BORDER=0></A><BR>
and by <A HREF="http://sourceforge.net">sourceforge.net</A><BR>
<A href="http://sourceforge.net">
<IMG src="sflogo-88-1.png" BORDER="0" ALT="SourceForge Logo"></A>
<!-- on sourceforge use : <IMG src="http://sourceforge.net/sflogo.php?group_id=16010" width="88" height="31" border="0" alt="SourceForge Logo"></A> -->
</FONT></CENTER>
<HR>
<DL>
<DT>Links to my other published software projects :
<DD><A HREF=http://scdbackup.webframe.org/main_eng.html>
scdbackup, multi volume CD backup</A>
<DL><DD><A HREF=http://scdbackup.sourceforge.net/main_eng.html>
(a second source of above)</A></DL>
<DD><A HREF=http://stic.webframe.org>Some Tools for Image Collectors</A>
<DL><DD><A HREF=http://stic.sourceforge.net>(a second source of above)</A></DL>
<DD><A HREF=http://scdbackup.webframe.org/pppoem>
pppoem, a DSL throughput monitor (mainly for Linux kernel 2.4)</A>
</DL>
<BR><BR>
Legal statement: This website does not serve any commercial purpose.<BR>
</FONT>
</BODY>
</HTML>

View File

@ -1 +0,0 @@
#define Cdrskin_timestamP "2006.11.12.185342"

File diff suppressed because it is too large Load Diff

View File

@ -1,214 +0,0 @@
/*
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
A signal handler which cleans up an application and exits.
Provided under GPL license within GPL projects, BSD license elsewise.
*/
/*
cc -g -o cleanup -DCleanup_standalonE cleanup.c
*/
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
#include "cleanup.h"
#ifdef __FreeBSD__
/* Signals to be caught */
static int signal_list[]= {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
SIGTTOU,
SIGBUS, SIGPROF, SIGSYS, SIGTRAP,
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
};
static char *signal_name_list[]= {
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
"SIGTTOU",
"SIGBUS", "SIGPROF", "SIGSYS", "SIGTRAP",
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
};
static int signal_list_count= 23;
#else /* __FreeBSD__ */
/* Signals to be caught */
static int signal_list[]= {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
SIGTTOU,
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
};
static char *signal_name_list[]= {
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
"SIGTTOU",
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
};
static int signal_list_count= 24;
#endif /* ! __FreeBSD__ */
/* Signals not to be caught */
static int non_signal_list[]= {
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1
};
static int non_signal_list_count= 4;
/* run time dynamic part */
static char cleanup_msg[4096]= {""};
static int cleanup_exiting= 0;
static void *cleanup_app_handle= NULL;
static Cleanup_app_handler_T cleanup_app_handler= NULL;
static int cleanup_perform_app_handler_first= 0;
static int Cleanup_handler_exit(int exit_value, int signum, int flag)
{
int ret;
if(cleanup_msg[0]!=0)
fprintf(stderr,"\n%s\n",cleanup_msg);
if(cleanup_perform_app_handler_first)
if(cleanup_app_handler!=NULL) {
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
if(ret==2 || ret==-2)
return(2);
}
if(cleanup_exiting) {
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
getpid(),signum);
return(0);
}
cleanup_exiting= 1;
alarm(0);
if(!cleanup_perform_app_handler_first)
if(cleanup_app_handler!=NULL) {
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
if(ret==2 || ret==-2)
return(2);
}
exit(exit_value);
}
static void Cleanup_handler_generic(int signum)
{
int i;
sprintf(cleanup_msg,"UNIX-SIGNAL caught: %d errno= %d",signum,errno);
for(i= 0; i<signal_list_count; i++)
if(signum==signal_list[i]) {
sprintf(cleanup_msg,"UNIX-SIGNAL: %s errno= %d",
signal_name_list[i],errno);
break;
}
Cleanup_handler_exit(1,signum,0);
}
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
/*
bit0= set to default handlers
bit1= set to ignore
bit2= set cleanup_perform_app_handler_first
bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
*/
{
int i,j,max_sig= -1,min_sig= 0x7fffffff;
sighandler_t sig_handler;
cleanup_msg[0]= 0;
cleanup_app_handle= handle;
cleanup_app_handler= handler;
/* <<< make cleanup_exiting thread safe to get rid of this */
if(flag&4)
cleanup_perform_app_handler_first= 1;
if(flag&1)
sig_handler= SIG_DFL;
else if(flag&2)
sig_handler= SIG_IGN;
else
sig_handler= Cleanup_handler_generic;
/* set all signal numbers between the lowest and highest in the list
except those in the non-signal list */
for(i= 0; i<signal_list_count; i++) {
if(signal_list[i]>max_sig)
max_sig= signal_list[i];
if(signal_list[i]<min_sig)
min_sig= signal_list[i];
}
for(i= min_sig; i<=max_sig; i++) {
for(j= 0; j<non_signal_list_count; j++)
if(i==non_signal_list[j])
break;
if(j>=non_signal_list_count) {
if(i==SIGABRT && (flag&8))
signal(i,Cleanup_handler_generic);
else
signal(i,sig_handler);
}
}
return(1);
}
#ifdef Cleanup_standalonE
struct Demo_apP {
char *msg;
};
int Demo_app_handler(struct Demo_apP *demoapp, int signum, int flag)
{
printf("Handling exit of demo application on signal %d. msg=\"%s\"\n",
signum,demoapp->msg);
return(1);
}
main()
{
struct Demo_apP demoapp;
demoapp.msg= "Good Bye";
Cleanup_set_handlers(&demoapp,(Cleanup_app_handler_T) Demo_app_handler,0);
if(1) { /* change to 0 in order to wait for external signals */
char *cpt= NULL,c;
printf("Intentionally provoking SIGSEGV ...\n");
c= *cpt;
} else {
printf("killme: %d\n",getpid());
sleep(3600);
}
Cleanup_set_handlers(NULL,NULL,1);
exit(0);
}
#endif /* Cleanup_standalonE */

View File

@ -1,34 +0,0 @@
/*
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
A signal handler which cleans up an application and exits.
Provided under GPL license within GPL projects, BSD license elsewise.
*/
#ifndef Cleanup_includeD
#define Cleanup_includeD 1
/** Layout of an application provided cleanup function using an application
provided handle as first argument and the signal number as second
argument. The third argument is a flag bit field with no defined bits yet.
If the handler returns 2 or -2 then it has delegated exit() to some other
instance and the Cleanup handler shall return rather than exit.
*/
typedef int (*Cleanup_app_handler_T)(void *, int, int);
/** Establish exiting signal handlers on (hopefully) all signals that are
not ignored by default or non-catchable.
@param handle Opaque object which knows how to cleanup application
@param handler Function which uses handle to perform application cleanup
@param flag Control Bitfield
bit0= reset to default signal handling
*/
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler,
int flag);
#endif /* ! Cleanup_includeD */

View File

@ -1,218 +0,0 @@
#!/bin/sh
# compile_cdrskin.sh
# Copyright 2005 - 2006 Thomas Schmitt, scdbackup@gmx.net, GPL
# to be executed within ./libburn-* resp ./cdrskin-*
debug_opts=
def_opts=
largefile_opts="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1"
libvers="-DCdrskin_libburn_0_2_3"
cleanup_src_or_obj="libburn/cleanup.o"
libdax_msgs_o="libburn/libdax_msgs.o"
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
do_strip=0
static_opts=
warn_opts="-Wall"
fifo_source="cdrskin/cdrfifo.c"
compile_cdrskin=1
compile_cdrfifo=0
compile_dewav=0
for i in "$@"
do
if test "$i" = "-compile_cdrfifo"
then
compile_cdrfifo=1
elif test "$i" = "-compile_dewav"
then
compile_dewav=1
elif test "$i" = "-cvs_A60220"
then
libvers="-DCdrskin_libburn_cvs_A60220_tS"
libdax_audioxtr_o=
libdax_msgs_o="libburn/message.o"
cleanup_src_or_obj="cdrskin/cleanup.c"
elif test "$i" = "-libburn_0_2_2"
then
libvers="-DCdrskin_libburn_0_2_2"
libdax_audioxtr_o=
libdax_msgs_o="libburn/message.o"
cleanup_src_or_obj="cdrskin/cleanup.c"
elif test "$i" = "-libburn_0_2_3"
then
libvers="-DCdrskin_libburn_0_2_3"
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
libdax_msgs_o="libburn/libdax_msgs.o"
cleanup_src_or_obj="libburn/cleanup.o"
elif test "$i" = "-newapi" -o "$i" = "-experimental"
then
def_opts="$def_opts -DCdrskin_new_api_tesT"
elif test "$i" = "-oldfashioned"
then
def_opts="$def_opts -DCdrskin_oldfashioned_api_usE"
elif test "$i" = "-no_largefile"
then
largefile_opts=
elif test "$i" = "-do_not_compile_cdrskin"
then
compile_cdrskin=0
elif test "$i" = "-do_diet"
then
fifo_source=
def_opts="$def_opts -DCdrskin_extra_leaN"
warn_opts=
elif test "$i" = "-do_strip"
then
do_strip=1
elif test "$i" = "-g"
then
debug_opts="$debug_opts -g"
elif test "$i" = "-O2"
then
debug_opts="$debug_opts -O2"
elif test "$i" = "-help" -o "$i" = "--help" -o "$i" = "-h"
then
echo "cdrskin/compile_cdrskin.sh : to be executed within top level directory"
echo "Options:"
echo " -compile_cdrfifo compile program cdrskin/cdrfifo."
echo " -compile_dewav compile program test/dewav without libburn."
echo " -cvs_A60220 set macro to match libburn-CVS of 20 Feb 2006."
echo " -libburn_0_2_2 set macro to match libburn-0.2.2."
echo " -libburn_0_2_3 set macro to match current libburn-SVN."
echo " -no_largefile do not use 64 bit off_t (must match libburn)."
echo " -do_not_compile_cdrskin omit compilation of cdrskin/cdrskin."
echo " -experimental use newly introduced libburn features."
echo " -oldfashioned use pre-0.2.2 libburn features only."
echo " -do_diet produce capability reduced lean version."
echo " -do_strip apply program strip to compiled programs."
echo " -g compile with cc option -g."
echo " -O2 compile with cc option -O2."
echo " -static compile with cc option -static."
exit 0
elif test "$i" = "-static"
then
static_opts="-static"
fi
done
timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
echo "Version timestamp : $(sed -e 's/#define Cdrskin_timestamP "//' -e 's/"$//' cdrskin/cdrskin_timestamp.h)"
echo "Build timestamp : $timestamp"
if test "$compile_cdrskin"
then
echo "compiling program cdrskin/cdrskin.c $static_opts $debug_opts $libvers $def_opts $cleanup_src_or_obj"
cc -I. \
$warn_opts \
$static_opts \
$debug_opts \
$libvers \
$largefile_opts \
$def_opts \
\
-DCdrskin_build_timestamP='"'"$timestamp"'"' \
\
-o cdrskin/cdrskin \
\
cdrskin/cdrskin.c \
$fifo_source \
\
$cleanup_src_or_obj \
\
libburn/async.o \
libburn/debug.o \
libburn/drive.o \
libburn/file.o \
libburn/init.o \
libburn/options.o \
libburn/source.o \
libburn/structure.o \
\
libburn/sg.o \
libburn/write.o \
$libdax_audioxtr_o \
$libdax_msgs_o \
\
libburn/mmc.o \
libburn/sbc.o \
libburn/spc.o \
libburn/util.o \
\
libburn/sector.o \
libburn/toc.o \
\
libburn/crc.o \
libburn/lec.o \
\
-lpthread
ret=$?
if test "$ret" = 0
then
dummy=dummy
else
echo >&2
echo "+++ FATAL : Compilation of cdrskin failed" >&2
echo >&2
exit 1
fi
fi
if test "$compile_cdrfifo" = 1
then
echo "compiling program cdrskin/cdrfifo.c $static_opts $debug_opts"
cc $static_opts $debug_opts \
-DCdrfifo_standalonE \
-o cdrskin/cdrfifo \
cdrskin/cdrfifo.c
ret=$?
if test "$ret" = 0
then
dummy=dummy
else
echo >&2
echo "+++ FATAL : Compilation of cdrfifo failed" >&2
echo >&2
exit 2
fi
fi
if test "$compile_dewav" = 1
then
echo "compiling program test/dewav.c -DDewav_without_libburN $static_opts $debug_opts"
cc $static_opts $debug_opts \
-DDewav_without_libburN \
-o test/dewav \
test/dewav.c \
libburn/libdax_audioxtr.o \
libburn/libdax_msgs.o \
\
-lpthread
ret=$?
if test "$ret" = 0
then
dummy=dummy
else
echo >&2
echo "+++ FATAL : Compilation of test/dewav failed" >&2
echo >&2
exit 2
fi
fi
if test "$do_strip" = 1
then
echo "stripping result cdrskin/cdrskin"
strip cdrskin/cdrskin
if test "$compile_cdrfifo" = 1
then
echo "stripping result cdrskin/cdrfifo"
strip cdrskin/cdrfifo
fi
fi
echo 'done.'

View File

@ -1,9 +0,0 @@
#!/bin/sh
# Create version timestamp cdrskin/cdrskin_timestamp.h
# to be executed within ./libburn-* resp ./cdrskin-*
timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
echo "Version timestamp : $timestamp"
echo '#define Cdrskin_timestamP "'"$timestamp"'"' >cdrskin/cdrskin_timestamp.h

View File

@ -1,204 +0,0 @@
--------------------------------------------------------------------------
cdrskin Wiki - plain text copy
--------------------------------------------------------------------------
cdrskin-0.2.5 is the cdrecord compatibility middleware of libburn.
Its paragon, 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. Currently it does CD-R and CD-RW.
Its future ability to burn DVD media depends on the development of libburn.
cdrskin does not contain any bytes copied from cdrecord's sources.
Many bytes have been copied from the message output of cdrecord
runs, though. The most comprehensive technical overview of cdrskin
can be found in cdrskin/README . Online available as :
http://libburn.pykix.org/browser/trunk/cdrskin/README?format=raw
--------------------------------------------------------------------------
cdrskin with CD media fails to match its paragon cdrecord on one major field:
Multi session.
Convenient TAO burn mode is provided in development version 0.2.5 but not in
current "stable" release 0.2.4.
cdrskin does not provide DVD burning yet. See advise to use dvd+rw-tools
at the end of this text.
--------------------------------------------------------------------------
About the command line options of cdrskin:
There are two families of options: cdrecord-compatible ones and options
which are specific to cdrskin. The latter are mostly used to configure
cdrskin for its task to emulate cdrecord. There are some, nevertheless,
which provide rather exotic unique features of cdrskin.
The cdrecord-compatible options are listed in the output of
cdrskin -help
where the option "help" has *one* dash.
For these options you may expect program behavior that is roughly the
same as described in original man 1 cdrecord .
Online: http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html
The cdrskin-specific options are listed by
cdrskin --help
where the option "help" has *two* dashes.
Those have no man page yet. Some are very experimental and should only be
used in coordination with the libburn developer team.
Some are of general user interest, though:
--------------------------------------------------------------------------
--devices allows the sysadmin to scan the system for possible drives
and displays their detected properties.
The drives are listed one per line, with fields:
libburn-drive-number sysadmin-device-file permissions : vendor type
0 dev='/dev/sg0' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
This feature is valuable since cdrskin -scanbus will not give you
the device file name and its current permissions.
cdrskin will accept of course the proposed dev= option as address
for any usage of the drive.
Different from cdrecord, cdrskin is intended to be run without special
privileges, i.e. no superuser setuid. It is intended that the sysadmin
controls drive accessability by rw-permissions of the drive rather than
by x-permission of the burn binary. To be usable with cdrskin, the drive
has to offer both, r- and w-permission.
--------------------------------------------------------------------------
--fifo_start_empty is a throughput enhancer for unsteady data streams
like they are produced by a compressing archiver program when piping to
CD on-the-fly. It makes better use of the general property of a FIFO
buffer to transport surplus bandwidth into the future. Yep. A time machine.
One-way, i fear.
FIFO originally was introduced by cdrecord's author Joerg Schilling in order
to protect mediocre burner hardware from suffering buffer underruns
and thus producing misburns (at 1x speed on CD-R media at the price of a
DVD-RAM nowadays). This purpose would not justify a fifo any more -
given the limited life time of burners and the seamless underrun protection
of contemporary consumer drives.
With an unsteady data stream the task of the buffer is to soak up peak
performance and to release it steadily at the drive's maximum speed.
The larger the buffer the more reserves can be built up and the longer
input drought can be compensated.
Original cdrecord has the historical property, though, to first wait until
the buffer is completely filled. Best practice for fighting drive
underruns, of course.
With a very fat fs=# buffer (128 MB for 12x CD is not unrealistic) this
can cause a big delay until burning finally starts and takes its due time.
--fifo_start_empty makes cdrskin start burning without waiting for the
FIFO to be full resp. the data stream to end. It can make use of the
seconds spend with drive preparation and lead-in, it risks a few drive
buffer underruns at the beginning of burn - but modern drives stand this.
Note: no FIFO can give you better average throughput than the average
throughput of the data source and the throughput of the burner.
It can be used, though, to bring the effective throughput very close
to the theoretical limit. Especially with high speed media.
--------------------------------------------------------------------------
--no_rc allows you to surely ban influence from systemwide or user specific
default settings of cdrskin. Possible locations for such settings:
/etc/default/cdrskin
/etc/opt/cdrskin/rc
$HOME/.cdrskinrc
--------------------------------------------------------------------------
tao_to_sao_tsize=<num> allows the - actually unsupported - cdrecord option
-tao and defines a default track size to be used if - as custom with -tao -
no option tsize=# is given.
Since -tao is supported in cdrskin-0.2.5 the TAO-to-SAO workaround on its way
to obsolescence. Nevertheless, tao_to_sao_tsize= allows to preset a default
size for SAO mode which is in effect only if no track size is available.
As in general with cdrskin tsize=# the data source does not have to provide
the full annouced amount of data. Missing data will be padded up by 0-bytes.
Surplus data is supposed to cause an error, though. The burn will then
be a failure in any way.
--------------------------------------------------------------------------
dev_translation=<sep><from><sep><to> may be needed to foist cdrskin to
frontend programs of cdrecord which do *not* ask cdrecord -scanbus but
which make own assumptions and guesses about cdrecord's device addresses.
Normally, cdrskin understands all addresses which are suitable for cdrecord
under Linux. See cdrskin/README, "Pseudo-SCSI Adresses".
This option is mainly for (yet unknown) exotic configurations or very
stubborn frontend programs.
If a frontend refuses to work with cdrskin, look into the error protocol
of that frontend, look at the output of a run of cdrskin --devices and give
cdrskin the necessary hint.
Example: Your frontend insists in using "0,0,0" and --devices reported
dev='/dev/hdc' resp. cdrskin dev=ATA -scanbus reported "1,0,0" then this
would be the appropriate translation:
dev_translation=+0,0,0+/dev/hdc
The "+" character is a separator to be choosen by you.
Currently i am not aware of the need to choose any other than "+"
unless you get playful with custom translations like
dev_translation=-"cd+dvd"-1,0,0
See http://scdbackup.sourceforge.net/k3b_on_cdrskin.html
for an illustrated example with K3b 0.10 .
--------------------------------------------------------------------------
DVD advise:
For burning of DVD media the cdrskin project currently advises to use
Andy Polyakov's dvd+rw-tools which despite their historic name burn
for me on above burner: DVD+RW, DVD+R, DVD-RW, DVD-R .
http://fy.chalmers.se/~appro/linux/DVD+RW/tools
They are not compatible or related to cdrecord resp. cdrecord-ProDVD
(now obsoleted by original source cdrtools cdrecord with identical
capabilities besides the license key).
If there is sincere and well motivated interest, the cdrskin project could try
to employ growisofs as DVD burning engine. The cdrskin project would prefer to
wait for DVD support being included in libburn, though.
A very limited and specialized cdrecord-compatibility wrapper for growisofs
serves in my project scdbackup. It is not overly hard to make one that serves
some very few fixed use cases.
To my knowledge, Linux kernels 2.6 do write to DVD+RW via block devices as
they would write to a traditional tape device. Try old tape archiver
commands with addresses like /dev/sr0 or /dev/hdc rather than /dev/mt0 .
I have heard rumors that DVD-RW in mode "restricted overwrite" would be
block device ready, too. My burner is not a real friend of DVD-RW and
in an experiment the burn worked fine - but the result was not identical
to the stream sent to the device. I had similar failure with DVD-RAM, too.
Beware of the impact of a slow block device on overall system i/o buffering.
It is wise to curb its input to a speed which it is able to deliver to media.
Else your i/o dedicated RAM might buffer a big amount of stream data.
--------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
AC_INIT([libburn], [0.2.3], [http://libburn.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
@ -63,8 +63,9 @@ AC_C_BIGENDIAN
dnl Large file support
AC_SYS_LARGEFILE
AC_FUNC_FSEEKO
AC_CHECK_FUNC([fseeko])
if test ! $ac_cv_func_fseeko; then
AC_ERROR([Libburn requires largefile support.])
AC_ERROR([Libisofs requires largefile support.])
fi
AC_PROG_LIBTOOL
@ -111,7 +112,6 @@ AC_CONFIG_FILES([
Makefile
doc/doxygen.conf
version.h
libburn-1.pc
libisofs-1.pc
libisofs-5.pc
])
AC_OUTPUT

View File

@ -120,5 +120,4 @@ Program tar would need a clean EOF which our padded CD cannot deliver.
Click on blue names of functions, structures, variables, etc in oder to
get to the according specs of libburn API or libburner sourcecode.
@include libburner.c
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libburn
Description: Disc reading/writing library
Version: @VERSION@
Requires:
Libs: -L${libdir} -lburn
Libs.private: @THREAD_LIBS@ @LIBBURN_ARCH_LIBS@
Cflags: -I${includedir}/libburn

View File

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

View File

@ -1,65 +0,0 @@
pkgconfigdir=$(libdir)/pkgconfig
libincludedir=$(includedir)/libburn
lib_LTLIBRARIES = libburn.la
libburn_la_SOURCES = \
async.c \
async.h \
crc.c \
crc.h \
debug.c \
debug.h \
drive.c \
drive.h \
file.c \
file.h \
init.c \
init.h \
lec.c \
lec.h \
message.c \
message.h \
mmc.c \
mmc.h \
null.c \
null.h \
options.c \
options.h \
read.c \
read.h \
sbc.c \
sbc.h \
sector.c \
sector.h \
sg.c \
sg.h \
spc.c \
spc.h \
source.h \
source.c \
structure.c \
structure.h \
toc.c \
toc.h \
transport.h \
util.c \
util.h \
write.c \
write.h
libinclude_HEADERS = libburn.h
## ========================================================================= ##
indent_files = $(libburn_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
## ========================================================================= ##

View File

@ -1,792 +0,0 @@
List of assert() calls in libburn. 6 Oct 2006.
Format:
------------------------------------------------------------------------------
Number) grep'ed line
(++ before number means: is fully done, + means is done so far )
function():
Description of abort condition.
Possible callers and their relation to the abort condition.
: Error Evaluation
=> Consequences
Eventual implementation timestamp
------------------------------------------------------------------------------
++ 1) libburn/async.c: assert(a != NULL); /* wasn't found.. this should not be possible */
static remove_worker():
A thread describing structure (struct w_list) could not be found in
order to be released.
Called by API burn_drive_scan()
Called by static erase_worker_func() , thread under API burn_disc_erase()
Called by static write_disc_worker_func(), thread under API burn_disc_write()
All three want to clean up after they are done.
: Severe Libburn Error
=> issue LIBDAX_MSGS_SEV_WARNING
ts A61006
------------------------------------------------------------------------------
++ 2) libburn/async.c: assert(!(workers && workers->drive));
API burn_drive_scan():
Before spawning a thread, the function refuses work because another
drive activity is going on.
: Severe Application Error
=> return -1; redefine @return in API , issue LIBDAX_MSGS_SEV_SORRY
ts A61006
------------------------------------------------------------------------------
+ 3) libburn/async.c: assert(workers == NULL);
API burn_drive_scan():
After thread is done and remover_worker() succeeded, there is still a
worker registered. Shall probably detect roguely appeared burn or
erase runs. (I consider to install a mutex shielded function for that.)
: Severe Libburn Error
=> Same as 1)
ts A61006
------------------------------------------------------------------------------
++ 4) libburn/async.c: assert(drive);
libburn/async.c: assert(!SCAN_GOING());
libburn/async.c: assert(!find_worker(drive));
API burn_disc_erase():
Wants to see a drive (assumes NULL == 0), wants to see no scan and
wants to see no other worker on that drive. I.e. this would tolerate
a parallel activity on another drive.
: Severe Application Error
=> (no return value), issue LIBDAX_MSGS_SEV_SORRY
ts A61006
------------------------------------------------------------------------------
++ 5) libburn/async.c: assert(!SCAN_GOING());
libburn/async.c: assert(!find_worker(opts->drive));
API burn_disc_write():
Same as 4)
: Severe Application Error
=> Same as 4)
ts A61006
---------------------------------------------------------------------
++ 6) libburn/drive.c: assert(d->busy == BURN_DRIVE_IDLE);
API burn_drive_release():
A drive is not idle on release.
: Severe Application Error
=> Same as 4)
ts A61007
------------------------------------------------------------------------------
++ 7) libburn/drive.c: assert(d->released);
burn_wait_all()
A drive is found grabbed.
Called by burn_drive_scan_sync(), thread under API burn_drive_scan()
Called by API burn_finish
: Severe Application Error
=> rename and redefine burn_wait_all() : now burn_drives_are_clear()
=> change all use of burn_wait_all()
=> Move tests up to burn_drive_scan()
=> There: return -1; issue LIBDAX_MSGS_SEV_SORRY
ts A61007
------------------------------------------------------------------------------
++ 8) libburn/drive.c: assert(!d->released);
API burn_disc_get_status()
Attempt to read status of non-grabbed drive.
: Severe Application Error
=> extend enum burn_disc_status by BURN_DISC_UNGRABBED
=> return BURN_DISC_UNGRABBED, issue LIBDAX_MSGS_SEV_SORRY
ts A61007
------------------------------------------------------------------------------
++ 9) libburn/drive.c: assert( /* (write_type >= BURN_WRITE_PACKET) && */
burn_drive_get_block_types():
Will not work on BURN_WRITE below BURN_WRITE_RAW.
Called by -nobody- ?
: Severe Application Error
=> inactivate unused function
ts A61007
------------------------------------------------------------------------------
++ 10) libburn/drive.c: assert(d->idata);
libburn/drive.c: assert(d->mdata);
static drive_getcaps():
sg.c:enumerate_common() did not succeed in creating a proper struct burn_drive
Called by burn_drive_scan_sync()
: Severe System Error
=> This could possibly really stay an abort() because the reason is
a plain failure of the system's memory management.
=> Detect this failure already in enumerate_common(),
issue LIBDAX_MSGS_SEV_FATAL, return
ts A61007
------------------------------------------------------------------------------
++ 11) libburn/drive.c: assert(burn_running);
burn_drive_scan_sync():
The library was not initialized.
Called as thread by API burn_drive_scan()
: Severe Application Error
=> Move this test up to burn_drive_scan()
=> There: return -1; redefine @return in API , issue LIBDAX_MSGS_SEV_FATAL
ts A61007
------------------------------------------------------------------------------
++ 12) libburn/drive.c: assert(d->released == 1);
burn_drive_scan_sync():
Inactivated
: (Severe Application Error)
=> throw out inactivated code
ts A61007
------------------------------------------------------------------------------
++ 13) libburn/drive.c: assert(strlen(d->devname) < BURN_DRIVE_ADR_LEN);
burn_drive_raw_get_adr():
An enumerated device address is longer than the API's maximum length
Called by API burn_drive_get_adr()
Called by API burn_drive_obtain_scsi_adr()
: Severe Libburn Error
=> return -1; in all three functions, enhance burn_drive_get_adr @return docs
=> issue LIBDAX_MSGS_SEV_SORRY
ts A61007
------------------------------------------------------------------------------
++ 14) libburn/drive.c: assert(drive_info->drive!=NULL);
API burn_drive_get_adr():
Drive info has no drive attached.
: Severe Libburn Error (unlikely, will eventually SIGSEGV on NULL)
=> delete assert
ts A61007
------------------------------------------------------------------------------
++ 15) libburn/init.c: assert(burn_running);
API burn_finish():
The library is not initialized
: Severe Application Error
=> return (assume no msg system)
ts A61007
------------------------------------------------------------------------------
++ 16) libburn/init.c: assert(burn_running);
API burn_preset_device_open():
The library is not initialized
: Severe Application Error
=> return (assume no msg system)
ts A61007
------------------------------------------------------------------------------
++ 17) libburn/mmc.c: assert(o->drive == d);
mmc_close_disc():
alias: struct burn_drive.close_disc()
Parameters struct burn_drive and struct burn_write_opts do not match
Called by -nobody- ?
( => Disable unused function ? )
=> removed redundant parameter struct burn_drive
ts A61009
------------------------------------------------------------------------------
++ 18) libburn/mmc.c: assert(o->drive == d);
mmc_close_session():
Same as 17)
alias: struct burn_drive.close_session()
Called by -nobody- ?
( => Disable unused function ? )
=> removed redundant parameter struct burn_drive
ts A61009
------------------------------------------------------------------------------
++ 19) libburn/mmc.c: assert(buf->bytes >= buf->sectors); /* can be == at 0... */
mmc_write_12():
- Unclear what .bytes and .sectors mean in struct buffer -
Called by -nobody- ?
=> problems with filling the write buffer have to be handled by callers
=> delete assert
ts A61009
------------------------------------------------------------------------------
++ 20) libburn/mmc.c: assert(buf->bytes >= buf->sectors); /* can be == at 0... */
mmc_write():
- Unclear what .bytes and .sectors mean in struct buffer -
libburn/mmc.c: c.page->sectors = errorblock - start + 1;
mmc_read_sectors() by toc_find_modes() by mmc_read_toc() alias drive.read_toc()
by burn_drive_grab()
This seems to be unrelated to mmc_write().
libburn/sector.c: out->sectors++;
get_sector()
Seems to hand out sector start pointer in opts->drive->buffer
and to count reservation transactions as well as reserved bytes.
Ensures out->bytes >= out->sectors
libburn/mmc.c: c.page->bytes = s->count * 8;
mmc_send_cue_sheet()
Does not use mmc_write() but directly (sg_)issue_command()
libburn/sector.c: out->bytes += seclen;
get_sector()
See above
Ensures out->bytes >= out->sectors
libburn/spc.c: c.page->bytes = 8 + 2 + d->mdata->retry_page_length;
spc_select_error_params()
Does not use mmc_write() but directly (sg_)issue_command()
libburn/spc.c: c.page->bytes = 8 + 2 + d->mdata->write_page_length;
spc_select_error_params()
Does not use mmc_write() but directly (sg_)issue_command()
libburn/spc.c: c.page->bytes = 8 + 2 + 0x32;
spc_probe_write_modes()
Does not use mmc_write() but directly (sg_)issue_command()
alias struct burn_drive.write()
Called by static get_sector, by many
Called by burn_write_flush
Called by burn_write_track
=> problems with filling the write buffer have to be handled by callers
=> delete assert
ts A61009
------------------------------------------------------------------------------
++ 21) libburn/mmc.c: assert(((dlen - 2) % 11) == 0);
mmc_read_toc():
- Is defunct -
=> :)
ts A61009
------------------------------------------------------------------------------
++ 22) libburn/mmc.c: assert(len >= 0);
mmc_read_sectors():
Catches a bad parameter
alias: struct burn_drive.read_sectors()
Called by API burn_disc_read() , - is defunct -, one could catch the problem
Called by toc_find_modes(), problem cannot occur: mem.sectors = 1;
: Severe Libburn Error
(=> in burn_disc_read() check page.sectors before d->read_sectors() )
=> :)
ts A61009
------------------------------------------------------------------------------
++ 23) libburn/mmc.c: assert(d->busy);
mmc_read_sectors():
Catches use of a drive that is not marked as busy
alias: struct burn_drive.read_sectors()
Called by API burn_disc_read() , - is defunct -, busy = BURN_DRIVE_READING;
Called by toc_find_modes(), does the same assert. To be solved there.
: Severe Libburn Error
=> :)
ts A61009
------------------------------------------------------------------------------
++ 24) libburn/options.c: assert(0);
API burn_write_opts_set_write_type():
Detects unsuitable enum burn_write_types write_type and int block_type.
API promises return 0 on failure
: Severe Application Error
=> issue LIBDAX_MSGS_SEV_SORRY
=> should also detect problem of 26) : wrong write_type,block_type combination
by calling sector_get_outmode() and checking for -1
=> should also detect problem of 41) : unknown block_type
by spc_block_type() and checking for -1
=> delete assert(0)
ts A61007
------------------------------------------------------------------------------
++ 25) libburn/read.c: assert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));
libburn/read.c: assert(!d->busy);
libburn/read.c: assert(d->toc->valid);
libburn/read.c: assert(o->datafd != -1);
API burn_disc_read():
- ? -
burn_disc_read() is defunct
OPTIONS_VERSION does not occur outside this line
( => one would return )
( 22) => catch page.sectors<0 before d->read_sectors() )
( 37) => catch ! d->mdata->valid )
=> :)
ts A61007
------------------------------------------------------------------------------
++ 26) libburn/sector.c: assert(0); /* return BURN_MODE_UNIMPLEMENTED :) */
static get_outmode():
burn_write_opts is wrongly programmed with .write_type and .block_type
: Severe Application Error
=> This gets handled by burn_write_opts_set_write_type()
ts A61007 by new semi-public sector_get_outmode()
=> delete assert()
ts A61007
------------------------------------------------------------------------------
++ 27) libburn/sector.c: assert(outlen >= inlen);
libburn/sector.c: assert(outmode & BURN_MODE_RAW);
libburn/sector.c: assert(offset != -1);
static convert_data():
Several unacceptable settings within struct burn_write_opts
Called by sector_toc() sector_pregap() sector_postgap() sector_lout()
sector_data()
: Severe Application Error
=> change return type of convert_data()
=> all callers interpret return value and eventually return failure
ts A61007
------------------------------------------------------------------------------
++ 28) libburn/sector.c: assert(0);
static char_to_isrc():
Called by subcode_user() with data set by API burn_track_set_isrc()
Some character conversion fails on wrong input
: Severe Application Error
=> burn_track_set_isrc() has to make sure that only good data are set
=> char_to_isrc() returns 0 as default
=> delete assert()
ts A61008
------------------------------------------------------------------------------
++ 29) libburn/sector.c: assert(qmode == 1 || qmode == 2 || qmode == 3);
subcode_user():
- can not happen -
: Unknown reason of assert()
=> remove assert()
ts A61010
------------------------------------------------------------------------------
++ 30) libburn/sector.c: assert(modebyte == 1);
sector_headers():
Does only accept modes BURN_AUDIO, BURN_MODE1 or write_type BURN_WRITE_SAO
Called by sector_toc() sector_pregap() sector_postgap() sector_lout()
sector_data()
: Severe Libburn Error
=> new functions sector_headers_is_ok(), burn_disc_write_is_ok()
help to catch problem in API burn_disc_write()
=> issue LIBDAX_MSGS_SEV_FATAL
ts A61009
------------------------------------------------------------------------------
++ 31) libburn/sector.c: assert(0);
process_q()
- defunct -
=> :)
ts A61009
------------------------------------------------------------------------------
++ 32) libburn/sg.c: assert("drive busy" == "non fatal");
sg_handle_busy_device():
Intentional abort preset by the app
=> change to abort()
ts A61007
------------------------------------------------------------------------------
++ 33) libburn/sg.c: assert(fd != -1337);
sg_grab():
The drive device file could not be opened
:Severe External Problem
=> obsolete by normal drive open failure handling
ts A61007
------------------------------------------------------------------------------
++ 34) libburn/sg.c: assert(!c->page);
sg_issue_command():
An SCSI command of direction NO_TRANSFER may not have a .page != NULL.
Since it is about exposing a libburn detail towards the sg driver, i believe
it is sufficient to just not use it.
: Libburn Error
=> enhance internal logics of sg_issue_command()
ts A61007
------------------------------------------------------------------------------
++ 35) libburn/sg.c: assert(c->page->bytes > 0);
sg_issue_command():
An SCSI command of direction TO_DRIVE wants to transfer 0 bytes.
: Severe Libburn Error
=> set command.error = 1 and return 0
ts A61010
------------------------------------------------------------------------------
++ 36) libburn/sg.c: assert(err != -1);
sg_issue_command():
The transfer of the command via ioctl() failed
: Severe Transport Level Problem
=> close drive fd, set idle and released
=> set command.error = 1 and return -1
ts A61010
------------------------------------------------------------------------------
++ 37) libburn/spc.c: assert(d->mdata->valid);
spc_select_error_params():
Drive was not properly programmed
alias struct burn_drive.send_parameters()
Called by burn_disc_read, - defunct -
: Severe Application Error
=> moved up as mangled assert to burn_disc_read()
ts A61007
------------------------------------------------------------------------------
++ 38) libburn/spc.c: assert(d->mdata->cdr_write || d->mdata->cdrw_write ||
spc_sense_write_params():
Drive does not offer write of any known media type
alias struct burn_drive.read_disc_info()
Called by API burn_drive_grab (assert test made there in soft)
: Severe Command Level Problem
=> remove assert()
ts A61007
------------------------------------------------------------------------------
++ 39) libburn/spc.c: assert(o->drive == d);
spc_select_write_params():
Drive does not match struct burn_write_opts
alias struct burn_drive.send_write_parameters()
Called by mmc_close_disc() (-defunct- ?), mmc_close_session() (-defunct- ?),
burn_write_track() (d = o->drive;),
burn_disc_write_sync() d = (o->drive;)
: Severe Libburn Error
=> remove assert()
ts A61007
------------------------------------------------------------------------------
++ 40) libburn/spc.c: assert(d->mdata->valid);
spc_select_write_params():
Drive was not properly programmed
Called by (see 39)
burn_write_track() by burn_write_session() by burn_disc_write_sync()
burn_disc_write_sync() indirectly by API burn_disc_write()
: Severe Libburn Error
=> caught in burn_disc_write() now
ts A61007
------------------------------------------------------------------------------
++ 41) libburn/spc.c: assert(0);
spc_block_type():
Unknown value with enum burn_block_types
Called by spc_select_write_params, uses burn_write_opts.block_type,
set by API burn_write_opts_set_write_type()
: Severe Application Error
=> catch in API burn_write_opts_set_write_type
by calling spc_block_type()
=> delete assert
ts A61007
------------------------------------------------------------------------------
++ 42) libburn/structure.c: assert(!(pos > BURN_POS_END));\
macro RESIZE
An illegal list index is given by the app.
( TO->NEW##s obviusly means to append "s" to cpp result of TO->NEW )
Used by API burn_session_add_track() and API burn_disc_add_session()
: Severe Application Error
=> replace assert by if-and-return-0
ts A61008
------------------------------------------------------------------------------
++ 43) libburn/structure.c: assert(s->track != NULL);
API burn_session_remove_track()
An application supplied pointer is NULL
: Severe Application Error
=> replace by if-and-return-0
ts A61008
------------------------------------------------------------------------------
++ 44) libburn/structure.c: assert((country[i] >= '0' || country[i] < '9') &&
libburn/structure.c: assert((owner[i] >= '0' || owner[i] < '9') &&
libburn/structure.c: assert(year <= 99);
libburn/structure.c: assert(serial <= 99999);
API burn_track_set_isrc():
Illegal texts supplied by application.
The logical expression is always true !
: Severe Application Error
=> issue LIBDAX_MSGS_SEV_SORRY and return
=> delete assert
=> delete assert 28) in char_to_isrc()
ts A61008
------------------------------------------------------------------------------
++ 45) libburn/toc.c: assert(0); /* unhandled! find out ccd's
static write_clonecd2():
- defunct -, - unused -
=> mangle assert
ts A61008
------------------------------------------------------------------------------
++ 46) libburn/toc.c: assert(d->busy);
toc_find_modes():
The drive to work on is not marked busy
Called by mmc_read_toc() alias read_toc() by ... burn_drive_grab()
: Severe Libburn Error
=> to be prevented on the higher levels
=> delete assert
ts A61008
------------------------------------------------------------------------------
++ 47) libburn/util.c: assert(s);
burn_strdup()
Abort on NULL string which would elsewise cause a SIGSEGV
Used once in enumerate_common() with a string that worked with open(2) before
: Severe Libburn Error
=> delete assert
ts A61008
------------------------------------------------------------------------------
++ 48) libburn/util.c: assert(s);
burn_strndup(): - unused -
Same as 47
: Severe Libburn Error
=> return NULL
=> delete assert
ts A61008
------------------------------------------------------------------------------
++ 49) libburn/util.c: assert(n > 0);
burn_strndup(): - unused -
Prevent problems by negative copy length
: Severe Libburn Error
=> return NULL
=> delete assert
ts A61008
------------------------------------------------------------------------------
++ 50) libburn/write.c: assert(0);
static type_to_ctrl():
Unsuitable mode to be converted into "ctrl"
Called by static type_to_form() finally burn_create_toc_entries()
: Severe Application Error
=> to be caught in burn_track_define_data by calling for test type_to_form()
=> return -1;
ts A61008
------------------------------------------------------------------------------
++ 51) libburn/write.c: assert(0);
libburn/write.c: assert(0); /* XXX someone's gonna want this sometime */
static type_to_form():
Does not like BURN_MODE0 or BURN_MODE2 but tolerates unknown modes
Called by static burn_create_toc_entries() by burn_disc_write_sync()
: Undocumented Libburn Restriction
=> set *form = -1 , *ctladr = 0xff , return
=> make function non-static
=> call for test in API burn_track_define_data()
ts A61009
------------------------------------------------------------------------------
++ 52) libburn/write.c: assert(ptr);
static add_cue():
realloc() failed
Called by burn_create_toc_entries() by burn_disc_write_sync()
(burn_create_toc_entries is ignorant towards own potential memory problems)
(This could possibly really stay an abort() because the reason is
a plain failure of the system's memory management.)
: Severe System Error
=> change return type of add_cue to int
=> react on return -1 in burn_create_toc_entries, return NULL on failure
=> abort burn_disc_write_sync() on NULL return
ts A61009
------------------------------------------------------------------------------
++ 53) libburn/write.c: assert(d->toc_entry == NULL);
burn_create_toc_entries():
Multiple usage of struct burn_drive.toc_entry
Called by burn_disc_write_sync()
This will probably trigger an abort with disc->sessions > 1
(disc->sessions is incremented in macro RESIZE() as "NEW##s")
: Design Problem
( => ? disallow multiple sessions ? )
=> replace assert by soft means and wait what happens
ts A61009
------------------------------------------------------------------------------
++ 54) libburn/write.c: assert(0);
burn_sector_length():
Only BURN_AUDIO, BURN_MODE_RAW, BURN_MODE1 are allowed
Called by get_sector(), convert_data(), ...
=> call burn_sector_length() for test in API burn_track_define_data()
=> replace assert by -1
ts A61009
------------------------------------------------------------------------------

View File

@ -1,280 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include "libburn.h"
#include "transport.h"
#include "drive.h"
#include "write.h"
#include "options.h"
#include "async.h"
#include "init.h"
#include <pthread.h>
#include <stdlib.h>
/*
#include <a ssert.h>
*/
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
#define SCAN_GOING() (workers && !workers->drive)
typedef void *(*WorkerFunc) (void *);
struct scan_opts
{
struct burn_drive_info **drives;
unsigned int *n_drives;
int done;
};
struct erase_opts
{
struct burn_drive *drive;
int fast;
};
struct write_opts
{
struct burn_drive *drive;
struct burn_write_opts *opts;
struct burn_disc *disc;
};
struct w_list
{
struct burn_drive *drive;
pthread_t thread;
struct w_list *next;
union w_list_data
{
struct scan_opts scan;
struct erase_opts erase;
struct write_opts write;
} u;
};
static struct w_list *workers;
static struct w_list *find_worker(struct burn_drive *d)
{
struct w_list *a;
for (a = workers; a; a = a->next)
if (a->drive == d)
return a;
return NULL;
}
static void add_worker(struct burn_drive *d, WorkerFunc f, void *data)
{
struct w_list *a;
struct w_list *tmp;
a = malloc(sizeof(struct w_list));
a->drive = d;
a->u = *(union w_list_data *)data;
/* insert at front of the list */
a->next = workers;
tmp = workers;
workers = a;
if (d)
d->busy = BURN_DRIVE_SPAWNING;
if (pthread_create(&a->thread, NULL, f, a)) {
free(a);
workers = tmp;
return;
}
}
static void remove_worker(pthread_t th)
{
struct w_list *a, *l = NULL;
for (a = workers; a; l = a, a = a->next)
if (a->thread == th) {
if (l)
l->next = a->next;
else
workers = a->next;
free(a);
break;
}
/* ts A61006 */
/* a ssert(a != NULL);/ * wasn't found.. this should not be possible */
if (a == NULL)
libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
"remove_worker() cannot find given worker item", 0, 0);
}
static void *scan_worker_func(struct w_list *w)
{
burn_drive_scan_sync(w->u.scan.drives, w->u.scan.n_drives);
w->u.scan.done = 1;
return NULL;
}
int burn_drive_scan(struct burn_drive_info *drives[], unsigned int *n_drives)
{
struct scan_opts o;
int ret = 0;
/* ts A61006 : moved up from burn_drive_scan_sync , former Assert */
if (!burn_running) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020109,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Library not running (on attempt to scan)", 0, 0);
*drives = NULL;
*n_drives = 0;
return -1;
}
/* cant be anything working! */
/* ts A61006 */
/* a ssert(!(workers && workers->drive)); */
if (workers != NULL && workers->drive != NULL) {
drive_is_active:;
libdax_msgs_submit(libdax_messenger, -1, 0x00020102,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"A drive operation is still going on (want to scan)",
0, 0);
*drives = NULL;
*n_drives = 0;
return -1;
}
if (!workers) {
/* start it */
/* ts A61007 : test moved up from burn_drive_scan_sync()
was burn_wait_all() */
if (!burn_drives_are_clear())
goto drive_is_active;
*drives = NULL;
*n_drives = 0;
o.drives = drives;
o.n_drives = n_drives;
o.done = 0;
add_worker(NULL, (WorkerFunc) scan_worker_func, &o);
} else if (workers->u.scan.done) {
/* its done */
ret = workers->u.scan.done;
remove_worker(workers->thread);
/* ts A61006 */
/* a ssert(workers == NULL); */
if (workers != NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
"After scan a drive operation is still going on",
0, 0);
return -1;
}
} else {
/* still going */
}
return ret;
}
static void *erase_worker_func(struct w_list *w)
{
burn_disc_erase_sync(w->u.erase.drive, w->u.erase.fast);
remove_worker(pthread_self());
return NULL;
}
void burn_disc_erase(struct burn_drive *drive, int fast)
{
struct erase_opts o;
/* ts A61006 */
/* a ssert(drive); */
/* a ssert(!SCAN_GOING()); */
/* a ssert(!find_worker(drive)); */
if((drive == NULL)) {
libdax_msgs_submit(libdax_messenger, drive->global_index,
0x00020104,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"NULL pointer caught in burn_disc_erase", 0, 0);
return;
}
if ((SCAN_GOING()) || find_worker(drive)) {
libdax_msgs_submit(libdax_messenger, drive->global_index,
0x00020102,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"A drive operation is still going on (want to erase)",
0, 0);
return;
}
o.drive = drive;
o.fast = fast;
add_worker(drive, (WorkerFunc) erase_worker_func, &o);
}
static void *write_disc_worker_func(struct w_list *w)
{
burn_disc_write_sync(w->u.write.opts, w->u.write.disc);
/* the options are refcounted, free out ref count which we added below
*/
burn_write_opts_free(w->u.write.opts);
remove_worker(pthread_self());
return NULL;
}
void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
{
struct write_opts o;
/* ts A61006 */
/* a ssert(!SCAN_GOING()); */
/* a ssert(!find_worker(opts->drive)); */
if ((SCAN_GOING()) || find_worker(opts->drive)) {
libdax_msgs_submit(libdax_messenger, opts->drive->global_index,
0x00020102,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"A drive operation is still going on (want to write)",
0, 0);
return;
}
/* ts A61007 : obsolete Assert in spc_select_write_params() */
if (!opts->drive->mdata->valid) {
libdax_msgs_submit(libdax_messenger,
opts->drive->global_index, 0x00020113,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Drive capabilities not inquired yet", 0, 0);
return;
}
/* ts A61009 : obsolete Assert in sector_headers() */
if (! burn_disc_write_is_ok(opts, disc)) /* issues own msgs */
return;
o.drive = opts->drive;
o.opts = opts;
o.disc = disc;
opts->refcount++;
add_worker(opts->drive, (WorkerFunc) write_disc_worker_func, &o);
}
void burn_async_join_all(void)
{
void *ret;
while (workers)
pthread_join(workers->thread, &ret);
}

View File

@ -1,8 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef BURN__ASYNC_H
#define BURN__ASYNC_H
void burn_async_join_all(void);
struct burn_write_opts;
#endif /* BURN__ASYNC_H */

View File

@ -1,54 +0,0 @@
/**
This file bundles variables which disable changes in libburn which are
not yet completely accepted.
The use of these variables is *strongly discouraged* unless you have sincere
reason and are willing to share your gained knowledge with the libburn
developers.
Do *not silently rely* on these variables with your application. Tell us
that you needed one or more of them. They are subject to removal as soon
as consense has been found about correctness of the change they revoke.
Value 0 means that the new behavior is enabled. Any other value enables
the described old time behavior.
If you doubt one of the changes here broke your application, then do
*in your application*, *not here* :
- #include "libburn/back_hacks.h" like you include "libburn/libburn.h"
- Set the libburn_back_hack_* variable of your choice to 1.
In your app. Not here.
- Then start and use libburn as usual. Watch out for results.
- If you believe to have detected a flaw in our change, come forward
and report it to the libburn developers. Thanks in advance. :)
*/
/** Do not define this macro in your application. Only libburn/init.c is
entitled to set it.
*/
#ifdef BURN_BACK_HACKS_INIT
/** Corresponds to http://libburn.pykix.org/ticket/42
Reinstates the old ban not to blank appendable CD-RW. We see no reason
for this ban yet. It appears unusual. But maybe it patches a bug.
*/
int libburn_back_hack_42= 0;
#else /* BURN_BACK_HACKS_INIT */
/* Note: no application programmer info beyond this point */
extern int libburn_back_hack_42;
#endif /* ! BURN_BACK_HACKS_INIT */

View File

@ -1,214 +0,0 @@
/*
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
A signal handler which cleans up an application and exits.
Provided under GPL license within GPL projects, BSD license elsewise.
*/
/*
cc -g -o cleanup -DCleanup_standalonE cleanup.c
*/
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
typedef void (*sighandler_t)(int);
#include "cleanup.h"
#ifdef __FreeBSD__
/* Signals to be caught */
static int signal_list[]= {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
SIGTTOU,
SIGBUS, SIGPROF, SIGSYS, SIGTRAP,
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
};
static char *signal_name_list[]= {
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
"SIGTTOU",
"SIGBUS", "SIGPROF", "SIGSYS", "SIGTRAP",
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
};
static int signal_list_count= 23;
#else /* __FreeBSD__ */
/* Signals to be caught */
static int signal_list[]= {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
SIGTTOU,
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
};
static char *signal_name_list[]= {
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
"SIGTTOU",
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
};
static int signal_list_count= 24;
#endif /* ! __FreeBSD__ */
/* Signals not to be caught */
static int non_signal_list[]= {
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1
};
static int non_signal_list_count= 4;
/* run time dynamic part */
static char cleanup_msg[4096]= {""};
static int cleanup_exiting= 0;
static void *cleanup_app_handle= NULL;
static Cleanup_app_handler_T cleanup_app_handler= NULL;
static int cleanup_perform_app_handler_first= 0;
static int Cleanup_handler_exit(int exit_value, int signum, int flag)
{
int ret;
if(cleanup_msg[0]!=0)
fprintf(stderr,"\n%s\n",cleanup_msg);
if(cleanup_perform_app_handler_first)
if(cleanup_app_handler!=NULL) {
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
if(ret==2 || ret==-2)
return(2);
}
if(cleanup_exiting) {
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
getpid(),signum);
return(0);
}
cleanup_exiting= 1;
alarm(0);
if(!cleanup_perform_app_handler_first)
if(cleanup_app_handler!=NULL) {
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
if(ret==2 || ret==-2)
return(2);
}
exit(exit_value);
}
static void Cleanup_handler_generic(int signum)
{
int i;
sprintf(cleanup_msg,"UNIX-SIGNAL caught: %d errno= %d",signum,errno);
for(i= 0; i<signal_list_count; i++)
if(signum==signal_list[i]) {
sprintf(cleanup_msg,"UNIX-SIGNAL: %s errno= %d",
signal_name_list[i],errno);
break;
}
Cleanup_handler_exit(1,signum,0);
}
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
/*
bit0= set to default handlers
bit1= set to ignore
bit2= set cleanup_perform_app_handler_first
bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
*/
{
int i,j,max_sig= -1,min_sig= 0x7fffffff;
sighandler_t sig_handler;
cleanup_msg[0]= 0;
cleanup_app_handle= handle;
cleanup_app_handler= handler;
/* <<< make cleanup_exiting thread safe to get rid of this */
if(flag&4)
cleanup_perform_app_handler_first= 1;
if(flag&1)
sig_handler= SIG_DFL;
else if(flag&2)
sig_handler= SIG_IGN;
else
sig_handler= Cleanup_handler_generic;
/* set all signal numbers between the lowest and highest in the list
except those in the non-signal list */
for(i= 0; i<signal_list_count; i++) {
if(signal_list[i]>max_sig)
max_sig= signal_list[i];
if(signal_list[i]<min_sig)
min_sig= signal_list[i];
}
for(i= min_sig; i<=max_sig; i++) {
for(j= 0; j<non_signal_list_count; j++)
if(i==non_signal_list[j])
break;
if(j>=non_signal_list_count) {
if(i==SIGABRT && (flag&8))
signal(i,Cleanup_handler_generic);
else
signal(i,sig_handler);
}
}
return(1);
}
#ifdef Cleanup_standalonE
struct Demo_apP {
char *msg;
};
int Demo_app_handler(struct Demo_apP *demoapp, int signum, int flag)
{
printf("Handling exit of demo application on signal %d. msg=\"%s\"\n",
signum,demoapp->msg);
return(1);
}
main()
{
struct Demo_apP demoapp;
demoapp.msg= "Good Bye";
Cleanup_set_handlers(&demoapp,(Cleanup_app_handler_T) Demo_app_handler,0);
if(1) { /* change to 0 in order to wait for external signals */
char *cpt= NULL,c;
printf("Intentionally provoking SIGSEGV ...\n");
c= *cpt;
} else {
printf("killme: %d\n",getpid());
sleep(3600);
}
Cleanup_set_handlers(NULL,NULL,1);
exit(0);
}
#endif /* Cleanup_standalonE */

View File

@ -1,34 +0,0 @@
/*
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
A signal handler which cleans up an application and exits.
Provided under GPL license within GPL projects, BSD license elsewise.
*/
#ifndef Cleanup_includeD
#define Cleanup_includeD 1
/** Layout of an application provided cleanup function using an application
provided handle as first argument and the signal number as second
argument. The third argument is a flag bit field with no defined bits yet.
If the handler returns 2 or -2 then it has delegated exit() to some other
instance and the Cleanup handler shall return rather than exit.
*/
typedef int (*Cleanup_app_handler_T)(void *, int, int);
/** Establish exiting signal handlers on (hopefully) all signals that are
not ignored by default or non-catchable.
@param handle Opaque object which knows how to cleanup application
@param handler Function which uses handle to perform application cleanup
@param flag Control Bitfield
bit0= reset to default signal handling
*/
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler,
int flag);
#endif /* ! Cleanup_includeD */

View File

@ -1,122 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include "crc.h"
static unsigned short ccitt_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
unsigned long crc32_table[256] = {
0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
};
unsigned short crc_ccitt(unsigned char *q, int len)
{
unsigned short crc = 0;
while (len-- > 0)
crc = ccitt_table[(crc >> 8 ^ *q++) & 0xff] ^ (crc << 8);
return ~crc;
}
unsigned int crc_32(unsigned char *data, int len)
{
unsigned int crc = 0;
while (len-- > 0)
crc = crc32_table[(crc ^ *data++) & 0xffL] ^ (crc >> 8);
return crc;
}

View File

@ -1,9 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef BURN__CRC_H
#define BURN__CRC_H
unsigned short crc_ccitt(unsigned char *, int len);
unsigned int crc_32(unsigned char *, int len);
#endif /* BURN__CRC_H */

View File

@ -1,35 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifdef WIN32
#include <windows.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include "libburn.h"
#include "debug.h"
static int burn_verbosity = 0;
void burn_set_verbosity(int v)
{
burn_verbosity = v;
}
void burn_print(int level, const char *a, ...)
{
#ifdef WIN32
char debug_string_data[256];
#endif
va_list vl;
if (level <= burn_verbosity) {
va_start(vl, a);
#ifdef WIN32
vsprintf(debug_string_data, a, vl);
OutputDebugString(debug_string_data);
#else
vfprintf(stderr, a, vl);
#endif
}
}

View File

@ -1,8 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef BURN__DEBUG_H
#define BURN__DEBUG_H
void burn_print(int level, const char *a, ...);
#endif /* BURN__DEBUG_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __DRIVE
#define __DRIVE
#include "libburn.h"
#include "toc.h"
#include "structure.h"
struct burn_drive;
struct command;
struct mempage;
#define LEAD_IN 1
#define GAP 2
#define USER_DATA 3
#define LEAD_OUT 4
#define SYNC 5
#define SESSION_LEADOUT_ENTRY(d,s) (d)->toc->session[(s)].leadout_entry
#define CURRENT_SESSION_START(d) \
burn_msf_to_lba(d->toc->session[d->currsession].start_m, \
d->toc->session[d->currsession].start_s, \
d->toc->session[d->currsession].start_f)
#define SESSION_END(d,s) \
TOC_ENTRY_PLBA((d)->toc, SESSION_LEADOUT_ENTRY((d), (s)))
#define PREVIOUS_SESSION_END(d) \
TOC_ENTRY_PLBA((d)->toc, SESSION_LEADOUT_ENTRY((d), (d)->currsession-1))
#define LAST_SESSION_END(d) \
TOC_ENTRY_PLBA((d)->toc, \
SESSION_LEADOUT_ENTRY((d), (d)->toc->sessions-1))
struct burn_drive *burn_drive_register(struct burn_drive *);
int burn_drive_unregister(struct burn_drive *d);
unsigned int burn_drive_count(void);
/* ts A61007 */
/* void burn_wait_all(void); */
int burn_drives_are_clear(void);
int burn_sector_length_write(struct burn_drive *d);
int burn_track_control(struct burn_drive *d, int);
void burn_write_empty_sector(int fd);
void burn_write_empty_subcode(int fd);
void burn_drive_free(struct burn_drive *d);
void burn_drive_free_all(void);
int burn_drive_scan_sync(struct burn_drive_info *drives[],
unsigned int *n_drives);
void burn_disc_erase_sync(struct burn_drive *d, int fast);
int burn_drive_get_block_types(struct burn_drive *d,
enum burn_write_types write_type);
int burn_drive_is_open(struct burn_drive *d);
int burn_drive_is_occupied(struct burn_drive *d);
int burn_drive_forget(struct burn_drive *d, int force);
int burn_drive_convert_fs_adr_sub(char *path, char adr[], int *rec_count);
/* ts A61021 : the unspecific part of sg.c:enumerate_common()
*/
int burn_setup_drive(struct burn_drive *d, char *fname);
/* ts A61021 : after-setup activities from sg.c:enumerate_common()
*/
struct burn_drive *burn_drive_finish_enum(struct burn_drive *d);
#endif /* __DRIVE */

View File

@ -1,8 +0,0 @@
/* -*- indent-tabs-mode; t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __ERROR_H
#define __ERROR_H
#define BE_CANCELLED 1
#endif /* __ERROR_H */

View File

@ -1,187 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "source.h"
#include "libburn.h"
#include "file.h"
/* main channel data can be padded on read, but 0 padding the subs will make
an unreadable disc */
/* This is a generic OS oriented function wrapper which compensates
shortcommings of read() in respect to a guaranteed amount of return data.
See man 2 read , paragraph "RETURN VALUE".
Possibly libburn/file.c is not the right storage location for this.
To make it ready for a move, this function is not declared static.
*/
static int read_full_buffer(int fd, unsigned char *buffer, int size)
{
int ret,summed_ret = 0;
/* make safe against partial buffer returns */
while (1) {
ret = read(fd, buffer + summed_ret, size - summed_ret);
if (ret <= 0)
break;
summed_ret += ret;
if (summed_ret >= size)
break;
}
if (ret < 0) /* error encountered. abort immediately */
return ret;
return summed_ret;
}
static int file_read(struct burn_source *source,
unsigned char *buffer,
int size)
{
struct burn_source_fd *fs = source->data;
return read_full_buffer(fs->datafd, buffer, size);
}
static int file_read_sub(struct burn_source *source,
unsigned char *buffer,
int size)
{
struct burn_source_file *fs = source->data;
return read_full_buffer(fs->subfd, buffer, size);
}
static void file_free(struct burn_source *source)
{
struct burn_source_file *fs = source->data;
close(fs->datafd);
if (source->read_sub)
close(fs->subfd);
free(fs);
}
static off_t file_size(struct burn_source *source)
{
struct stat buf;
struct burn_source_file *fs = source->data;
if (fstat(fs->datafd, &buf) == -1)
return (off_t) 0;
/* for now we keep it compatible to the old (int) return value */
if(buf.st_size >= 1308622848) /* 2 GB - 800 MB to prevent rollover */
return (off_t) 1308622848;
return (off_t) buf.st_size;
}
struct burn_source *burn_file_source_new(const char *path, const char *subpath)
{
struct burn_source_file *fs;
struct burn_source *src;
int fd1, fd2 = 0;
if (!path)
return NULL;
fd1 = open(path, O_RDONLY);
if (fd1 == -1)
return NULL;
if (subpath) {
fd2 = open(subpath, O_RDONLY);
if (fd2 == -1) {
close(fd1);
return NULL;
}
}
fs = malloc(sizeof(struct burn_source_file));
fs->datafd = fd1;
if (subpath)
fs->subfd = fd2;
src = burn_source_new();
src->read = file_read;
if (subpath)
src->read_sub = file_read_sub;
src->get_size = file_size;
src->free_data = file_free;
src->data = fs;
return src;
}
/* ------ provisory location for the new source subclass fd --------- */
static off_t fd_get_size(struct burn_source *source)
{
struct stat buf;
struct burn_source_fd *fs = source->data;
if (fs->fixed_size > 0)
return fs->fixed_size;
if (fstat(fs->datafd, &buf) == -1)
return (off_t) 0;
/* for now we keep it compatible to the old (int) return value */
if (buf.st_size >= 1308622848) /* 2 GB - 800 MB to prevent rollover */
return (off_t) 1308622848;
return buf.st_size;
}
static int fd_read(struct burn_source *source,
unsigned char *buffer,
int size)
{
struct burn_source_fd *fs = source->data;
return read_full_buffer(fs->datafd, buffer, size);
}
static int fd_read_sub(struct burn_source *source,
unsigned char *buffer,
int size)
{
struct burn_source_fd *fs = source->data;
return read_full_buffer(fs->subfd, buffer, size);
}
static void fd_free_data(struct burn_source *source)
{
struct burn_source_fd *fs = source->data;
close(fs->datafd);
if (source->read_sub)
close(fs->subfd);
free(fs);
}
struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size)
{
struct burn_source_fd *fs;
struct burn_source *src;
if (datafd == -1)
return NULL;
fs = malloc(sizeof(struct burn_source_fd));
fs->datafd = datafd;
fs->subfd = subfd;
fs->fixed_size = size;
src = burn_source_new();
src->read = fd_read;
if(subfd != -1)
src->read = fd_read_sub;
src->get_size = fd_get_size;
src->free_data = fd_free_data;
src->data = fs;
return src;
}

View File

@ -1,22 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef BURN__FILE_H
#define BURN__FILE_H
struct burn_source_file
{
int datafd;
int subfd;
};
/* ------ provisory location for the new source subclass fd --------- */
struct burn_source_fd
{
int datafd;
int subfd;
off_t fixed_size;
};
#endif /* LIBBURN__FILE_H */

View File

@ -1,246 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <unistd.h>
/* ts A61007 */
/* #include <a ssert.h> */
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include "init.h"
#include "sg.h"
#include "error.h"
#include "libburn.h"
#include "drive.h"
/* ts A60825 : The storage location for back_hacks.h variables. */
#define BURN_BACK_HACKS_INIT 1
#include "back_hacks.h"
/* ts A60924 : a new message handling facility */
#include "libdax_msgs.h"
struct libdax_msgs *libdax_messenger= NULL;
int burn_running = 0;
/* ts A60813 : wether to use O_EXCL and/or O_NONBLOCK in libburn/sg.c */
int burn_sg_open_o_excl = 1;
/* O_NONBLOCK was hardcoded in enumerate_ata() which i hardly use.
For enumerate_sg() it seems ok.
So it should stay default mode until enumerate_ata() without O_NONBLOCK
has been thoroughly tested. */
int burn_sg_open_o_nonblock = 1;
/* wether to take a busy drive as an error */
/* Caution: this is implemented by a rough hack and eventually leads
to unconditional abort of the process */
int burn_sg_open_abort_busy = 0;
/* ts A61002 */
#include "cleanup.h"
/* Parameters for builtin abort handler */
static char abort_message_prefix[81] = {"libburn : "};
static pid_t abort_control_pid= 0;
/* ts A60925 : ticket 74 */
/** Create the messenger object for libburn. */
int burn_msgs_initialize(void)
{
int ret;
if(libdax_messenger == NULL) {
ret = libdax_msgs_new(&libdax_messenger,0);
if (ret <= 0)
return 0;
}
libdax_msgs_set_severities(libdax_messenger, LIBDAX_MSGS_SEV_NEVER,
LIBDAX_MSGS_SEV_FATAL, "libburn: ", 0);
return 1;
}
/* ts A60924 : ticket 74 : Added use of global libdax_messenger */
int burn_initialize(void)
{
int ret;
if (burn_running)
return 1;
ret = burn_msgs_initialize();
if (ret <= 0)
return 0;
burn_running = 1;
return 1;
}
void burn_finish(void)
{
/* ts A61007 : assume no messageing system */
/* a ssert(burn_running); */
if (!burn_running)
return;
/* ts A61007 */
/* burn_wait_all(); */
if (!burn_drives_are_clear()) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020107,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Drive is busy on attempt to shut down library", 0, 0);
return;
}
/* ts A60904 : ticket 62, contribution by elmom : name addon "_all" */
burn_drive_free_all();
/* ts A60924 : ticket 74 */
libdax_msgs_destroy(&libdax_messenger,0);
burn_running = 0;
}
/* ts A60813 */
/** API function. See libburn.h */
void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy)
{
/* ts A61007 */
/* a ssert(burn_running); */
if (!burn_running)
return;
burn_sg_open_o_excl= exclusive;
burn_sg_open_o_nonblock= !blocking;
burn_sg_open_abort_busy= !!abort_on_busy;
}
/* ts A60924 : ticket 74 */
/** Control queueing and stderr printing of messages from libburn.
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 burn_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 burn_msgs_set_severities(char *queue_severity,
char *print_severity, char *print_id)
{
int ret, queue_sevno, print_sevno;
ret = libdax_msgs__text_to_sev(queue_severity, &queue_sevno, 0);
if (ret <= 0)
return 0;
ret = libdax_msgs__text_to_sev(print_severity, &print_sevno, 0);
if (ret <= 0)
return 0;
ret = libdax_msgs_set_severities(libdax_messenger, queue_sevno,
print_sevno, print_id, 0);
if (ret <= 0)
return 0;
return 1;
}
/* ts A60924 : ticket 74 */
#define BURM_MSGS_MESSAGE_LEN 4096
/** Obtain the oldest pending libburn 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 liste in
libburn/libdax_msgs.h
@param msg_text Must provide at least BURM_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 burn_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 libdax_msgs_item *item = NULL;
ret = libdax_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
if (ret <= 0)
return 0;
ret = libdax_msgs_obtain(libdax_messenger, &item, minimum_sevno,
LIBDAX_MSGS_PRIO_ZERO, 0);
if (ret <= 0)
goto ex;
ret = libdax_msgs_item_get_msg(item, error_code, &textpt, os_errno, 0);
if (ret <= 0)
goto ex;
strncpy(msg_text, textpt, BURM_MSGS_MESSAGE_LEN-1);
if(strlen(textpt) >= BURM_MSGS_MESSAGE_LEN)
msg_text[BURM_MSGS_MESSAGE_LEN-1] = 0;
severity[0]= 0;
ret = libdax_msgs_item_get_rank(item, &sevno, &priority, 0);
if(ret <= 0)
goto ex;
ret = libdax_msgs__sev_to_text(sevno, &sev_name, 0);
if(ret <= 0)
goto ex;
strcpy(severity,sev_name);
ret = 1;
ex:
libdax_msgs_destroy_item(libdax_messenger, &item, 0);
return ret;
}
int burn_builtin_abort_handler(void *handle, int signum, int flag)
{
if(getpid() != abort_control_pid)
return -2;
Cleanup_set_handlers(NULL, NULL, 2);
fprintf(stderr,"%sABORT : Trying to shut down drive and library\n",
abort_message_prefix);
fprintf(stderr,
"%sABORT : Wait the normal burning time before any kill -9\n",
abort_message_prefix);
close(0); /* somehow stdin as input blocks abort until EOF */
burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
fprintf(stderr,
"\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
abort_message_prefix);
return(1);
}
void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
int mode)
{
if(handler == NULL && mode == 0) {
handler = burn_builtin_abort_handler;
/*
fprintf(stderr, "libburn_experimental: activated burn_builtin_abort_handler() with handle '%s'\n",(handle==NULL ? "libburn : " : (char *) handle));
*/
}
strcpy(abort_message_prefix, "libburn : ");
if(handle != NULL)
strncpy(abort_message_prefix, (char *) handle,
sizeof(abort_message_prefix)-1);
abort_message_prefix[sizeof(abort_message_prefix)-1] = 0;
abort_control_pid= getpid();
Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler, mode|4);
}

View File

@ -1,8 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef BURN__INIT_H
#define BURN__INIT_H
extern int burn_running;
#endif /* BURN__INIT_H */

View File

@ -1,451 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* borrowed HEAVILY from cdrdao */
#include <string.h>
#include "lec.h"
#define LEC_HEADER_OFFSET 12
#define LEC_MODE1_P_PARITY_OFFSET 2076
#define LEC_MODE1_Q_PARITY_OFFSET 2248
static unsigned char gf8_ilog[255] = {
1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76,
152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96,
192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119,
238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186,
105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94,
188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187,
107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217,
175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103,
206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197,
151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79,
158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85,
170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99,
198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227,
219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87,
174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224,
221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195,
155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244,
245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125,
250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142,
};
static unsigned char gf8_log[256] = {
0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100,
224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113,
5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18,
130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9,
120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253,
226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143,
150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182,
163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61,
202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115,
243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222,
237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124,
17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188,
207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211,
171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31,
45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12,
111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134,
177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11,
245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231,
173, 232, 116, 214, 244, 234, 168, 80, 88, 175,
};
static unsigned char gf8_q_coeffs[2][45] = {
{97, 251, 133, 60, 82, 160, 155, 201, 8, 112, 246, 11, 21, 42, 157,
169, 80, 174, 232, 230, 172, 211, 241, 18, 68, 216, 44, 121, 9, 200,
75, 103, 221, 252, 96, 176, 88, 167, 114, 76, 199, 26, 1, 0, 0},
{190, 96, 250, 132, 59, 81, 159, 154, 200, 7, 111, 245, 10, 20, 41,
156, 168, 79, 173, 231, 229, 171, 210, 240, 17, 67, 215, 43, 120, 8,
199, 74, 102, 220, 251, 95, 175, 87, 166, 113, 75, 198, 25, 0, 0}
};
static unsigned char gf8_p_coeffs[2][26] = {
{230, 172, 211, 241, 18, 68, 216, 44, 121, 9, 200, 75, 103, 221, 252,
96, 176, 88, 167, 114, 76, 199, 26, 1, 0, 0},
{231, 229, 171, 210, 240, 17, 67, 215, 43, 120, 8, 199, 74, 102, 220,
251, 95, 175, 87, 166, 113, 75, 198, 25, 0, 0}
};
static unsigned char yellowbook_scrambler[2340] = {
1, 128, 0, 96, 0, 40, 0, 30, 128, 8, 96, 6, 168, 2, 254, 129, 128, 96,
96, 40, 40, 30, 158,
136, 104, 102, 174, 170, 252, 127, 1, 224, 0, 72, 0, 54, 128, 22, 224,
14, 200, 4, 86, 131, 126, 225,
224, 72, 72, 54, 182, 150, 246, 238, 198, 204, 82, 213, 253, 159, 1,
168, 0, 126, 128, 32, 96, 24, 40,
10, 158, 135, 40, 98, 158, 169, 168, 126, 254, 160, 64, 120, 48, 34,
148, 25, 175, 74, 252, 55, 1, 214,
128, 94, 224, 56, 72, 18, 182, 141, 182, 229, 182, 203, 54, 215, 86,
222, 190, 216, 112, 90, 164, 59, 59,
83, 83, 125, 253, 225, 129, 136, 96, 102, 168, 42, 254, 159, 0, 104, 0,
46, 128, 28, 96, 9, 232, 6,
206, 130, 212, 97, 159, 104, 104, 46, 174, 156, 124, 105, 225, 238,
200, 76, 86, 181, 254, 247, 0, 70, 128,
50, 224, 21, 136, 15, 38, 132, 26, 227, 75, 9, 247, 70, 198, 178, 210,
245, 157, 135, 41, 162, 158, 249,
168, 66, 254, 177, 128, 116, 96, 39, 104, 26, 174, 139, 60, 103, 81,
234, 188, 79, 49, 244, 20, 71, 79,
114, 180, 37, 183, 91, 54, 187, 86, 243, 126, 197, 224, 83, 8, 61, 198,
145, 146, 236, 109, 141, 237, 165,
141, 187, 37, 179, 91, 53, 251, 87, 3, 126, 129, 224, 96, 72, 40, 54,
158, 150, 232, 110, 206, 172, 84,
125, 255, 97, 128, 40, 96, 30, 168, 8, 126, 134, 160, 98, 248, 41, 130,
158, 225, 168, 72, 126, 182, 160,
118, 248, 38, 194, 154, 209, 171, 28, 127, 73, 224, 54, 200, 22, 214,
142, 222, 228, 88, 75, 122, 183, 99,
54, 169, 214, 254, 222, 192, 88, 80, 58, 188, 19, 49, 205, 212, 85,
159, 127, 40, 32, 30, 152, 8, 106,
134, 175, 34, 252, 25, 129, 202, 224, 87, 8, 62, 134, 144, 98, 236, 41,
141, 222, 229, 152, 75, 42, 183,
95, 54, 184, 22, 242, 142, 197, 164, 83, 59, 125, 211, 97, 157, 232,
105, 142, 174, 228, 124, 75, 97, 247,
104, 70, 174, 178, 252, 117, 129, 231, 32, 74, 152, 55, 42, 150, 159,
46, 232, 28, 78, 137, 244, 102, 199,
106, 210, 175, 29, 188, 9, 177, 198, 244, 82, 199, 125, 146, 161, 173,
184, 125, 178, 161, 181, 184, 119, 50,
166, 149, 186, 239, 51, 12, 21, 197, 207, 19, 20, 13, 207, 69, 148, 51,
47, 85, 220, 63, 25, 208, 10,
220, 7, 25, 194, 138, 209, 167, 28, 122, 137, 227, 38, 201, 218, 214,
219, 30, 219, 72, 91, 118, 187, 102,
243, 106, 197, 239, 19, 12, 13, 197, 197, 147, 19, 45, 205, 221, 149,
153, 175, 42, 252, 31, 1, 200, 0,
86, 128, 62, 224, 16, 72, 12, 54, 133, 214, 227, 30, 201, 200, 86, 214,
190, 222, 240, 88, 68, 58, 179,
83, 53, 253, 215, 1, 158, 128, 104, 96, 46, 168, 28, 126, 137, 224,
102, 200, 42, 214, 159, 30, 232, 8,
78, 134, 180, 98, 247, 105, 134, 174, 226, 252, 73, 129, 246, 224, 70,
200, 50, 214, 149, 158, 239, 40, 76,
30, 181, 200, 119, 22, 166, 142, 250, 228, 67, 11, 113, 199, 100, 82,
171, 125, 191, 97, 176, 40, 116, 30,
167, 72, 122, 182, 163, 54, 249, 214, 194, 222, 209, 152, 92, 106, 185,
239, 50, 204, 21, 149, 207, 47, 20,
28, 15, 73, 196, 54, 211, 86, 221, 254, 217, 128, 90, 224, 59, 8, 19,
70, 141, 242, 229, 133, 139, 35,
39, 89, 218, 186, 219, 51, 27, 85, 203, 127, 23, 96, 14, 168, 4, 126,
131, 96, 97, 232, 40, 78, 158,
180, 104, 119, 110, 166, 172, 122, 253, 227, 1, 137, 192, 102, 208, 42,
220, 31, 25, 200, 10, 214, 135, 30,
226, 136, 73, 166, 182, 250, 246, 195, 6, 209, 194, 220, 81, 153, 252,
106, 193, 239, 16, 76, 12, 53, 197,
215, 19, 30, 141, 200, 101, 150, 171, 46, 255, 92, 64, 57, 240, 18,
196, 13, 147, 69, 173, 243, 61, 133,
209, 163, 28, 121, 201, 226, 214, 201, 158, 214, 232, 94, 206, 184, 84,
114, 191, 101, 176, 43, 52, 31, 87,
72, 62, 182, 144, 118, 236, 38, 205, 218, 213, 155, 31, 43, 72, 31,
118, 136, 38, 230, 154, 202, 235, 23,
15, 78, 132, 52, 99, 87, 105, 254, 174, 192, 124, 80, 33, 252, 24, 65,
202, 176, 87, 52, 62, 151, 80,
110, 188, 44, 113, 221, 228, 89, 139, 122, 231, 99, 10, 169, 199, 62,
210, 144, 93, 172, 57, 189, 210, 241,
157, 132, 105, 163, 110, 249, 236, 66, 205, 241, 149, 132, 111, 35,
108, 25, 237, 202, 205, 151, 21, 174, 143,
60, 100, 17, 235, 76, 79, 117, 244, 39, 7, 90, 130, 187, 33, 179, 88,
117, 250, 167, 3, 58, 129, 211,
32, 93, 216, 57, 154, 146, 235, 45, 143, 93, 164, 57, 187, 82, 243,
125, 133, 225, 163, 8, 121, 198, 162,
210, 249, 157, 130, 233, 161, 142, 248, 100, 66, 171, 113, 191, 100,
112, 43, 100, 31, 107, 72, 47, 118, 156,
38, 233, 218, 206, 219, 20, 91, 79, 123, 116, 35, 103, 89, 234, 186,
207, 51, 20, 21, 207, 79, 20, 52,
15, 87, 68, 62, 179, 80, 117, 252, 39, 1, 218, 128, 91, 32, 59, 88, 19,
122, 141, 227, 37, 137, 219,
38, 219, 90, 219, 123, 27, 99, 75, 105, 247, 110, 198, 172, 82, 253,
253, 129, 129, 160, 96, 120, 40, 34,
158, 153, 168, 106, 254, 175, 0, 124, 0, 33, 192, 24, 80, 10, 188, 7,
49, 194, 148, 81, 175, 124, 124,
33, 225, 216, 72, 90, 182, 187, 54, 243, 86, 197, 254, 211, 0, 93, 192,
57, 144, 18, 236, 13, 141, 197,
165, 147, 59, 45, 211, 93, 157, 249, 169, 130, 254, 225, 128, 72, 96,
54, 168, 22, 254, 142, 192, 100, 80,
43, 124, 31, 97, 200, 40, 86, 158, 190, 232, 112, 78, 164, 52, 123, 87,
99, 126, 169, 224, 126, 200, 32,
86, 152, 62, 234, 144, 79, 44, 52, 29, 215, 73, 158, 182, 232, 118,
206, 166, 212, 122, 223, 99, 24, 41,
202, 158, 215, 40, 94, 158, 184, 104, 114, 174, 165, 188, 123, 49, 227,
84, 73, 255, 118, 192, 38, 208, 26,
220, 11, 25, 199, 74, 210, 183, 29, 182, 137, 182, 230, 246, 202, 198,
215, 18, 222, 141, 152, 101, 170, 171,
63, 63, 80, 16, 60, 12, 17, 197, 204, 83, 21, 253, 207, 1, 148, 0, 111,
64, 44, 48, 29, 212, 9,
159, 70, 232, 50, 206, 149, 148, 111, 47, 108, 28, 45, 201, 221, 150,
217, 174, 218, 252, 91, 1, 251, 64,
67, 112, 49, 228, 20, 75, 79, 119, 116, 38, 167, 90, 250, 187, 3, 51,
65, 213, 240, 95, 4, 56, 3,
82, 129, 253, 160, 65, 184, 48, 114, 148, 37, 175, 91, 60, 59, 81, 211,
124, 93, 225, 249, 136, 66, 230,
177, 138, 244, 103, 7, 106, 130, 175, 33, 188, 24, 113, 202, 164, 87,
59, 126, 147, 96, 109, 232, 45, 142,
157, 164, 105, 187, 110, 243, 108, 69, 237, 243, 13, 133, 197, 163, 19,
57, 205, 210, 213, 157, 159, 41, 168,
30, 254, 136, 64, 102, 176, 42, 244, 31, 7, 72, 2, 182, 129, 182, 224,
118, 200, 38, 214, 154, 222, 235,
24, 79, 74, 180, 55, 55, 86, 150, 190, 238, 240, 76, 68, 53, 243, 87,
5, 254, 131, 0, 97, 192, 40,
80, 30, 188, 8, 113, 198, 164, 82, 251, 125, 131, 97, 161, 232, 120,
78, 162, 180, 121, 183, 98, 246, 169,
134, 254, 226, 192, 73, 144, 54, 236, 22, 205, 206, 213, 148, 95, 47,
120, 28, 34, 137, 217, 166, 218, 250,
219, 3, 27, 65, 203, 112, 87, 100, 62, 171, 80, 127, 124, 32, 33, 216,
24, 90, 138, 187, 39, 51, 90,
149, 251, 47, 3, 92, 1, 249, 192, 66, 208, 49, 156, 20, 105, 207, 110,
212, 44, 95, 93, 248, 57, 130,
146, 225, 173, 136, 125, 166, 161, 186, 248, 115, 2, 165, 193, 187, 16,
115, 76, 37, 245, 219, 7, 27, 66,
139, 113, 167, 100, 122, 171, 99, 63, 105, 208, 46, 220, 28, 89, 201,
250, 214, 195, 30, 209, 200, 92, 86,
185, 254, 242, 192, 69, 144, 51, 44, 21, 221, 207, 25, 148, 10, 239,
71, 12, 50, 133, 213, 163, 31, 57,
200, 18, 214, 141, 158, 229, 168, 75, 62, 183, 80, 118, 188, 38, 241,
218, 196, 91, 19, 123, 77, 227, 117,
137, 231, 38, 202, 154, 215, 43, 30, 159, 72, 104, 54, 174, 150, 252,
110, 193, 236, 80, 77, 252, 53, 129,
215, 32, 94, 152, 56, 106, 146, 175, 45, 188, 29, 177, 201, 180, 86,
247, 126, 198, 160, 82, 248, 61, 130,
145, 161, 172, 120, 125, 226, 161, 137, 184, 102, 242, 170, 197, 191,
19, 48, 13, 212, 5, 159, 67, 40, 49,
222, 148, 88, 111, 122, 172, 35, 61, 217, 209, 154, 220, 107, 25, 239,
74, 204, 55, 21, 214, 143, 30, 228,
8, 75, 70, 183, 114, 246, 165, 134, 251, 34, 195, 89, 145, 250, 236,
67, 13, 241, 197, 132, 83, 35, 125,
217, 225, 154, 200, 107, 22, 175, 78, 252, 52, 65, 215, 112, 94, 164,
56, 123, 82, 163, 125, 185, 225, 178,
200, 117, 150, 167, 46, 250, 156, 67, 41, 241, 222, 196, 88, 83, 122,
189, 227, 49, 137, 212, 102, 223, 106,
216, 47, 26, 156, 11, 41, 199, 94, 210, 184, 93, 178, 185, 181, 178,
247, 53, 134, 151, 34, 238, 153, 140,
106, 229, 239, 11, 12, 7, 69, 194, 179, 17, 181, 204, 119, 21, 230,
143, 10, 228, 7, 11, 66, 135, 113,
162, 164, 121, 187, 98, 243, 105, 133, 238, 227, 12, 73, 197, 246, 211,
6, 221, 194, 217, 145, 154, 236, 107,
13, 239, 69, 140, 51, 37, 213, 219, 31, 27, 72, 11, 118, 135, 102, 226,
170, 201, 191, 22, 240, 14, 196,
4, 83, 67, 125, 241, 225, 132, 72, 99, 118, 169, 230, 254, 202, 192,
87, 16, 62, 140, 16, 101, 204, 43,
21, 223, 79, 24, 52, 10, 151, 71, 46, 178, 156, 117, 169, 231, 62, 202,
144, 87, 44, 62, 157, 208, 105,
156, 46, 233, 220, 78, 217, 244, 90, 199, 123, 18, 163, 77, 185, 245,
178, 199, 53, 146, 151, 45, 174, 157,
188, 105, 177, 238, 244, 76, 71, 117, 242, 167, 5, 186, 131, 51, 33,
213, 216, 95, 26, 184, 11, 50, 135,
85, 162, 191, 57, 176, 18, 244, 13, 135, 69, 162, 179, 57, 181, 210,
247, 29, 134, 137, 162, 230, 249, 138,
194, 231, 17, 138, 140, 103, 37, 234, 155, 15, 43, 68, 31, 115, 72, 37,
246, 155, 6, 235, 66, 207, 113,
148, 36, 111, 91, 108, 59, 109, 211, 109, 157, 237, 169, 141, 190, 229,
176, 75, 52, 55, 87, 86, 190, 190,
240, 112, 68, 36, 51, 91, 85, 251, 127, 3, 96, 1, 232, 0, 78, 128, 52,
96, 23, 104, 14, 174, 132,
124, 99, 97, 233, 232, 78, 206, 180, 84, 119, 127, 102, 160, 42, 248,
31, 2, 136, 1, 166, 128, 122, 224,
35, 8, 25, 198, 138, 210, 231, 29, 138, 137, 167, 38, 250, 154, 195,
43, 17, 223, 76, 88, 53, 250, 151,
3, 46, 129, 220, 96, 89, 232, 58, 206, 147, 20, 109, 207, 109, 148, 45,
175, 93, 188, 57, 177, 210, 244,
93, 135, 121, 162, 162, 249, 185, 130, 242, 225, 133, 136, 99, 38, 169,
218, 254, 219, 0, 91, 64, 59, 112,
19, 100, 13, 235, 69, 143, 115, 36, 37, 219, 91, 27, 123, 75, 99, 119,
105, 230, 174, 202, 252, 87, 1,
254, 128, 64, 96, 48, 40, 20, 30, 143, 72, 100, 54, 171, 86, 255, 126,
192, 32, 80, 24, 60, 10, 145,
199, 44, 82, 157, 253, 169, 129, 190, 224, 112, 72, 36, 54, 155, 86,
235, 126, 207, 96, 84, 40, 63, 94,
144, 56, 108, 18, 173, 205, 189, 149, 177, 175, 52, 124, 23, 97, 206,
168, 84, 126, 191, 96, 112, 40, 36,
30, 155, 72, 107, 118, 175, 102, 252, 42, 193, 223, 16, 88, 12, 58,
133, 211, 35, 29, 217, 201, 154, 214,
235, 30, 207, 72, 84, 54, 191, 86, 240, 62, 196, 16, 83, 76, 61, 245,
209, 135, 28, 98, 137, 233, 166,
206, 250, 212, 67, 31, 113, 200, 36, 86, 155, 126, 235, 96, 79, 104,
52, 46, 151, 92, 110, 185, 236, 114,
205, 229, 149, 139, 47, 39, 92, 26, 185, 203, 50, 215, 85, 158, 191,
40, 112, 30, 164, 8, 123, 70, 163,
114, 249, 229, 130, 203, 33, 151, 88, 110, 186, 172, 115, 61, 229, 209,
139, 28, 103, 73, 234, 182, 207, 54,
212, 22, 223, 78, 216, 52, 90, 151, 123, 46, 163, 92, 121, 249, 226,
194, 201, 145, 150, 236, 110, 205, 236,
85, 141, 255, 37, 128, 27, 32, 11, 88, 7, 122, 130, 163, 33, 185, 216,
114, 218, 165, 155, 59, 43, 83,
95, 125, 248, 33, 130, 152, 97, 170, 168, 127, 62, 160, 16, 120, 12,
34, 133, 217, 163, 26, 249, 203, 2,
215, 65, 158, 176, 104, 116, 46, 167, 92, 122, 185, 227, 50, 201, 213,
150, 223, 46, 216, 28, 90, 137, 251,
38, 195, 90, 209, 251, 28, 67, 73, 241, 246, 196, 70, 211, 114, 221,
229, 153,
};
void scramble(unsigned char *inout)
{
unsigned char *r = inout + 12;
unsigned char *s = yellowbook_scrambler;
unsigned int i;
for (i = 2340; i; i--) {
*r++ ^= *s++;
}
}
/* Calculate the P parities for the sector.
* The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
*/
void parity_p(unsigned char *sector)
{
int i, j;
unsigned char p0_msb, p1_msb;
unsigned char p0_lsb, p1_lsb;
unsigned char *p_msb_start, *p_lsb_start;
unsigned char *p_msb, *p_lsb;
unsigned char *coeffs0, *coeffs1;
unsigned char *p0, *p1;
unsigned char d;
unsigned short c;
p_lsb_start = sector + LEC_HEADER_OFFSET;
p_msb_start = sector + LEC_HEADER_OFFSET + 1;
p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
for (i = 0; i <= 42; i++) {
p_lsb = p_lsb_start;
p_msb = p_msb_start;
coeffs0 = gf8_p_coeffs[0];
coeffs1 = gf8_p_coeffs[1];
p0_lsb = p1_lsb = p0_msb = p1_msb = 0;
for (j = 0; j <= 23; j++) {
d = *p_lsb;
if (d != 0) {
c = gf8_log[d] + *coeffs0;
if (c >= 255)
c -= 255;
p0_lsb ^= gf8_ilog[c];
c = gf8_log[d] + *coeffs1;
if (c >= 255)
c -= 255;
p1_lsb ^= gf8_ilog[c];
}
d = *p_msb;
if (d != 0) {
c = gf8_log[d] + *coeffs0;
if (c >= 255)
c -= 255;
p0_msb ^= gf8_ilog[c];
c = gf8_log[d] + *coeffs1;
if (c >= 255)
c -= 255;
p1_msb ^= gf8_ilog[c];
}
coeffs0++;
coeffs1++;
p_lsb += 2 * 43;
p_msb += 2 * 43;
}
*p0 = p0_lsb;
*(p0 + 1) = p0_msb;
*p1 = p1_lsb;
*(p1 + 1) = p1_msb;
p0 += 2;
p1 += 2;
p_lsb_start += 2;
p_msb_start += 2;
}
}
/* Calculate the Q parities for the sector.
* The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
*/
void parity_q(unsigned char *sector)
{
int i, j;
unsigned char q0_msb, q1_msb;
unsigned char q0_lsb, q1_lsb;
unsigned char *q_msb_start, *q_lsb_start;
unsigned char *q_msb, *q_lsb;
unsigned char *coeffs0, *coeffs1;
unsigned char *q0, *q1, *q_start;
unsigned char d;
unsigned short c;
q_lsb_start = sector + LEC_HEADER_OFFSET;
q_msb_start = sector + LEC_HEADER_OFFSET + 1;
q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
for (i = 0; i <= 25; i++) {
q_lsb = q_lsb_start;
q_msb = q_msb_start;
coeffs0 = gf8_q_coeffs[0];
coeffs1 = gf8_q_coeffs[1];
q0_lsb = q1_lsb = q0_msb = q1_msb = 0;
for (j = 0; j <= 42; j++) {
d = *q_lsb;
if (d != 0) {
c = gf8_log[d] + *coeffs0;
if (c >= 255)
c -= 255;
q0_lsb ^= gf8_ilog[c];
c = gf8_log[d] + *coeffs1;
if (c >= 255)
c -= 255;
q1_lsb ^= gf8_ilog[c];
}
d = *q_msb;
if (d != 0) {
c = gf8_log[d] + *coeffs0;
if (c >= 255)
c -= 255;
q0_msb ^= gf8_ilog[c];
c = gf8_log[d] + *coeffs1;
if (c >= 255)
c -= 255;
q1_msb ^= gf8_ilog[c];
}
coeffs0++;
coeffs1++;
q_lsb += 2 * 44;
q_msb += 2 * 44;
if (q_lsb >= q_start) {
q_msb -= 2 * 1118;
q_lsb -= 2 * 1118;
}
}
*q0 = q0_lsb;
*(q0 + 1) = q0_msb;
*q1 = q1_lsb;
*(q1 + 1) = q1_msb;
q0 += 2;
q1 += 2;
q_lsb_start += 2 * 43;
q_msb_start += 2 * 43;
}
}

View File

@ -1,12 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __LEC
#define __LEC
#define RS_L12_BITS 8
void scramble(unsigned char *);
void parity_p(unsigned char *in);
void parity_q(unsigned char *in);
#endif /* __LEC */

File diff suppressed because it is too large Load Diff

View File

@ -1,326 +0,0 @@
/* libdax_audioxtr
Audio track data extraction facility of libdax and libburn.
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
/* Only this single source module is entitled to do this */
#define LIBDAX_AUDIOXTR_H_INTERNAL 1
/* All clients of the extraction facility must do this */
#include "libdax_audioxtr.h"
int libdax_audioxtr_new(struct libdax_audioxtr **xtr, char *path, int flag)
{
int ret= -1;
struct libdax_audioxtr *o;
o= *xtr= (struct libdax_audioxtr *) malloc(sizeof(struct libdax_audioxtr));
if(o==NULL)
return(-1);
strncpy(o->path,path,LIBDAX_AUDIOXTR_STRLEN-1);
o->path[LIBDAX_AUDIOXTR_STRLEN]= 0;
o->fd= -1;
strcpy(o->fmt,"unidentified");
o->fmt_info[0]= 0;
o->data_size= 0;
o->extract_count= 0;
o->num_channels= 0;
o->sample_rate= 0;
o->bits_per_sample= 0;
o->msb_first= 0;
o->wav_subchunk2_size= 0;
o->au_data_location= 0;
o->au_data_size= 0xffffffff;
ret= libdax_audioxtr_open(o,0);
if(ret<=0)
{ret= -2*(ret<0); goto failure;}
return(1);
failure:
libdax_audioxtr_destroy(xtr,0);
return(ret);
}
int libdax_audioxtr_destroy(struct libdax_audioxtr **xtr, int flag)
{
struct libdax_audioxtr *o;
o= *xtr;
if(o==NULL)
return(0);
if(o->fd>=0 && strcmp(o->path,"-")!=0)
close(o->fd);
free((char *) o);
*xtr= NULL;
return(1);
}
static int libdax_audioxtr_open(struct libdax_audioxtr *o, int flag)
{
int ret;
char msg[LIBDAX_AUDIOXTR_STRLEN+80];
if(strcmp(o->path,"-")==0)
o->fd= 0;
else
o->fd= open(o->path, O_RDONLY);
if(o->fd<0) {
sprintf(msg,"Cannot open audio source file : %s",o->path);
libdax_msgs_submit(libdax_messenger,-1,0x00020200,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, errno, 0);
return(-1);
}
ret= libdax_audioxtr_identify(o,0);
if(ret<=0) {
sprintf(msg,"Audio source file has unsuitable format : %s",o->path);
libdax_msgs_submit(libdax_messenger,-1,0x00020201,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
return(0);
}
ret= libdax_audioxtr_init_reading(o,0);
if(ret<=0) {
sprintf(msg,"Failed to prepare reading of audio data : %s",o->path);
libdax_msgs_submit(libdax_messenger,-1,0x00020202,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
return(0);
}
return(1);
}
static int libdax_audioxtr_identify_wav(struct libdax_audioxtr *o, int flag)
{
int ret;
char buf[45];
/* check wether this is a MS WAVE file .wav */
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
if(o->fd!=0) {
ret= lseek(o->fd,0,SEEK_SET);
if(ret==-1)
return(0);
}
ret= read(o->fd, buf, 44);
if(ret<44)
return(0);
buf[44]= 0; /* as stopper for any string operations */
if(strncmp(buf,"RIFF",4)!=0) /* ChunkID */
return(0);
if(strncmp(buf+8,"WAVE",4)!=0) /* Format */
return(0);
if(strncmp(buf+12,"fmt ",4)!=0) /* Subchunk1ID */
return(0);
if(buf[16]!=16 || buf[17]!=0 || buf[18]!=0 || buf[19]!=0) /* Subchunk1Size */
return(0);
if(buf[20]!=1 || buf[21]!=0) /* AudioFormat must be 1 (Linear quantization) */
return(0);
strcpy(o->fmt,".wav");
o->msb_first= 0;
o->num_channels= libdax_audioxtr_to_int(o,(unsigned char *) buf+22,2,0);
o->sample_rate= libdax_audioxtr_to_int(o,(unsigned char *) buf+24,4,0);
o->bits_per_sample= libdax_audioxtr_to_int(o,(unsigned char *)buf+34,2,0);
sprintf(o->fmt_info,
".wav , num_channels=%d , sample_rate=%d , bits_per_sample=%d",
o->num_channels,o->sample_rate,o->bits_per_sample);
o->wav_subchunk2_size= libdax_audioxtr_to_int(o,(unsigned char *)buf+40,4,0);
o->data_size= o->wav_subchunk2_size;
return(1);
}
static int libdax_audioxtr_identify_au(struct libdax_audioxtr *o, int flag)
{
int ret,encoding;
char buf[24];
/* Check wether this is a Sun Audio, .au file */
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
if(o->fd!=0) {
ret= lseek(o->fd,0,SEEK_SET);
if(ret==-1)
return(0);
}
ret= read(o->fd, buf, 24);
if(ret<24)
return(0);
if(strncmp(buf,".snd",4)!=0)
return(0);
strcpy(o->fmt,".au");
o->msb_first= 1;
o->au_data_location= libdax_audioxtr_to_int(o,(unsigned char *)buf+4,4,1);
o->au_data_size= libdax_audioxtr_to_int(o,(unsigned char *)buf+8,4,1);
encoding= libdax_audioxtr_to_int(o,(unsigned char *)buf+12,4,1);
if(encoding==2)
o->bits_per_sample= 8;
else if(encoding==3)
o->bits_per_sample= 16;
else if(encoding==4)
o->bits_per_sample= 24;
else if(encoding==5)
o->bits_per_sample= 32;
else
o->bits_per_sample= -encoding;
o->sample_rate= libdax_audioxtr_to_int(o,(unsigned char *)buf+16,4,1);
o->num_channels= libdax_audioxtr_to_int(o,(unsigned char *)buf+20,4,1);
if(o->au_data_size!=0xffffffff)
o->data_size= o->au_data_size;
else
o->data_size= 0;
sprintf(o->fmt_info,
".au , num_channels=%d , sample_rate=%d , bits_per_sample=%d",
o->num_channels,o->sample_rate,o->bits_per_sample);
/* <<< for testing only */;
return(1);
return(o->bits_per_sample>0); /* Audio format must be linear PCM */
}
static int libdax_audioxtr_identify(struct libdax_audioxtr *o, int flag)
{
int ret;
ret= libdax_audioxtr_identify_wav(o, 0);
if(ret!=0)
return(ret);
if(o->fd==0) /* cannot rewind stdin */
return(0);
ret= libdax_audioxtr_identify_au(o, 0);
if(ret!=0)
return(ret);
return(0);
}
/* @param flag bit0=msb_first */
static unsigned libdax_audioxtr_to_int(struct libdax_audioxtr *o,
unsigned char *bytes, int len, int flag)
{
unsigned int ret= 0;
int i;
if(flag&1)
for(i= 0; i<len; i++)
ret= ret*256+bytes[i];
else
for(i= len-1; i>=0; i--)
ret= ret*256+bytes[i];
return(ret);
}
static int libdax_audioxtr_init_reading(struct libdax_audioxtr *o, int flag)
{
int ret;
/* currently this only works for MS WAVE files .wav and Sun .au*/;
if(o->fd==0) /* stdin: hope no read came after libdax_audioxtr_identify() */
return(1);
o->extract_count= 0;
if(strcmp(o->fmt,".wav")==0)
ret= lseek(o->fd,44,SEEK_SET);
else if(strcmp(o->fmt,".au")==0)
ret= lseek(o->fd,o->au_data_location,SEEK_SET);
else
ret= -1;
if(ret==-1)
return(0);
return(1);
}
int libdax_audioxtr_get_id(struct libdax_audioxtr *o,
char **fmt, char **fmt_info,
int *num_channels, int *sample_rate, int *bits_per_sample,
int *msb_first, int flag)
{
*fmt= o->fmt;
*fmt_info= o->fmt_info;
*num_channels= o->num_channels;
*sample_rate= o->sample_rate;
*bits_per_sample= o->bits_per_sample;
*msb_first= o->msb_first;
return(1);
}
int libdax_audioxtr_get_size(struct libdax_audioxtr *o, off_t *size, int flag)
{
*size= o->data_size;
return(1);
}
int libdax_audioxtr_read(struct libdax_audioxtr *o,
char buffer[], int buffer_size, int flag)
{
int ret;
if(buffer_size<=0 || o->fd<0)
return(-2);
if(o->data_size>0 && !(flag&1))
if(buffer_size > o->data_size - o->extract_count)
buffer_size= o->data_size - o->extract_count;
if(buffer_size<=0)
return(0);
ret= read(o->fd,buffer,buffer_size);
if(ret>0)
o->extract_count+= ret;
return(ret);
}
int libdax_audioxtr_detach_fd(struct libdax_audioxtr *o, int *fd, int flag)
{
if(o->fd<0)
return(-1);
if(strcmp(o->fmt,".wav")!=0 && strcmp(o->fmt,".au")!=0)
return(0);
if(flag&1) {
*fd= o->fd;
} else {
*fd= dup(o->fd);
if(*fd>=0 && strcmp(o->path,"-")!=0)
close(o->fd);
}
if(*fd>=0) {
o->fd= -1;
return(1);
}
return(-1);
}

View File

@ -1,229 +0,0 @@
/* libdax_audioxtr
Audio track data extraction facility of libdax and libburn.
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
*/
#ifndef LIBDAX_AUDIOXTR_H_INCLUDED
#define LIBDAX_AUDIOXTR_H_INCLUDED 1
/* Public Macros */
/* Maximum size for address paths and fmt_info strings */
#define LIBDAX_AUDIOXTR_STRLEN 4096
/* Public Opaque Handles */
/** Extractor object encapsulating intermediate states of extraction.
The clients of libdax_audioxtr shall only allocate pointers to this
struct and get a storage object via libdax_audioxtr_new().
Appropriate initial value for the pointer is NULL.
*/
struct libdax_audioxtr;
/* Public Functions */
/* Calls initiated from inside libdax/libburn */
/* Calls from applications (to be forwarded by libdax/libburn) */
/** Open an audio file, check wether suitable, create extractor object.
@param xtr Opaque handle to extractor. Gets attached extractor object.
@param path Address of the audio file to extract. "-" is stdin (but might
be not suitable for all futurely supported formats).
@param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success
0 unsuitable format
-1 severe error
-2 path not found
*/
int libdax_audioxtr_new(struct libdax_audioxtr **xtr, char *path, int flag);
/** Obtain identification parameters of opened audio source.
@param xtr Opaque handle to extractor
@param fmt Gets pointed to the audio file format id text: ".wav" , ".au"
@param fmt_info Gets pointed to a format info text telling parameters
@param num_channels e.g. 1=mono, 2=stereo, etc
@param sample_rate e.g. 11025, 44100
@param bits_per_sample e.g. 8= 8 bits per sample, 16= 16 bits ...
@param msb_first Byte order of samples: 0=Intel 1=Motorola
@param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success, <=0 failure
*/
int libdax_audioxtr_get_id(struct libdax_audioxtr *xtr,
char **fmt, char **fmt_info,
int *num_channels, int *sample_rate,
int *bits_per_sample, int *msb_first, int flag);
/** Obtain a prediction about the extracted size based on internal information
of the formatted file.
@param xtr Opaque handle to extractor
@param size Gets filled with the predicted size
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 prediction was possible , 0 no prediction could be made
*/
int libdax_audioxtr_get_size(struct libdax_audioxtr *o, off_t *size, int flag);
/** Obtain next buffer full of extracted data in desired format (only raw audio
for now).
@param xtr Opaque handle to extractor
@param buffer Gets filled with extracted data
@param buffer_size Maximum number of bytes to be filled into buffer
@param flag Bitfield for control purposes
bit0= do not stop at predicted end of data
@return >0 number of valid buffer bytes,
0 End of file
-1 operating system reports error
-2 usage error by application
*/
int libdax_audioxtr_read(struct libdax_audioxtr *xtr,
char buffer[], int buffer_size, int flag);
/** Try to obtain a file descriptor which will deliver extracted data
to normal calls of read(2). This may fail because the format is
unsuitable for that, but ".wav" is ok. If this call succeeds the xtr
object will have forgotten its file descriptor and libdax_audioxtr_read()
will return a usage error. One may use *fd after libdax_audioxtr_destroy()
and will have to close it via close(2) when done with it.
@param xtr Opaque handle to extractor
@param fd Eventually returns the file descriptor number
@param flag Bitfield for control purposes
bit0= do not dup(2) and close(2) but hand out original fd
@return 1 success, 0 cannot hand out fd , -1 severe error
*/
int libdax_audioxtr_detach_fd(struct libdax_audioxtr *o, int *fd, int flag);
/** Clean up after extraction and destroy extractor object.
@param xtr Opaque handle to extractor, *xtr is allowed to be NULL,
*xtr is set to NULL by this function
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 = destroyed object, 0 = was already destroyed
*/
int libdax_audioxtr_destroy(struct libdax_audioxtr **xtr, int flag);
#ifdef LIDBAX_AUDIOXTR________________
-- place documentation text here ---
#endif /* LIDBAX_AUDIOXTR_________________ */
/*
*Never* set this macro outside libdax_audioxtr.c !
The entrails of this facility are not to be seen by
the other library components or the applications.
*/
#ifdef LIBDAX_AUDIOXTR_H_INTERNAL
/* Internal Structures */
/** Extractor object encapsulating intermediate states of extraction */
struct libdax_audioxtr {
/* Source of the encoded audio data */
char path[LIBDAX_AUDIOXTR_STRLEN];
/* File descriptor to path. Anything else than 0 must be lseek-able */
int fd;
/* Format identifier. E.g. ".wav" */
char fmt[80];
/* Format parameter info text */
char fmt_info[LIBDAX_AUDIOXTR_STRLEN];
/* 1= mono, 2= stereo, etc. */
int num_channels;
/* 8000, 44100, etc. */
int sample_rate;
/* 8 bits = 8, 16 bits = 16, etc. */
int bits_per_sample;
/* Byte order of samples: 0=Intel 1=Motorola */
int msb_first;
/* Number of bytes to extract (0= unknown/unlimited) */
off_t data_size;
/* Number of extracted data bytes */
off_t extract_count;
/* Format dependent parameters */
/* MS WAVE Format */
/* info used: http://ccrma.stanford.edu/courses/422/projects/WaveFormat/ */
/* == NumSamples * NumChannels * BitsPerSample/8
This is the number of bytes in the data. */
unsigned wav_subchunk2_size;
/* Sun Audio, .au */
/* info used: http://www.opengroup.org/public/pubs/external/auformat.html */
/* Number of bytes in non-payload header part */
unsigned au_data_location;
/* Number of payload bytes or 0xffffffff */
unsigned au_data_size;
};
/* Internal Functions */
/** Open the audio source pointed to by .path and evaluate suitability.
@return -1 failure to open, 0 unsuitable format, 1 success
*/
static int libdax_audioxtr_open(struct libdax_audioxtr *o, int flag);
/** Identify format and evaluate suitability.
@return 0 unsuitable format, 1 format is suitable
*/
static int libdax_audioxtr_identify(struct libdax_audioxtr *o, int flag);
/** Specialized identifier for .wav */
static int libdax_audioxtr_identify_wav(struct libdax_audioxtr *o, int flag);
/** Specialized identifier for .au */
static int libdax_audioxtr_identify_au(struct libdax_audioxtr *o, int flag);
/** Convert a byte string into a number (currently only little endian)
@param flag Bitfield for control purposes
bit0=msb_first
@return The resulting number
*/
static unsigned libdax_audioxtr_to_int(struct libdax_audioxtr *o,
unsigned char *bytes, int len, int flag);
/** Prepare for reading of first buffer.
@return 0 error, 1 success
*/
static int libdax_audioxtr_init_reading(struct libdax_audioxtr *o, int flag);
#endif /* LIBDAX_AUDIOXTR_H_INTERNAL */
#endif /* ! LIBDAX_AUDIOXTR_H_INCLUDED */

View File

@ -1,906 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* ts A61009 */
/* #include <a ssert.h> */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include "error.h"
#include "sector.h"
#include "libburn.h"
#include "transport.h"
#include "mmc.h"
#include "spc.h"
#include "drive.h"
#include "debug.h"
#include "toc.h"
#include "structure.h"
#include "options.h"
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif /* Libburn_log_in_and_out_streaM */
/* ts A61005 */
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
static unsigned char MMC_GET_TOC[] = { 0x43, 2, 2, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_GET_ATIP[] = { 0x43, 2, 4, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_GET_DISC_INFO[] =
{ 0x51, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_READ_CD[] = { 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_ERASE[] = { 0xA1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_SEND_OPC[] = { 0x54, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_SET_SPEED[] =
{ 0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_WRITE_12[] =
{ 0xAA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_WRITE_10[] = { 0x2A, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_GET_CONFIGURATION[] =
{ 0x46, 0, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_SYNC_CACHE[] = { 0x35, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_GET_EVENT[] = { 0x4A, 1, 0, 0, 16, 0, 0, 0, 8, 0 };
static unsigned char MMC_CLOSE[] = { 0x5B, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_TRACK_INFO[] = { 0x52, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_SEND_CUE_SHEET[] =
{ 0x5D, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* ts A61023 : get size and free space of drive buffer */
static unsigned char MMC_READ_BUFFER_CAPACITY[] = { 0x5C, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
static int mmc_function_spy_do_tell = 0;
int mmc_function_spy(char * text)
{
if (mmc_function_spy_do_tell)
fprintf(stderr,"libburn: experimental: mmc_function_spy: %s\n",
text);
return 1;
}
int mmc_function_spy_ctrl(int do_tell)
{
mmc_function_spy_do_tell= !!do_tell;
return 1;
}
void mmc_send_cue_sheet(struct burn_drive *d, struct cue_sheet *s)
{
struct buffer buf;
struct command c;
mmc_function_spy("mmc_send_cue_sheet");
c.retry = 1;
c.oplen = sizeof(MMC_SEND_CUE_SHEET);
memcpy(c.opcode, MMC_SEND_CUE_SHEET, sizeof(MMC_SEND_CUE_SHEET));
c.page = &buf;
c.page->bytes = s->count * 8;
c.page->sectors = 0;
c.opcode[6] = (c.page->bytes >> 16) & 0xFF;
c.opcode[7] = (c.page->bytes >> 8) & 0xFF;
c.opcode[8] = c.page->bytes & 0xFF;
c.dir = TO_DRIVE;
memcpy(c.page->data, s->data, c.page->bytes);
d->issue_command(d, &c);
}
/* ts A61110 : added parameters trackno, lba, nwa. Redefined return value.
@return 1=nwa is valid , 0=nwa is not valid , -1=error */
int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
{
struct buffer buf;
struct command c;
unsigned char *data;
mmc_function_spy("mmc_get_nwa");
c.retry = 1;
c.oplen = sizeof(MMC_TRACK_INFO);
memcpy(c.opcode, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO));
c.opcode[1] = 1;
if(trackno<=0)
c.opcode[5] = 0xFF;
else
c.opcode[5] = trackno;
c.page = &buf;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
data = c.page->data;
*lba = (data[8] << 24) + (data[9] << 16)
+ (data[10] << 8) + data[11];
*nwa = (data[12] << 24) + (data[13] << 16)
+ (data[14] << 8) + data[15];
/* ts A61106 : MMC-1 Table 142 : NWA_V = NWA Valid Flag */
if (!(data[7]&1)) {
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
"mmc_get_nwa: Track Info Block: NWA_V == 0", 0, 0);
return 0;
}
return 1;
}
/* ts A61009 : function is obviously unused. */
/* void mmc_close_disc(struct burn_drive *d, struct burn_write_opts *o) */
void mmc_close_disc(struct burn_write_opts *o)
{
struct burn_drive *d;
mmc_function_spy("mmc_close_disc");
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
"HOW THAT ? mmc_close_disc() was called", 0, 0);
/* ts A61009 : made impossible by removing redundant parameter d */
/* a ssert(o->drive == d); */
d = o->drive;
o->multi = 0;
spc_select_write_params(d, o);
mmc_close(d, 1, 0);
}
/* ts A61009 : function is obviously unused. */
/* void mmc_close_session(struct burn_drive *d, struct burn_write_opts *o) */
void mmc_close_session(struct burn_write_opts *o)
{
struct burn_drive *d;
mmc_function_spy("mmc_close_session");
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
"HOW THAT ? mmc_close_session() was called", 0, 0);
/* ts A61009 : made impossible by removing redundant parameter d */
/* a ssert(o->drive == d); */
d = o->drive;
o->multi = 3;
spc_select_write_params(d, o);
mmc_close(d, 1, 0);
}
void mmc_close(struct burn_drive *d, int session, int track)
{
struct command c;
mmc_function_spy("mmc_close");
c.retry = 1;
c.oplen = sizeof(MMC_CLOSE);
memcpy(c.opcode, MMC_CLOSE, sizeof(MMC_CLOSE));
/* ts A61030 : shifted !!session rather than or-ing plain session */
c.opcode[2] = ((!!session)<<1) | !!track;
c.opcode[4] = track >> 8;
c.opcode[5] = track & 0xFF;
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void mmc_get_event(struct burn_drive *d)
{
struct buffer buf;
struct command c;
mmc_function_spy("mmc_get_event");
c.retry = 1;
c.oplen = sizeof(MMC_GET_EVENT);
memcpy(c.opcode, MMC_GET_EVENT, sizeof(MMC_GET_EVENT));
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
burn_print(12, "0x%x:0x%x:0x%x:0x%x\n",
c.page->data[0], c.page->data[1], c.page->data[2],
c.page->data[3]);
burn_print(12, "event: %d:%d:%d:%d\n", c.page->data[4],
c.page->data[5], c.page->data[6], c.page->data[7]);
}
void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf)
{
struct command c;
int len;
mmc_function_spy("mmc_write_12");
len = buf->sectors;
/* ts A61009 */
/* a ssert(buf->bytes >= buf->sectors);*/ /* can be == at 0... */
burn_print(100, "trying to write %d at %d\n", len, start);
memcpy(c.opcode, MMC_WRITE_12, sizeof(MMC_WRITE_12));
c.retry = 1;
c.oplen = sizeof(MMC_WRITE_12);
c.opcode[2] = start >> 24;
c.opcode[3] = (start >> 16) & 0xFF;
c.opcode[4] = (start >> 8) & 0xFF;
c.opcode[5] = start & 0xFF;
c.opcode[6] = len >> 24;
c.opcode[7] = (len >> 16) & 0xFF;
c.opcode[8] = (len >> 8) & 0xFF;
c.opcode[9] = len & 0xFF;
c.page = buf;
c.dir = TO_DRIVE;
d->issue_command(d, &c);
}
int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
{
int cancelled;
struct command c;
int len;
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
static int tee_fd= -1;
if(tee_fd==-1)
tee_fd= open("/tmp/libburn_sg_written",
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
#endif /* Libburn_log_in_and_out_streaM */
mmc_function_spy("mmc_write");
pthread_mutex_lock(&d->access_lock);
cancelled = d->cancel;
pthread_mutex_unlock(&d->access_lock);
if (cancelled)
return BE_CANCELLED;
len = buf->sectors;
/* ts A61009 : buffer fill problems are to be handled by caller */
/* a ssert(buf->bytes >= buf->sectors);*/ /* can be == at 0... */
burn_print(100, "trying to write %d at %d\n", len, start);
memcpy(c.opcode, MMC_WRITE_10, sizeof(MMC_WRITE_10));
c.retry = 1;
c.oplen = sizeof(MMC_WRITE_10);
c.opcode[2] = start >> 24;
c.opcode[3] = (start >> 16) & 0xFF;
c.opcode[4] = (start >> 8) & 0xFF;
c.opcode[5] = start & 0xFF;
c.opcode[6] = 0;
c.opcode[7] = (len >> 8) & 0xFF;
c.opcode[8] = len & 0xFF;
c.page = buf;
c.dir = TO_DRIVE;
/*
burn_print(12, "%d, %d, %d, %d - ", c->opcode[2], c->opcode[3], c->opcode[4], c->opcode[5]);
burn_print(12, "%d, %d, %d, %d\n", c->opcode[6], c->opcode[7], c->opcode[8], c->opcode[9]);
*/
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
if(tee_fd!=-1) {
write(tee_fd,c.page->data,len*2048);
}
#endif /* Libburn_log_in_and_out_streaM */
d->issue_command(d, &c);
/* ts A61112 : react on eventual error condition */
if (c.error && c.sense[2]!=0) {
/* >>> make this scsi_notify_error() when liberated */
if (c.sense[2]!=0) {
char msg[80];
sprintf(msg,
"SCSI error condition on write : key=%X asc=%2.2Xh ascq=%2.2Xh",
c.sense[2],c.sense[12],c.sense[13]);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002011d,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
}
pthread_mutex_lock(&d->access_lock);
d->cancel = 1;
pthread_mutex_unlock(&d->access_lock);
return BE_CANCELLED;
}
return 0;
}
void mmc_read_toc(struct burn_drive *d)
{
/* read full toc, all sessions, in m/s/f form, 4k buffer */
struct burn_track *track;
struct burn_session *session;
struct buffer buf;
struct command c;
int dlen;
int i, bpl= 12;
unsigned char *tdata;
mmc_function_spy("mmc_read_toc");
memcpy(c.opcode, MMC_GET_TOC, sizeof(MMC_GET_TOC));
c.retry = 1;
c.oplen = sizeof(MMC_GET_TOC);
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
if (c.error) {
/* ts A61020 : this snaps on non-blank DVD media */
/* ts A61106 : also snaps on CD with unclosed track/session */
/* Very unsure wether this old measure is ok.
Obviously higher levels do not care about this.
DVD+RW burns go on after passing through here.
d->busy = BURN_DRIVE_IDLE;
*/
libdax_msgs_submit(libdax_messenger, d->global_index,
0x0002010d,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
"Could not inquire TOC (non-blank DVD media ?)", 0,0);
d->status = BURN_DISC_UNSUITABLE;
d->toc_entries = 0;
/* Prefering memory leaks over fandangos */
d->toc_entry = malloc(sizeof(struct burn_toc_entry));
return;
}
dlen = c.page->data[0] * 256 + c.page->data[1];
d->toc_entries = (dlen - 2) / 11;
/*
some drives fail this check.
ts A61007 : if re-enabled then not via Assert.
a ssert(((dlen - 2) % 11) == 0);
*/
d->toc_entry = malloc(d->toc_entries * sizeof(struct burn_toc_entry));
tdata = c.page->data + 4;
burn_print(12, "TOC:\n");
d->disc = burn_disc_create();
for (i = 0; i < c.page->data[3]; i++) {
session = burn_session_create();
burn_disc_add_session(d->disc, session, BURN_POS_END);
burn_session_free(session);
}
/* ts A61022 */
burn_print(bpl, "-----------------------------------\n");
for (i = 0; i < d->toc_entries; i++, tdata += 11) {
/* ts A61022: was burn_print level 12 */
burn_print(bpl, "S %d, PT %2.2Xh, TNO %d :", tdata[0],tdata[3],
tdata[2]);
burn_print(bpl, " MSF(%d:%d:%d)", tdata[4],tdata[5],tdata[6]);
burn_print(bpl, " PMSF(%d:%d:%d %d)",
tdata[8], tdata[9], tdata[10],
burn_msf_to_lba(tdata[8], tdata[9], tdata[10])
);
burn_print(bpl, " - control %d, adr %d\n", tdata[1] & 0xF,
tdata[1] >> 4);
/*
fprintf(stderr, "libburn_experimental: toc entry #%d : %d %d %d\n",i,tdata[8], tdata[9], tdata[10]);
*/
if (tdata[3] == 1) {
if (burn_msf_to_lba(tdata[8], tdata[9], tdata[10])) {
d->disc->session[0]->hidefirst = 1;
track = burn_track_create();
burn_session_add_track(d->disc->
session[tdata[0] - 1],
track, BURN_POS_END);
burn_track_free(track);
}
}
if (tdata[3] < 100) {
track = burn_track_create();
burn_session_add_track(d->disc->session[tdata[0] - 1],
track, BURN_POS_END);
track->entry = &d->toc_entry[i];
burn_track_free(track);
}
d->toc_entry[i].session = tdata[0];
d->toc_entry[i].adr = tdata[1] >> 4;
d->toc_entry[i].control = tdata[1] & 0xF;
d->toc_entry[i].tno = tdata[2];
d->toc_entry[i].point = tdata[3];
d->toc_entry[i].min = tdata[4];
d->toc_entry[i].sec = tdata[5];
d->toc_entry[i].frame = tdata[6];
d->toc_entry[i].zero = tdata[7];
d->toc_entry[i].pmin = tdata[8];
d->toc_entry[i].psec = tdata[9];
d->toc_entry[i].pframe = tdata[10];
if (tdata[3] == 0xA0)
d->disc->session[tdata[0] - 1]->firsttrack = tdata[8];
if (tdata[3] == 0xA1)
d->disc->session[tdata[0] - 1]->lasttrack = tdata[8];
if (tdata[3] == 0xA2)
d->disc->session[tdata[0] - 1]->leadout_entry =
&d->toc_entry[i];
}
/* ts A61022 */
burn_print(bpl, "-----------------------------------\n");
if (d->status != BURN_DISC_APPENDABLE)
d->status = BURN_DISC_FULL;
toc_find_modes(d);
}
void mmc_read_disc_info(struct burn_drive *d)
{
struct buffer buf;
unsigned char *data;
struct command c;
mmc_function_spy("mmc_read_disc_info");
memcpy(c.opcode, MMC_GET_DISC_INFO, sizeof(MMC_GET_DISC_INFO));
c.retry = 1;
c.oplen = sizeof(MMC_GET_DISC_INFO);
c.page = &buf;
c.page->sectors = 0;
c.page->bytes = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
if (c.error) {
d->busy = BURN_DRIVE_IDLE;
return;
}
data = c.page->data;
d->erasable = !!(data[2] & 16);
/* ts A61020 */
d->start_lba = d->end_lba = -2000000000;
/*
fprintf(stderr, "libburn_experimental: data[2]= %d 0x%x\n",
(unsigned) data[2], (unsigned) data[2]);
*/
switch (data[2] & 3) {
case 0:
d->toc_entries = 0;
d->start_lba = burn_msf_to_lba(data[17], data[18], data[19]);
d->end_lba = burn_msf_to_lba(data[21], data[22], data[23]);
/*
fprintf(stderr, "libburn_experimental: start_lba = %d (%d %d %d) , end_lba = %d (%d %d %d)\n",
d->start_lba, data[17], data[18], data[19],
d->end_lba, data[21], data[22], data[23]);
*/
d->status = BURN_DISC_BLANK;
break;
case 1:
d->status = BURN_DISC_APPENDABLE;
case 2:
mmc_read_toc(d);
break;
}
}
void mmc_read_atip(struct burn_drive *d)
{
struct buffer buf;
struct command c;
/* ts A61021 */
unsigned char *data;
/* Speed values from A1:
With 4 cdrecord tells "10" or "8" where MMC-1 says "8".
cdrecord "8" appear on 4xCD-RW and thus seem to be quite invalid.
My CD-R (>=24 speed) tell no A1.
The higher non-MMC-1 values are hearsay.
*/
static int speed_value[16]= { 0, 2, 4, 6, 10, -5, 16, -7,
24, 32, 40, 48, -12, -13, -14, -15};
mmc_function_spy("mmc_read_atip");
memcpy(c.opcode, MMC_GET_ATIP, sizeof(MMC_GET_ATIP));
c.retry = 1;
c.oplen = sizeof(MMC_GET_ATIP);
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
burn_print(1, "atip shit for you\n");
/* ts A61021 */
data = c.page->data;
d->erasable= !!(data[6]&64);
d->start_lba= burn_msf_to_lba(data[8],data[9],data[10]);
d->end_lba= burn_msf_to_lba(data[12],data[13],data[14]);
if (data[6]&4) {
if (speed_value[(data[16]>>4)&7] > 0)
d->mdata->min_write_speed =
speed_value[(data[16]>>4)&7]*176;
if (speed_value[(data[16])&15] > 0)
d->mdata->max_write_speed =
speed_value[(data[16])&15]*176;
}
#ifdef Burn_mmc_be_verbous_about_atiP
{ int i;
fprintf(stderr,"libburn_experimental: Returned ATIP Data\n");
for(i= 0; i<28; i++)
fprintf(stderr,"%3.3d (0x%2.2x)%s",
data[i],data[i],((i+1)%5 ? " ":"\n"));
fprintf(stderr,"\n");
fprintf(stderr,
"libburn_experimental: Indicative Target Writing Power= %d\n",
(data[4]>>4)&7);
fprintf(stderr,
"libburn_experimental: Reference speed= %d ->%d\n",
data[4]&7, speed_value[data[4]&7]);
fprintf(stderr,
"libburn_experimental: Is %sunrestricted\n",
(data[5]&64?"":"not "));
fprintf(stderr,
"libburn_experimental: Is %serasable, sub-type %d\n",
(data[6]&64?"":"not "),(data[6]>>3)&3);
fprintf(stderr,
"libburn_experimental: lead in: %d (%-2.2d:%-2.2d/%-2.2d)\n",
burn_msf_to_lba(data[8],data[9],data[10]),
data[8],data[9],data[10]);
fprintf(stderr,
"libburn_experimental: lead out: %d (%-2.2d:%-2.2d/%-2.2d)\n",
burn_msf_to_lba(data[12],data[13],data[14]),
data[12],data[13],data[14]);
if(data[6]&4)
fprintf(stderr,
"libburn_experimental: A1 speed low %d speed high %d\n",
speed_value[(data[16]>>4)&7], speed_value[(data[16])&7]);
if(data[6]&2)
fprintf(stderr,
"libburn_experimental: A2 speed low %d speed high %d\n",
speed_value[(data[20]>>4)&7], speed_value[(data[20])&7]);
if(data[6]&1)
fprintf(stderr,
"libburn_experimental: A3 speed low %d speed high %d\n",
speed_value[(data[24]>>4)&7], speed_value[(data[24])&7]);
}
#endif /* Burn_mmc_be_verbous_about_atiP */
/* ts A61020
http://www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf , table 77 :
0 ATIP Data Length MSB
1 ATIP Data Length LSB
2 Reserved
3 Reserved
4 bit7=1, bit4-6="Indicative Target Writing Power", bit3=reserved ,
bit0-2="Reference speed"
5 bit7=0, bit6="URU" , bit0-5=reserved
6 bit7=1, bit6="Disc Type", bit3-4="Disc Sub-Type",
bit2="A1", bit1="A2", bit0="A3"
7 reserved
8 ATIP Start Time of lead-in (Min)
9 ATIP Start Time of lead-in (Sec)
10 ATIP Start Time of lead-in (Frame)
11 reserved
12 ATIP Last Possible Start Time of lead-out (Min)
13 ATIP Last Possible Start Time of lead-out (Sec)
14 ATIP Last Possible Start Time of lead-out (Frame)
15 reserved
16 bit7=0, bit4-6="Lowest Usable CLV Recording speed"
bit0-3="Highest Usable CLV Recording speed"
17 bit7=0, bit4-6="Power Multiplication Factor p",
bit1-3="Target y value of the Modulation/Power function", bit0=reserved
18 bit7=1, bit4-6="Recommended Erase/Write Power Ratio (P(inf)/W(inf))"
bit0-3=reserved
19 reserved
20-22 A2 Values
23 reserved
24-26 A3 Values
27 reserved
Disc Type - zero indicates CD-R media; one indicates CD-RW media.
Disc Sub-Type - shall be set to zero.
A1 - when set to one, indicates that bytes 16-18 are valid.
Lowest Usable CLV Recording Speed
000b Reserved
001b 2X
010b - 111b Reserved
Highest CLV Recording Speeds
000b Reserved
001b 2X
010b 4X
011b 6X
100b 8X
101b - 111b Reserved
MMC-3 seems to recommend MODE SENSE (5Ah) page 2Ah rather than A1, A2, A3.
This page is loaded in libburn function spc_sense_caps() .
Speed is given in kbytes/sec there. But i suspect this to be independent
of media. So one would habe to associate the speed descriptor blocks with
the ATIP media characteristics ? How ?
*/
}
void mmc_read_sectors(struct burn_drive *d,
int start,
int len,
const struct burn_read_opts *o, struct buffer *buf)
{
int temp;
int errorblock, req;
struct command c;
mmc_function_spy("mmc_read_sectors");
/* ts A61009 : to be ensured by callers */
/* a ssert(len >= 0); */
/* if the drive isn't busy, why the hell are we here? */
/* ts A61006 : i second that question */
/* a ssert(d->busy); */
burn_print(12, "reading %d from %d\n", len, start);
memcpy(c.opcode, MMC_READ_CD, sizeof(MMC_READ_CD));
c.retry = 1;
c.oplen = sizeof(MMC_READ_CD);
temp = start;
c.opcode[5] = temp & 0xFF;
temp >>= 8;
c.opcode[4] = temp & 0xFF;
temp >>= 8;
c.opcode[3] = temp & 0xFF;
temp >>= 8;
c.opcode[2] = temp & 0xFF;
c.opcode[8] = len & 0xFF;
len >>= 8;
c.opcode[7] = len & 0xFF;
len >>= 8;
c.opcode[6] = len & 0xFF;
req = 0xF8;
/* ts A61106 : LG GSA-4082B dislikes this. key=5h asc=24h ascq=00h
if (d->busy == BURN_DRIVE_GRABBING || o->report_recovered_errors)
req |= 2;
*/
c.opcode[10] = 0;
/* always read the subcode, throw it away later, since we don't know
what we're really reading
*/
if (d->busy == BURN_DRIVE_GRABBING || (o->subcodes_audio)
|| (o->subcodes_data))
c.opcode[10] = 1;
c.opcode[9] = req;
c.page = buf;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
if (c.error) {
burn_print(12, "got an error over here\n");
burn_print(12, "%d, %d, %d, %d\n", c.sense[3], c.sense[4],
c.sense[5], c.sense[6]);
errorblock =
(c.sense[3] << 24) + (c.sense[4] << 16) +
(c.sense[5] << 8) + c.sense[6];
c.page->sectors = errorblock - start + 1;
burn_print(1, "error on block %d\n", errorblock);
burn_print(12, "error on block %d\n", errorblock);
burn_print(12, "returning %d sectors\n", c.page->sectors);
}
}
void mmc_erase(struct burn_drive *d, int fast)
{
struct command c;
mmc_function_spy("mmc_erase");
memcpy(c.opcode, MMC_ERASE, sizeof(MMC_ERASE));
c.opcode[1] = 16; /* IMMED set to 1 */
c.opcode[1] |= !!fast;
c.retry = 1;
c.oplen = sizeof(MMC_ERASE);
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void mmc_read_lead_in(struct burn_drive *d, struct buffer *buf)
{
int len;
struct command c;
mmc_function_spy("mmc_read_lead_in");
len = buf->sectors;
memcpy(c.opcode, MMC_READ_CD, sizeof(MMC_READ_CD));
c.retry = 1;
c.oplen = sizeof(MMC_READ_CD);
c.opcode[5] = 0;
c.opcode[4] = 0;
c.opcode[3] = 0;
c.opcode[2] = 0xF0;
c.opcode[8] = 1;
c.opcode[7] = 0;
c.opcode[6] = 0;
c.opcode[9] = 0;
c.opcode[10] = 2;
c.page = buf;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
}
void mmc_perform_opc(struct burn_drive *d)
{
struct command c;
mmc_function_spy("mmc_perform_opc");
memcpy(c.opcode, MMC_SEND_OPC, sizeof(MMC_SEND_OPC));
c.retry = 1;
c.oplen = sizeof(MMC_SEND_OPC);
c.opcode[1] = 1;
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void mmc_set_speed(struct burn_drive *d, int r, int w)
{
struct command c;
/* ts A61112 : MMC standards prescribe FFFFh as max speed.
But libburn.h prescribes 0. */
if (r<=0 || r>0xffff)
r = 0xffff;
if (w<=0 || w>0xffff)
w = 0xffff;
mmc_function_spy("mmc_set_speed");
memcpy(c.opcode, MMC_SET_SPEED, sizeof(MMC_SET_SPEED));
c.retry = 1;
c.oplen = sizeof(MMC_SET_SPEED);
c.opcode[2] = r >> 8;
c.opcode[3] = r & 0xFF;
c.opcode[4] = w >> 8;
c.opcode[5] = w & 0xFF;
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void mmc_get_configuration(struct burn_drive *d)
{
struct buffer buf;
int len;
struct command c;
mmc_function_spy("mmc_get_configuration");
memcpy(c.opcode, MMC_GET_CONFIGURATION, sizeof(MMC_GET_CONFIGURATION));
c.retry = 1;
c.oplen = sizeof(MMC_GET_CONFIGURATION);
c.page = &buf;
c.page->sectors = 0;
c.page->bytes = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
burn_print(1, "got it back\n");
len = (c.page->data[0] << 24)
+ (c.page->data[1] << 16)
+ (c.page->data[2] << 8)
+ c.page->data[3];
burn_print(1, "all %d bytes of it\n", len);
burn_print(1, "%d, %d, %d, %d\n",
c.page->data[0],
c.page->data[1], c.page->data[2], c.page->data[3]);
}
void mmc_sync_cache(struct burn_drive *d)
{
struct command c;
mmc_function_spy("mmc_sync_cache");
memcpy(c.opcode, MMC_SYNC_CACHE, sizeof(MMC_SYNC_CACHE));
c.retry = 1;
c.oplen = sizeof(MMC_SYNC_CACHE);
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
/* ts A61023 : http://libburn.pykix.org/ticket/14
get size and free space of drive buffer
*/
int mmc_read_buffer_capacity(struct burn_drive *d)
{
struct buffer buf;
struct command c;
unsigned char *data;
mmc_function_spy("mmc_read_buffer_capacity");
memcpy(c.opcode, MMC_READ_BUFFER_CAPACITY,
sizeof(MMC_READ_BUFFER_CAPACITY));
c.retry = 1;
c.oplen = sizeof(MMC_READ_BUFFER_CAPACITY);
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
/* >>> ??? error diagnostics */
data = c.page->data;
d->progress.buffer_capacity =
(data[4]<<24)|(data[5]<<16)|(data[6]<<8)|data[7];
d->progress.buffer_available =
(data[8]<<24)|(data[9]<<16)|(data[10]<<8)|data[11];
return 1;
}
/* ts A61021 : the mmc specific part of sg.c:enumerate_common()
*/
int mmc_setup_drive(struct burn_drive *d)
{
d->read_atip = mmc_read_atip;
d->read_toc = mmc_read_toc;
d->write = mmc_write;
d->erase = mmc_erase;
d->read_sectors = mmc_read_sectors;
d->perform_opc = mmc_perform_opc;
d->set_speed = mmc_set_speed;
d->send_cue_sheet = mmc_send_cue_sheet;
d->sync_cache = mmc_sync_cache;
d->get_nwa = mmc_get_nwa;
d->close_disc = mmc_close_disc;
d->close_session = mmc_close_session;
d->close_track_session = mmc_close;
d->read_buffer_capacity = mmc_read_buffer_capacity;
/* ts A61020 */
d->start_lba= -2000000000;
d->end_lba= -2000000000;
return 1;
}

View File

@ -1,54 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __MMC
#define __MMC
struct burn_drive;
struct burn_write_opts;
struct command;
struct buffer;
struct cue_sheet;
/* MMC commands */
void mmc_read(struct burn_drive *);
/* ts A61009 : removed redundant parameter d in favor of o->drive */
/* void mmc_close_session(struct burn_drive *, struct burn_write_opts *); */
/* void mmc_close_disc(struct burn_drive *, struct burn_write_opts *); */
void mmc_close_session(struct burn_write_opts *o);
void mmc_close_disc(struct burn_write_opts *o);
void mmc_close(struct burn_drive *, int session, int track);
void mmc_get_event(struct burn_drive *);
int mmc_write(struct burn_drive *, int start, struct buffer *buf);
void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf);
void mmc_sync_cache(struct burn_drive *);
void mmc_load(struct burn_drive *);
void mmc_eject(struct burn_drive *);
void mmc_erase(struct burn_drive *, int);
void mmc_read_toc(struct burn_drive *);
void mmc_read_disc_info(struct burn_drive *);
void mmc_read_atip(struct burn_drive *);
void mmc_read_sectors(struct burn_drive *,
int,
int, const struct burn_read_opts *, struct buffer *);
void mmc_set_speed(struct burn_drive *, int, int);
void mmc_read_lead_in(struct burn_drive *, struct buffer *);
void mmc_perform_opc(struct burn_drive *);
void mmc_get_configuration(struct burn_drive *);
/* ts A61110 : added parameters trackno, lba, nwa. Redefined return value.
@return 1=nwa is valid , 0=nwa is not valid , -1=error */
int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa);
void mmc_send_cue_sheet(struct burn_drive *, struct cue_sheet *);
/* ts A61023 : get size and free space of drive buffer */
int mmc_read_buffer_capacity(struct burn_drive *d);
/* ts A61021 : the mmc specific part of sg.c:enumerate_common()
*/
int mmc_setup_drive(struct burn_drive *d);
#endif /*__MMC*/

View File

@ -1,27 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include "null.h"
#include "libburn.h"
#include <stdlib.h>
#include <string.h>
int null_read(struct burn_source *source, unsigned char *buffer, int size)
{
memset(buffer, 0, size);
return size;
}
struct burn_source *burn_null_source_new(void)
{
struct burn_source *src;
src = malloc(sizeof(struct burn_source));
src->refcount = 1;
src->read = null_read;
src->read_sub = NULL;
src->get_size = 0;
src->free_data = NULL;
src->data = NULL;
return src;
}

View File

@ -1,10 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef BURN__NULL_H
#define BURN__NULL_H
struct burn_source;
int null_read(struct burn_source *source, unsigned char *buffer, int size);
struct burn_source *burn_null_source_new(void);
#endif /* LIBBURN__NULL_H */

View File

@ -1,209 +0,0 @@
#include "libburn.h"
#include "options.h"
#include "transport.h"
/* ts A61007 */
/* #include <a ssert.h> */
#include <stdlib.h>
#include <string.h>
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive)
{
struct burn_write_opts *opts;
opts = malloc(sizeof(struct burn_write_opts));
if (opts == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Could not allocate new auxiliary object", 0, 0);
return NULL;
}
opts->drive = drive;
opts->refcount = 1;
opts->write_type = BURN_WRITE_TAO;
opts->block_type = BURN_BLOCK_MODE1;
opts->toc_entry = NULL;
opts->toc_entries = 0;
opts->simulate = 0;
opts->underrun_proof = drive->mdata->underrun_proof;
opts->perform_opc = 1;
opts->has_mediacatalog = 0;
opts->format = BURN_CDROM;
opts->multi = 0;
opts->control = 0;
return opts;
}
void burn_write_opts_free(struct burn_write_opts *opts)
{
if (--opts->refcount <= 0)
free(opts);
}
struct burn_read_opts *burn_read_opts_new(struct burn_drive *drive)
{
struct burn_read_opts *opts;
opts = malloc(sizeof(struct burn_read_opts));
opts->drive = drive;
opts->refcount = 1;
opts->raw = 0;
opts->c2errors = 0;
opts->subcodes_audio = 0;
opts->subcodes_data = 0;
opts->hardware_error_recovery = 0;
opts->report_recovered_errors = 0;
opts->transfer_damaged_blocks = 0;
opts->hardware_error_retries = 3;
return opts;
}
void burn_read_opts_free(struct burn_read_opts *opts)
{
if (--opts->refcount <= 0)
free(opts);
}
int burn_write_opts_set_write_type(struct burn_write_opts *opts,
enum burn_write_types write_type,
int block_type)
{
int sector_get_outmode(enum burn_write_types write_type,
enum burn_block_types block_type);
int spc_block_type(enum burn_block_types b);
/* ts A61007 */
if (! ( (write_type == BURN_WRITE_SAO && block_type == BURN_BLOCK_SAO)
|| (opts->drive->block_types[write_type] & block_type) ) ) {
bad_combination:;
libdax_msgs_submit(libdax_messenger, -1, 0x00020112,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Bad combination of write_type and block_type", 0, 0);
return 0;
}
/* ts A61007 : obsoleting Assert in sector.c:get_outmode() */
if (sector_get_outmode(write_type, (enum burn_block_types) block_type)
== -1)
goto bad_combination;
/* ts A61007 : obsoleting Assert in spc.c:spc_block_type() */
if (spc_block_type((enum burn_block_types) block_type) == -1)
goto bad_combination;
opts->write_type = write_type;
opts->block_type = block_type;
return 1;
/* a ssert(0); */
}
void burn_write_opts_set_toc_entries(struct burn_write_opts *opts, int count,
struct burn_toc_entry *toc_entries)
{
opts->toc_entries = count;
opts->toc_entry = malloc(count * sizeof(struct burn_toc_entry));
memcpy(opts->toc_entry, &toc_entries,
sizeof(struct burn_toc_entry) * count);
}
void burn_write_opts_set_format(struct burn_write_opts *opts, int format)
{
opts->format = format;
}
int burn_write_opts_set_simulate(struct burn_write_opts *opts, int sim)
{
if (opts->drive->mdata->simulate) {
opts->simulate = sim;
return 1;
}
return 0;
}
int burn_write_opts_set_underrun_proof(struct burn_write_opts *opts,
int underrun_proof)
{
if (opts->drive->mdata->underrun_proof) {
opts->underrun_proof = underrun_proof;
return 1;
}
return 0;
}
void burn_write_opts_set_perform_opc(struct burn_write_opts *opts, int opc)
{
opts->perform_opc = opc;
}
void burn_write_opts_set_has_mediacatalog(struct burn_write_opts *opts,
int has_mediacatalog)
{
opts->has_mediacatalog = has_mediacatalog;
}
void burn_write_opts_set_mediacatalog(struct burn_write_opts *opts,
unsigned char mediacatalog[13])
{
memcpy(opts->mediacatalog, &mediacatalog, 13);
}
/* ts A61106 */
void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi)
{
opts->multi = !!multi;
}
void burn_read_opts_set_raw(struct burn_read_opts *opts, int raw)
{
opts->raw = raw;
}
void burn_read_opts_set_c2errors(struct burn_read_opts *opts, int c2errors)
{
opts->c2errors = c2errors;
}
void burn_read_opts_read_subcodes_audio(struct burn_read_opts *opts,
int subcodes_audio)
{
opts->subcodes_audio = subcodes_audio;
}
void burn_read_opts_read_subcodes_data(struct burn_read_opts *opts,
int subcodes_data)
{
opts->subcodes_data = subcodes_data;
}
void burn_read_opts_set_hardware_error_recovery(struct burn_read_opts *opts,
int hardware_error_recovery)
{
opts->hardware_error_recovery = hardware_error_recovery;
}
void burn_read_opts_report_recovered_errors(struct burn_read_opts *opts,
int report_recovered_errors)
{
opts->report_recovered_errors = report_recovered_errors;
}
void burn_read_opts_transfer_damaged_blocks(struct burn_read_opts *opts,
int transfer_damaged_blocks)
{
opts->transfer_damaged_blocks = transfer_damaged_blocks;
}
void burn_read_opts_set_hardware_error_retries(struct burn_read_opts *opts,
unsigned char
hardware_error_retries)
{
opts->hardware_error_retries = hardware_error_retries;
}

View File

@ -1,78 +0,0 @@
#ifndef BURN__OPTIONS_H
#define BURN__OPTIONS_H
#include "libburn.h"
/** Options for disc writing operations. This should be created with
burn_write_opts_new() and freed with burn_write_opts_free(). */
struct burn_write_opts
{
/** Drive the write opts are good for */
struct burn_drive *drive;
/** For internal use. */
int refcount;
/** The method/style of writing to use. */
enum burn_write_types write_type;
/** format of the data to send to the drive */
enum burn_block_types block_type;
/** Number of toc entries. if this is 0, they will be auto generated*/
int toc_entries;
/** Toc entries for the disc */
struct burn_toc_entry *toc_entry;
/** Simulate the write so that the disc is not actually written */
unsigned int simulate:1;
/** If available, enable a drive feature which prevents buffer
underruns if not enough data is available to keep up with the
drive. */
unsigned int underrun_proof:1;
/** Perform calibration of the drive's laser before beginning the
write. */
unsigned int perform_opc:1;
/** A disc can have a media catalog number */
int has_mediacatalog;
unsigned char mediacatalog[13];
/** Session format */
int format;
/* internal use only */
unsigned char control;
unsigned char multi;
};
/** Options for disc reading operations. This should be created with
burn_read_opts_new() and freed with burn_read_opts_free(). */
struct burn_read_opts
{
/** Drive the read opts are good for */
struct burn_drive *drive;
/** For internal use. */
int refcount;
/** Read in raw mode, so that everything in the data tracks on the
disc is read, including headers. Not needed if just reading a
filesystem off a disc, but it should usually be used when making a
disc image or copying a disc. */
unsigned int raw:1;
/** Report c2 errors. Useful for statistics reporting */
unsigned int c2errors:1;
/** Read subcodes from audio tracks on the disc */
unsigned int subcodes_audio:1;
/** Read subcodes from data tracks on the disc */
unsigned int subcodes_data:1;
/** Have the drive recover errors if possible */
unsigned int hardware_error_recovery:1;
/** Report errors even when they were recovered from */
unsigned int report_recovered_errors:1;
/** Read blocks even when there are unrecoverable errors in them */
unsigned int transfer_damaged_blocks:1;
/** The number of retries the hardware should make to correct
errors. */
unsigned char hardware_error_retries;
};
#endif /* BURN__OPTIONS_H */

View File

@ -1,282 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* #include <m alloc.h> ts A61013 : not in Linux man 3 malloc */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
/* ts A61007 */
/* #include <a ssert.h> */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "sector.h"
#include "libburn.h"
#include "drive.h"
#include "transport.h"
/* ts A60925 : obsoleted by libdax_msgs.h
#include "message.h"
*/
#include "crc.h"
#include "debug.h"
#include "init.h"
#include "lec.h"
#include "toc.h"
#include "util.h"
#include "sg.h"
#include "read.h"
#include "options.h"
void burn_disc_read(struct burn_drive *d, const struct burn_read_opts *o)
{
#if 0
int i, end, maxsects, finish;
int seclen;
int drive_lba;
unsigned short crc;
unsigned char fakesub[96];
struct buffer page;
int speed;
/* ts A61007 : if this function gets revived, then these
tests have to be done more graceful */
a ssert((o->version & 0xfffff000) == (OPTIONS_VERSION & 0xfffff000));
a ssert(!d->busy);
a ssert(d->toc->valid);
a ssert(o->datafd != -1);
/* moved up from spc_select_error_params alias d->send_parameters() */
a ssert(d->mdata->valid);
/* XXX not sure this is a good idea. copy it? */
/* XXX also, we have duplicated data now, do we remove the fds from struct
drive, or only store a subset of the _opts structs in drives */
/* set the speed on the drive */
speed = o->speed > 0 ? o->speed : d->mdata->max_read_speed;
d->set_speed(d, speed, 0);
d->params.retries = o->hardware_error_retries;
d->send_parameters(d, o);
d->cancel = 0;
d->busy = BURN_DRIVE_READING;
d->currsession = 0;
/* drive_lba = 232000;
d->currtrack = 18;
*/
d->currtrack = 0;
drive_lba = 0;
/* XXX removal of this line obviously breaks *
d->track_end = burn_track_end(d, d->currsession, d->currtrack);*/
printf("track ends at %d\n", d->track_end);
page.sectors = 0;
page.bytes = 0;
if (o->subfd != -1) {
memset(fakesub, 0xFF, 12);
memset(fakesub + 12, 0, 84);
fakesub[13] = 1;
fakesub[14] = 1;
fakesub[20] = 2;
fakesub[12] = (d->toc->toc_entry[0].control << 4) +
d->toc->toc_entry[0].adr;
crc = crc_ccitt(fakesub + 12, 10);
fakesub[22] = crc >> 8;
fakesub[23] = crc & 0xFF;
write(o->subfd, fakesub, 96);
}
while (1) {
seclen = burn_sector_length_read(d, o);
burn_print(12, "received %d blocks\n", page.sectors);
for (i = 0; i < page.sectors; i++) {
burn_packet_process(d, page.data + seclen * i, o);
d->track_end--;
drive_lba++;
}
if ((d->cancel) || (drive_lba == LAST_SESSION_END(d))) {
burn_print(1, "finished or cancelled\n");
d->busy = BURN_DRIVE_IDLE;
if (!d->cancel)
d->toc->complete = 1;
return;
}
/* XXX: removal of this line obviously breaks *
end = burn_track_end(d, d->currsession, d->currtrack); */
if (drive_lba == end) {
d->currtrack++;
if (d->currtrack >
d->toc->session[d->currsession].lasttrack) {
d->currsession++;
burn_print(12, "session switch to %d\n",
d->currsession);
burn_print(12, "skipping a lead out\n");
drive_lba = CURRENT_SESSION_START(d);
burn_print(12, "new lba %d\n", drive_lba);
/* XXX more of the same
end = burn_track_end(d, d->currsession,
d->currtrack);
*/ }
burn_print(12, "track switch to %d\n", d->currtrack);
}
page.sectors = 0;
page.bytes = 0;
maxsects = BUFFER_SIZE / seclen;
finish = end - drive_lba;
d->track_end = finish;
page.sectors = (finish < maxsects) ? finish : maxsects;
printf("reading %d sectors from %d\n", page.sectors,
drive_lba);
/* >>> ts A61009 : ensure page.sectors >= 0 before calling */
d->r ead_sectors(d, drive_lba, page.sectors, o, &page);
printf("Read %d\n", page.sectors);
}
#endif
}
int burn_sector_length_read(struct burn_drive *d,
const struct burn_read_opts *o)
{
int dlen = 2352;
int data;
/*XXX how do we handle this crap now?*/
/* data = d->toc->track[d->currtrack].toc_entry->control & 4;*/
data = 1;
if (o->report_recovered_errors)
dlen += 294;
if ((o->subcodes_data) && data)
dlen += 96;
if ((o->subcodes_audio) && !data)
dlen += 96;
return dlen;
}
static int bitcount(unsigned char *data, int n)
{
int i, j, count = 0;
unsigned char tem;
for (i = 0; i < n; i++) {
tem = data[i];
for (j = 0; j < 8; j++) {
count += tem & 1;
tem >>= 1;
}
}
return count;
}
void burn_packet_process(struct burn_drive *d, unsigned char *data,
const struct burn_read_opts *o)
{
unsigned char sub[96];
unsigned short crc;
int ptr = 2352, i, j, code, fb;
int audio = 1;
if (o->c2errors) {
fb = bitcount(data + ptr, 294);
if (fb) {
burn_print(1, "%d damaged bits\n",
bitcount(data + ptr, 294));
burn_print(1, "sending error on %s %s\n",
d->idata->vendor, d->idata->product);
/* XXX send a burn_message! burn_message_error(d,
something); */
}
ptr += 294;
}
/*
if (d->toc->track[d->currtrack].mode == BURN_MODE_UNINITIALIZED) {
if ((d->toc->track[d->currtrack].toc_entry->control & 4) == 0)
d->toc->track[d->currtrack].mode = BURN_MODE_AUDIO;
else
switch (data[15]) {
case 0:
d->toc->track[d->currtrack].mode = BURN_MODE0;
break;
case 1:
d->toc->track[d->currtrack].mode = BURN_MODE1;
break;
case 2:
d->toc->track[d->currtrack].mode =
BURN_MODE2_FORMLESS;
break;
}
}
*/
if ((audio && o->subcodes_audio)
|| (!audio && o->subcodes_data)) {
memset(sub, 0, sizeof(sub));
for (i = 0; i < 12; i++) {
for (j = 0; j < 8; j++) {
for (code = 0; code < 8; code++) {
sub[code * 12 + i] <<= 1;
if (data[ptr + j + i * 8] &
(1 << (7 - code)))
sub[code * 12 + i]++;
}
}
}
crc = (*(sub + 22) << 8) + *(sub + 23);
if (crc != crc_ccitt(sub + 12, 10)) {
burn_print(1, "sending error on %s %s\n",
d->idata->vendor, d->idata->product);
/* e = burn_error();
e->drive = d;
*/
burn_print(1, "crc mismatch in Q\n");
}
/* else process_q(d, sub + 12); */
/*
if (o->subfd != -1) write(o->subfd, sub, 96); */
}
/*
if ((d->track_end <= 150)
&& (drive_lba + 150 < CURRENT_SESSION_END(d))
&& (TOC_ENTRY(d->toc, d->currtrack).control == 4)
&& (TOC_ENTRY(d->toc, d->currtrack + 1).control == 0)) {
burn_print(12, "pregap : %d\n", d->track_end);
write(o->binfd, zeros, 2352);
#warning XXX WHERE ARE MY SUBCODES
} else
*//* write(o->datafd, data, 2352); */
}
/* so yeah, when you uncomment these, make them write zeros insted of crap
static void write_empty_sector(int fd)
{
char sec[2352];
burn_print(1, "writing an 'empty' sector\n");
write(fd, sec, 2352);
}
static void write_empty_subcode(int fd)
{
char sub[96];
write(fd, sub, 96);
}
static void flipq(unsigned char *sub)
{
*(sub + 12 + 10) = ~*(sub + 12 + 10);
*(sub + 12 + 11) = ~*(sub + 12 + 11);
}
*/

View File

@ -1,14 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __LIBBURN_READ
#define __LIBBURN_READ
struct burn_drive;
struct burn_read_opts;
int burn_sector_length_read(struct burn_drive *d,
const struct burn_read_opts *o);
void burn_packet_process(struct burn_drive *d, unsigned char *data,
const struct burn_read_opts *o);
#endif /* __LIBBURN_READ */

View File

@ -1,48 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* scsi block commands */
#include <string.h>
#include "transport.h"
#include "sbc.h"
#include "options.h"
/* spc command set */
static char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
static char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
void sbc_load(struct burn_drive *d)
{
struct command c;
memcpy(c.opcode, SBC_LOAD, sizeof(SBC_LOAD));
c.retry = 1;
c.oplen = sizeof(SBC_LOAD);
c.dir = NO_TRANSFER;
c.page = NULL;
d->issue_command(d, &c);
}
void sbc_eject(struct burn_drive *d)
{
struct command c;
c.page = NULL;
memcpy(c.opcode, SBC_UNLOAD, sizeof(SBC_UNLOAD));
c.oplen = 1;
c.oplen = sizeof(SBC_UNLOAD);
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
/* ts A61021 : the sbc specific part of sg.c:enumerate_common()
*/
int sbc_setup_drive(struct burn_drive *d)
{
d->eject = sbc_eject;
d->load = sbc_load;
return 1;
}

View File

@ -1,15 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __SBC
#define __SBC
struct burn_drive;
void sbc_load(struct burn_drive *);
void sbc_eject(struct burn_drive *);
/* ts A61021 : the sbc specific part of sg.c:enumerate_common()
*/
int sbc_setup_drive(struct burn_drive *d);
#endif /* __SBC */

View File

@ -1,825 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <stdio.h>
/* ts A61010 */
/* #include <a ssert.h> */
#include <unistd.h>
#include <string.h>
#include "error.h"
#include "options.h"
#include "transport.h"
#include "libburn.h"
#include "drive.h"
#include "sector.h"
#include "crc.h"
#include "debug.h"
#include "lec.h"
#include "toc.h"
#include "write.h"
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif /* Libburn_log_in_and_out_streaM */
/*static unsigned char isrc[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";*/
#define sector_common(X) d->alba++; d->rlba X;
static void uncook_subs(unsigned char *dest, unsigned char *source)
{
int i, j, code;
memset(dest, 0, 96);
for (i = 0; i < 12; i++) {
for (j = 0; j < 8; j++) {
for (code = 0; code < 8; code++) {
if (source[code * 12 + i] & 0x80)
dest[j + i * 8] |= (1 << (7 - code));
source[code * 12 + i] <<= 1;
}
}
}
}
/* @return >=0 : valid , <0 invalid */
int sector_get_outmode(enum burn_write_types write_type,
enum burn_block_types block_type)
{
/* ts A61103 : extended SAO condition to TAO */
if (write_type == BURN_WRITE_SAO || write_type == BURN_WRITE_TAO)
return 0;
else
switch (block_type) {
case BURN_BLOCK_RAW0:
return BURN_MODE_RAW;
case BURN_BLOCK_RAW16:
return BURN_MODE_RAW | BURN_SUBCODE_P16;
case BURN_BLOCK_RAW96P:
return BURN_MODE_RAW | BURN_SUBCODE_P96;
case BURN_BLOCK_RAW96R:
return BURN_MODE_RAW | BURN_SUBCODE_R96;
case BURN_BLOCK_MODE1:
return BURN_MODE1;
default:
return -1;
}
/* ts A61007 : now handled in burn_write_opts_set_write_type() */
/* a ssert(0); */ /* return BURN_MODE_UNIMPLEMENTED :) */
}
/* 0 means "same as inmode" */
static int get_outmode(struct burn_write_opts *o)
{
/* ts A61007 */
return sector_get_outmode(o->write_type, o->block_type);
/* -1 is prevented by check in burn_write_opts_set_write_type() */
/* a ssert(0); */ /* return BURN_MODE_UNIMPLEMENTED :) */
}
static void get_bytes(struct burn_track *track, int count, unsigned char *data)
{
int valid, shortage, curr, i, tr;
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
static int tee_fd= -1;
if(tee_fd==-1)
tee_fd= open("/tmp/libburn_sg_readin",
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
#endif /* Libburn_log_in_and_out_streaM */
/* no track pointer means we're just generating 0s */
if (!track) {
memset(data, 0, count);
return;
}
/* first we use up any offset */
valid = track->offset - track->offsetcount;
if (valid > count)
valid = count;
if (valid) {
track->offsetcount += valid;
memset(data, 0, valid);
}
shortage = count - valid;
if (!shortage)
goto ex;
/* Next we use source data */
curr = valid;
if (!track->eos) {
valid = track->source->read(track->source, data + curr, count - curr);
} else valid = 0;
if (valid <= 0) { /* ts A61031 : extended from (valid == -1) */
track->eos = 1;
valid = 0;
}
track->sourcecount += valid;
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
if(tee_fd!=-1 && valid>0) {
write(tee_fd, data + curr, valid);
}
#endif /* Libburn_log_in_and_out_streaM */
curr += valid;
shortage = count - curr;
if (!shortage)
goto ex;
/* Before going to the next track, we run through any tail */
valid = track->tail - track->tailcount;
if (valid > count - curr)
valid = count - curr;
if (valid) {
track->tailcount += valid;
memset(data + curr, 0, valid);
}
curr += valid;
shortage -= valid;
if (!shortage)
goto ex;
/* ts A61031 */
if (shortage >= count)
track->track_data_done = 1;
if (track->open_ended)
goto ex;
/* If we're still short, and there's a "next" pointer, we pull from that.
if that depletes, we'll just fill with 0s.
*/
if (track->source->next) {
struct burn_source *src;
printf("pulling from next track\n");
src = track->source->next;
valid = src->read(src, data + curr, shortage);
if (valid > 0) {
shortage -= valid;
curr += valid;
}
}
ex:;
/* ts A61024 : general finalizing processing */
if(shortage)
memset(data + curr, 0, shortage); /* this is old icculus.org */
if (track->swap_source_bytes == 1) {
for (i = 1; i < count; i += 2) {
tr = data[i];
data[i] = data[i-1];
data[i-1] = tr;
}
}
}
/* ts A61009 : seems to hand out sector start pointer in opts->drive->buffer
and to count hand outs as well as reserved bytes */
/* ts A61101 : added parameter track for counting written bytes */
static unsigned char *get_sector(struct burn_write_opts *opts,
struct burn_track *track, int inmode)
{
struct burn_drive *d = opts->drive;
struct buffer *out = d->buffer;
int outmode;
int seclen;
unsigned char *ret;
outmode = get_outmode(opts);
if (outmode == 0)
outmode = inmode;
/* ts A61009 : react on eventual failure of burn_sector_length()
(should not happen if API tested properly).
Ensures out->bytes >= out->sectors */
seclen = burn_sector_length(outmode);
if (seclen <= 0)
return NULL;
seclen += burn_subcode_length(outmode);
if (out->bytes + (seclen) >= BUFFER_SIZE) {
int err;
err = d->write(d, d->nwa, out);
if (err == BE_CANCELLED)
return NULL;
/* ts A61101 */
if(track != NULL) {
track->writecount += out->bytes;
track->written_sectors += out->sectors;
}
d->nwa += out->sectors;
out->bytes = 0;
out->sectors = 0;
}
ret = out->data + out->bytes;
out->bytes += seclen;
out->sectors++;
return ret;
}
/* ts A61031 */
/* Revoke the counting of the most recent sector handed out by get_sector() */
static void unget_sector(struct burn_write_opts *opts, int inmode)
{
struct burn_drive *d = opts->drive;
struct buffer *out = d->buffer;
int outmode;
int seclen;
outmode = get_outmode(opts);
if (outmode == 0)
outmode = inmode;
/* ts A61009 : react on eventual failure of burn_sector_length()
(should not happen if API tested properly).
Ensures out->bytes >= out->sectors */
seclen = burn_sector_length(outmode);
if (seclen <= 0)
return;
seclen += burn_subcode_length(outmode);
out->bytes -= seclen;
out->sectors--;
}
/* either inmode == outmode, or outmode == raw. anything else is bad news */
/* ts A61010 : changed type to int in order to propagate said bad news */
/** @return 1 is ok, <= 0 is failure */
static int convert_data(struct burn_write_opts *o, struct burn_track *track,
int inmode, unsigned char *data)
{
int outlen, inlen;
int offset = -1;
int outmode;
outmode = get_outmode(o);
if (outmode == 0)
outmode = inmode;
outlen = burn_sector_length(outmode);
inlen = burn_sector_length(inmode);
/* ts A61010 */
/* a ssert(outlen >= inlen); */
if (outlen < inlen)
return 0;
if ((outmode & BURN_MODE_BITS) == (inmode & BURN_MODE_BITS)) {
get_bytes(track, inlen, data);
return 1;
}
/* ts A61010 */
/* a ssert(outmode & BURN_MODE_RAW); */
if (!(outmode & BURN_MODE_RAW))
return 0;
if (inmode & BURN_MODE1)
offset = 16;
if (inmode & BURN_MODE_RAW)
offset = 0;
if (inmode & BURN_AUDIO)
offset = 0;
/* ts A61010 */
/* a ssert(offset != -1); */
if (offset == -1)
return 0;
get_bytes(track, inlen, data + offset);
return 1;
}
static void convert_subs(struct burn_write_opts *o, int inmode,
unsigned char *subs, unsigned char *sector)
{
unsigned char *out;
int outmode;
outmode = get_outmode(o);
if (outmode == 0)
outmode = inmode;
sector += burn_sector_length(outmode);
/* XXX for sao with subs, we'd need something else... */
switch (o->block_type) {
case BURN_BLOCK_RAW96R:
uncook_subs(sector, subs);
break;
case BURN_BLOCK_RAW16:
memcpy(sector, subs + 12, 12);
out = sector + 12;
out[0] = 0;
out[1] = 0;
out[2] = 0;
/*XXX find a better way to deal with partially damaged P channels*/
if (subs[2] != 0)
out[3] = 0x80;
else
out[3] = 0;
out = sector + 10;
out[0] = ~out[0];
out[1] = ~out[1];
break;
}
}
static void subcode_toc(struct burn_drive *d, int mode, unsigned char *data)
{
unsigned char *q;
int track;
int crc;
int min, sec, frame;
track = d->toc_temp / 3;
memset(data, 0, 96);
q = data + 12;
burn_lba_to_msf(d->rlba, &min, &sec, &frame);
/*XXX track numbers are BCD
a0 - 1st track ctrl
a1 - last track ctrl
a2 - lout ctrl
*/
q[0] = (d->toc_entry[track].control << 4) + 1;
q[1] = 0;
if (d->toc_entry[track].point < 100)
q[2] = dec_to_bcd(d->toc_entry[track].point);
else
q[2] = d->toc_entry[track].point;
q[3] = dec_to_bcd(min);
q[4] = dec_to_bcd(sec);
q[5] = dec_to_bcd(frame);
q[6] = 0;
q[7] = dec_to_bcd(d->toc_entry[track].pmin);
q[8] = dec_to_bcd(d->toc_entry[track].psec);
q[9] = dec_to_bcd(d->toc_entry[track].pframe);
crc = crc_ccitt(q, 10);
q[10] = crc >> 8;
q[11] = crc & 0xFF;
d->toc_temp++;
d->toc_temp %= (d->toc_entries * 3);
}
int sector_toc(struct burn_write_opts *o, int mode)
{
struct burn_drive *d = o->drive;
unsigned char *data;
unsigned char subs[96];
data = get_sector(o, NULL, mode);
if (data == NULL)
return 0;
/* ts A61010 */
if (convert_data(o, NULL, mode, data) <= 0)
return 0;
subcode_toc(d, mode, subs);
convert_subs(o, mode, subs, data);
sector_headers(o, data, mode, 1);
sector_common(++)
return 1;
}
int sector_pregap(struct burn_write_opts *o,
unsigned char tno, unsigned char control, int mode)
{
struct burn_drive *d = o->drive;
unsigned char *data;
unsigned char subs[96];
data = get_sector(o, NULL, mode);
if (data == NULL)
return 0;
/* ts A61010 */
if (convert_data(o, NULL, mode, data) <= 0)
return 0;
subcode_user(o, subs, tno, control, 0, NULL, 1);
convert_subs(o, mode, subs, data);
sector_headers(o, data, mode, 0);
sector_common(--)
return 1;
}
int sector_postgap(struct burn_write_opts *o,
unsigned char tno, unsigned char control, int mode)
{
struct burn_drive *d = o->drive;
unsigned char subs[96];
unsigned char *data;
data = get_sector(o, NULL, mode);
if (data == NULL)
return 0;
/* ts A61010 */
if (convert_data(o, NULL, mode, data) <= 0)
return 0;;
/* use last index in track */
subcode_user(o, subs, tno, control, 1, NULL, 1);
convert_subs(o, mode, subs, data);
sector_headers(o, data, mode, 0);
sector_common(++)
return 1;
}
static void subcode_lout(struct burn_write_opts *o, unsigned char control,
unsigned char *data)
{
struct burn_drive *d = o->drive;
unsigned char *q;
int crc;
int rmin, min, rsec, sec, rframe, frame;
memset(data, 0, 96);
q = data + 12;
burn_lba_to_msf(d->alba, &min, &sec, &frame);
burn_lba_to_msf(d->rlba, &rmin, &rsec, &rframe);
if (((rmin == 0) && (rsec == 0) && (rframe == 0)) ||
((rsec >= 2) && !((rframe / 19) % 2)))
memset(data, 0xFF, 12);
q[0] = (control << 4) + 1;
q[1] = 0xAA;
q[2] = 0x01;
q[3] = dec_to_bcd(rmin);
q[4] = dec_to_bcd(rsec);
q[5] = dec_to_bcd(rframe);
q[6] = 0;
q[7] = dec_to_bcd(min);
q[8] = dec_to_bcd(sec);
q[9] = dec_to_bcd(frame);
crc = crc_ccitt(q, 10);
q[10] = crc >> 8;
q[11] = crc & 0xFF;
}
static char char_to_isrc(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'Z')
return 0x11 + (c - 'A');
if (c >= 'a' && c <= 'z')
return 0x11 + (c - 'a');
/* ts A61008 : obsoleted by test in burn_track_set_isrc() */
/* a ssert(0); */
return 0;
}
void subcode_user(struct burn_write_opts *o, unsigned char *subcodes,
unsigned char tno, unsigned char control,
unsigned char indx, struct isrc *isrc, int psub)
{
struct burn_drive *d = o->drive;
unsigned char *p, *q;
int crc;
int m, s, f, c, qmode; /* 1, 2 or 3 */
memset(subcodes, 0, 96);
p = subcodes;
if ((tno == 1) && (d->rlba == -150))
memset(p, 0xFF, 12);
if (psub)
memset(p, 0xFF, 12);
q = subcodes + 12;
qmode = 1;
/* every 1 in 10 we can do something different */
if (d->rlba % 10 == 0) {
/* each of these can occur 1 in 100 */
if ((d->rlba / 10) % 10 == 0) {
if (o->has_mediacatalog)
qmode = 2;
} else if ((d->rlba / 10) % 10 == 1) {
if (isrc && isrc->has_isrc)
qmode = 3;
}
}
/* ts A61010 : this cannot happen. Assert for fun ? */
/* a ssert(qmode == 1 || qmode == 2 || qmode == 3); */
switch (qmode) {
case 1:
q[1] = dec_to_bcd(tno); /* track number */
q[2] = dec_to_bcd(indx); /* index XXX read this shit
from the track array */
burn_lba_to_msf(d->rlba, &m, &s, &f);
q[3] = dec_to_bcd(m); /* rel min */
q[4] = dec_to_bcd(s); /* rel sec */
q[5] = dec_to_bcd(f); /* rel frame */
q[6] = 0; /* zero */
burn_lba_to_msf(d->alba, &m, &s, &f);
q[7] = dec_to_bcd(m); /* abs min */
q[8] = dec_to_bcd(s); /* abs sec */
q[9] = dec_to_bcd(f); /* abs frame */
break;
case 2:
/* media catalog number */
q[1] = (o->mediacatalog[0] << 4) + o->mediacatalog[1];
q[2] = (o->mediacatalog[2] << 4) + o->mediacatalog[3];
q[3] = (o->mediacatalog[4] << 4) + o->mediacatalog[5];
q[4] = (o->mediacatalog[6] << 4) + o->mediacatalog[7];
q[5] = (o->mediacatalog[8] << 4) + o->mediacatalog[9];
q[6] = (o->mediacatalog[10] << 4) + o->mediacatalog[11];
q[7] = o->mediacatalog[12] << 4;
q[8] = 0;
burn_lba_to_msf(d->alba, &m, &s, &f);
q[9] = dec_to_bcd(f); /* abs frame */
break;
case 3:
c = char_to_isrc(isrc->country[0]);
/* top 6 bits of [1] is the first country code */
q[1] = c << 2;
c = char_to_isrc(isrc->country[1]);
/* bottom 2 bits of [1] is part of the second country code */
q[1] += (c >> 4);
/* top 4 bits if [2] is the rest of the second country code */
q[2] = c << 4;
c = char_to_isrc(isrc->owner[0]);
/* bottom 4 bits of [2] is part of the first owner code */
q[2] += (c >> 2);
/* top 2 bits of [3] is the rest of the first owner code */
q[3] = c << 6;
c = char_to_isrc(isrc->owner[1]);
/* bottom 6 bits of [3] is the entire second owner code */
q[3] += c;
c = char_to_isrc(isrc->owner[2]);
/* top 6 bits of [4] are the third owner code */
q[4] = c << 2;
/* [5] is the year in 2 BCD numbers */
q[5] = dec_to_bcd(isrc->year % 100);
/* [6] is the first 2 digits in the serial */
q[6] = dec_to_bcd(isrc->serial % 100);
/* [7] is the next 2 digits in the serial */
q[7] = dec_to_bcd((isrc->serial / 100) % 100);
/* the top 4 bits of [8] is the last serial digit, the rest is
zeros */
q[8] = dec_to_bcd((isrc->serial / 10000) % 10) << 4;
burn_lba_to_msf(d->alba, &m, &s, &f);
q[9] = dec_to_bcd(f); /* abs frame */
break;
}
q[0] = (control << 4) + qmode;
crc = crc_ccitt(q, 10);
q[10] = crc >> 8;
q[11] = crc & 0xff;
}
int sector_lout(struct burn_write_opts *o, unsigned char control, int mode)
{
struct burn_drive *d = o->drive;
unsigned char subs[96];
unsigned char *data;
data = get_sector(o, NULL, mode);
if (!data)
return 0;
/* ts A61010 */
if (convert_data(o, NULL, mode, data) <= 0)
return 0;
subcode_lout(o, control, subs);
convert_subs(o, mode, subs, data);
sector_headers(o, data, mode, 0);
sector_common(++)
return 1;
}
int sector_data(struct burn_write_opts *o, struct burn_track *t, int psub)
{
struct burn_drive *d = o->drive;
unsigned char subs[96];
unsigned char *data;
data = get_sector(o, t, t->mode);
if (!data)
return 0;
/* ts A61010 */
if (convert_data(o, t, t->mode, data) <= 0)
return 0;
/* ts A61031 */
if (t->open_ended && t->track_data_done) {
unget_sector(o, t->mode);
return 2;
}
if (!t->source->read_sub)
subcode_user(o, subs, t->entry->point,
t->entry->control, 1, &t->isrc, psub);
else if (!t->source->read_sub(t->source, subs, 96))
subcode_user(o, subs, t->entry->point,
t->entry->control, 1, &t->isrc, psub);
convert_subs(o, t->mode, subs, data);
sector_headers(o, data, t->mode, 0);
sector_common(++)
return 1;
}
int burn_msf_to_lba(int m, int s, int f)
{
if (m < 90)
return (m * 60 + s) * 75 + f - 150;
else
return (m * 60 + s) * 75 + f - 450150;
}
void burn_lba_to_msf(int lba, int *m, int *s, int *f)
{
if (lba >= -150) {
*m = (lba + 150) / (60 * 75);
*s = (lba + 150 - *m * 60 * 75) / 75;
*f = lba + 150 - *m * 60 * 75 - *s * 75;
} else {
*m = (lba + 450150) / (60 * 75);
*s = (lba + 450150 - *m * 60 * 75) / 75;
*f = lba + 450150 - *m * 60 * 75 - *s * 75;
}
}
int dec_to_bcd(int d)
{
int top, bottom;
top = d / 10;
bottom = d - (top * 10);
return (top << 4) + bottom;
}
int sector_headers_is_ok(struct burn_write_opts *o, int mode)
{
if (mode & BURN_AUDIO) /* no headers for "audio" */
return 1;
if (o->write_type == BURN_WRITE_SAO)
return 1;
/* ts A61031 */
if (o->write_type == BURN_WRITE_TAO)
return 1;
if (mode & BURN_MODE1)
return 2;
return 0;
}
void sector_headers(struct burn_write_opts *o, unsigned char *out,
int mode, int leadin)
{
struct burn_drive *d = o->drive;
unsigned int crc;
int min, sec, frame;
int modebyte = -1;
/* ts A61009 */
#if 1
int ret;
ret = sector_headers_is_ok(o, mode);
if (ret != 2)
return;
modebyte = 1;
#else
if (mode & BURN_AUDIO) /* no headers for "audio" */
return;
if (o->write_type == BURN_WRITE_SAO)
return;
/* ts A61031 */
if (o->write_type == BURN_WRITE_TAO)
return;
if (mode & BURN_MODE1)
modebyte = 1;
#endif
/* ts A61009 : now ensured by burn_disc_write_is_ok() */
/* a ssert(modebyte == 1); */
out[0] = 0;
memset(out + 1, 0xFF, 10); /* sync */
out[11] = 0;
if (leadin) {
burn_lba_to_msf(d->rlba, &min, &sec, &frame);
out[12] = dec_to_bcd(min) + 0xA0;
out[13] = dec_to_bcd(sec);
out[14] = dec_to_bcd(frame);
out[15] = modebyte;
} else {
burn_lba_to_msf(d->alba, &min, &sec, &frame);
out[12] = dec_to_bcd(min);
out[13] = dec_to_bcd(sec);
out[14] = dec_to_bcd(frame);
out[15] = modebyte;
}
if (mode & BURN_MODE1) {
crc = crc_32(out, 2064);
out[2064] = crc & 0xFF;
crc >>= 8;
out[2065] = crc & 0xFF;
crc >>= 8;
out[2066] = crc & 0xFF;
crc >>= 8;
out[2067] = crc & 0xFF;
}
if (mode & BURN_MODE1) {
memset(out + 2068, 0, 8);
parity_p(out);
parity_q(out);
}
scramble(out);
}
#if 0
void process_q(struct burn_drive *d, unsigned char *q)
{
unsigned char i[5];
int mode;
mode = q[0] & 0xF;
/* burn_print(12, "mode: %d : ", mode);*/
switch (mode) {
case 1:
/* burn_print(12, "tno = %d : ", q[1]);
burn_print(12, "index = %d\n", q[2]);
*/
/* q[1] is the track number (starting at 1) q[2] is the index
number (starting at 0) */
#warning this is totally bogus
if (q[1] - 1 > 99)
break;
if (q[2] > d->toc->track[q[1] - 1].indices) {
burn_print(12, "new index at %d\n", d->alba);
d->toc->track[q[1] - 1].index[q[2]] = d->alba;
d->toc->track[q[1] - 1].indices++;
}
break;
case 2:
/* XXX dont ignore these */
break;
case 3:
/* burn_print(12, "ISRC data in mode 3 q\n");*/
i[0] = isrc[(q[1] << 2) >> 2];
/* burn_print(12, "0x%x 0x%x 0x%x 0x%x 0x%x\n", q[1], q[2], q[3], q[4], q[5]);
burn_print(12, "ISRC - %c%c%c%c%c\n", i[0], i[1], i[2], i[3], i[4]);
*/
break;
default:
/* ts A61009 : if reactivated then witout Assert */
a ssert(0);
}
}
#endif
/* this needs more info. subs in the data? control/adr? */
#warning sector_identify needs to be written
int sector_identify(unsigned char *data)
{
scramble(data);
/*
check mode byte for 1 or 2
test parity to see if it's a valid sector
if invalid, return BURN_MODE_AUDIO;
else return mode byte (what about mode 2 formless? heh)
*/
return BURN_MODE1;
}

View File

@ -1,35 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __SECTOR
#define __SECTOR
#include "libburn.h"
#include "transport.h"
struct burn_drive;
struct isrc;
int dec_to_bcd(int);
int sector_toc(struct burn_write_opts *, int mode);
int sector_pregap(struct burn_write_opts *, unsigned char tno,
unsigned char control, int mode);
int sector_postgap(struct burn_write_opts *, unsigned char tno,
unsigned char control, int mode);
int sector_lout(struct burn_write_opts *, unsigned char control, int mode);
int sector_data(struct burn_write_opts *, struct burn_track *t, int psub);
/* ts A61009 */
int sector_headers_is_ok(struct burn_write_opts *o, int mode);
void sector_headers(struct burn_write_opts *, unsigned char *,
int mode, int leadin);
void subcode_user(struct burn_write_opts *, unsigned char *s,
unsigned char tno, unsigned char control,
unsigned char index, struct isrc *isrc, int psub);
int sector_identify(unsigned char *);
void process_q(struct burn_drive *d, unsigned char *q);
#endif /* __SECTOR */

View File

@ -1,769 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* >>> ts A61021 : for testing the new arrangement of code
please outcomment these defines : */
/* Keeps alive old enumerate_common(). New version delegates much work
to methods in drive, mmc, spc, and sbc .
*/
#define Scsi_freebsd_make_own_enumeratE 1
/* Keeps alive old sg_enumerate(). New version delegates most work to
sg_give_next_adr().
*/
#define Scsi_freebsd_old_sg_enumeratE 1
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <camlib.h>
#include <cam/scsi/scsi_message.h>
#include <cam/scsi/scsi_pass.h>
#include <err.h> /* XXX */
#include "transport.h"
#include "drive.h"
#include "sg.h"
#include "spc.h"
#include "mmc.h"
#include "sbc.h"
#include "debug.h"
#include "toc.h"
#include "util.h"
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
static void enumerate_common(char *fname, int bus_no, int host_no,
int channel_no, int target_no, int lun_no);
/* ts A51221 */
int burn_drive_is_banned(char *device_address);
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
int mmc_function_spy(char * text);
#ifdef Scsi_freebsd_old_sg_enumeratE
int sg_give_next_adr(burn_drive_enumerator_t *idx,
char adr[], int adr_size, int initialize)
{
return (0);
}
int sg_is_enumerable_adr(char* adr)
{
return (0);
}
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no)
{
return (0);
}
#else /* Scsi_freebsd_old_sg_enumeratE */
/* ts A61021 : Moved most code from sg_enumerate under sg_give_next_adr() */
/* Some helper functions for sg_give_next_adr() */
static int sg_init_enumerator(burn_drive_enumerator_t *idx)
{
idx->skip_device = 0;
if ((idx->fd = open(XPT_DEVICE, O_RDWR)) == -1) {
warn("couldn't open %s", XPT_DEVICE);
return -1;
}
bzero(&(idx->ccb), sizeof(union ccb));
idx->ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
idx->ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
idx->ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
idx->ccb.ccb_h.func_code = XPT_DEV_MATCH;
idx->bufsize = sizeof(struct dev_match_result) * 100;
idx->ccb.cdm.match_buf_len = idx->bufsize;
idx->ccb.cdm.matches = (struct dev_match_result *)malloc(idx->bufsize);
if (idx->ccb.cdm.matches == NULL) {
warnx("can't malloc memory for matches");
close(idx->fd);
return -1;
}
idx->ccb.cdm.num_matches = 0;
idx->i = idx->ccb.cdm.num_matches; /* to trigger buffer load */
/*
* We fetch all nodes, since we display most of them in the default
* case, and all in the verbose case.
*/
idx->ccb.cdm.num_patterns = 0;
idx->ccb.cdm.pattern_buf_len = 0;
return 1;
}
static int sg_next_enumeration_buffer(burn_drive_enumerator_t *idx)
{
/*
* We do the ioctl multiple times if necessary, in case there are
* more than 100 nodes in the EDT.
*/
if (ioctl(idx->fd, CAMIOCOMMAND, &(idx->ccb)) == -1) {
warn("error sending CAMIOCOMMAND ioctl");
return -1;
}
if ((idx->ccb.ccb_h.status != CAM_REQ_CMP)
|| ((idx->ccb.cdm.status != CAM_DEV_MATCH_LAST)
&& (idx->ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
warnx("got CAM error %#x, CDM error %d\n",
idx->ccb.ccb_h.status, idx->ccb.cdm.status);
return -1;
}
return 1;
}
/** Returns the next index number and the next enumerated drive address.
@param idx An opaque handle. Make no own theories about it.
@param adr Takes the reply
@param adr_size Gives maximum size of reply including final 0
@param initialize 1 = start new,
0 = continue, use no other values for now
-1 = finish
@return 1 = reply is a valid address , 0 = no further address available
-1 = severe error (e.g. adr_size too small)
*/
int sg_give_next_adr(burn_drive_enumerator_t *idx,
char adr[], int adr_size, int initialize)
{
int ret;
if (initialize == 1) {
ret = sg_init_enumerator(idx);
if (ret<=0)
return ret;
} else if (initialize == -1) {
if(idx->fd != -1)
close(idx->fd);
idx->fd = -1;
return 0;
}
try_item:; /* This spaghetti loop keeps the number of tabs small */
/* Loop content from old sg_enumerate() */
while (idx->i >= idx->ccb.cdm.num_matches) {
ret = sg_next_enumeration_buffer(idx);
if (ret<=0)
return -1;
if (!((idx->ccb.ccb_h.status == CAM_REQ_CMP)
&& (idx->ccb.cdm.status == CAM_DEV_MATCH_MORE)) )
return 0;
idx->i = 0;
}
switch (idx->ccb.cdm.matches[idx->i].type) {
case DEV_MATCH_BUS:
break;
case DEV_MATCH_DEVICE: {
struct device_match_result* result;
result = &(idx->ccb.cdm.matches[i].result.device_result);
if (result->flags & DEV_RESULT_UNCONFIGURED)
idx->skip_device = 1;
else
idx->skip_device = 0;
break;
}
case DEV_MATCH_PERIPH: {
struct periph_match_result* result;
char buf[64];
result = &(idx->ccb.cdm.matches[i].result.periph_result);
if (idx->skip_device ||
strcmp(result->periph_name, "pass") == 0)
break;
snprintf(buf, sizeof (buf), "/dev/%s%d",
result->periph_name, result->unit_number);
if(adr_size <= strlen(buf)
return -1;
strcpy(adr, buf);
/* Found next enumerable address */
return 1;
}
default:
/* printf(stderr, "unknown match type\n"); */
break;
}
(idx->i)++;
goto try_item; /* Regular function exit is return 1 above */
}
int sg_is_enumerable_adr(char* adr)
{
burn_drive_enumerator_t idx;
int initialize = 1;
char buf[64];
while(1) {
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
initialize = 0;
if (ret <= 0)
break;
if (strcmp(adr, buf) == 0) {
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
return 1;
}
}
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
return (0);
}
/** Try to obtain SCSI address parameters.
@return 1 is success , 0 is failure
*/
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no)
{
burn_drive_enumerator_t idx;
int initialize = 1;
char buf[64];
struct periph_match_result* result;
while(1) {
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
initialize = 0;
if (ret <= 0)
break;
if (strcmp(adr, buf) != 0)
continue;
result = &(idx->ccb.cdm.matches[i].result.periph_result);
*bus_no = result->path_id;
*host_no = result->path_id;
*channel_no = 0;
*target_no = result->target_id
*lun_no = result->target_lun;
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
return 1;
}
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
return (0);
}
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
int sg_close_drive(struct burn_drive * d)
{
if (d->cam != NULL) {
cam_close_device(d->cam);
d->cam = NULL;
}
return 0;
}
int sg_drive_is_open(struct burn_drive * d)
{
return (d->cam != NULL);
}
void ata_enumerate(void)
{
/* ts A61021: Only a dummy function is needed in FreeBSD */
/* The difference between sg and ata should be encapsulated
in sg-linux.c */
;
}
void sg_enumerate(void)
{
#ifdef Scsi_freebsd_old_sg_enumeratE
union ccb ccb;
int bufsize, fd;
unsigned int i;
int skip_device = 0;
if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
warn("couldn't open %s", XPT_DEVICE);
return;
}
bzero(&ccb, sizeof(union ccb));
ccb.ccb_h.path_id = CAM_XPT_PATH_ID;
ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
ccb.ccb_h.target_lun = CAM_LUN_WILDCARD;
ccb.ccb_h.func_code = XPT_DEV_MATCH;
bufsize = sizeof(struct dev_match_result) * 100;
ccb.cdm.match_buf_len = bufsize;
ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize);
if (ccb.cdm.matches == NULL) {
warnx("can't malloc memory for matches");
close(fd);
return;
}
ccb.cdm.num_matches = 0;
/*
* We fetch all nodes, since we display most of them in the default
* case, and all in the verbose case.
*/
ccb.cdm.num_patterns = 0;
ccb.cdm.pattern_buf_len = 0;
/*
* We do the ioctl multiple times if necessary, in case there are
* more than 100 nodes in the EDT.
*/
do {
if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) {
warn("error sending CAMIOCOMMAND ioctl");
break;
}
if ((ccb.ccb_h.status != CAM_REQ_CMP)
|| ((ccb.cdm.status != CAM_DEV_MATCH_LAST)
&& (ccb.cdm.status != CAM_DEV_MATCH_MORE))) {
warnx("got CAM error %#x, CDM error %d\n",
ccb.ccb_h.status, ccb.cdm.status);
break;
}
for (i = 0; i < ccb.cdm.num_matches; i++) {
switch (ccb.cdm.matches[i].type) {
case DEV_MATCH_BUS:
break;
case DEV_MATCH_DEVICE: {
struct device_match_result* result;
result = &ccb.cdm.matches[i].result.device_result;
if (result->flags & DEV_RESULT_UNCONFIGURED)
skip_device = 1;
else
skip_device = 0;
break;
}
case DEV_MATCH_PERIPH: {
struct periph_match_result* result;
char buf[64];
result = &ccb.cdm.matches[i].result.periph_result;
if (skip_device || strcmp(result->periph_name, "pass") == 0)
break;
snprintf(buf, sizeof (buf), "/dev/%s%d", result->periph_name, result->unit_number);
/* ts A51221 */
if (burn_drive_is_banned(buf))
break;
enumerate_common(buf, result->path_id, result->path_id, 0,
result->target_id, result->target_lun);
break;
}
default:
fprintf(stdout, "unknown match type\n");
break;
}
}
} while ((ccb.ccb_h.status == CAM_REQ_CMP)
&& (ccb.cdm.status == CAM_DEV_MATCH_MORE));
close(fd);
#else /* Scsi_freebsd_old_sg_enumeratE */
burn_drive_enumerator_t idx;
int initialize = 1;
char buf[64];
while(1) {
ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
initialize = 0;
if (ret <= 0)
break;
if (burn_drive_is_banned(buf))
continue;
enumerate_common(buf, idx.result->path_id, idx.result->path_id,
0, idx.result->target_id,
idx.result->target_lun);
}
sg_give_next_adr(&idx, buf, sizeof(buf), -1);
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
}
#ifdef Scsi_freebsd_make_own_enumeratE
/* ts A61021: The old version which mixes SCSI and operating system adapter
*/
static void enumerate_common(char *fname, int bus_no, int host_no,
int channel_no, int target_no, int lun_no)
{
struct burn_drive *t;
struct burn_drive out;
/* ts A60923 */
out.bus_no = bus_no;
out.host = host_no;
out.id = target_no;
out.channel = channel_no;
out.lun = lun_no;
out.devname = burn_strdup(fname);
out.cam = NULL;
out.start_lba= -2000000000;
out.end_lba= -2000000000;
out.read_atip = mmc_read_atip;
out.grab = sg_grab;
out.release = sg_release;
out.drive_is_open= sg_drive_is_open;
out.issue_command = sg_issue_command;
out.getcaps = spc_getcaps;
out.released = 1;
out.status = BURN_DISC_UNREADY;
out.eject = sbc_eject;
out.load = sbc_load;
out.lock = spc_prevent;
out.unlock = spc_allow;
out.read_disc_info = spc_sense_write_params;
out.get_erase_progress = spc_get_erase_progress;
out.test_unit_ready = spc_test_unit_ready;
out.probe_write_modes = spc_probe_write_modes;
out.read_toc = mmc_read_toc;
out.write = mmc_write;
out.erase = mmc_erase;
out.read_sectors = mmc_read_sectors;
out.perform_opc = mmc_perform_opc;
out.set_speed = mmc_set_speed;
out.send_parameters = spc_select_error_params;
out.send_write_parameters = spc_select_write_params;
out.send_cue_sheet = mmc_send_cue_sheet;
out.sync_cache = mmc_sync_cache;
out.get_nwa = mmc_get_nwa;
out.close_disc = mmc_close_disc;
out.close_session = mmc_close_session;
out.close_track_session = mmc_close;
out.read_buffer_capacity = mmc_read_buffer_capacity;
out.idata = malloc(sizeof(struct burn_scsi_inquiry_data));
out.idata->valid = 0;
out.mdata = malloc(sizeof(struct scsi_mode_data));
out.mdata->valid = 0;
if (out.idata == NULL || out.mdata == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020108,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Could not allocate new drive object", 0, 0);
return;
}
memset(&out.params, 0, sizeof(struct params));
t = burn_drive_register(&out);
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
mmc_function_spy("enumerate_common : -------- doing grab");
/* try to get the drive info */
if (t->grab(t)) {
burn_print(2, "getting drive info\n");
t->getcaps(t);
t->unlock(t);
t->released = 1;
} else {
burn_print(2, "unable to grab new located drive\n");
}
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
mmc_function_spy("enumerate_common : ----- would release ");
}
#else /* Scsi_freebsd_make_own_enumeratE */
/* The new, more concise version of enumerate_common */
static void enumerate_common(char *fname, int bus_no, int host_no,
int channel_no, int target_no, int lun_no)
{
int ret;
struct burn_drive out;
/* General libburn drive setup */
burn_setup_drive(&out, fname);
/* This transport adapter uses SCSI-family commands and models
(seems the adapter would know better than its boss, if ever) */
ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
target_no, lun_no, 0);
if (ret<=0)
return;
/* Operating system adapter is CAM */
/* Adapter specific handles and data */
out.cam = NULL;
/* Adapter specific functions */
out.grab = sg_grab;
out.release = sg_release;
out.drive_is_open = sg_drive_is_open;
out.issue_command = sg_issue_command;
/* Finally register drive and inquire drive information */
burn_drive_finish_enum(&out);
}
#endif /* ! Scsi_freebsd_make_own_enumeratE */
/* ts A61021: do not believe this:
we use the sg reference count to decide whether we can use the
drive or not.
if refcount is not one, drive is open somewhere else.
*/
int sg_grab(struct burn_drive *d)
{
int count;
struct cam_device *cam;
mmc_function_spy("sg_grab");
assert(d->cam == NULL);
cam = cam_open_device(d->devname, O_RDWR);
if (cam == NULL) {
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Could not grab drive", 0/*os_errno*/, 0);
return 0;
}
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
count = 1;
if (1 == count) {
d->cam = cam;
fcntl(cam->fd, F_SETOWN, getpid());
d->released = 0;
return 1;
}
burn_print(1, "could not acquire drive - already open\n");
sg_close_drive(d);
return 0;
}
/*
non zero return means you still have the drive and it's not
in a state to be released? (is that even possible?)
*/
int sg_release(struct burn_drive *d)
{
mmc_function_spy("sg_release");
if (d->cam == NULL) {
burn_print(1, "release an ungrabbed drive. die\n");
return 0;
}
mmc_function_spy("sg_release ----------- closing.");
sg_close_drive(d);
return 0;
}
int sg_issue_command(struct burn_drive *d, struct command *c)
{
int done = 0;
int err;
union ccb *ccb;
char buf[161];
snprintf(buf, sizeof (buf), "sg_issue_command d->cam=%p d->released=%d",
(void*)d->cam, d->released);
mmc_function_spy(buf);
if (d->cam == NULL) {
c->error = 0;
return 0;
}
c->error = 0;
ccb = cam_getccb(d->cam);
cam_fill_csio(&ccb->csio,
1, /* retries */
NULL, /* cbfncp */
CAM_DEV_QFRZDIS, /* flags */
MSG_SIMPLE_Q_TAG, /* tag_action */
NULL, /* data_ptr */
0, /* dxfer_len */
sizeof (ccb->csio.sense_data), /* sense_len */
0, /* cdb_len */
30*1000); /* timeout */
switch (c->dir) {
case TO_DRIVE:
ccb->csio.ccb_h.flags |= CAM_DIR_OUT;
break;
case FROM_DRIVE:
ccb->csio.ccb_h.flags |= CAM_DIR_IN;
break;
case NO_TRANSFER:
ccb->csio.ccb_h.flags |= CAM_DIR_NONE;
break;
}
ccb->csio.cdb_len = c->oplen;
memcpy(&ccb->csio.cdb_io.cdb_bytes, &c->opcode, c->oplen);
memset(&ccb->csio.sense_data, 0, sizeof (ccb->csio.sense_data));
if (c->page) {
ccb->csio.data_ptr = c->page->data;
if (c->dir == FROM_DRIVE) {
ccb->csio.dxfer_len = BUFFER_SIZE;
/* touch page so we can use valgrind */
memset(c->page->data, 0, BUFFER_SIZE);
} else {
assert(c->page->bytes > 0);
ccb->csio.dxfer_len = c->page->bytes;
}
} else {
ccb->csio.data_ptr = NULL;
ccb->csio.dxfer_len = 0;
}
do {
err = cam_send_ccb(d->cam, ccb);
if (err == -1) {
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x0002010c,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Failed to transfer command to drive",
errno, 0);
cam_freeccb(ccb);
sg_close_drive(d);
d->released = 1;
d->busy = BURN_DRIVE_IDLE;
c->error = 1;
return -1;
}
/* XXX */
memcpy(c->sense, &ccb->csio.sense_data, ccb->csio.sense_len);
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
if (!c->retry) {
c->error = 1;
cam_freeccb(ccb);
return 1;
}
switch (scsi_error(d, c->sense, 0)) {
case RETRY:
done = 0;
break;
case FAIL:
done = 1;
c->error = 1;
break;
}
} else {
done = 1;
}
} while (!done);
cam_freeccb(ccb);
return 1;
}
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
int senselen)
{
int key, asc, ascq;
senselen = senselen;
key = sense[2];
asc = sense[12];
ascq = sense[13];
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
key, asc, ascq, d->idata->vendor, d->idata->product);
switch (asc) {
case 0:
burn_print(12, "NO ERROR!\n");
return RETRY;
case 2:
burn_print(1, "not ready\n");
return RETRY;
case 4:
burn_print(1,
"logical unit is in the process of becoming ready\n");
return RETRY;
case 0x20:
if (key == 5)
burn_print(1, "bad opcode\n");
return FAIL;
case 0x21:
burn_print(1, "invalid address or something\n");
return FAIL;
case 0x24:
if (key == 5)
burn_print(1, "invalid field in cdb\n");
else
break;
return FAIL;
case 0x26:
if (key == 5)
burn_print( 1, "invalid field in parameter list\n" );
return FAIL;
case 0x28:
if (key == 6)
burn_print(1,
"Not ready to ready change, medium may have changed\n");
else
break;
return RETRY;
case 0x3A:
burn_print(12, "Medium not present in %s %s\n",
d->idata->vendor, d->idata->product);
d->status = BURN_DISC_EMPTY;
return FAIL;
}
burn_print(1, "unknown failure\n");
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
return FAIL;
}

View File

@ -1,870 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* ts A61010 */
/* #include <a ssert.h> */
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
/* #include <m alloc.h> ts A61013 : not in Linux man 3 malloc */
#include <string.h>
#include <sys/poll.h>
#include <linux/hdreg.h>
#include <stdlib.h>
#include <scsi/sg.h>
#include <scsi/scsi.h>
#include "transport.h"
#include "drive.h"
#include "sg.h"
#include "spc.h"
#include "mmc.h"
#include "sbc.h"
#include "debug.h"
#include "toc.h"
#include "util.h"
/* kludge! glibc headers don't define all the SCSI stuff that we use! */
#ifndef SG_GET_ACCESS_COUNT
# define SG_GET_ACCESS_COUNT 0x2289
#endif
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
static void enumerate_common(char *fname, int bus_no, int host_no,
int channel_no, int target_no, int lun_no);
/* ts A51221 */
int burn_drive_is_banned(char *device_address);
/* ts A60813 : storage objects are in libburn/init.c
wether to use O_EXCL
wether to use O_NOBLOCK with open(2) on devices
wether to take O_EXCL rejection as fatal error */
extern int burn_sg_open_o_excl;
extern int burn_sg_open_o_nonblock;
extern int burn_sg_open_abort_busy;
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
int mmc_function_spy(char * text);
static int sgio_test(int fd)
{
unsigned char test_ops[] = { 0, 0, 0, 0, 0, 0 };
sg_io_hdr_t s;
memset(&s, 0, sizeof(sg_io_hdr_t));
s.interface_id = 'S';
s.dxfer_direction = SG_DXFER_NONE;
s.cmd_len = 6;
s.cmdp = test_ops;
s.timeout = 12345;
return ioctl(fd, SG_IO, &s);
}
/* ts A60925 : ticket 74 */
int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
{
int ret, os_errno, sevno= LIBDAX_MSGS_SEV_DEBUG;
char msg[4096+100];
if(*fd < 0)
return(0);
ret = close(*fd);
*fd = -1337;
if(ret != -1)
return 1;
os_errno= errno;
if (fname != NULL)
sprintf(msg, "Encountered error when closing drive '%s'",
fname);
else
sprintf(msg, "Encountered error when closing drive");
if (sorry)
sevno = LIBDAX_MSGS_SEV_SORRY;
libdax_msgs_submit(libdax_messenger, driveno, 0x00020002,
sevno, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno, 0);
return 0;
}
int sg_drive_is_open(struct burn_drive * d)
{
/* a bit more detailed case distinction than needed */
if (d->fd == -1337)
return 0;
if (d->fd < 0)
return 0;
return 1;
}
/* ts A60924 */
int sg_handle_busy_device(char *fname, int os_errno)
{
char msg[4096];
/* ts A60814 : i saw no way to do this more nicely */
if (burn_sg_open_abort_busy) {
fprintf(stderr,
"\nlibburn: FATAL : Application triggered abort on busy device '%s'\n",
fname);
/* ts A61007 */
abort();
/* a ssert("drive busy" == "non fatal"); */
}
/* ts A60924 : now reporting to libdax_msgs */
sprintf(msg, "Cannot open busy device '%s'", fname);
libdax_msgs_submit(libdax_messenger, -1, 0x00020001,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_LOW,
msg, os_errno, 0);
return 1;
}
/* ts A60922 ticket 33 */
/** Returns the next index number and the next enumerated drive address.
@param idx An opaque handle. Make no own theories about it.
@param adr Takes the reply
@param adr_size Gives maximum size of reply including final 0
@param initialize 1 = start new,
0 = continue, use no other values for now
-1 = finish
@return 1 = reply is a valid address , 0 = no further address available
-1 = severe error (e.g. adr_size too small)
*/
int sg_give_next_adr(burn_drive_enumerator_t *idx,
char adr[], int adr_size, int initialize)
{
/* sg.h : typedef int burn_drive_enumerator_t; */
static int sg_limit = 32, ata_limit = 26;
int baseno = 0;
if (initialize == -1)
return 0;
if (initialize == 1)
*idx = -1;
(*idx)++;
if (*idx >= sg_limit)
goto next_ata;
if (adr_size < 10)
return -1;
sprintf(adr, "/dev/sg%d", *idx);
return 1;
next_ata:;
baseno += sg_limit;
if (*idx - baseno >= ata_limit)
goto next_nothing;
if (adr_size < 9)
return -1;
sprintf(adr, "/dev/hd%c", 'a' + (*idx - baseno));
return 1;
next_nothing:;
baseno += ata_limit;
return 0;
}
int sg_is_enumerable_adr(char *adr)
{
char fname[4096];
int i, ret = 0, first = 1;
while (1) {
ret= sg_give_next_adr(&i, fname, sizeof(fname), first);
if(ret <= 0)
break;
first = 0;
if (strcmp(adr, fname) == 0)
return 1;
}
return(0);
}
/* ts A60926 */
int sg_release_siblings(int sibling_fds[], int *sibling_count)
{
int i;
char msg[81];
for(i= 0; i < *sibling_count; i++)
sg_close_drive_fd(NULL, -1, &(sibling_fds[i]), 0);
if(*sibling_count > 0) {
sprintf(msg, "Closed %d O_EXCL scsi siblings", *sibling_count);
libdax_msgs_submit(libdax_messenger, -1, 0x00020007,
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg, 0,0);
}
*sibling_count = 0;
return 1;
}
/* ts A60926 */
int sg_open_drive_fd(char *fname, int scan_mode)
{
int open_mode = O_RDWR, fd;
char msg[81];
/* ts A60813 - A60927
O_EXCL with devices is a non-POSIX feature
of Linux kernels. Possibly introduced 2002.
Mentioned in "The Linux SCSI Generic (sg) HOWTO" */
if(burn_sg_open_o_excl)
open_mode |= O_EXCL;
/* ts A60813
O_NONBLOCK was already hardcoded in ata_ but not in sg_.
There must be some reason for this. So O_NONBLOCK is
default mode for both now. Disable on own risk. */
if(burn_sg_open_o_nonblock)
open_mode |= O_NONBLOCK;
/* <<< debugging
fprintf(stderr,
"\nlibburn: experimental: o_excl= %d , o_nonblock= %d, abort_on_busy= %d\n",
burn_sg_open_o_excl,burn_sg_open_o_nonblock,burn_sg_open_abort_busy);
fprintf(stderr,
"libburn: experimental: O_EXCL= %d , O_NONBLOCK= %d\n",
!!(open_mode&O_EXCL),!!(open_mode&O_NONBLOCK));
*/
fd = open(fname, open_mode);
if (fd == -1) {
/* <<< debugging
fprintf(stderr,
"\nlibburn: experimental: fname= %s , errno= %d\n",
fname,errno);
*/
if (errno == EBUSY) {
sg_handle_busy_device(fname, errno);
return -1;
}
if (scan_mode)
return -1;
sprintf(msg, "Failed to open device '%s'",fname);
libdax_msgs_submit(libdax_messenger, -1, 0x00020005,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
msg, errno, 0);
return -1;
}
return fd;
}
/* ts A60926 */
int sg_open_scsi_siblings(char *path, int driveno,
int sibling_fds[], int *sibling_count,
int host_no, int channel_no, int id_no, int lun_no)
{
int tld, i, ret, fd, i_bus_no = -1;
int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
char msg[161], fname[81];
static char tldev[][81]= {"/dev/sr%d", "/dev/scd%d", "/dev/st%d", ""};
if(host_no < 0 || id_no < 0 || channel_no < 0 || lun_no < 0)
return(2);
if(*sibling_count > 0)
sg_release_siblings(sibling_fds, sibling_count);
for (tld = 0; tldev[tld][0] != 0; tld++) {
for (i = 0; i < 32; i++) {
sprintf(fname, tldev[tld], i);
ret = sg_obtain_scsi_adr(fname, &i_bus_no, &i_host_no,
&i_channel_no, &i_target_no, &i_lun_no);
if (ret <= 0)
continue;
if (i_host_no != host_no || i_channel_no != channel_no)
continue;
if (i_target_no != id_no || i_lun_no != lun_no)
continue;
fd = sg_open_drive_fd(fname, 0);
if (fd < 0)
goto failed;
if (*sibling_count>=LIBBURN_SG_MAX_SIBLINGS) {
sprintf(msg, "Too many scsi siblings of '%s'",
path);
libdax_msgs_submit(libdax_messenger,
driveno, 0x00020006,
LIBDAX_MSGS_SEV_FATAL,
LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
goto failed;
}
sprintf(msg, "Opened O_EXCL scsi sibling '%s' of '%s'",
fname, path);
libdax_msgs_submit(libdax_messenger, driveno,
0x00020004,
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
sibling_fds[*sibling_count] = fd;
(*sibling_count)++;
}
}
return(1);
failed:;
sg_release_siblings(sibling_fds, sibling_count);
return 0;
}
/* ts A60926 */
int sg_close_drive(struct burn_drive *d)
{
int ret;
if (!burn_drive_is_open(d))
return 0;
sg_release_siblings(d->sibling_fds, &(d->sibling_count));
ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
return ret;
}
void ata_enumerate(void)
{
struct hd_driveid tm;
int i, fd;
char fname[10];
for (i = 0; i < 26; i++) {
sprintf(fname, "/dev/hd%c", 'a' + i);
/* ts A51221 */
if (burn_drive_is_banned(fname))
continue;
fd = sg_open_drive_fd(fname, 1);
if (fd == -1)
continue;
/* found a drive */
ioctl(fd, HDIO_GET_IDENTITY, &tm);
/* not atapi */
if (!(tm.config & 0x8000) || (tm.config & 0x4000)) {
sg_close_drive_fd(fname, -1, &fd, 0);
continue;
}
/* if SG_IO fails on an atapi device, we should stop trying to
use hd* devices */
if (sgio_test(fd) == -1) {
sg_close_drive_fd(fname, -1, &fd, 0);
return;
}
if (sg_close_drive_fd(fname, -1, &fd, 1) <= 0)
continue;
enumerate_common(fname, -1, -1, -1, -1, -1);
}
}
void sg_enumerate(void)
{
struct sg_scsi_id sid;
int i, fd, sibling_fds[LIBBURN_SG_MAX_SIBLINGS], sibling_count= 0, ret;
int bus_no = -1;
char fname[10];
for (i = 0; i < 32; i++) {
sprintf(fname, "/dev/sg%d", i);
/* ts A51221 */
if (burn_drive_is_banned(fname))
continue;
/* ts A60927 */
fd = sg_open_drive_fd(fname, 1);
if (fd == -1)
continue;
/* found a drive */
ioctl(fd, SG_GET_SCSI_ID, &sid);
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
/* Hearsay A61005 */
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus_no) == -1)
bus_no = -1;
#endif
if (sg_close_drive_fd(fname, -1, &fd,
sid.scsi_type == TYPE_ROM ) <= 0)
continue;
if (sid.scsi_type != TYPE_ROM)
continue;
/* ts A60927 : trying to do locking with growisofs */
if(burn_sg_open_o_excl>1) {
ret = sg_open_scsi_siblings(
fname, -1, sibling_fds, &sibling_count,
sid.host_no, sid.channel,
sid.scsi_id, sid.lun);
if (ret<=0) {
sg_handle_busy_device(fname, 0);
continue;
}
/* the final occupation will be done in sg_grab() */
sg_release_siblings(sibling_fds, &sibling_count);
}
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
if(bus_no == -1)
bus_no = 1000 * (sid.host_no + 1) + sid.channel;
#else
bus_no = sid.host_no;
#endif
enumerate_common(fname, bus_no, sid.host_no, sid.channel,
sid.scsi_id, sid.lun);
}
}
/* ts A60923 - A61005 : introduced new SCSI parameters */
/* ts A61021 : moved non os-specific code to spc,sbc,mmc,drive */
static void enumerate_common(char *fname, int bus_no, int host_no,
int channel_no, int target_no, int lun_no)
{
int ret, i;
struct burn_drive out;
/* General libburn drive setup */
burn_setup_drive(&out, fname);
/* This transport adapter uses SCSI-family commands and models
(seems the adapter would know better than its boss, if ever) */
ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
target_no, lun_no, 0);
if (ret<=0)
return;
/* Operating system adapter is Linux Generic SCSI (sg) */
/* Adapter specific handles and data */
out.fd = -1337;
out.sibling_count = 0;
for(i= 0; i<LIBBURN_SG_MAX_SIBLINGS; i++)
out.sibling_fds[i] = -1337;
/* Adapter specific functions */
out.grab = sg_grab;
out.release = sg_release;
out.drive_is_open= sg_drive_is_open;
out.issue_command = sg_issue_command;
/* Finally register drive and inquire drive information */
burn_drive_finish_enum(&out);
}
/*
we use the sg reference count to decide whether we can use the
drive or not.
if refcount is not one, drive is open somewhere else.
ts A60813: this test is too late. O_EXCL is the stronger solution.
After all the test was disabled already in icculus.org/burn CVS.
*/
int sg_grab(struct burn_drive *d)
{
int fd, count, os_errno= 0, ret;
/* ts A60813 */
int open_mode = O_RDWR;
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
mmc_function_spy("sg_grab");
/* ts A60813 - A60927
O_EXCL with devices is a non-POSIX feature
of Linux kernels. Possibly introduced 2002.
Mentioned in "The Linux SCSI Generic (sg) HOWTO".
*/
if(burn_sg_open_o_excl)
open_mode |= O_EXCL;
/* ts A60813
O_NONBLOCK was hardcoded here. So it should stay default mode. */
if(burn_sg_open_o_nonblock)
open_mode |= O_NONBLOCK;
/* ts A60813
After enumeration the drive fd is probably still open.
-1337 is the initial value of burn_drive.fd and the value after
relase of drive. Unclear why not the official error return
value -1 of open(2) war used. */
/* ts A60822: was if(d->fd == -1337) { */
if(! burn_drive_is_open(d)) {
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
mmc_function_spy("sg_grab ----------- opening");
/* ts A60926 */
if(burn_sg_open_o_excl>1) {
fd = -1;
ret = sg_open_scsi_siblings(d->devname,
d->global_index,d->sibling_fds,
&(d->sibling_count),
d->host, d->channel, d->id, d->lun);
if(ret <= 0)
goto drive_is_in_use;
}
fd = open(d->devname, open_mode);
os_errno = errno;
} else
fd= d->fd;
/* ts A61007 : this is redundant */
/* a ssert(fd != -1337); */
if (fd >= 0) {
/* ts A60814:
according to my experiments this test would work now ! */
/* ts A60926 : this was disabled */
/* Tests with growisofs on kernel 2.4.21 yielded that this
does not help against blocking on busy drives.
*/
/* <<< the old dummy */
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
count = 1;
if (1 == count) {
d->fd = fd;
fcntl(fd, F_SETOWN, getpid());
d->released = 0;
return 1;
}
drive_is_in_use:;
libdax_msgs_submit(libdax_messenger, d->global_index,
0x00020003,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Could not grab drive - already in use", 0, 0);
sg_close_drive(d);
d->fd = -1337;
return 0;
}
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020003,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Could not grab drive", os_errno, 0);
return 0;
}
/*
non zero return means you still have the drive and it's not
in a state to be released? (is that even possible?)
*/
int sg_release(struct burn_drive *d)
{
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
mmc_function_spy("sg_release");
if (d->fd < 1) {
burn_print(1, "release an ungrabbed drive. die\n");
return 0;
}
/* ts A60821
<<< debug: for tracing calls which might use open drive fds */
mmc_function_spy("sg_release ----------- closing");
sg_close_drive(d);
return 0;
}
int sg_issue_command(struct burn_drive *d, struct command *c)
{
int done = 0, no_c_page = 0;
int err;
sg_io_hdr_t s;
#ifdef Libburn_log_sg_commandS
/* <<< ts A61030 */
static FILE *fp= NULL;
static int fpcount= 0;
int i;
#endif /* Libburn_log_sg_commandS */
/* <<< ts A60821
debug: for tracing calls which might use open drive fds */
char buf[161];
sprintf(buf,"sg_issue_command d->fd= %d d->released= %d\n",
d->fd,d->released);
mmc_function_spy(buf);
#ifdef Libburn_log_sg_commandS
/* <<< ts A61030 */
if(fp==NULL) {
fp= fopen("/tmp/libburn_sg_command_log","a");
fprintf(fp,"\n-----------------------------------------\n");
}
for(i=0;i<10;i++)
fprintf(fp,"%2.2x ", c->opcode[i]);
fprintf(fp,"\n");
fpcount++;
#endif /* Libburn_log_sg_commandS */
/* ts A61010 : with no fd there is no chance to send an ioctl */
if (d->fd < 0) {
c->error = 1;
return 0;
}
c->error = 0;
memset(&s, 0, sizeof(sg_io_hdr_t));
s.interface_id = 'S';
if (c->dir == TO_DRIVE)
s.dxfer_direction = SG_DXFER_TO_DEV;
else if (c->dir == FROM_DRIVE)
s.dxfer_direction = SG_DXFER_FROM_DEV;
else if (c->dir == NO_TRANSFER) {
s.dxfer_direction = SG_DXFER_NONE;
/* ts A61007 */
/* a ssert(!c->page); */
no_c_page = 1;
}
s.cmd_len = c->oplen;
s.cmdp = c->opcode;
s.mx_sb_len = 32;
s.sbp = c->sense;
memset(c->sense, 0, sizeof(c->sense));
s.timeout = 200000;
if (c->page && !no_c_page) {
s.dxferp = c->page->data;
if (c->dir == FROM_DRIVE) {
s.dxfer_len = BUFFER_SIZE;
/* touch page so we can use valgrind */
memset(c->page->data, 0, BUFFER_SIZE);
} else {
/* ts A61010 */
/* a ssert(c->page->bytes > 0); */
if (c->page->bytes <= 0) {
c->error = 1;
return 0;
}
s.dxfer_len = c->page->bytes;
}
} else {
s.dxferp = NULL;
s.dxfer_len = 0;
}
s.usr_ptr = c;
do {
err = ioctl(d->fd, SG_IO, &s);
/* ts A61010 */
/* a ssert(err != -1); */
if (err == -1) {
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x0002010c,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Failed to transfer command to drive",
errno, 0);
sg_close_drive(d);
d->released = 1;
d->busy = BURN_DRIVE_IDLE;
c->error = 1;
return -1;
}
if (s.sb_len_wr) {
if (!c->retry) {
c->error = 1;
/* A61106: rather than : return 1 */
goto ex;
}
switch (scsi_error(d, s.sbp, s.sb_len_wr)) {
case RETRY:
done = 0;
break;
case FAIL:
done = 1;
c->error = 1;
break;
}
} else {
done = 1;
}
} while (!done);
/* ts A61106 */
ex:;
if (c->error) {
/* >>> to become d->notify_error() */
scsi_notify_error(d, c, s.sbp, s.sb_len_wr, 0);
}
return 1;
}
/* ts A61030 - A61109 */
/* @param flag bit0=do report conditions which are considered not an error */
int scsi_notify_error(struct burn_drive *d, struct command *c,
unsigned char *sense, int senselen, int flag)
{
int key= -1, asc= -1, ascq= -1, ret;
char msg[160];
if (d->silent_on_scsi_error)
return 1;
if (senselen > 2)
key = sense[2];
if (senselen > 13) {
asc = sense[12];
ascq = sense[13];
}
if(!(flag & 1)) {
/* SPC : TEST UNIT READY command */
if (c->opcode[0] == 0)
return 1;
/* MMC : READ DISC INFORMATION command */
if (c->opcode[0] == 0x51)
if (key == 0x2 && asc == 0x3A &&
ascq>=0 && ascq <= 0x02) /* MEDIUM NOT PRESENT */
return 1;
}
sprintf(msg,"SCSI error condition on command %2.2Xh :", c->opcode[0]);
if (key>=0)
sprintf(msg+strlen(msg), " key=%Xh", key);
if (asc>=0)
sprintf(msg+strlen(msg), " asc=%2.2Xh", asc);
if (ascq>=0)
sprintf(msg+strlen(msg), " ascq=%2.2Xh", ascq);
ret = libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010f,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
return ret;
}
enum response scsi_error(struct burn_drive *d, unsigned char *sense,
int senselen)
{
int key, asc, ascq;
senselen = senselen;
key = sense[2];
asc = sense[12];
ascq = sense[13];
burn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
key, asc, ascq, d->idata->vendor, d->idata->product);
switch (asc) {
case 0:
burn_print(12, "NO ERROR!\n");
return RETRY;
case 2:
burn_print(1, "not ready\n");
return RETRY;
case 4:
burn_print(1,
"logical unit is in the process of becoming ready\n");
return RETRY;
case 0x20:
if (key == 5)
burn_print(1, "bad opcode\n");
return FAIL;
case 0x21:
burn_print(1, "invalid address or something\n");
return FAIL;
case 0x24:
if (key == 5)
burn_print(1, "invalid field in cdb\n");
else
break;
return FAIL;
case 0x26:
if ( key == 5 )
burn_print( 1, "invalid field in parameter list\n" );
return FAIL;
case 0x28:
if (key == 6)
burn_print(1,
"Not ready to ready change, medium may have changed\n");
else
break;
return RETRY;
case 0x3A:
burn_print(12, "Medium not present in %s %s\n",
d->idata->vendor, d->idata->product);
d->status = BURN_DISC_EMPTY;
return FAIL;
}
burn_print(1, "unknown failure\n");
burn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
return FAIL;
}
/* ts A60922 */
/** Try to obtain SCSI address parameters.
@return 1 is success , 0 is failure
*/
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no)
{
int fd, ret;
struct my_scsi_idlun {
int x;
int host_unique_id;
};
struct my_scsi_idlun idlun;
if (strncmp(path, "/dev/hd", 7) == 0
&& path[7] >= 'a' && path[7] <= 'z' && path[8] == 0)
return 0; /* on RIP 14 all hdx return SCSI adr 0,0,0,0 */
fd = open(path, O_RDONLY | O_NONBLOCK);
if(fd < 0)
return 0;
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
/* Hearsay A61005 */
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, bus_no) == -1)
*bus_no = -1;
#endif
/* http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/scsi_g_idlun.html */
ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
sg_close_drive_fd(path, -1, &fd, 0);
if (ret == -1)
return(0);
*host_no= (idlun.x>>24)&255;
*channel_no= (idlun.x>>16)&255;
*target_no= (idlun.x)&255;
*lun_no= (idlun.x>>8)&255;
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
if(*bus_no == -1)
*bus_no = 1000 * (*host_no + 1) + *channel_no;
#else
*bus_no= *host_no;
#endif
return 1;
}

View File

@ -1,13 +0,0 @@
/* ts A61013 : It would be nice if autotools could do that job */
#ifdef __FreeBSD__
#include "sg-freebsd.c"
#else
#include "sg-linux.c"
#endif

View File

@ -1,72 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __SG
#define __SG
#ifdef __FreeBSD__
/* >>> To hold all state information of BSD device enumeration
which are now local in sg_enumerate() . So that sg_give_next_adr()
can work in BSD and sg_enumerate() can use it. */
struct burn_drive_enumeration_state {
#ifdef Scsi_freebsd_old_sg_enumeratE
int dummy;
#else
union ccb ccb;
int bufsize, fd;
unsigned int i;
int skip_device;
#endif /* ! Scsi_freebsd_old_sg_enumeratE */
};
typedef struct burn_drive_enumeration_state burn_drive_enumerator_t;
#else /* __FreeBSD__ */
/* <<< just for testing the C syntax */
struct burn_drive_enumeration_state {
int dummy;
};
typedef struct burn_drive_enumeration_state burn_drive_enumerator_tX;
typedef int burn_drive_enumerator_t;
#endif /* ! __FreeBSD__ */
struct burn_drive;
struct command;
enum response
{ RETRY, FAIL };
/* ts A60925 : ticket 74 */
int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry);
/* ts A60922 ticket 33 */
int sg_give_next_adr(burn_drive_enumerator_t *enm_context,
char adr[], int adr_size, int initialize);
int sg_is_enumerable_adr(char *adr);
int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
int *target_no, int *lun_no);
/* ts A60926 : ticket 33 ++ */
int sg_open_scsi_siblings(char *fname, int driveno,
int sibling_fds[], int *sibling_count,
int host_no, int channel_no, int id_no, int lun_no);
int sg_release_siblings(int sibling_fds[], int *sibling_count);
int sg_close_drive(struct burn_drive *d);
void sg_enumerate(void);
void ata_enumerate(void);
int sg_grab(struct burn_drive *);
int sg_release(struct burn_drive *);
int sg_issue_command(struct burn_drive *, struct command *);
enum response scsi_error(struct burn_drive *, unsigned char *, int);
/* ts A61030 */
/* @param flag bit0=do also report TEST UNIT READY failures */
int scsi_notify_error(struct burn_drive *, struct command *c,
unsigned char *sense, int senselen, int flag);
#endif /* __SG */

View File

@ -1,39 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <stdlib.h>
#include <string.h>
#include "libburn.h"
#include "source.h"
#include "structure.h"
void burn_source_free(struct burn_source *src)
{
if (--src->refcount < 1) {
if (src->free_data)
src->free_data(src);
free(src);
}
}
enum burn_source_status burn_track_set_source(struct burn_track *t,
struct burn_source *s)
{
if (!s->read)
return BURN_SOURCE_FAILED;
s->refcount++;
t->source = s;
/* ts A61031 */
t->open_ended = (s->get_size(s) <= 0);
return BURN_SOURCE_OK;
}
struct burn_source *burn_source_new(void)
{
struct burn_source *out;
out = calloc(1, sizeof(struct burn_source));
out->refcount = 1;
return out;
}

View File

@ -1,8 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __SOURCE
#define __SOURCE
struct burn_source *burn_source_new(void);
#endif /*__SOURCE*/

View File

@ -1,525 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* scsi primary commands */
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
/* ts A61008 */
/* #include <a ssert.h> */
#include <stdlib.h>
#include "transport.h"
#include "spc.h"
#include "mmc.h"
#include "sbc.h"
#include "drive.h"
#include "debug.h"
#include "options.h"
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
/* spc command set */
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 255, 0 };
/*static char SPC_TEST[]={0,0,0,0,0,0};*/
static unsigned char SPC_PREVENT[] = { 0x1e, 0, 0, 0, 1, 0 };
static unsigned char SPC_ALLOW[] = { 0x1e, 0, 0, 0, 0, 0 };
static unsigned char SPC_MODE_SENSE[] = { 0x5a, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char SPC_MODE_SELECT[] =
{ 0x55, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char SPC_REQUEST_SENSE[] = { 0x03, 0, 0, 0, 18, 0 };
static unsigned char SPC_TEST_UNIT_READY[] = { 0x00, 0, 0, 0, 0, 0 };
int spc_test_unit_ready(struct burn_drive *d)
{
struct command c;
c.retry = 0;
c.oplen = sizeof(SPC_TEST_UNIT_READY);
memcpy(c.opcode, SPC_TEST_UNIT_READY, sizeof(SPC_TEST_UNIT_READY));
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
if (c.error)
return (c.sense[2] & 0xF) == 0;
return 1;
}
void spc_request_sense(struct burn_drive *d, struct buffer *buf)
{
struct command c;
c.retry = 0;
c.oplen = sizeof(SPC_REQUEST_SENSE);
memcpy(c.opcode, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
c.page = buf;
c.page->sectors = 0;
c.page->bytes = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
}
int spc_get_erase_progress(struct burn_drive *d)
{
struct buffer b;
spc_request_sense(d, &b);
return (b.data[16] << 8) | b.data[17];
}
void spc_inquiry(struct burn_drive *d)
{
struct buffer buf;
struct burn_scsi_inquiry_data *id;
struct command c;
memcpy(c.opcode, SPC_INQUIRY, sizeof(SPC_INQUIRY));
c.retry = 1;
c.oplen = sizeof(SPC_INQUIRY);
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
id = (struct burn_scsi_inquiry_data *)d->idata;
id->vendor[8] = 0;
id->product[16] = 0;
id->revision[4] = 0;
memcpy(id->vendor, c.page->data + 8, 8);
memcpy(id->product, c.page->data + 16, 16);
memcpy(id->revision, c.page->data + 32, 4);
id->valid = 1;
return;
}
void spc_prevent(struct burn_drive *d)
{
struct command c;
memcpy(c.opcode, SPC_PREVENT, sizeof(SPC_PREVENT));
c.retry = 1;
c.oplen = sizeof(SPC_PREVENT);
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void spc_allow(struct burn_drive *d)
{
struct command c;
memcpy(c.opcode, SPC_ALLOW, sizeof(SPC_ALLOW));
c.retry = 1;
c.oplen = sizeof(SPC_ALLOW);
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void spc_sense_caps(struct burn_drive *d)
{
struct buffer buf;
struct scsi_mode_data *m;
int size;
unsigned char *page;
struct command c;
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
c.opcode[2] = 0x2A;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
size = c.page->data[0] * 256 + c.page->data[1];
m = d->mdata;
page = c.page->data + 8;
m->buffer_size = page[12] * 256 + page[13];
m->dvdram_read = page[2] & 32;
m->dvdram_write = page[3] & 32;
m->dvdr_read = page[2] & 16;
m->dvdr_write = page[3] & 16;
m->dvdrom_read = page[2] & 8;
m->simulate = page[3] & 4;
m->cdrw_read = page[2] & 2;
m->cdrw_write = page[3] & 2;
m->cdr_read = page[2] & 1;
m->cdr_write = page[3] & 1;
/* ts A61021 : these fields are marked obsolete in MMC 3 */
m->max_read_speed = page[8] * 256 + page[9];
m->cur_read_speed = page[14] * 256 + page[15];
/* in MMC-3 : see [30-31] and blocks beginning at [32] */
m->max_write_speed = page[18] * 256 + page[19];
/* New field to be set by atip */
m->min_write_speed = m->max_write_speed;
/* in MMC-3 : [28-29] */
m->cur_write_speed = page[20] * 256 + page[21];
/* >>> ts A61021 : iterate over all speeds :
data[30-31]: number of speed performance descriptor blocks
data[32-35]: block 0 : [+2-3] speed in kbytes/sec
*/
m->c2_pointers = page[5] & 16;
m->valid = 1;
m->underrun_proof = page[4] & 128;
}
void spc_sense_error_params(struct burn_drive *d)
{
struct buffer buf;
struct scsi_mode_data *m;
int size;
unsigned char *page;
struct command c;
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
c.opcode[2] = 0x01;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
size = c.page->data[0] * 256 + c.page->data[1];
m = d->mdata;
page = c.page->data + 8;
d->params.retries = page[3];
m->retry_page_length = page[1];
m->retry_page_valid = 1;
}
void spc_select_error_params(struct burn_drive *d,
const struct burn_read_opts *o)
{
struct buffer buf;
struct command c;
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
c.opcode[8] = 8 + 2 + d->mdata->retry_page_length;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
/* ts A61007 : moved up to only caller burn_disc_read() */
/* a ssert(d->mdata->valid); */
memset(c.page->data, 0, 8 + 2 + d->mdata->retry_page_length);
c.page->bytes = 8 + 2 + d->mdata->retry_page_length;
c.page->data[8] = 1;
c.page->data[9] = d->mdata->retry_page_length;
if (o->transfer_damaged_blocks)
c.page->data[10] |= 32;
if (o->report_recovered_errors)
c.page->data[10] |= 4;
if (!o->hardware_error_recovery)
c.page->data[10] |= 1;
/*burn_print(1, "error parameter 0x%x\n", c->page->data[10]);*/
c.page->data[11] = d->params.retries;
c.dir = TO_DRIVE;
d->issue_command(d, &c);
}
void spc_sense_write_params(struct burn_drive *d)
{
struct buffer buf;
struct scsi_mode_data *m;
int size;
unsigned char *page;
struct command c;
/* ts A61007 : Done in soft at only caller burn_drive_grab() */
/* a ssert(d->mdata->cdr_write || d->mdata->cdrw_write ||
d->mdata->dvdr_write || d->mdata->dvdram_write); */
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
c.opcode[2] = 0x05;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
size = c.page->data[0] * 256 + c.page->data[1];
m = d->mdata;
page = c.page->data + 8;
burn_print(1, "write page length 0x%x\n", page[1]);
m->write_page_length = page[1];
m->write_page_valid = 1;
mmc_read_disc_info(d);
}
/* remark ts A61104 :
Although command MODE SELECT is SPC, the content of the
Write Parameters Mode Page (05h) is MMC (Table 108 in MMC-1).
Thus the filling of the mode page should be done by a mmc_ function.
*/
void spc_select_write_params(struct burn_drive *d,
const struct burn_write_opts *o)
{
struct buffer buf;
struct command c;
int bufe, sim;
/* ts A61007 : All current callers are safe. */
/* a ssert(o->drive == d); */
/* <<< A61030
fprintf(stderr,"libburn_debug: write_type=%d multi=%d control=%d\n",
o->write_type,o->multi,o->control);
fprintf(stderr,"libburn_debug: block_type=%d spc_block_type=%d\n",
o->block_type,spc_block_type(o->block_type));
*/
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
c.opcode[8] = 8 + 2 + d->mdata->write_page_length;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
/* ts A61007 : moved up to burn_disc_write() */
/* a ssert(d->mdata->valid); */
memset(c.page->data, 0, 8 + 2 + d->mdata->write_page_length);
c.page->bytes = 8 + 2 + d->mdata->write_page_length;
c.page->data[8] = 5;
c.page->data[9] = d->mdata->write_page_length;
burn_print(12, "using write page length %d (valid %d)\n",
d->mdata->write_page_length, d->mdata->write_page_valid);
bufe = o->underrun_proof;
sim = o->simulate;
c.page->data[10] = (bufe << 6)
+ (sim << 4)
+ o->write_type;
/* ts A61106 : MMC-1 table 110 : multi==0 or multi==3 */
c.page->data[11] = ((3 * !!o->multi) << 6) | o->control;
c.page->data[12] = spc_block_type(o->block_type);
/* ts A61104 */
if(!(o->control&4)) /* audio (MMC-1 table 61) */
if(o->write_type == BURN_WRITE_TAO) /* ??? for others too ? */
c.page->data[12] = 0; /* Data Block Type: Raw Data */
c.page->data[22] = 0;
c.page->data[23] = 150; /* audio pause length */
/*XXX need session format! */
c.dir = TO_DRIVE;
d->issue_command(d, &c);
}
void spc_getcaps(struct burn_drive *d)
{
spc_inquiry(d);
spc_sense_caps(d);
spc_sense_error_params(d);
}
/*
only called when a blank is present, so we set type to blank
(on the last pass)
don't check totally stupid modes (raw/raw0)
some drives say they're ok, and they're not.
*/
void spc_probe_write_modes(struct burn_drive *d)
{
struct buffer buf;
int try_write_type = 1;
int try_block_type = 0;
int key, asc, ascq;
struct command c;
while (try_write_type != 4) {
burn_print(9, "trying %d, %d\n", try_write_type,
try_block_type);
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
c.opcode[8] = 8 + 2 + 0x32;
c.page = &buf;
memset(c.page->data, 0, 8 + 2 + 0x32);
c.page->bytes = 8 + 2 + 0x32;
c.page->data[8] = 5;
c.page->data[9] = 0x32;
c.page->data[10] = try_write_type;
if (try_block_type > 4)
c.page->data[11] = 4;
else
c.page->data[11] = 0;
c.page->data[12] = try_block_type;
c.page->data[23] = 150;
c.dir = TO_DRIVE;
d->silent_on_scsi_error = 1;
d->issue_command(d, &c);
d->silent_on_scsi_error = 0;
key = c.sense[2];
asc = c.sense[12];
ascq = c.sense[13];
if (key)
burn_print(7, "%d not supported\n", try_block_type);
else {
burn_print(7, "%d:%d SUPPORTED MODE!\n",
try_write_type, try_block_type);
if (try_write_type == 2) /* sao */
d->block_types[try_write_type] =
BURN_BLOCK_SAO;
else
d->block_types[try_write_type] |=
1 << try_block_type;
}
switch (try_block_type) {
case 0:
case 1:
case 2:
try_block_type++;
break;
case 3:
try_block_type = 8;
break;
case 8:
case 9:
case 10:
case 11:
case 12:
try_block_type++;
break;
case 13:
try_block_type = 0;
try_write_type++;
break;
default:
return;
}
}
}
/** @return -1 = error */
int spc_block_type(enum burn_block_types b)
{
switch (b) {
case BURN_BLOCK_SAO:
return 0; /* ignored bitz */
case BURN_BLOCK_RAW0:
return 0;
case BURN_BLOCK_RAW16:
return 1;
case BURN_BLOCK_RAW96P:
return 2;
case BURN_BLOCK_RAW96R:
return 3;
case BURN_BLOCK_MODE1:
return 8;
case BURN_BLOCK_MODE2R:
return 9;
case BURN_BLOCK_MODE2_PATHETIC:
return 10;
case BURN_BLOCK_MODE2_LAME:
return 11;
case BURN_BLOCK_MODE2_OBSCURE:
return 12;
case BURN_BLOCK_MODE2_OK:
return 13;
default:
return -1;
}
/* ts A61007 : already prevented in burn_write_opts_set_write_type() */
/* a ssert(0); */;
}
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
*/
int spc_setup_drive(struct burn_drive *d)
{
d->getcaps = spc_getcaps;
d->lock = spc_prevent;
d->unlock = spc_allow;
d->read_disc_info = spc_sense_write_params;
d->get_erase_progress = spc_get_erase_progress;
d->test_unit_ready = spc_test_unit_ready;
d->probe_write_modes = spc_probe_write_modes;
d->send_parameters = spc_select_error_params;
d->send_write_parameters = spc_select_write_params;
return 1;
}
/* ts A61021 : the general SCSI specific part of sg.c:enumerate_common()
@param flag Bitfiled for control purposes
bit0= do not setup spc/sbc/mmc
*/
int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
int channel_no, int target_no, int lun_no, int flag)
{
int ret;
/* ts A60923 */
d->bus_no = bus_no;
d->host = host_no;
d->id = target_no;
d->channel = channel_no;
d->lun = lun_no;
/* ts A61106 */
d->silent_on_scsi_error = 0;
d->idata = malloc(sizeof(struct burn_scsi_inquiry_data));
d->idata->valid = 0;
d->mdata = malloc(sizeof(struct scsi_mode_data));
d->mdata->valid = 0;
/* ts A61007 : obsolete Assert in drive_getcaps() */
if(d->idata == NULL || d->mdata == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020108,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Could not allocate new drive object", 0, 0);
return -1;
}
if(!(flag & 1)) {
ret = spc_setup_drive(d);
if (ret<=0)
return ret;
ret = sbc_setup_drive(d);
if (ret<=0)
return ret;
ret = mmc_setup_drive(d);
if (ret<=0)
return ret;
}
return 1;
}

View File

@ -1,37 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __SPC
#define __SPC
#include "libburn.h"
void spc_inquiry(struct burn_drive *);
void spc_prevent(struct burn_drive *);
void spc_allow(struct burn_drive *);
void spc_sense_caps(struct burn_drive *);
void spc_sense_error_params(struct burn_drive *);
void spc_select_error_params(struct burn_drive *,
const struct burn_read_opts *);
void spc_getcaps(struct burn_drive *d);
void spc_sense_write_params(struct burn_drive *);
void spc_select_write_params(struct burn_drive *,
const struct burn_write_opts *);
void spc_probe_write_modes(struct burn_drive *);
void spc_request_sense(struct burn_drive *d, struct buffer *buf);
int spc_block_type(enum burn_block_types b);
int spc_get_erase_progress(struct burn_drive *d);
int spc_test_unit_ready(struct burn_drive *d);
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
*/
int spc_setup_drive(struct burn_drive *d);
/* ts A61021 : the general SCSI specific part of sg.c:enumerate_common()
@param flag Bitfield for control purposes
bit0= do not setup spc/sbc/mmc
*/
int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
int channel_no, int target_no, int lun_no, int flag);
#endif /*__SPC*/

View File

@ -1,418 +0,0 @@
/* ts A61008 */
/* #include <a ssert.h> */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libburn.h"
#include "structure.h"
#include "write.h"
#include "debug.h"
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
/* ts A61008 : replaced Assert by if and return 0 */
/* a ssert(!(pos > BURN_POS_END)); */
#define RESIZE(TO, NEW, pos) {\
void *tmp;\
\
if (pos > BURN_POS_END)\
return 0;\
if (pos == BURN_POS_END)\
pos = TO->NEW##s;\
if (pos > TO->NEW##s)\
return 0;\
\
tmp = realloc(TO->NEW, sizeof(struct NEW *) * (TO->NEW##s + 1));\
if (!tmp)\
return 0;\
TO->NEW = tmp;\
memmove(TO->NEW + pos + 1, TO->NEW + pos,\
sizeof(struct NEW *) * (TO->NEW##s - pos));\
TO->NEW##s++;\
}
struct burn_disc *burn_disc_create(void)
{
struct burn_disc *d;
d = calloc(1, sizeof(struct burn_disc));
d->refcnt = 1;
d->sessions = 0;
d->session = NULL;
return d;
}
void burn_disc_free(struct burn_disc *d)
{
d->refcnt--;
if (d->refcnt == 0) {
/* dec refs on all elements */
int i;
for (i = 0; i < d->sessions; i++)
burn_session_free(d->session[i]);
free(d->session);
free(d);
}
}
struct burn_session *burn_session_create(void)
{
struct burn_session *s;
s = calloc(1, sizeof(struct burn_session));
s->refcnt = 1;
s->tracks = 0;
s->track = NULL;
s->hidefirst = 0;
return s;
}
void burn_session_hide_first_track(struct burn_session *s, int onoff)
{
s->hidefirst = onoff;
}
void burn_session_free(struct burn_session *s)
{
s->refcnt--;
if (s->refcnt == 0) {
/* dec refs on all elements */
int i;
for (i = 0; i < s->tracks; i++)
burn_track_free(s->track[i]);
free(s->track);
free(s);
}
}
int burn_disc_add_session(struct burn_disc *d, struct burn_session *s,
unsigned int pos)
{
RESIZE(d, session, pos);
d->session[pos] = s;
s->refcnt++;
return 1;
}
struct burn_track *burn_track_create(void)
{
struct burn_track *t;
t = calloc(1, sizeof(struct burn_track));
t->refcnt = 1;
t->indices = 0;
t->offset = 0;
t->offsetcount = 0;
t->tail = 0;
t->tailcount = 0;
t->mode = BURN_MODE1;
t->isrc.has_isrc = 0;
t->pad = 1;
t->entry = NULL;
t->source = NULL;
t->eos = 0;
/* ts A61101 */
t->sourcecount = 0;
t->writecount = 0;
t->written_sectors = 0;
/* ts A61031 */
t->open_ended = 0;
t->track_data_done = 0;
t->postgap = 0;
t->pregap1 = 0;
t->pregap2 = 0;
/* ts A61024 */
t->swap_source_bytes = 0;
return t;
}
void burn_track_free(struct burn_track *t)
{
t->refcnt--;
if (t->refcnt == 0) {
/* dec refs on all elements */
if (t->source)
burn_source_free(t->source);
free(t);
}
}
int burn_session_add_track(struct burn_session *s, struct burn_track *t,
unsigned int pos)
{
RESIZE(s, track, pos);
s->track[pos] = t;
t->refcnt++;
return 1;
}
int burn_session_remove_track(struct burn_session *s, struct burn_track *t)
{
struct burn_track **tmp;
int i, pos = -1;
/* ts A61008 */
/* a ssert(s->track != NULL); */
if (s->track == NULL)
return 0;
burn_track_free(t);
/* Find the position */
for (i = 0; i < s->tracks; i++) {
if (t == s->track[i]) {
pos = i;
break;
}
}
if (pos == -1)
return 0;
/* Is it the last track? */
if (pos != s->tracks - 1) {
memmove(&s->track[pos], &s->track[pos + 1],
sizeof(struct burn_track *) * (s->tracks - (pos + 1)));
}
s->tracks--;
tmp = realloc(s->track, sizeof(struct burn_track *) * s->tracks);
if (tmp)
s->track = tmp;
return 1;
}
void burn_structure_print_disc(struct burn_disc *d)
{
int i;
burn_print(12, "This disc has %d sessions\n", d->sessions);
for (i = 0; i < d->sessions; i++) {
burn_structure_print_session(d->session[i]);
}
}
void burn_structure_print_session(struct burn_session *s)
{
int i;
burn_print(12, " Session has %d tracks\n", s->tracks);
for (i = 0; i < s->tracks; i++) {
burn_structure_print_track(s->track[i]);
}
}
void burn_structure_print_track(struct burn_track *t)
{
burn_print(12, "(%p) track size %d sectors\n", t,
burn_track_get_sectors(t));
}
void burn_track_define_data(struct burn_track *t, int offset, int tail,
int pad, int mode)
{
int type_to_form(int mode, unsigned char *ctladr, int *form);
int burn_sector_length(int tracktype);
unsigned char ctladr;
int form = -1; /* unchanged form will be considered an error too */
type_to_form(mode, &ctladr, &form);
if (form == -1 || burn_sector_length(mode) <= 0) {
char msg[160];
sprintf(msg, "Attempt to set track mode to unusable value %d",
mode);
libdax_msgs_submit(libdax_messenger, -1, 0x00020115,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
return;
}
t->offset = offset;
t->pad = pad;
t->mode = mode;
t->tail = tail;
}
/* ts A61024 */
int burn_track_set_byte_swap(struct burn_track *t, int swap_source_bytes)
{
if(swap_source_bytes!=0 && swap_source_bytes!=1)
return 0;
t->swap_source_bytes = swap_source_bytes;
return 1;
}
void burn_track_set_isrc(struct burn_track *t, char *country, char *owner,
unsigned char year, unsigned int serial)
{
int i;
for (i = 0; i < 2; ++i) {
/* ts A61008 : This is always true */
/* a ssert((country[i] >= '0' || country[i] < '9') &&
(country[i] >= 'a' || country[i] < 'z') &&
(country[i] >= 'A' || country[i] < 'Z')); */
/* ts A61008 : now coordinated with sector.c: char_to_isrc() */
if (! ((country[i] >= '0' && country[i] <= '9') ||
(country[i] >= 'a' && country[i] <= 'z') ||
(country[i] >= 'A' && country[i] <= 'Z') ) )
goto is_not_allowed;
t->isrc.country[i] = country[i];
}
for (i = 0; i < 3; ++i) {
/* ts A61008 : This is always true */
/* a ssert((owner[i] >= '0' || owner[i] < '9') &&
(owner[i] >= 'a' || owner[i] < 'z') &&
(owner[i] >= 'A' || owner[i] < 'Z')); */
/* ts A61008 : now coordinated with sector.c: char_to_isrc() */
if (! ((owner[i] >= '0' && owner[i] <= '9') ||
(owner[i] >= 'a' && owner[i] <= 'z') ||
(owner[i] >= 'A' && owner[i] <= 'Z') ) )
goto is_not_allowed;
t->isrc.owner[i] = owner[i];
}
/* ts A61008 */
/* a ssert(year <= 99); */
if (year > 99)
goto is_not_allowed;
t->isrc.year = year;
/* ts A61008 */
/* a ssert(serial <= 99999); */
if (serial > 99999)
goto is_not_allowed;
t->isrc.serial = serial;
/* ts A61008 */
t->isrc.has_isrc = 1;
return;
is_not_allowed:;
libdax_msgs_submit(libdax_messenger, -1, 0x00020114,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
"Attempt to set ISRC with bad data", 0, 0);
return;
}
void burn_track_clear_isrc(struct burn_track *t)
{
t->isrc.has_isrc = 0;
}
int burn_track_get_sectors(struct burn_track *t)
{
int size;
int sectors, seclen;
seclen = burn_sector_length(t->mode);
size = t->offset + t->source->get_size(t->source) + t->tail;
sectors = size / seclen;
if (size % seclen)
sectors++;
burn_print(1, "%d sectors of %d length\n", sectors, seclen);
return sectors;
}
/* ts A61031 */
int burn_track_is_open_ended(struct burn_track *t)
{
return !!t->open_ended;
}
/* ts A61101 : API function */
int burn_track_get_counters(struct burn_track *t,
off_t *read_bytes, off_t *written_bytes)
{
/*
fprintf(stderr, "libburn_experimental: sizeof(off_t)=%d\n",
sizeof(off_t));
*/
*read_bytes = t->sourcecount;
*written_bytes = t->writecount;
return 1;
}
/* ts A61031 */
int burn_track_is_data_done(struct burn_track *t)
{
return !!t->track_data_done;
}
int burn_track_get_shortage(struct burn_track *t)
{
int size;
int seclen;
seclen = burn_sector_length(t->mode);
size = t->offset + t->source->get_size(t->source) + t->tail;
if (size % seclen)
return seclen - size % seclen;
return 0;
}
int burn_session_get_sectors(struct burn_session *s)
{
int sectors = 0, i;
for (i = 0; i < s->tracks; i++)
sectors += burn_track_get_sectors(s->track[i]);
return sectors;
}
int burn_disc_get_sectors(struct burn_disc *d)
{
int sectors = 0, i;
for (i = 0; i < d->sessions; i++)
sectors += burn_session_get_sectors(d->session[i]);
return sectors;
}
void burn_track_get_entry(struct burn_track *t, struct burn_toc_entry *entry)
{
memcpy(entry, t->entry, sizeof(struct burn_toc_entry));
}
void burn_session_get_leadout_entry(struct burn_session *s,
struct burn_toc_entry *entry)
{
memcpy(entry, s->leadout_entry, sizeof(struct burn_toc_entry));
}
struct burn_session **burn_disc_get_sessions(struct burn_disc *d, int *num)
{
*num = d->sessions;
return d->session;
}
struct burn_track **burn_session_get_tracks(struct burn_session *s, int *num)
{
*num = s->tracks;
return s->track;
}
int burn_track_get_mode(struct burn_track *track)
{
return track->mode;
}
int burn_session_get_hidefirst(struct burn_session *session)
{
return session->hidefirst;
}

View File

@ -1,92 +0,0 @@
#ifndef BURN__STRUCTURE_H
#define BURN__STRUCTURE_H
struct isrc
{
int has_isrc;
char country[2]; /* each must be 0-9, A-Z */
char owner[3]; /* each must be 0-9, A-Z */
unsigned char year; /* must be 0-99 */
unsigned int serial; /* must be 0-99999 */
};
struct burn_track
{
int refcnt;
struct burn_toc_entry *entry;
unsigned char indices;
/* lba address of the index */
unsigned int index[99];
/** number of 0 bytes to write before data */
int offset;
/** how much offset has been used */
int offsetcount;
/** Number of zeros to write after data */
int tail;
/** how much tail has been used */
int tailcount;
/** 1 means Pad with zeros, 0 means start reading the next track */
int pad;
/** Data source */
struct burn_source *source;
/** End of Source flag */
int eos;
/* ts A61101 */
off_t sourcecount;
off_t writecount;
off_t written_sectors;
/* ts A61031 */
/** Source is of undefined length */
int open_ended;
/** End of open ended track flag : offset+payload+tail are delivered */
int track_data_done;
/** The audio/data mode for the entry. Derived from control and
possibly from reading the track's first sector. */
int mode;
/** The track contains interval one of a pregap */
int pregap1;
/** The track contains interval two of a pregap */
int pregap2;
/** The track contains a postgap */
int postgap;
struct isrc isrc;
/* ts A61024 */
/** Byte swapping on source data stream : 0=none , 1=pairwise */
int swap_source_bytes;
};
struct burn_session
{
unsigned char firsttrack;
unsigned char lasttrack;
int hidefirst;
unsigned char start_m;
unsigned char start_s;
unsigned char start_f;
struct burn_toc_entry *leadout_entry;
int tracks;
struct burn_track **track;
int refcnt;
};
struct burn_disc
{
int sessions;
struct burn_session **session;
int refcnt;
};
int burn_track_get_shortage(struct burn_track *t);
/* ts A61031 : might go to libburn.h */
int burn_track_is_open_ended(struct burn_track *t);
int burn_track_is_data_done(struct burn_track *t);
#endif /* BURN__STRUCTURE_H */

View File

@ -1,136 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* ts A61008 */
/* #include <a ssert.h> */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "toc.h"
#include "transport.h"
#include "libburn.h"
#include "sector.h"
#include "options.h"
#if 0
static void write_clonecd2(volatile struct toc *toc, int f);
static void write_clonecd2(volatile struct toc *toc, int f)
{
int i;
/* header */
dprintf(f, "[CloneCD]\r\n");
dprintf(f, "Version=2\r\n");
dprintf(f, "\r\n");
/* disc data */
dprintf(f, "[Disc]\r\n");
dprintf(f, "TocEntries=%d\r\n", toc->toc_entries);
dprintf(f, "Sessions=%d\r\n", toc->sessions);
dprintf(f, "DataTracksScrambled=%d\r\n", toc->datatracksscrambled);
dprintf(f, "CDTextLength=%d\r\n", toc->cdtextlength);
dprintf(f, "\r\n");
/* session data */
for (i = 0; i < toc->sessions; ++i) {
dprintf(f, "[Session %d]\r\n", i + 1);
{
int m;
switch (toc->session[i].track[0]->mode) {
case BURN_MODE_RAW_DATA:
case BURN_MODE_AUDIO:
m = 0;
break;
case BURN_MODE0:
m = 1;
break;
case BURN_MODE1:
case BURN_MODE2_FORMLESS:
case BURN_MODE2_FORM1:
case BURN_MODE2_FORM2:
case BURN_MODE_UNINITIALIZED:
/* ts A61008 : do this softly without Assert */
a ssert(0); /* unhandled! find out ccd's
value for these modes! */
}
dprintf(f, "PreGapMode=%d\r\n", m);
}
dprintf(f, "\r\n");
}
for (i = 0; i < toc->toc_entries; ++i) {
dprintf(f, "[Entry %d]\r\n", i);
dprintf(f, "Session=%d\r\n", toc->toc_entry[i].session);
dprintf(f, "Point=0x%02x\r\n", toc->toc_entry[i].point);
dprintf(f, "ADR=0x%02x\r\n", toc->toc_entry[i].adr);
dprintf(f, "Control=0x%02x\r\n", toc->toc_entry[i].control);
dprintf(f, "TrackNo=%d\r\n", toc->toc_entry[i].tno);
dprintf(f, "AMin=%d\r\n", toc->toc_entry[i].min);
dprintf(f, "ASec=%d\r\n", toc->toc_entry[i].sec);
dprintf(f, "AFrame=%d\r\n", toc->toc_entry[i].frame);
dprintf(f, "ALBA=%d\r\n",
burn_msf_to_lba(toc->toc_entry[i].min,
toc->toc_entry[i].sec,
toc->toc_entry[i].frame));
dprintf(f, "Zero=%d\r\n", toc->toc_entry[i].zero);
dprintf(f, "PMin=%d\r\n", toc->toc_entry[i].pmin);
dprintf(f, "PSec=%d\r\n", toc->toc_entry[i].psec);
dprintf(f, "PFrame=%d\r\n", toc->toc_entry[i].pframe);
dprintf(f, "PLBA=%d\r\n",
burn_msf_to_lba(toc->toc_entry[i].pmin,
toc->toc_entry[i].psec,
toc->toc_entry[i].pframe));
dprintf(f, "\r\n");
}
}
#endif
void toc_find_modes(struct burn_drive *d)
{
struct burn_read_opts o;
int lba;
int i, j;
struct buffer mem;
struct burn_toc_entry *e;
/* ts A61008 : to be prevented on the higher levels */
/* a ssert(d->busy); */
mem.bytes = 0;
mem.sectors = 1;
o.raw = 1;
o.c2errors = 0;
o.subcodes_audio = 1;
o.subcodes_data = 1;
o.hardware_error_recovery = 1;
o.report_recovered_errors = 0;
o.transfer_damaged_blocks = 1;
o.hardware_error_retries = 1;
for (i = 0; i < d->disc->sessions; i++)
for (j = 0; j < d->disc->session[i]->tracks; j++) {
struct burn_track *t = d->disc->session[i]->track[j];
e = t->entry;
if (!e)
lba = 0;
else
lba = burn_msf_to_lba(e->pmin, e->psec,
e->pframe);
/* XXX | in the subcodes if appropriate! */
if (e && !(e->control & 4)) {
t->mode = BURN_AUDIO;
} else {
mem.sectors = 1;
d->read_sectors(d, lba, mem.sectors, &o, &mem);
t->mode = sector_identify(mem.data);
}
}
}

View File

@ -1,48 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __TOC_H
#define __TOC_H
struct command;
#include "libburn.h"
#include "structure.h"
/* return if a given entry refers to a track position */
#define TOC_ENTRY_IS_TRACK(drive, entrynum) \
((drive)->toc_entry[entrynum].point < 100)
/* return if a given entry is in audio or data format */
#define TOC_ENTRY_IS_AUDIO(drive, entrynum) \
(~(drive)->toc_entry[entrynum].control & 4)
/* return the point value for a given entry number */
#define TOC_POINT(drive, entrynum) ((drive)->toc_entry[entrynum].point)
/* return the track struct for a given entry number */
#define TOC_TRACK(drive, entrynum) \
((drive)->track[TOC_POINT(drive, entrynum) - 1])
/* return the lba of a toc entry */
#define TOC_ENTRY_PLBA(drive, entrynum) \
burn_msf_to_lba((drive)->toc_entry[(entrynum)].pmin, \
(drive)->toc_entry[(entrynum)].psec, \
(drive)->toc_entry[(entrynum)].pframe)
/* flags for the q subchannel control field */
#define TOC_CONTROL_AUDIO (0)
#define TOC_CONTROL_DATA (1 << 2)
#define TOC_CONTROL_AUDIO_TWO_CHANNELS (0)
#define TOC_CONTROL_AUDIO_FOUR_CHANNELS (1 << 3)
#define TOC_CONTROL_AUDIO_PRE_EMPHASIS (1 << 0)
#define TOC_CONTROL_DATA_RECORDED_UNINTERRUPTED (0)
#define TOC_CONTROL_DATA_RECORDED_INCREMENT (1 << 0)
#define TOC_CONTROL_COPY_PROHIBITED (0)
#define TOC_CONTROL_COPY_PERMITTED (1 << 1)
/** read a sector from each track on disc to determine modes
@param d The drive.
*/
void toc_find_modes(struct burn_drive *d);
#endif /*__TOC_H*/

View File

@ -1,215 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __TRANSPORT
#define __TRANSPORT
#include "libburn.h"
#include <pthread.h>
/* sg data structures */
#include <sys/types.h>
#ifdef __FreeBSD__
#define BUFFER_SIZE 65536/2
#else /* __FreeBSD__ */
#define BUFFER_SIZE 65536
#endif /* ! __FreeBSD__ */
enum transfer_direction
{ TO_DRIVE, FROM_DRIVE, NO_TRANSFER };
/* end of sg data structures */
/* generic 'drive' data structures */
struct cue_sheet
{
int count;
unsigned char *data;
};
struct params
{
int speed;
int retries;
};
struct buffer
{
unsigned char data[BUFFER_SIZE];
int sectors;
int bytes;
};
struct command
{
unsigned char opcode[16];
int oplen;
int dir;
unsigned char sense[128];
int error;
int retry;
struct buffer *page;
};
struct burn_scsi_inquiry_data
{
char vendor[9];
char product[17];
char revision[5];
int valid;
};
struct scsi_mode_data
{
int buffer_size;
int dvdram_read;
int dvdram_write;
int dvdr_read;
int dvdr_write;
int dvdrom_read;
int cdrw_read;
int cdrw_write;
int cdr_read;
int cdr_write;
int simulate;
int max_read_speed;
int max_write_speed;
/* ts A61021 */
int min_write_speed;
int cur_read_speed;
int cur_write_speed;
int retry_page_length;
int retry_page_valid;
int write_page_length;
int write_page_valid;
int c2_pointers;
int valid;
int underrun_proof;
};
#define LIBBURN_SG_MAX_SIBLINGS 16
/** Gets initialized in enumerate_common() and burn_drive_register() */
struct burn_drive
{
int bus_no;
int host;
int id;
int channel;
int lun;
char *devname;
#if defined(__FreeBSD__)
struct cam_device* cam;
#else
int fd;
/* ts A60926 : trying to lock against growisofs /dev/srN, /dev/scdN */
int sibling_count;
int sibling_fds[LIBBURN_SG_MAX_SIBLINGS];
#endif
/* ts A60904 : ticket 62, contribution by elmom */
/**
Tells the index in scanned burn_drive_info array.
-1 if fallen victim to burn_drive_info_forget()
*/
int global_index;
pthread_mutex_t access_lock;
enum burn_disc_status status;
int erasable;
volatile int released;
/* ts A61106 */
int silent_on_scsi_error;
int nwa; /* next writeable address */
int alba; /* absolute lba */
int rlba; /* relative lba in section */
int start_lba;
int end_lba;
int toc_temp;
struct burn_disc *disc; /* disc structure */
int block_types[4];
struct buffer *buffer;
struct burn_progress progress;
volatile int cancel;
volatile enum burn_drive_status busy;
/* transport functions */
int (*grab) (struct burn_drive *);
int (*release) (struct burn_drive *);
/* ts A61021 */
int (*drive_is_open) (struct burn_drive *);
int (*issue_command) (struct burn_drive *, struct command *);
/* lower level functions */
void (*erase) (struct burn_drive *, int);
void (*getcaps) (struct burn_drive *);
/* ts A61021 */
void (*read_atip) (struct burn_drive *);
int (*write) (struct burn_drive *, int, struct buffer *);
void (*read_toc) (struct burn_drive *);
void (*lock) (struct burn_drive *);
void (*unlock) (struct burn_drive *);
void (*eject) (struct burn_drive *);
void (*load) (struct burn_drive *);
void (*read_disc_info) (struct burn_drive *);
void (*read_sectors) (struct burn_drive *,
int start,
int len,
const struct burn_read_opts *, struct buffer *);
void (*perform_opc) (struct burn_drive *);
void (*set_speed) (struct burn_drive *, int, int);
void (*send_parameters) (struct burn_drive *,
const struct burn_read_opts *);
void (*send_write_parameters) (struct burn_drive *,
const struct burn_write_opts *);
void (*send_cue_sheet) (struct burn_drive *, struct cue_sheet *);
void (*sync_cache) (struct burn_drive *);
int (*get_erase_progress) (struct burn_drive *);
int (*get_nwa) (struct burn_drive *, int trackno, int *lba, int *nwa);
/* ts A61009 : removed d in favor of o->drive */
/* void (*close_disc) (struct burn_drive * d,
struct burn_write_opts * o);
void (*close_session) (struct burn_drive * d,
struct burn_write_opts * o);
*/
void (*close_disc) (struct burn_write_opts * o);
void (*close_session) ( struct burn_write_opts * o);
/* ts A61029 */
void (*close_track_session) ( struct burn_drive *d,
int session, int track);
int (*test_unit_ready) (struct burn_drive * d);
void (*probe_write_modes) (struct burn_drive * d);
struct params params;
struct burn_scsi_inquiry_data *idata;
struct scsi_mode_data *mdata;
int toc_entries;
struct burn_toc_entry *toc_entry;
/* ts A61023 : get size and free space of drive buffer */
int (*read_buffer_capacity) (struct burn_drive *d);
};
/* end of generic 'drive' data structures */
#endif /* __TRANSPORT */

View File

@ -1,53 +0,0 @@
#include <string.h>
/* ts A61008 */
/* #include <a ssert.h> */
#include <stdlib.h>
#include "../version.h"
#include "util.h"
#include "libburn.h"
char *burn_strdup(char *s)
{
char *ret;
int l;
/* ts A61008 */
/* a ssert(s); */
if (s == NULL)
return NULL;
l = strlen(s) + 1;
ret = malloc(l);
memcpy(ret, s, l);
return ret;
}
char *burn_strndup(char *s, int n)
{
char *ret;
int l;
/* ts A61008 */
/* a ssert(s); */
/* a ssert(n > 0); */
if (s == NULL || n <= 0)
return NULL;
l = strlen(s);
ret = malloc(l < n ? l : n);
memcpy(ret, s, l < n - 1 ? l : n - 1);
ret[n - 1] = '\0';
return ret;
}
void burn_version(int *major, int *minor, int *micro)
{
*major = BURN_MAJOR_VERSION;
*minor = BURN_MINOR_VERSION;
*micro = BURN_MICRO_VERSION;
}

View File

@ -1,8 +0,0 @@
#ifndef __UTIL
#define __UTIL
char *burn_strdup(char *s);
char *burn_strndup(char *s, int n);
#endif

View File

@ -1,897 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <unistd.h>
#include <signal.h>
/* ts A61009 */
/* #include <a ssert.h> */
/* ts A61106 : Deliberate defect provocation macros
DO NOT DEFINE THESE IF YOU WANT SUCCESSFUL TAO !
#define Libburn_experimental_no_close_tracK 1
#define Libburn_experimental_no_close_sessioN 1
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "error.h"
#include "sector.h"
#include "libburn.h"
#include "drive.h"
#include "transport.h"
#include "crc.h"
#include "debug.h"
#include "init.h"
#include "lec.h"
#include "toc.h"
#include "util.h"
#include "sg.h"
#include "write.h"
#include "options.h"
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;
static int type_to_ctrl(int mode)
{
int ctrl = 0;
int data = BURN_MODE2 | BURN_MODE1 | BURN_MODE0;
if (mode & data) {
ctrl |= 4;
} else if (mode & BURN_AUDIO) {
if (mode & BURN_4CH)
ctrl |= 8;
if (mode & BURN_PREEMPHASIS)
ctrl |= 1;
} else
/* ts A61008 */
/* a ssert(0); */
return -1;
if (mode & BURN_COPY)
ctrl |= 2;
return ctrl;
}
/* only the ctrl nibble is set here (not adr) */
/* ts A61009 : removed "static" , reacted on type_to_ctrl() == -1
preserved ignorance towards unknown modes (for now) */
void type_to_form(int mode, unsigned char *ctladr, int *form)
{
int ret;
ret = type_to_ctrl(mode) << 4;
if (ret == -1) {
*ctladr = 0xff;
*form = -1;
return;
}
*ctladr = ret;
if (mode & BURN_AUDIO)
*form = 0;
if (mode & BURN_MODE0) {
/* ts A61009 */
/* a ssert(0); */
*form = -1;
return;
}
if (mode & BURN_MODE1)
*form = 0x10;
if (mode & BURN_MODE2) {
/* ts A61009 */
/* a ssert(0); */ /* XXX someone's gonna want this sometime */
*form = -1;
return;
}
if (mode & BURN_MODE_RAW)
*form = 0;
if (mode & BURN_SUBCODE_P16) /* must be expanded to R96 */
*form |= 0x40;
if (mode & BURN_SUBCODE_P96)
*form |= 0xC0;
if (mode & BURN_SUBCODE_R96)
*form |= 0x40;
}
int burn_write_flush(struct burn_write_opts *o, struct burn_track *track)
{
struct burn_drive *d = o->drive;
if (d->buffer->bytes && !d->cancel) {
int err;
err = d->write(d, d->nwa, d->buffer);
if (err == BE_CANCELLED)
return 0;
/* A61101 */
if(track != NULL) {
track->writecount += d->buffer->bytes;
track->written_sectors += d->buffer->sectors;
}
d->nwa += d->buffer->sectors;
d->buffer->bytes = 0;
d->buffer->sectors = 0;
}
d->sync_cache(d);
return 1;
}
/* ts A61030 */
int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
int tnum)
{
char msg[81];
struct burn_drive *d;
struct burn_track *t;
int todo, step, cancelled, seclen;
/* ts A61106 */
#ifdef Libburn_experimental_no_close_tracK
return 1;
#endif
d = o->drive;
t = s->track[tnum];
/* ts A61103 : pad up track to minimum size of 600 sectors */
if (t->written_sectors < 300) {
todo = 300 - t->written_sectors;
sprintf(msg,"Padding up track to minimum size (+ %d sectors)",
todo);
libdax_msgs_submit(libdax_messenger, o->drive->global_index,
0x0002011a,
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
step = BUFFER_SIZE / 4096; /* shall fit any sector size */
if (step <= 0)
step = 1;
seclen = burn_sector_length(t->mode);
if (seclen <= 0)
seclen = 2048;
memset(d->buffer, 0, sizeof(struct buffer));
cancelled = d->cancel;
for (; todo > 0; todo -= step) {
if (step > todo)
step = todo;
d->buffer->bytes = step*seclen;
d->buffer->sectors = step;
d->cancel = 0;
d->write(d, d->nwa, d->buffer);
d->nwa += d->buffer->sectors;
t->writecount += d->buffer->bytes;
t->written_sectors += d->buffer->sectors;
}
d->cancel = cancelled;
}
/* ts A61102 */
d->busy = BURN_DRIVE_CLOSING_TRACK;
sprintf(msg, "Closing track %2.2d", tnum+1);
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
/* MMC-1 mentions track number 0xFF for "the incomplete track",
MMC-3 does not. I tried both. 0xFF was in effect when other
bugs finally gave up and made way for readable tracks. */
d->close_track_session(o->drive, 0, 0xff); /* tnum+1); */
/* ts A61102 */
d->busy = BURN_DRIVE_WRITING;
return 1;
}
/* ts A61030 */
int burn_write_close_session(struct burn_write_opts *o, struct burn_session *s)
{
/* ts A61106 */
#ifdef Libburn_experimental_no_close_sessioN
return 1;
#endif
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
"Closing session", 0, 0);
/* ts A61102 */
o->drive->busy = BURN_DRIVE_CLOSING_SESSION;
o->drive->close_track_session(o->drive, 1, 0);
/* ts A61102 */
o->drive->busy = BURN_DRIVE_WRITING;
return 1;
}
/* ts A60819:
This is unused since about Feb 2006, icculus.org/burn CVS.
The compiler complains. We shall please our compiler.
*/
#ifdef Libburn_write_with_function_print_cuE
static void print_cue(struct cue_sheet *sheet)
{
int i;
unsigned char *unit;
printf("\n");
printf("ctladr|trno|indx|form|scms| msf\n");
printf("------+----+----+----+----+--------\n");
for (i = 0; i < sheet->count; i++) {
unit = sheet->data + 8 * i;
printf(" %1X %1X | %02X | %02X | %02X | %02X |",
(unit[0] & 0xf0) >> 4, unit[0] & 0xf, unit[1], unit[2],
unit[3], unit[4]);
printf("%02X:%02X:%02X\n", unit[5], unit[6], unit[7]);
}
}
#endif /* Libburn_write_with_print_cuE */
/* ts A61009 : changed type from void to int */
/** @return 1 = success , <=0 failure */
static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
unsigned char tno, unsigned char indx,
unsigned char form, unsigned char scms, int lba)
{
unsigned char *unit;
unsigned char *ptr;
int m, s, f;
burn_lba_to_msf(lba, &m, &s, &f);
sheet->count++;
ptr = realloc(sheet->data, sheet->count * 8);
/* ts A61009 */
/* a ssert(ptr); */
if (ptr == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Could not allocate new auxiliary object (cue_sheet->data)",
0, 0);
return -1;
}
sheet->data = ptr;
unit = sheet->data + (sheet->count - 1) * 8;
unit[0] = ctladr;
unit[1] = tno;
unit[2] = indx;
unit[3] = form;
unit[4] = scms;
unit[5] = m;
unit[6] = s;
unit[7] = f;
return 1;
}
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
struct burn_session *session)
{
int i, m, s, f, form, pform, runtime = -150, ret;
unsigned char ctladr;
struct burn_drive *d;
struct burn_toc_entry *e;
struct cue_sheet *sheet;
struct burn_track **tar = session->track;
int ntr = session->tracks;
int rem = 0;
d = o->drive;
sheet = malloc(sizeof(struct cue_sheet));
/* ts A61009 : react on failures of malloc(), add_cue_sheet()
type_to_form() */
if (sheet == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Could not allocate new auxiliary object (cue_sheet)",
0, 0);
return NULL;
}
sheet->data = NULL;
sheet->count = 0;
type_to_form(tar[0]->mode, &ctladr, &form);
if (form == -1) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020116,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Track mode has unusable value", 0, 0);
goto failed;
}
ret = add_cue(sheet, ctladr | 1, 0, 0, 1, 0, runtime);
if (ret <= 0)
goto failed;
ret = add_cue(sheet, ctladr | 1, 1, 0, form, 0, runtime);
if (ret <= 0)
goto failed;
runtime += 150;
burn_print(1, "toc for %d tracks:\n", ntr);
d->toc_entries = ntr + 3;
/* ts A61009 */
/* a ssert(d->toc_entry == NULL); */
if (d->toc_entry != NULL) {
/* ts A61109 : this happens with appendable CDs
>>> Open question: is the existing TOC needed ? */
/* ts A61109 : for non-SAO, this sheet is thrown away later */
free((char *) d->toc_entry);
/*
libdax_msgs_submit(libdax_messenger,
d->global_index, 0x00020117,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"toc_entry of drive is already in use", 0, 0);
goto failed;
*/
}
d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
e = d->toc_entry;
e[0].point = 0xA0;
if (tar[0]->mode & BURN_AUDIO)
e[0].control = TOC_CONTROL_AUDIO;
else
e[0].control = TOC_CONTROL_DATA;
e[0].pmin = 1;
e[0].psec = o->format;
e[0].adr = 1;
e[1].point = 0xA1;
e[1].pmin = ntr;
e[1].adr = 1;
if (tar[ntr - 1]->mode & BURN_AUDIO)
e[1].control = TOC_CONTROL_AUDIO;
else
e[1].control = TOC_CONTROL_DATA;
e[2].point = 0xA2;
e[2].control = e[1].control;
e[2].adr = 1;
tar[0]->pregap2 = 1;
pform = form;
for (i = 0; i < ntr; i++) {
type_to_form(tar[i]->mode, &ctladr, &form);
if (pform != form) {
ret = add_cue(sheet, ctladr | 1, i + 1, 0, form, 0,
runtime);
if (ret <= 0)
goto failed;
runtime += 150;
/* XXX fix pregap interval 1 for data tracks */
/* ts A60813 silence righteous compiler warning about C++ style comments
This is possibly not a comment but rather a trace of Derek Foreman
experiments. Thus not to be beautified - but to be preserved rectified.
/ / if (!(form & BURN_AUDIO))
/ / tar[i]->pregap1 = 1;
*/
tar[i]->pregap2 = 1;
}
/* XXX HERE IS WHERE WE DO INDICES IN THE CUE SHEET */
/* XXX and we should make sure the gaps conform to ecma-130... */
tar[i]->entry = &e[3 + i];
e[3 + i].point = i + 1;
burn_lba_to_msf(runtime, &m, &s, &f);
e[3 + i].pmin = m;
e[3 + i].psec = s;
e[3 + i].pframe = f;
e[3 + i].adr = 1;
e[3 + i].control = type_to_ctrl(tar[i]->mode);
burn_print(1, "track %d control %d\n", tar[i]->mode,
e[3 + i].control);
ret = add_cue(sheet, ctladr | 1, i + 1, 1, form, 0, runtime);
if (ret <= 0)
goto failed;
runtime += burn_track_get_sectors(tar[i]);
/* if we're padding, we'll clear any current shortage.
if we're not, we'll slip toc entries by a sector every time our
shortage is more than a sector
XXX this is untested :)
*/
if (!tar[i]->pad) {
rem += burn_track_get_shortage(tar[i]);
/* ts A61101 : I doubt that linking would yield a
desireable effect. With TAO it is
counterproductive in any way.
*/
if (o->write_type == BURN_WRITE_TAO)
tar[i]->source->next = NULL;
else
if (i +1 != ntr)
tar[i]->source->next = tar[i+1]->source;
} else if (rem) {
rem = 0;
runtime++;
}
if (rem > burn_sector_length(tar[i]->mode)) {
rem -= burn_sector_length(tar[i]->mode);
runtime--;
}
pform = form;
}
burn_lba_to_msf(runtime, &m, &s, &f);
e[2].pmin = m;
e[2].psec = s;
e[2].pframe = f;
burn_print(1, "run time is %d (%d:%d:%d)\n", runtime, m, s, f);
for (i = 0; i < d->toc_entries; i++)
burn_print(1, "point %d (%02d:%02d:%02d)\n",
d->toc_entry[i].point, d->toc_entry[i].pmin,
d->toc_entry[i].psec, d->toc_entry[i].pframe);
ret = add_cue(sheet, ctladr | 1, 0xAA, 1, 1, 0, runtime);
if (ret <= 0)
goto failed;
return sheet;
failed:;
if (sheet != NULL)
free((char *) sheet);
return NULL;
}
int burn_sector_length(int tracktype)
{
if (tracktype & BURN_AUDIO)
return 2352;
if (tracktype & BURN_MODE_RAW)
return 2352;
if (tracktype & BURN_MODE1)
return 2048;
/* ts A61009 */
/* a ssert(0); */
return -1;
}
int burn_subcode_length(int tracktype)
{
if (tracktype & BURN_SUBCODE_P16)
return 16;
if ((tracktype & BURN_SUBCODE_P96) || (tracktype & BURN_SUBCODE_R96))
return 96;
return 0;
}
int burn_write_leadin(struct burn_write_opts *o,
struct burn_session *s, int first)
{
struct burn_drive *d = o->drive;
int count;
d->busy = BURN_DRIVE_WRITING_LEADIN;
burn_print(5, first ? " first leadin\n" : " leadin\n");
if (first)
count = 0 - d->alba - 150;
else
count = 4500;
d->progress.start_sector = d->alba;
d->progress.sectors = count;
d->progress.sector = 0;
while (count != 0) {
if (!sector_toc(o, s->track[0]->mode))
return 0;
count--;
d->progress.sector++;
}
d->busy = BURN_DRIVE_WRITING;
return 1;
}
int burn_write_leadout(struct burn_write_opts *o,
int first, unsigned char control, int mode)
{
struct burn_drive *d = o->drive;
int count;
d->busy = BURN_DRIVE_WRITING_LEADOUT;
d->rlba = -150;
burn_print(5, first ? " first leadout\n" : " leadout\n");
if (first)
count = 6750;
else
count = 2250;
d->progress.start_sector = d->alba;
d->progress.sectors = count;
d->progress.sector = 0;
while (count != 0) {
if (!sector_lout(o, control, mode))
return 0;
count--;
d->progress.sector++;
}
d->busy = BURN_DRIVE_WRITING;
return 1;
}
int burn_write_session(struct burn_write_opts *o, struct burn_session *s)
{
struct burn_drive *d = o->drive;
struct burn_track *prev = NULL, *next = NULL;
int i, ret;
d->rlba = 0;
burn_print(1, " writing a session\n");
for (i = 0; i < s->tracks; i++) {
if (i > 0)
prev = s->track[i - 1];
if (i + 1 < s->tracks)
next = s->track[i + 1];
else
next = NULL;
if (!burn_write_track(o, s, i))
{ ret = 0; goto ex; }
}
/* ts A61103 */
ret = 1;
ex:;
if (o->write_type == BURN_WRITE_TAO)
burn_write_close_session(o, s);
return ret;
}
int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
int tnum)
{
struct burn_track *t = s->track[tnum];
struct burn_drive *d = o->drive;
int i, tmp = 0, open_ended = 0, ret, nwa, lba;
int sectors;
char msg[80];
d->rlba = -150;
/* XXX for tao, we don't want the pregaps but still want post? */
if (o->write_type != BURN_WRITE_TAO) {
/* ts A61102 */
d->busy = BURN_DRIVE_WRITING_PREGAP;
if (t->pregap1)
d->rlba += 75;
if (t->pregap2)
d->rlba += 150;
if (t->pregap1) {
struct burn_track *pt = s->track[tnum - 1];
if (tnum == 0) {
printf("first track should not have a pregap1\n");
pt = t;
}
for (i = 0; i < 75; i++)
if (!sector_pregap(o, t->entry->point,
pt->entry->control, pt->mode))
{ ret = 0; goto ex; }
}
if (t->pregap2)
for (i = 0; i < 150; i++)
if (!sector_pregap(o, t->entry->point,
t->entry->control, t->mode))
{ ret = 0; goto ex; }
} else {
o->control = t->entry->control;
d->send_write_parameters(d, o);
/* ts A61103 */
ret = d->get_nwa(d, -1, &lba, &nwa);
sprintf(msg,
"pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d\n",
tnum+1, nwa, ret, d->nwa);
libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg,0,0);
if (nwa > d->nwa)
d->nwa = nwa;
}
/* user data */
/* ts A61102 */
d->busy = BURN_DRIVE_WRITING;
sectors = burn_track_get_sectors(t);
open_ended = burn_track_is_open_ended(t);
/* Update progress */
d->progress.start_sector = d->nwa;
d->progress.sectors = sectors;
d->progress.sector = 0;
/* ts A60831: added tnum-line, extended print message on proposal
by bonfire-app@wanadoo.fr in http://libburn.pykix.org/ticket/58 */
d->progress.track = tnum;
burn_print(12, "track %d is %d sectors long\n", tnum, sectors);
/* ts A61030 : this cannot happen. tnum is alsways < s-tracks */
if (tnum == s->tracks)
tmp = sectors > 150 ? 150 : sectors;
for (i = 0; open_ended || i < sectors - tmp; i++) {
/* ts A61023 : http://libburn.pykix.org/ticket/14
From time to time inquire drive buffer */
if ((i%64)==0)
d->read_buffer_capacity(d);
if (!sector_data(o, t, 0))
{ ret = 0; goto ex; }
/* ts A61031 */
if (open_ended) {
d->progress.sectors = sectors = i;
if (burn_track_is_data_done(t))
break;
}
/* update current progress */
d->progress.sector++;
}
for (; i < sectors; i++) {
/* ts A61030: program execution never gets to this point */
fprintf(stderr,"LIBBURN_DEBUG: TNUM=%d TRACKS=%d TMP=%d\n",
tnum, s->tracks, tmp);
burn_print(1, "last track, leadout prep\n");
/* ts A61023 */
if ((i%64)==0)
d->read_buffer_capacity(d);
if (!sector_data(o, t, 1))
{ ret = 0; goto ex; }
/* update progress */
d->progress.sector++;
}
if (t->postgap)
for (i = 0; i < 150; i++)
if (!sector_postgap(o, t->entry->point, t->entry->control,
t->mode))
{ ret = 0; goto ex; }
i = t->offset;
if (o->write_type == BURN_WRITE_SAO) {
if (d->buffer->bytes) {
int err;
err = d->write(d, d->nwa, d->buffer);
if (err == BE_CANCELLED)
{ ret = 0; goto ex; }
/* A61101 : probably this is not all payload data */
/* A61108 : but audio count is short without this */
t->writecount += d->buffer->bytes;
d->nwa += d->buffer->sectors;
d->buffer->bytes = 0;
d->buffer->sectors = 0;
}
}
/* ts A61103 */
ret = 1;
ex:;
if (o->write_type == BURN_WRITE_TAO) {
/* ts A61103 */
/* >>> if cancelled: ensure that at least 600 kB get written */
if (!burn_write_flush(o, t))
ret = 0;
/* ts A61030 */
if (burn_write_close_track(o, s, tnum) <= 0)
ret = 0;
}
return ret;
}
/* ts A61009 */
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc)
{
int i, t;
char msg[80];
for (i = 0; i < disc->sessions; i++)
for (t = 0; t < disc->session[i]->tracks; t++)
if (!sector_headers_is_ok(
o, disc->session[i]->track[t]->mode))
goto bad_track_mode_found;
return 1;
bad_track_mode_found:;
sprintf(msg, "Unsuitable track mode 0x%x in track %d of session %d",
disc->session[i]->track[t]->mode, i+1, t+1);
libdax_msgs_submit(libdax_messenger, -1, 0x0002010a,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
return 0;
}
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
{
struct cue_sheet *sheet;
struct burn_drive *d = o->drive;
struct buffer buf;
struct burn_track *lt;
int first = 1, i, ret, lba, nwa;
char msg[80];
/* ts A60924 : libburn/message.c gets obsoleted
burn_message_clear_queue();
*/
burn_print(1, "sync write of %d sessions\n", disc->sessions);
d->buffer = &buf;
memset(d->buffer, 0, sizeof(struct buffer));
d->rlba = -150;
d->toc_temp = 9;
/* Apparently some drives require this command to be sent, and a few drives
return crap. so we send the command, then ignore the result.
*/
/* ts A61107 : moved up send_write_parameters because LG GSA-4082B
seems to dislike get_nwa() in advance */
d->alba = d->start_lba;
d->nwa = d->alba;
if (o->write_type == BURN_WRITE_TAO) {
nwa = 0; /* get_nwa() will be called in burn_track() */
} else {
d->send_write_parameters(d, o);
ret = d->get_nwa(d, -1, &lba, &nwa);
sprintf(msg, "Inquired nwa: %d (ret=%d)", nwa, ret);
libdax_msgs_submit(libdax_messenger, d->global_index,
0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
msg,0,0);
}
/* init progress before showing the state */
d->progress.session = 0;
d->progress.sessions = disc->sessions;
d->progress.track = 0;
d->progress.tracks = disc->session[0]->tracks;
/* TODO: handle indices */
d->progress.index = 0;
d->progress.indices = disc->session[0]->track[0]->indices;
/* TODO: handle multissession discs */
/* XXX: sectors are only set during write track */
d->progress.start_sector = 0;
d->progress.sectors = 0;
d->progress.sector = 0;
/* ts A61023 */
d->progress.buffer_capacity = 0;
d->progress.buffer_available = 0;
d->busy = BURN_DRIVE_WRITING;
for (i = 0; i < disc->sessions; i++) {
/* update progress */
d->progress.session = i;
d->progress.tracks = disc->session[i]->tracks;
sheet = burn_create_toc_entries(o, disc->session[i]);
/* ts A61009 */
if (sheet == NULL)
goto fail;
/* print_cue(sheet);*/
if (o->write_type == BURN_WRITE_SAO)
d->send_cue_sheet(d, sheet);
free(sheet);
if (o->write_type == BURN_WRITE_RAW) {
if (!burn_write_leadin(o, disc->session[i], first))
goto fail;
} else {
if (first) {
/* ts A61030 : 0 made the burner take data. */
/* ts A61103 : Meanwhile d->nwa is updated in
burn_write_track() */
if(o->write_type == BURN_WRITE_TAO) {
d->nwa= d->alba = 0;
} else {
d->nwa = -150;
d->alba = -150;
}
} else {
d->nwa += 4500;
d->alba += 4500;
}
}
if (!burn_write_session(o, disc->session[i]))
goto fail;
lt = disc->session[i]->track[disc->session[i]->tracks - 1];
if (o->write_type == BURN_WRITE_RAW) {
if (!burn_write_leadout(o, first, lt->entry->control,
lt->mode))
goto fail;
} else {
/* ts A61030 */
if (o->write_type != BURN_WRITE_TAO)
if (!burn_write_flush(o, NULL))
goto fail;
d->nwa += first ? 6750 : 2250;
d->alba += first ? 6750 : 2250;
}
if (first)
first = 0;
/* XXX: currently signs an end of session */
d->progress.sector = 0;
d->progress.start_sector = 0;
d->progress.sectors = 0;
}
/* ts A61030: extended skipping of flush to TAO: session is closed */
if (o->write_type != BURN_WRITE_SAO && o->write_type != BURN_WRITE_TAO)
if (!burn_write_flush(o, NULL))
goto fail;
sleep(1);
burn_print(1, "done\n");
d->busy = BURN_DRIVE_IDLE;
/* ts A61012 : This return was traditionally missing. I suspect this
to have caused Cdrskin_eject() failures */
return;
fail:
d->sync_cache(d);
burn_print(1, "done - failed\n");
libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010b,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
"Burn run failed", 0, 0);
d->busy = BURN_DRIVE_IDLE;
}

View File

@ -1,34 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef BURN__WRITE_H
#define BURN__WRITE_H
struct cue_sheet;
struct burn_session;
struct burn_write_opts;
struct burn_disc;
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
struct burn_session *session);
int burn_sector_length(int trackmode);
int burn_subcode_length(int trackmode);
/* ts A61009 */
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc);
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc);
int burn_write_leadin(struct burn_write_opts *o,
struct burn_session *s, int first);
int burn_write_leadout(struct burn_write_opts *o,
int first, unsigned char control, int mode);
int burn_write_session(struct burn_write_opts *o, struct burn_session *s);
int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
int tnum);
int burn_write_flush(struct burn_write_opts *o, struct burn_track *track);
/* ts A61030 : necessary for TAO */
int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
int tnum);
int burn_write_close_session(struct burn_write_opts *o,struct burn_session *s);
#endif /* BURN__WRITE_H */

View File

@ -8,4 +8,4 @@ Description: ISO9660 filesystem creation library
Version: @VERSION@
Requires:
Libs: -L${libdir} -lisofs
Cflags: -I${includedir}/libburn
Cflags: -I${includedir}/libisofs

0
libisofs/Makefile Executable file → Normal file
View File

View 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
View File

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

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

@ -7,6 +7,9 @@
#include <time.h>
#include <assert.h>
#include <err.h>
#include <locale.h>
#include <langinfo.h>
#include <limits.h>
#include "ecma119.h"
#include "ecma119_tree.h"
@ -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
View 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
View File

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

76
libisofs/ecma119_read.h Normal file
View File

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

316
libisofs/ecma119_read_rr.c Normal file
View File

@ -0,0 +1,316 @@
/*
* This file contains functions related to the reading of SUSP and
* Rock Ridge extensions on an ECMA-119 image.
*/
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ecma119.h"
#include "ecma119_read.h"
#include "ecma119_read_rr.h"
#include "util.h"
#include "messages.h"
#define BLOCK_SIZE 2048
/**
* Fills a struct stat with the values of a Rock Ridge PX entry
* On error, info->error is set propertly and the function returns != 0
*/
int
read_rr_PX(struct iso_read_info *info, struct susp_sys_user_entry *px,
struct stat *st)
{
assert( info && px && st);
assert( px->sig[0] == 'P' && px->sig[1] == 'X');
if ( info->rr == RR_EXT_112 && px->len_sue[0] != 44 ) {
iso_msg_sorry(LIBISO_RR_ERROR, "Invalid PX entry for RR version 1.12");
info->error = LIBISOFS_WRONG_RR;
return -1;
} else if ( info->rr == RR_EXT_110 && px->len_sue[0] != 36 ) {
iso_msg_sorry(LIBISO_RR_ERROR, "Invalid PX entry for RR version 1.10");
info->error = LIBISOFS_WRONG_RR;
return -1;
}
st->st_mode = iso_read_bb(px->data.PX.mode, 4, NULL);
st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL);
st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL);
st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL);
if (info->rr == RR_EXT_112) {
st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
} else {
st->st_ino = ++info->ino;
}
return 0;
}
/**
* Fills a struct stat with the values of a Rock Ridge TF entry
* On error, info->error is set propertly and the function returns != 0
*/
int
read_rr_TF(struct iso_read_info *info, struct susp_sys_user_entry *tf,
struct stat *st)
{
time_t time;
int s;
int nts = 0;
assert( info && tf && st);
assert( tf->sig[0] == 'T' && tf->sig[1] == 'F');
if (tf->data.TF.flags[0] & (1 << 7)) {
/* long form */
s = 17;
} else {
s = 7;
}
/* 1. Creation time */
if (tf->data.TF.flags[0] & (1 << 0)) {
/* the creation is the recording time. we ignore this */
/* TODO maybe it would be good to manage it in ms discs, where
* the recording time could be different than now!! */
++nts;
}
/* 2. modify time */
if (tf->data.TF.flags[0] & (1 << 1)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
iso_msg_sorry(LIBISO_RR_ERROR, "RR TF entry too short.");
info->error = LIBISOFS_WRONG_RR;
return -1;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_mtime = time;
++nts;
}
/* 3. access time */
if (tf->data.TF.flags[0] & (1 << 2)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
iso_msg_sorry(LIBISO_RR_ERROR, "RR TF entry too short.");
info->error = LIBISOFS_WRONG_RR;
return -1;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_atime = time;
++nts;
}
/* 4. attributes time */
if (tf->data.TF.flags[0] & (1 << 3)) {
if (tf->len_sue[0] < 5 + (nts+1) * s) {
iso_msg_sorry(LIBISO_RR_ERROR, "RR TF entry too short.");
info->error = LIBISOFS_WRONG_RR;
return -1;
}
if (s == 7) {
time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
} else {
time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
}
st->st_ctime = time;
++nts;
}
/* we ignore backup, expire and effect times */
return 0;
}
char *
read_rr_NM(struct susp_sys_user_entry *nm, char *name)
{
assert(nm);
assert( nm->sig[0] == 'N' && nm->sig[1] == 'M');
/* concatenate the results */
if (name) {
name = realloc(name, strlen(name) + nm->len_sue[0] - 5 + 1);
strncat(name, (char*)nm->data.NM.name, nm->len_sue[0] - 5);
} else {
name = strcopy((char*)nm->data.NM.name, nm->len_sue[0] - 5);
}
return name;
}
char *
read_rr_SL(struct susp_sys_user_entry *sl, char *dest)
{
int pos;
assert(sl);
assert( sl->sig[0] == 'S' && sl->sig[1] == 'L');
for (pos = 0; pos + 5 < sl->len_sue[0];
pos += 2 + sl->data.SL.comps[pos + 1]) {
char *comp;
uint8_t len;
uint8_t flags = sl->data.SL.comps[pos];
if (flags & 0x2) {
/* current directory */
len = 1;
comp = ".";
} else if (flags & 0x4) {
/* parent directory */
len = 2;
comp = "..";
} else if (flags & 0x8) {
/* root directory */
len = 1;
comp = "/";
} else if (flags & ~0x01) {
char msg[38];
sprintf(msg, "SL component flag %x not supported.", flags);
iso_msg_sorry(LIBISO_RR_ERROR, msg);
return NULL;
} else {
len = sl->data.SL.comps[pos + 1];
comp = (char*)&sl->data.SL.comps[pos + 2];
}
if (dest) {
int size = strlen(dest);
dest = realloc(dest, strlen(dest) + len + 2);
if ( dest[size-1] != '/' ) {
dest[size] = '/';
dest[size+1] = '\0';
}
strncat(dest, comp, len);
} else {
dest = strcopy(comp, len);
}
}
return dest;
}
struct susp_iterator {
uint8_t* base;
int pos;
int size;
struct iso_read_info *info;
uint32_t ce_block;
uint32_t ce_off;
uint32_t ce_len; /*< Length of the next continuation area, 0 if
no more CA are specified */
uint8_t *buffer; /*< If there are continuation areas */
};
struct susp_iterator *
susp_iter_new(struct iso_read_info *info, struct ecma119_dir_record *record)
{
struct susp_iterator *iter = malloc(sizeof(struct susp_iterator));
int pad = (record->len_fi[0] + 1) % 2;
iter->base = record->file_id + record->len_fi[0] + pad;
iter->pos = info->len_skp; /* 0 in most cases */
iter->size = record->len_dr[0] - record->len_fi[0] - 33 -pad;
iter->info = info;
iter->ce_len = 0;
iter->buffer = NULL;
return iter;
}
struct susp_sys_user_entry *
susp_iter_next(struct susp_iterator* iter)
{
struct susp_sys_user_entry *entry;
entry = (struct susp_sys_user_entry*)(iter->base + iter->pos);
if ( (iter->pos + 4 > iter->size) || (SUSP_SIG(entry, 'S', 'T')) ) {
/*
* End of the System Use Area or Continuation Area.
* Note that ST is not needed when the space left is less than 4.
* (IEEE 1281, SUSP. section 4)
*/
if (iter->ce_len) {
uint32_t block;
int nblocks;
/* A CE has found, there is another continuation area */
nblocks = div_up(iter->ce_off + iter->ce_len, BLOCK_SIZE);
iter->buffer = realloc(iter->buffer, nblocks * BLOCK_SIZE);
/* read all block needed to cache the full CE */
for (block = 0; block < nblocks; ++block) {
if (iter->info->src->read_block(iter->info->src,
iter->ce_block + block,
iter->buffer + block * BLOCK_SIZE)) {
iter->info->error = LIBISOFS_READ_FAILURE;
return NULL;
}
}
iter->base = iter->buffer + iter->ce_off;
iter->pos = 0;
iter->size = iter->ce_len;
iter->ce_len = 0;
entry = (struct susp_sys_user_entry*)iter->base;
} else {
return NULL;
}
}
if (entry->len_sue[0] == 0) {
/* a wrong image with this lead us to a infinity loop */
iso_msg_sorry(LIBISO_RR_ERROR, "Damaged RR/SUSP information.");
iter->info->error = LIBISOFS_WRONG_RR;
return NULL;
}
iter->pos += entry->len_sue[0];
if ( SUSP_SIG(entry, 'C', 'E') ) {
/* Continuation entry */
if (iter->ce_len) {
iso_msg_sorry(LIBISO_RR_ERROR, "More than one CE System user entry "
"has found in a single System Use field or continuation area. "
"This breaks SUSP standard and it's not supported.\n"
"Ignoring last CE. Maybe the image is damaged.\n");
} else {
iter->ce_block = iso_read_bb(entry->data.CE.block, 4, NULL);
iter->ce_off = iso_read_bb(entry->data.CE.offset, 4, NULL);
iter->ce_len = iso_read_bb(entry->data.CE.len, 4, NULL);
}
/* we don't want to return CE entry to the user */
return susp_iter_next(iter);
} else if ( SUSP_SIG(entry, 'P', 'D') ) {
/* skip padding */
return susp_iter_next(iter);
}
return entry;
}
void
susp_iter_free(struct susp_iterator* iter)
{
free(iter->buffer);
free(iter);
}

144
libisofs/ecma119_read_rr.h Normal file
View File

@ -0,0 +1,144 @@
/*
* This file contains functions related to the reading of SUSP and
* Rock Ridge extensions on an ECMA-119 image.
*/
#ifndef ECMA119_READ_RR_H_
#define ECMA119_READ_RR_H_
#include "libisofs.h"
#include "ecma119.h"
#include "ecma119_read.h"
#define SUSP_SIG(entry, a, b) ( (entry->sig[0] == a) && (entry->sig[1] == b) )
/**
* The SUSP iterator is used to iterate over the System User Entries
* of a ECMA-168 directory record.
* It takes care about Continuation Areas, handles the end of the different
* system user entries and skip padding areas. Thus, using an iteration
* we are accessing just to the meaning entries.
*/
struct susp_iterator;
struct susp_iterator *susp_iter_new(struct iso_read_info *info,
struct ecma119_dir_record *record);
/**
* Get the next SUSP System User Entry using given iterator.
* The returned pointer refers directly to an internal buffer and it's not
* guaranteed to be allocated after calling susp_iter_next() again. Thus,
* if you need to keep some entry you have to do a copy.
*
* It return NULL when no more entries are available. Also, it will return
* NULL on error. You must check info->error to distinguish between both
* situations.
*/
struct susp_sys_user_entry *susp_iter_next(struct susp_iterator* iter);
/**
* Free a given susp iterator.
*/
void susp_iter_free(struct susp_iterator* iter);
struct susp_CE {
uint8_t block[8];
uint8_t offset[8];
uint8_t len[8];
};
struct susp_SP {
uint8_t be[1];
uint8_t ef[1];
uint8_t len_skp[1];
};
struct susp_ER {
uint8_t len_id[1];
uint8_t len_des[1];
uint8_t len_src[1];
uint8_t ext_ver[1];
uint8_t ext_id[1]; /*< up to len_id bytes */
/* ext_des, ext_src */
};
/** POSIX file attributes. */
struct rr_PX {
uint8_t mode[8];
uint8_t links[8];
uint8_t uid[8];
uint8_t gid[8];
uint8_t serial[8];
};
/** Time stamps for a file. */
struct rr_TF {
uint8_t flags[1];
uint8_t t_stamps[1];
};
/** Alternate name. */
struct rr_NM {
uint8_t flags[1];
uint8_t name[1];
};
/** Link for a relocated directory. */
struct rr_CL {
uint8_t child_loc[8];
};
/** Sim link. */
struct rr_SL {
uint8_t flags[1];
uint8_t comps[1];
};
/**
* Struct for a SUSP System User Entry
*/
struct susp_sys_user_entry
{
uint8_t sig[2];
uint8_t len_sue[1];
uint8_t version[1];
union {
struct susp_CE CE;
struct susp_SP SP;
struct susp_ER ER;
struct rr_PX PX;
struct rr_TF TF;
struct rr_NM NM;
struct rr_CL CL;
struct rr_SL SL;
} data; /* 5 to 4+len_sue */
};
/**
* Fills a struct stat with the values of a Rock Ridge PX entry
* On error, info->error is set propertly and the function returns != 0
*/
int read_rr_PX(struct iso_read_info *info, struct susp_sys_user_entry *px,
struct stat *st);
/**
* Fills a struct stat with the values of a Rock Ridge TF entry
* On error, info->error is set propertly and the function returns != 0
*/
int read_rr_TF(struct iso_read_info *info, struct susp_sys_user_entry *tf,
struct stat *st);
/**
* Apends the content of given Rock Ridge NM entry to \p name
* On error, returns NULL
*/
char *read_rr_NM(struct susp_sys_user_entry *nm, char *name);
/**
* Apends the components in specified SL entry to \p dest, adding
* needed '/'.
* On error, returns NULL
*/
char *read_rr_SL(struct susp_sys_user_entry *sl, char *dest);
#endif /*ECMA119_READ_RR_H_*/

View File

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

View File

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

View File

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

View File

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

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

94
libisofs/file_src.h Normal file
View File

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

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