Started cleaning libisofs tree

This commit is contained in:
Mario Danic 2006-11-14 00:58:21 +00:00
parent 58bb4389b3
commit 3a05fb4e87
80 changed files with 0 additions and 25021 deletions

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,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,404 +0,0 @@
/* libdax_msgs
Message handling facility of libdax.
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
/* Only this single source module is entitled to do this */
#define LIBDAX_MSGS_H_INTERNAL 1
/* All participants in the messaging system must do this */
#include "libdax_msgs.h"
/* ----------------------------- libdax_msgs_item ------------------------- */
static int libdax_msgs_item_new(struct libdax_msgs_item **item,
struct libdax_msgs_item *link, int flag)
{
int ret;
struct libdax_msgs_item *o;
struct timeval tv;
struct timezone tz;
(*item)= o=
(struct libdax_msgs_item *) malloc(sizeof(struct libdax_msgs_item));
if(o==NULL)
return(-1);
o->timestamp= 0.0;
ret= gettimeofday(&tv,&tz);
if(ret==0)
o->timestamp= tv.tv_sec+0.000001*tv.tv_usec;
o->process_id= getpid();
o->driveno= -1;
o->severity= LIBDAX_MSGS_SEV_ALL;
o->priority= LIBDAX_MSGS_PRIO_ZERO;
o->error_code= 0;
o->msg_text= NULL;
o->os_errno= 0;
o->prev= link;
o->next= NULL;
if(link!=NULL) {
if(link->next!=NULL) {
link->next->prev= o;
o->next= link->next;
}
link->next= o;
}
return(1);
}
/** Detaches item from its queue and eventually readjusts start, end pointers
of the queue */
int libdax_msgs_item_unlink(struct libdax_msgs_item *o,
struct libdax_msgs_item **chain_start,
struct libdax_msgs_item **chain_end, int flag)
{
if(o->prev!=NULL)
o->prev->next= o->next;
if(o->next!=NULL)
o->next->prev= o->prev;
if(chain_start!=NULL)
if(*chain_start == o)
*chain_start= o->next;
if(chain_end!=NULL)
if(*chain_end == o)
*chain_end= o->prev;
o->next= o->prev= NULL;
return(1);
}
int libdax_msgs_item_destroy(struct libdax_msgs_item **item,
int flag)
{
struct libdax_msgs_item *o;
o= *item;
if(o==NULL)
return(0);
libdax_msgs_item_unlink(o,NULL,NULL,0);
if(o->msg_text!=NULL)
free((char *) o->msg_text);
free((char *) o);
*item= NULL;
return(1);
}
int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
int *error_code, char **msg_text, int *os_errno,
int flag)
{
*error_code= item->error_code;
*msg_text= item->msg_text;
*os_errno= item->os_errno;
return(1);
}
int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
double *timestamp, pid_t *process_id, int *driveno,
int flag)
{
*timestamp= item->timestamp;
*process_id= item->process_id;
*driveno= item->driveno;
return(1);
}
int libdax_msgs_item_get_rank(struct libdax_msgs_item *item,
int *severity, int *priority, int flag)
{
*severity= item->severity;
*priority= item->priority;
return(1);
}
/* ------------------------------- libdax_msgs ---------------------------- */
int libdax_msgs_new(struct libdax_msgs **m, int flag)
{
struct libdax_msgs *o;
(*m)= o= (struct libdax_msgs *) malloc(sizeof(struct libdax_msgs));
if(o==NULL)
return(-1);
o->oldest= NULL;
o->youngest= NULL;
o->count= 0;
o->queue_severity= LIBDAX_MSGS_SEV_ALL;
o->print_severity= LIBDAX_MSGS_SEV_NEVER;
strcpy(o->print_id,"libdax: ");
#ifndef LIBDAX_MSGS_SINGLE_THREADED
pthread_mutex_init(&(o->lock_mutex),NULL);
#endif
return(1);
}
int libdax_msgs_destroy(struct libdax_msgs **m, int flag)
{
struct libdax_msgs *o;
struct libdax_msgs_item *item, *next_item;
o= *m;
if(o==NULL)
return(0);
#ifndef LIBDAX_MSGS_SINGLE_THREADED
if(pthread_mutex_destroy(&(o->lock_mutex))!=0) {
pthread_mutex_unlock(&(o->lock_mutex));
pthread_mutex_destroy(&(o->lock_mutex));
}
#endif
for(item= o->oldest; item!=NULL; item= next_item) {
next_item= item->next;
libdax_msgs_item_destroy(&item,0);
}
free((char *) o);
*m= NULL;
return(1);
}
int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
int print_severity, char *print_id, int flag)
{
m->queue_severity= queue_severity;
m->print_severity= print_severity;
strncpy(m->print_id,print_id,80);
m->print_id[80]= 0;
return(1);
}
static int libdax_msgs_lock(struct libdax_msgs *m, int flag)
{
#ifndef LIBDAX_MSGS_SINGLE_THREADED
int ret;
ret= pthread_mutex_lock(&(m->lock_mutex));
if(ret!=0)
return(0);
#endif
return(1);
}
static int libdax_msgs_unlock(struct libdax_msgs *m, int flag)
{
#ifndef LIBDAX_MSGS_SINGLE_THREADED
int ret;
ret= pthread_mutex_unlock(&(m->lock_mutex));
if(ret!=0)
return(0);
#endif
return(1);
}
int libdax_msgs__text_to_sev(char *severity_name, int *severity,
int flag)
{
if(strncmp(severity_name,"NEVER",5)==0)
*severity= LIBDAX_MSGS_SEV_NEVER;
else if(strncmp(severity_name,"ABORT",5)==0)
*severity= LIBDAX_MSGS_SEV_ABORT;
else if(strncmp(severity_name,"FATAL",5)==0)
*severity= LIBDAX_MSGS_SEV_FATAL;
else if(strncmp(severity_name,"SORRY",5)==0)
*severity= LIBDAX_MSGS_SEV_SORRY;
else if(strncmp(severity_name,"WARNING",7)==0)
*severity= LIBDAX_MSGS_SEV_WARNING;
else if(strncmp(severity_name,"HINT",4)==0)
*severity= LIBDAX_MSGS_SEV_HINT;
else if(strncmp(severity_name,"NOTE",4)==0)
*severity= LIBDAX_MSGS_SEV_NOTE;
else if(strncmp(severity_name,"UPDATE",6)==0)
*severity= LIBDAX_MSGS_SEV_UPDATE;
else if(strncmp(severity_name,"DEBUG",5)==0)
*severity= LIBDAX_MSGS_SEV_DEBUG;
else if(strncmp(severity_name,"ALL",3)==0)
*severity= LIBDAX_MSGS_SEV_ALL;
else {
*severity= LIBDAX_MSGS_SEV_NEVER;
return(0);
}
return(1);
}
int libdax_msgs__sev_to_text(int severity, char **severity_name,
int flag)
{
if(flag&1) {
*severity_name=
"NEVER\nABORT\nFATAL\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
return(1);
}
*severity_name= "";
if(severity>=LIBDAX_MSGS_SEV_NEVER)
*severity_name= "NEVER";
else if(severity>=LIBDAX_MSGS_SEV_ABORT)
*severity_name= "ABORT";
else if(severity>=LIBDAX_MSGS_SEV_FATAL)
*severity_name= "FATAL";
else if(severity>=LIBDAX_MSGS_SEV_SORRY)
*severity_name= "SORRY";
else if(severity>=LIBDAX_MSGS_SEV_WARNING)
*severity_name= "WARNING";
else if(severity>=LIBDAX_MSGS_SEV_HINT)
*severity_name= "HINT";
else if(severity>=LIBDAX_MSGS_SEV_NOTE)
*severity_name= "NOTE";
else if(severity>=LIBDAX_MSGS_SEV_UPDATE)
*severity_name= "UPDATE";
else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
*severity_name= "DEBUG";
else if(severity>=LIBDAX_MSGS_SEV_ALL)
*severity_name= "ALL";
else {
*severity_name= "";
return(0);
}
return(1);
}
int libdax_msgs_submit(struct libdax_msgs *m, int driveno, int error_code,
int severity, int priority, char *msg_text,
int os_errno, int flag)
{
int ret;
char *textpt,*sev_name,sev_text[81];
struct libdax_msgs_item *item= NULL;
if(severity >= m->print_severity) {
if(msg_text==NULL)
textpt= "";
else
textpt= msg_text;
sev_text[0]= 0;
ret= libdax_msgs__sev_to_text(severity,&sev_name,0);
if(ret>0)
sprintf(sev_text,"%s : ",sev_name);
fprintf(stderr,"%s%s%s\n",m->print_id,sev_text,textpt);
if(os_errno!=0) {
ret= libdax_msgs_lock(m,0);
if(ret<=0)
return(-1);
fprintf(stderr,"%s( Most recent system error: %d '%s' )\n",
m->print_id,os_errno,strerror(os_errno));
libdax_msgs_unlock(m,0);
}
}
if(severity < m->queue_severity)
return(0);
ret= libdax_msgs_lock(m,0);
if(ret<=0)
return(-1);
ret= libdax_msgs_item_new(&item,m->youngest,0);
if(ret<=0)
goto failed;
item->driveno= driveno;
item->error_code= error_code;
item->severity= severity;
item->priority= priority;
if(msg_text!=NULL) {
item->msg_text= malloc(strlen(msg_text)+1);
if(item->msg_text==NULL)
goto failed;
strcpy(item->msg_text,msg_text);
}
item->os_errno= os_errno;
if(m->oldest==NULL)
m->oldest= item;
m->youngest= item;
m->count++;
libdax_msgs_unlock(m,0);
/*
fprintf(stderr,"libdax_experimental: message submitted to queue (now %d)\n",
m->count);
*/
return(1);
failed:;
libdax_msgs_item_destroy(&item,0);
libdax_msgs_unlock(m,0);
return(-1);
}
int libdax_msgs_obtain(struct libdax_msgs *m, struct libdax_msgs_item **item,
int severity, int priority, int flag)
{
int ret;
struct libdax_msgs_item *im, *next_im= NULL;
*item= NULL;
ret= libdax_msgs_lock(m,0);
if(ret<=0)
return(-1);
for(im= m->oldest; im!=NULL; im= next_im) {
for(; im!=NULL; im= next_im) {
next_im= im->next;
if(im->severity>=severity)
break;
libdax_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
libdax_msgs_item_destroy(&im,0); /* severity too low: delete */
}
if(im==NULL)
break;
if(im->priority>=priority)
break;
}
if(im==NULL)
{ret= 0; goto ex;}
libdax_msgs_item_unlink(im,&(m->oldest),&(m->youngest),0);
*item= im;
ret= 1;
ex:;
libdax_msgs_unlock(m,0);
return(ret);
}
int libdax_msgs_destroy_item(struct libdax_msgs *m,
struct libdax_msgs_item **item, int flag)
{
int ret;
ret= libdax_msgs_lock(m,0);
if(ret<=0)
return(-1);
ret= libdax_msgs_item_destroy(item,0);
libdax_msgs_unlock(m,0);
return(ret);
}

View File

@ -1,382 +0,0 @@
/* libdax_msgs
Message handling facility of libdax.
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
*/
/*
*Never* set this macro outside libdax_msgs.c !
The entrails of the message handling facility are not to be seen by
the other library components or the applications.
*/
#ifdef LIBDAX_MSGS_H_INTERNAL
#ifndef LIBDAX_MSGS_SINGLE_THREADED
#include <pthread.h>
#endif
struct libdax_msgs_item {
double timestamp;
pid_t process_id;
int driveno;
int severity;
int priority;
/* Apply for your developer's error code range at
libburn-hackers@pykix.org
Report introduced codes in the list below. */
int error_code;
char *msg_text;
int os_errno;
struct libdax_msgs_item *prev,*next;
};
struct libdax_msgs {
struct libdax_msgs_item *oldest;
struct libdax_msgs_item *youngest;
int count;
int queue_severity;
int print_severity;
char print_id[81];
#ifndef LIBDAX_MSGS_SINGLE_THREADED
pthread_mutex_t lock_mutex;
#endif
};
#endif /* LIBDAX_MSGS_H_INTERNAL */
#ifndef LIBDAX_MSGS_H_INCLUDED
#define LIBDAX_MSGS_H_INCLUDED 1
#ifndef LIBDAX_MSGS_H_INTERNAL
/* Public Opaque Handles */
/** A pointer to this is a opaque handle to a message handling facility */
struct libdax_msgs;
/** A pointer to this is a opaque handle to a single message item */
struct libdax_msgs_item;
#endif /* ! LIBDAX_MSGS_H_INTERNAL */
/* Public Macros */
/* Registered Severities */
/* It is well advisable to let applications select severities via strings and
forwarded functions libdax_msgs__text_to_sev(), libdax_msgs__sev_to_text().
These macros are for use by libdax/libburn only.
*/
/** Use this to get messages of any severity. Do not use for submitting.
*/
#define LIBDAX_MSGS_SEV_ALL 0x00000000
/** Debugging messages not to be visible to normal users by default
*/
#define LIBDAX_MSGS_SEV_DEBUG 0x10000000
/** Update of a progress report about long running actions
*/
#define LIBDAX_MSGS_SEV_UPDATE 0x20000000
/** Not so usual events which were gracefully handled
*/
#define LIBDAX_MSGS_SEV_NOTE 0x30000000
/** Possibilities to achieve a better result
*/
#define LIBDAX_MSGS_SEV_HINT 0x40000000
/** Warnings about problems which could not be handled optimally
*/
#define LIBDAX_MSGS_SEV_WARNING 0x50000000
/** Non-fatal error messages indicating that parts of the action failed
but processing will/should go on
*/
#define LIBDAX_MSGS_SEV_SORRY 0x60000000
/** An error message which puts the whole operation of libdax in question
*/
#define LIBDAX_MSGS_SEV_FATAL 0x70000000
/** A message from an abort handler which will finally finish libburn
*/
#define LIBDAX_MSGS_SEV_ABORT 0x71000000
/** A severity to exclude resp. discard any possible message.
Do not use this severity for submitting.
*/
#define LIBDAX_MSGS_SEV_NEVER 0x7fffffff
/* Registered Priorities */
/* Priorities are to be used by libburn/libdax only. */
#define LIBDAX_MSGS_PRIO_ZERO 0x00000000
#define LIBDAX_MSGS_PRIO_LOW 0x10000000
#define LIBDAX_MSGS_PRIO_MEDIUM 0x20000000
#define LIBDAX_MSGS_PRIO_HIGH 0x30000000
#define LIBDAX_MSGS_PRIO_TOP 0x7ffffffe
/* Do not use this priority for submitting */
#define LIBDAX_MSGS_PRIO_NEVER 0x7fffffff
/* Public Functions */
/* Calls initiated from inside libdax/libburn */
/** Create new empty message handling facility with queue.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success, <=0 failure
*/
int libdax_msgs_new(struct libdax_msgs **m, int flag);
/** Destroy a message handling facility and all its eventual messages.
The submitted pointer gets set to NULL.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 for success, 0 for pointer to NULL
*/
int libdax_msgs_destroy(struct libdax_msgs **m, int flag);
/** Submit a message to a message handling facility.
@param driveno libdax drive number. Use -1 if no number is known.
@param error_code Unique error code. Use only registered codes. See below.
The same unique error_code may be issued at different
occasions but those should be equivalent out of the view
of a libdax application. (E.g. "cannot open ATA drive"
versus "cannot open SCSI drive" would be equivalent.)
@param severity The LIBDAX_MSGS_SEV_* of the event.
@param priority The LIBDAX_MSGS_PRIO_* number of the event.
@param msg_text Printable and human readable message text.
@param os_errno Eventual error code from operating system (0 if none)
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on rejection, <0 for severe errors
*/
int libdax_msgs_submit(struct libdax_msgs *m, int driveno, int error_code,
int severity, int priority, char *msg_text,
int os_errno, int flag);
/* Calls from applications (to be forwarded by libdax/libburn) */
/** Convert a registered severity number into a severity name
@param flag Bitfield for control purposes:
bit0= list all severity names in a newline separated string
@return >0 success, <=0 failure
*/
int libdax_msgs__sev_to_text(int severity, char **severity_name,
int flag);
/** Convert a severity name into a severity number,
@param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success, <=0 failure
*/
int libdax_msgs__text_to_sev(char *severity_name, int *severity,
int flag);
/** Set minimum severity for messages to be queued (default
LIBDAX_MSGS_SEV_ALL) and for messages to be printed directly to stderr
(default LIBDAX_MSGS_SEV_NEVER).
@param print_id A text of at most 80 characters to be printed before
any eventually printed message (default is "libdax: ").
@param flag Bitfield for control purposes (unused yet, submit 0)
@return always 1 for now
*/
int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
int print_severity, char *print_id, int flag);
/** Obtain a message item that has at least the given severity and priority.
Usually all older messages of lower severity are discarded then. If no
item of sufficient severity was found, all others are discarded from the
queue.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 if a matching item was found, 0 if not, <0 for severe errors
*/
int libdax_msgs_obtain(struct libdax_msgs *m, struct libdax_msgs_item **item,
int severity, int priority, int flag);
/** Destroy a message item obtained by libdax_msgs_obtain(). The submitted
pointer gets set to NULL.
Caution: Copy eventually obtained msg_text before destroying the item,
if you want to use it further.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 for success, 0 for pointer to NULL, <0 for severe errors
*/
int libdax_msgs_destroy_item(struct libdax_msgs *m,
struct libdax_msgs_item **item, int flag);
/** Obtain from a message item the three application oriented components as
submitted with the originating call of libdax_msgs_submit().
Caution: msg_text becomes a pointer into item, not a copy.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on invalid item, <0 for servere errors
*/
int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
int *error_code, char **msg_text, int *os_errno,
int flag);
/** Obtain from a message item the submitter identification submitted
with the originating call of libdax_msgs_submit().
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on invalid item, <0 for servere errors
*/
int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
double *timestamp, pid_t *process_id, int *driveno,
int flag);
/** Obtain from a message item severity and priority as submitted
with the originating call of libdax_msgs_submit().
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 on success, 0 on invalid item, <0 for servere errors
*/
int libdax_msgs_item_get_rank(struct libdax_msgs_item *item,
int *severity, int *priority, int flag);
#ifdef LIDBAX_MSGS_________________
/* Registered Error Codes */
Format: error_code (LIBDAX_MSGS_SEV_*,LIBDAX_MSGS_PRIO_*) = explanation
If no severity or priority are fixely associates, use "(,)".
------------------------------------------------------------------------------
Range "libdax_msgs" : 0x00000000 to 0x0000ffff
0x00000000 (ALL,ZERO) = Initial setting in new libdax_msgs_item
0x00000001 (DEBUG,ZERO) = Test error message
0x00000002 (DEBUG,ZERO) = Debugging message
------------------------------------------------------------------------------
Range "elmom" : 0x00010000 to 0x0001ffff
------------------------------------------------------------------------------
Range "scdbackup" : 0x00020000 to 0x0002ffff
Acessing and defending drives:
0x00020001 (SORRY,LOW) = Cannot open busy device
0x00020002 (SORRY,HIGH) = Encountered error when closing drive
0x00020003 (SORRY,HIGH) = Could not grab drive
0x00020004 (NOTE,HIGH) = Opened O_EXCL scsi sibling
0x00020005 (FATAL,HIGH) = Failed to open device
0x00020006 (FATAL,HIGH) = Too many scsi siblings
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
General library operations:
0x00020101 (WARNING,HIGH) = Cannot find given worker item
0x00020102 (SORRY,HIGH) = A drive operation is still going on
0x00020103 (WARNING,HIGH) = After scan a drive operation is still going on
0x00020104 (SORRY,HIGH) = NULL pointer caught
0x00020105 (SORRY,HIGH) = Drive is already released
0x00020106 (SORRY,HIGH) = Drive is busy on attempt to close
0x00020107 (SORRY,HIGH) = Drive is busy on attempt to shut down library
0x00020108 (SORRY,HIGH) = Drive is not grabbed on disc status inquiry
0x00020108 (FATAL,HIGH) = Could not allocate new drive object
0x00020109 (FATAL,HIGH) = Library not running
0x0002010a (FATAL,HIGH) = Unsuitable track mode
0x0002010b (FATAL,HIGH) = Burn run failed
0x0002010c (FATAL,HIGH) = Failed to transfer command to drive
0x0002010d (DEBUG,HIGH) = Could not inquire TOC
0x0002010e (FATAL,HIGH) = Attempt to read ATIP from ungrabbed drive
0x0002010f (DEBUG,HIGH) = SCSI error condition on command
0x00020110 (FATAL,HIGH) = Persistent drive address too long
0x00020111 (FATAL,HIGH) = Could not allocate new auxiliary object
0x00020112 (SORRY,HIGH) = Bad combination of write_type and block_type
0x00020113 (FATAL,HIGH) = Drive capabilities not inquired yet
0x00020114 (SORRY,HIGH) = Attempt to set ISRC with bad data
0x00020115 (SORRY,HIGH) = Attempt to set track mode to unusable value
0x00020116 (FATAL,HIGH) = Track mode has unusable value
0x00020117 (FATAL,HIGH) = toc_entry of drive is already in use
0x00020118 (DEBUG,HIGH) = Closing track
0x00020119 (DEBUG,HIGH) = Closing session
0x0002011a (NOTE,HIGH) = Padding up track to minimum size
0x0002011b (FATAL,HIGH) = Attempt to read track info from ungrabbed drive
0x0002011c (FATAL,HIGH) = Attempt to read track info from busy drive
0x0002011d (FATAL,HIGH) = SCSI error condition on write
libdax_audioxtr:
0x00020200 (SORRY,HIGH) = Cannot open audio source file
0x00020201 (SORRY,HIGH) = Audio source file has unsuitable format
0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data
------------------------------------------------------------------------------
#endif /* LIDBAX_MSGS_________________ */
#ifdef LIBDAX_MSGS_H_INTERNAL
/* Internal Functions */
/** Lock before doing side effect operations on m */
static int libdax_msgs_lock(struct libdax_msgs *m, int flag);
/** Unlock after effect operations on m are done */
static int libdax_msgs_unlock(struct libdax_msgs *m, int flag);
/** Create new empty message item.
@param link Previous item in queue
@param flag Bitfield for control purposes (unused yet, submit 0)
@return >0 success, <=0 failure
*/
static int libdax_msgs_item_new(struct libdax_msgs_item **item,
struct libdax_msgs_item *link, int flag);
/** Destroy a message item obtained by libdax_msgs_obtain(). The submitted
pointer gets set to NULL.
@param flag Bitfield for control purposes (unused yet, submit 0)
@return 1 for success, 0 for pointer to NULL
*/
static int libdax_msgs_item_destroy(struct libdax_msgs_item **item, int flag);
#endif /* LIBDAX_MSGS_H_INTERNAL */
#endif /* ! LIBDAX_MSGS_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

@ -1,4 +0,0 @@
int main()
{
return 0;
}

View File

@ -1,215 +0,0 @@
/* dewav
Demo of libburn extension 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 <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/* libdax_audioxtr is quite independent of libburn. It only needs
the messaging facility libdax_msgs. So we got two build variations:
*/
#ifdef Dewav_without_libburN
/* This build environment is standalone relying only on libdax components */
#include "../libburn/libdax_msgs.h"
struct libdax_msgs *libdax_messenger= NULL;
#else /* Dewav_without_libburN */
/* This build environment uses libdax_msgs via libburn */
/* Thus the API header of libburn */
#include "../libburn/libburn.h"
#endif /* ! Dewav_without_libburN */
/* The API for .wav extraction */
#include "../libburn/libdax_audioxtr.h"
int main(int argc, char **argv)
{
/* This program acts as filter from in_path to out_path */
char *in_path= "", *out_path= "-";
/* The read-and-extract object for use with in_path */
struct libdax_audioxtr *xtr= NULL;
/* The file descriptor eventually detached from xtr */
int xtr_fd= -2;
/* Default output is stdout */
int out_fd= 1;
/* Inquired source parameters */
char *fmt, *fmt_info;
int num_channels, sample_rate, bits_per_sample, msb_first;
off_t data_size;
/* Auxiliary variables */
int ret, i, be_strict= 1, buf_count, detach_fd= 0, extract_all= 0;
char buf[2048];
if(argc < 2)
goto help;
for(i= 1; i<argc; i++) {
if(strcmp(argv[i],"-o")==0) {
if(i>=argc-1) {
fprintf(stderr,"%s: option -o needs a file address as argument.\n",
argv[0]);
exit(1);
}
i++;
out_path= argv[i];
} else if(strcmp(argv[i],"--lax")==0) {
be_strict= 0;
} else if(strcmp(argv[i],"--strict")==0) {
be_strict= 1;
} else if(strcmp(argv[i],"--detach_fd")==0) {
/* Test the dirty detach method. Always --extract_all */
detach_fd= 1;
} else if(strcmp(argv[i],"--extract_all")==0) {
/* Dirty : read all available bytes regardless of data_size */
extract_all= 1;
} else if(strcmp(argv[i],"--help")==0) {
help:;
fprintf(stderr,
"usage: %s [-o output_path|\"-\"] [--lax|--strict] [source_path|\"-\"]\n",
argv[0]);
exit(0);
} else {
if(in_path[0]!=0) {
fprintf(stderr,"%s: only one input file is allowed.\n", argv[0]);
exit(2);
}
in_path= argv[i];
}
}
if(in_path[0] == 0)
in_path= "-";
/* Depending on wether this was built standalone or with full libburn :
*/
#ifdef Dewav_without_libburN
/* Initialize and set up libdax messaging system */
ret= libdax_msgs_new(&libdax_messenger,0);
if(ret<=0) {
fprintf(stderr,"Failed to create libdax_messenger object.\n");
exit(3);
}
libdax_msgs_set_severities(libdax_messenger, LIBDAX_MSGS_SEV_NEVER,
LIBDAX_MSGS_SEV_NOTE, "", 0);
fprintf(stderr, "dewav on libdax\n");
#else /* Dewav_without_libburN */
/* Initialize libburn and set up its messaging system */
if(burn_initialize() == 0) {
fprintf(stderr,"Failed to initialize libburn.\n");
exit(3);
}
/* Print messages of severity NOTE or more directly to stderr */
burn_msgs_set_severities("NEVER", "NOTE", "");
fprintf(stderr, "dewav on libburn\n");
#endif /* ! Dewav_without_libburN */
/* Open audio source and create extractor object */
ret= libdax_audioxtr_new(&xtr, in_path, 0);
if(ret<=0)
exit(4);
if(strcmp(out_path,"-")!=0) {
out_fd= open(out_path, O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if(out_fd == -1) {
fprintf(stderr, "Cannot open file: %s\n", out_path);
fprintf(stderr, "Error reported: '%s' (%d)\n",strerror(errno), errno);
exit(5);
}
}
/* Obtain and print parameters of audio source */
libdax_audioxtr_get_id(xtr, &fmt, &fmt_info,
&num_channels, &sample_rate, &bits_per_sample, &msb_first, 0);
fprintf(stderr, "Detected format: %s\n", fmt_info);
libdax_audioxtr_get_size(xtr, &data_size, 0);
fprintf(stderr, "Data size : %.f bytes\n", (double) data_size);
if((strcmp(fmt,".wav")!=0 && strcmp(fmt,".au")!=0) ||
num_channels!=2 || sample_rate!=44100 || bits_per_sample!=16) {
fprintf(stderr,
"%sAudio source parameters do not comply to cdrskin/README specs\n",
(be_strict ? "" : "WARNING: "));
if(be_strict)
exit(6);
}
if(msb_first==0)
fprintf(stderr,
"NOTE: Extracted data to be written with cdrskin option -swab\n");
if(detach_fd) {
/* Take over fd from xtr */;
ret= libdax_audioxtr_detach_fd(xtr, &xtr_fd, 0);
if(ret<=0) {
fprintf(stderr, "Cannot detach file descriptor from extractor\n");
exit(8);
}
/* not needed any more */
libdax_audioxtr_destroy(&xtr, 0);
fprintf(stderr, "Note: detached fd and freed extractor object.\n");
}
/* Extract and put out raw audio data */;
while(1) {
if(detach_fd) {
buf_count= read(xtr_fd, buf, sizeof(buf));
if(buf_count==-1)
fprintf(stderr,"Error while reading from detached fd\n(%d) '%s'\n",
errno, strerror(errno));
} else {
buf_count= libdax_audioxtr_read(xtr, buf, sizeof(buf), !!extract_all);
}
if(buf_count < 0)
exit(7);
if(buf_count == 0)
break;
ret= write(out_fd, buf, buf_count);
if(ret == -1) {
fprintf(stderr, "Failed to write buffer of %d bytes to: %s\n",
buf_count, out_path);
fprintf(stderr, "Error reported: '%s' (%d)\n", strerror(errno), errno);
exit(5);
}
}
/* Shutdown */
if(out_fd>2)
close(out_fd);
/* ( It is permissible to do this with xtr==NULL ) */
libdax_audioxtr_destroy(&xtr, 0);
#ifdef Dewav_without_libburN
libdax_msgs_destroy(&libdax_messenger,0);
#else /* Dewav_without_libburN */
burn_finish();
#endif /* ! Dewav_without_libburN */
exit(0);
}

View File

@ -1,164 +0,0 @@
/* fake_au
Fakes a file in SUN .au format from a raw little-endian PCM audio file
(e.g. a file extracted from .wav by test/dewav). The input data are assumed
to be 16 bit, stereo, 44100 Hz.
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
Info used: http://www.opengroup.org/public/pubs/external/auformat.html
*/
#include <ctype.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
int fake_write(unsigned char *buf, size_t size, FILE *fp)
{
int ret;
ret= fwrite(buf,size,1,fp);
if(ret==1)
return(1);
fprintf(stderr,"Error %d while writing: '%s'\n",errno,strerror(errno));
return(0);
}
int main(int argc, char **argv)
{
int ret, i;
unsigned data_size= 0,byte_count,exit_value= 0;
FILE *fp_out= stdout,*fp_in= stdin;
unsigned char buf[4];
char out_path[4096],in_path[4096];
struct stat stbuf;
strcpy(out_path,"-");
strcpy(in_path,"");
if(argc < 2) {
exit_value= 1;
goto help;
}
for(i= 1; i<argc; i++) {
if(strcmp(argv[i],"-o")==0) {
if(i>=argc-1) {
fprintf(stderr,"%s: option -o needs a file address as argument.\n",
argv[0]);
exit(1);
}
i++;
strcpy(out_path, argv[i]);
} else if(strcmp(argv[i],"--stdin_size")==0) {
if(i>=argc-1) {
fprintf(stderr,"%s: option --stdin_size needs a number as argument.\n",
argv[0]);
exit(1);
}
i++;
sscanf(argv[i],"%u",&data_size);
} else if(strcmp(argv[i],"--help")==0) {
exit_value= 0;
help:;
fprintf(stderr,"usage: %s \\\n", argv[0]);
fprintf(stderr," [-o output_path|\"-\"] [source_path | --stdin_size size]\n");
fprintf(stderr,
"Disguises an extracted .wav stream as .au stereo, 16bit, 44100Hz\n");
fprintf(stderr,
"stdin gets byte-swapped and appended up to the announced data_size.\n");
exit(exit_value);
} else {
if(in_path[0]!=0) {
fprintf(stderr,"%s: only one input file is allowed.\n", argv[0]);
exit(1);
}
strcpy(in_path, argv[i]);
}
}
if(strcmp(in_path,"-")==0 || in_path[0]==0) {
if(data_size==0) {
fprintf(stderr,"%s: input from stdin needs option --stdin_size.\n",
argv[0]);
exit(6);
}
fp_in= stdin;
} else {
fp_in= fopen(in_path,"r");
if(stat(in_path,&stbuf)!=-1)
data_size= stbuf.st_size;
}
if(fp_in==NULL) {
fprintf(stderr,"Error %d while fopen(\"%s\",\"r\") : '%s'\n",
errno,in_path,strerror(errno));
exit(2);
}
if(strcmp(out_path,"-")==0) {
fp_out= stdout;
} else {
if(stat(out_path,&stbuf)!=-1) {
fprintf(stderr,"%s: file '%s' already existing\n",argv[0],out_path);
exit(4);
}
fp_out= fopen(out_path,"w");
}
if(fp_out==NULL) {
fprintf(stderr,"Error %d while fopen(\"%s\",\"w\") : '%s'\n",
errno,out_path,strerror(errno));
exit(2);
}
fake_write((unsigned char *) ".snd",4,fp_out); /* magic number */
buf[0]= buf[1]= buf[2]= 0;
buf[3]= 32;
fake_write(buf,4,fp_out); /* data_location */
buf[0]= (data_size>>24)&0xff;
buf[1]= (data_size>>16)&0xff;
buf[2]= (data_size>>8)&0xff;
buf[3]= (data_size)&0xff;
fake_write(buf,4,fp_out); /* data_size */
buf[0]= buf[1]= buf[2]= 0;
buf[3]= 3;
fake_write(buf,4,fp_out); /* encoding 16 Bit PCM */
buf[0]= buf[1]= 0;
buf[2]= 172;
buf[3]= 68;
fake_write(buf,4,fp_out); /* sample rate 44100 Hz */
buf[0]= buf[1]= buf[2]= 0;
buf[3]= 2;
fake_write(buf,4,fp_out); /* number of channels */
buf[0]= buf[1]= buf[2]= buf[3]= 0;
fake_write(buf,4,fp_out); /* padding */
fake_write(buf,4,fp_out); /* padding */
for(byte_count= 0; byte_count<data_size; byte_count+=2) {
ret= fread(buf,2,1,fp_in);
if(ret<=0) {
fprintf(stderr,"Premature end end of input\n");
exit_value= 5;
break;
}
buf[3]= buf[0];
buf[2]= buf[1];
ret= fake_write(buf+2,2,fp_out);
if(ret<=0) {
exit_value= 3;
break;
}
}
if(fp_out!=stdout)
fclose(fp_out);
if(fp_in!=stdin)
fclose(fp_in);
fprintf(stderr, "Swapped and appended: %u stdin bytes\n",byte_count);
exit(exit_value);
}

View File

@ -1,684 +0,0 @@
/* test/libburner.c , API illustration of burning a single data track to CD */
/* Copyright (C) 2005 - 2006 Thomas Schmitt <scdbackup@gmx.net> */
/* Provided under GPL, see also "License and copyright aspects" at file end */
/** Overview
libburner is a minimal demo application for the library libburn as provided
on http://libburn.pykix.org . It can list the available devices, can
blank a CD-RW and can burn to CD-R or CD-RW.
It's main purpose, nevertheless, is to show you how to use libburn and also
to serve the libburn team as reference application. libburner.c does indeed
define the standard way how above three gestures can be implemented and
stay upward compatible for a good while.
Before you can do anything, you have to initialize libburn by
burn_initialize()
and provide some signal and abort handling, e.g. by the builtin handler, by
burn_set_signal_handling()
as it is done in main() at the end of this file. Then you aquire a
drive in an appropriate way conforming to the API. The two main
approaches are shown here in application functions:
libburner_aquire_by_adr() demonstrates usage as of cdrecord traditions
libburner_aquire_by_driveno() demonstrates a scan-and-choose approach
With that aquired drive you can blank a CD-RW
libburner_blank_disc()
Between blanking and burning one eventually has to reload the drive status
libburner_regrab()
With the aquired drive you can burn to CD-R or blank CD-RW
libburner_payload()
When everything is done, main() releases the drive and shuts down libburn:
burn_drive_release();
burn_finish()
*/
/** See this for the decisive API specs . libburn.h is The Original */
/* For using the installed header file : #include <libburn/libburn.h> */
/* This program insists in the own headerfile. */
#include "../libburn/libburn.h"
/* libburn is intended for Linux systems with kernel 2.4 or 2.6 for now */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
/** For simplicity i use global variables to represent the drives.
Drives are systemwide global, so we do not give away much of good style.
*/
/** This list will hold the drives known to libburn. This might be all CD
drives of the system and thus might impose severe impact on the system.
*/
static struct burn_drive_info *drive_list;
/** If you start a long lasting operation with drive_count > 1 then you are
not friendly to the users of other drives on those systems. Beware. */
static unsigned int drive_count;
/** This variable indicates wether the drive is grabbed and must be
finally released */
static int drive_is_grabbed = 0;
/* Some in-advance definitions to allow a more comprehensive ordering
of the functions and their explanations in here */
int libburner_aquire_by_adr(char *drive_adr);
int libburner_aquire_by_driveno(int *drive_no);
/* ------------------------------- API gestures ---------------------------- */
/** You need to aquire a drive before burning. The API offers this as one
compact call and alternatively as application controllable gestures of
whitelisting, scanning for drives and finally grabbing one of them.
If you have a persistent address of the drive, then the compact call is
to prefer because it only touches one drive. On modern Linux kernels,
there should be no fatal disturbance of ongoing burns of other libburn
instances with any of our approaches. We use open(O_EXCL) by default.
On /dev/hdX it should cooperate with growisofs and some cdrecord variants.
On /dev/sgN versus /dev/scdM expect it not to respect other programs.
*/
int libburner_aquire_drive(char *drive_adr, int *driveno)
{
int ret;
if(drive_adr != NULL && drive_adr[0] != 0)
ret = libburner_aquire_by_adr(drive_adr);
else
ret = libburner_aquire_by_driveno(driveno);
return ret;
}
/** If the persistent drive address is known, then this approach is much
more un-obtrusive to the systemwide livestock of drives. Only the
given drive device will be opened during this procedure.
*/
int libburner_aquire_by_adr(char *drive_adr)
{
int ret;
printf("Aquiring drive '%s' ...\n",drive_adr);
ret = burn_drive_scan_and_grab(&drive_list,drive_adr,1);
if (ret <= 0) {
fprintf(stderr,"FAILURE with persistent drive address '%s'\n",
drive_adr);
if (strncmp(drive_adr,"/dev/sg",7) != 0 &&
strncmp(drive_adr,"/dev/hd",7) != 0)
fprintf(stderr,"\nHINT: Consider addresses like '/dev/hdc' or '/dev/sg0'\n");
} else {
printf("Done\n");
drive_is_grabbed = 1;
}
return ret;
}
/** This method demonstrates how to use libburn without knowing a persistent
drive address in advance. It has to make sure that after assessing the list
of available drives, all unwanted drives get closed again. As long as they
are open, no other libburn instance can see them. This is an intended
locking feature. The application is responsible for giving up the locks
by either burn_drive_release() (only after burn_drive_grab() !),
burn_drive_info_forget(), burn_drive_info_free(), or burn_finish().
@param driveno the index number in libburn's drive list. This will get
set to 0 on success and will then be the drive index to
use in the further dourse of processing.
@return 1 success , <= 0 failure
*/
int libburner_aquire_by_driveno(int *driveno)
{
char adr[BURN_DRIVE_ADR_LEN];
int ret, i;
printf("Beginning to scan for devices ...\n");
while (!burn_drive_scan(&drive_list, &drive_count))
usleep(1002);
if (drive_count <= 0 && *driveno >= 0) {
printf("FAILED (no drives found)\n");
return 0;
}
printf("Done\n");
/*
Interactive programs may choose the drive number at this moment.
drive[0] to drive[drive_count-1] are struct burn_drive_info
as defined in libburn/libburn.h . This structure is part of API
and thus will strive for future compatibility on source level.
Have a look at the info offered.
Caution: do not take .location for drive address. Always use
burn_drive_get_adr() or you might become incompatible
in future.
Note: bugs with struct burn_drive_info - if any - will not be
easy to fix. Please report them but also strive for
workarounds on application level.
*/
printf("\nOverview of accessible drives (%d found) :\n",
drive_count);
printf("-----------------------------------------------------------------------------\n");
for (i = 0; i < drive_count; i++) {
if (burn_drive_get_adr(&(drive_list[i]), adr) <=0)
strcpy(adr, "-get_adr_failed-");
printf("%d --drive '%s' : '%s' '%s'\n",
i,adr,drive_list[i].vendor,drive_list[i].product);
}
printf("-----------------------------------------------------------------------------\n\n");
/*
On multi-drive systems save yourself from sysadmins' revenge.
Be aware that you hold reserved all available drives at this point.
So either make your choice quick enough not to annoy other system
users, or set free the drives for a while.
The tested way of setting free all drives is to shutdown the library
and to restart when the choice has been made. The list of selectable
drives should also hold persistent drive addresses as obtained
above by burn_drive_get_adr(). By such an address one may use
burn_drive_scan_and_grab() to finally aquire exactly one drive.
A not yet tested shortcut should be to call burn_drive_info_free()
and to call either burn_drive_scan() or burn_drive_scan_and_grab()
before accessing any drives again.
In both cases you have to be aware that the desired drive might get
aquired in the meantime by another user resp. libburn process.
*/
/* We already made our choice via command line. (default is 0)
So we just have to keep our desired drive and drop all others.
No other libburn instance will have a chance to steal our drive.
*/
if (*driveno < 0) {
printf("Pseudo-drive \"-\" given : bus scanning done.\n");
return 2; /* the program will end after this */
}
if (drive_count <= *driveno) {
fprintf(stderr,
"Found only %d drives. Number %d not available.\n",
drive_count, *driveno);
return 0; /* the program will end after this */
}
/* Drop all drives which we do not want to use */
for (i = 0; i < drive_count; i++) {
if (i == *driveno) /* the one drive we want to keep */
continue;
ret = burn_drive_info_forget(&(drive_list[i]),0);
if (ret != 1)
fprintf(stderr, "Cannot drop drive %d. Please report \"ret=%d\" to libburn-hackers@pykix.org\n",
i, ret);
else
printf("Dropped unwanted drive %d\n",i);
}
/* Make the one we want ready for blanking or burning */
ret= burn_drive_grab(drive_list[*driveno].drive, 1);
if (ret != 1)
return 0;
drive_is_grabbed = 1;
return 1;
}
/** Makes a previously used CD-RW ready for thorough re-usal.
To our knowledge it is hardly possible to abort an ongoing blank operation
because after start it is entirely handled by the drive.
So expect signal handling to wait the normal blanking timespan until it
can allow the process to end. External kill -9 will not help the drive.
*/
int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
{
enum burn_disc_status disc_state;
struct burn_progress p;
int percent = 1;
while (burn_drive_get_status(drive, NULL) != BURN_DRIVE_IDLE)
usleep(1001);
while ((disc_state = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
usleep(1001);
printf(
"Drive media status: %d (see libburn/libburn.h BURN_DISC_*)\n",
disc_state);
if (disc_state == BURN_DISC_BLANK) {
fprintf(stderr,
"IDLE: Blank CD media detected. Will leave it untouched\n");
return 2;
} else if (disc_state == BURN_DISC_FULL ||
disc_state == BURN_DISC_APPENDABLE) {
; /* this is what libburn is willing to blank */
} else if (disc_state == BURN_DISC_EMPTY) {
fprintf(stderr,"FATAL: No media detected in drive\n");
return 0;
} else {
fprintf(stderr,
"FATAL: Cannot recognize drive and media state\n");
return 0;
}
if(!burn_disc_erasable(drive)) {
fprintf(stderr,
"FATAL : Media is not of erasable type\n");
return 0;
}
printf(
"Beginning to %s-blank CD media.\n", (blank_fast?"fast":"full"));
burn_disc_erase(drive, blank_fast);
sleep(1);
while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
percent = 1.0 + ((double) p.sector+1.0)
/ ((double) p.sectors) * 98.0;
printf("Blanking ( %d%% done )\n", percent);
sleep(1);
}
printf("Done\n");
return 1;
}
/** This gesture is necessary to get the drive info after blanking.
It opens a small gap for losing the drive to another libburn instance.
We will work on closing this gap.
*/
int libburner_regrab(struct burn_drive *drive) {
int ret;
printf("Releasing and regrabbing drive ...\n");
if (drive_is_grabbed)
burn_drive_release(drive, 0);
drive_is_grabbed = 0;
ret = burn_drive_grab(drive, 0);
if (ret != 0) {
drive_is_grabbed = 1;
printf("Done\n");
} else
printf("FAILED\n");
return !!ret;
}
/** Brings preformatted track images (ISO 9660, audio, ...) onto media.
To make sure a data image is fully readable on any Linux machine, this
function adds 300 kB of padding to the (usualy single) track.
Audio tracks get padded to complete their last sector.
In case of external signals expect abort handling of an ongoing burn to
last up to a minute. Wait the normal burning timespan before any kill -9.
*/
int libburner_payload(struct burn_drive *drive,
char source_adr[][4096], int source_adr_count,
off_t stdin_size, int simulate_burn, int all_tracks_type)
{
struct burn_source *data_src;
struct burn_disc *target_disc;
struct burn_session *session;
struct burn_write_opts *burn_options;
enum burn_disc_status disc_state;
struct burn_track *track, *tracklist[99];
struct burn_progress progress;
time_t start_time;
int last_sector = 0, padding = 0, trackno;
char *adr;
if (all_tracks_type != BURN_AUDIO) {
all_tracks_type = BURN_MODE1;
/* a padding of 300 kB helps to avoid the read-ahead bug */
padding = 300*1024;
}
target_disc = burn_disc_create();
session = burn_session_create();
burn_disc_add_session(target_disc, session, BURN_POS_END);
for (trackno = 0 ; trackno < source_adr_count; trackno++) {
tracklist[trackno] = track = burn_track_create();
burn_track_define_data(track, 0, padding, 1, all_tracks_type);
adr = source_adr[trackno];
if (adr[0] == '-' && adr[1] == 0) {
data_src = burn_fd_source_new(0, -1, stdin_size);
printf("Note: using standard input as source with %.f bytes\n",
(double) stdin_size);
} else
data_src = burn_file_source_new(adr, NULL);
if (data_src == NULL) {
fprintf(stderr,
"FATAL: Could not open data source '%s'.\n",adr);
if(errno!=0)
fprintf(stderr,"(Most recent system error: %s )\n",
strerror(errno));
return 0;
}
if (burn_track_set_source(track, data_src) != BURN_SOURCE_OK) {
printf("FATAL: Cannot attach source object to track object\n");
return 0;
}
burn_session_add_track(session, track, BURN_POS_END);
printf("Track %d : source is '%s'\n", trackno, adr);
burn_source_free(data_src);
} /* trackno loop end */
while (burn_drive_get_status(drive, NULL) != BURN_DRIVE_IDLE)
usleep(100001);
/* Evaluate drive and media */
while ((disc_state = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
usleep(100001);
if (disc_state != BURN_DISC_BLANK) {
if (disc_state == BURN_DISC_FULL ||
disc_state == BURN_DISC_APPENDABLE) {
fprintf(stderr,
"FATAL: Media with data detected. Need blank media.\n");
if (burn_disc_erasable(drive))
fprintf(stderr, "HINT: Try --blank_fast\n\n");
} else if (disc_state == BURN_DISC_EMPTY)
fprintf(stderr,"FATAL: No media detected in drive\n");
else
fprintf(stderr,
"FATAL: Cannot recognize drive and media state\n");
return 0;
}
burn_options = burn_write_opts_new(drive);
burn_write_opts_set_perform_opc(burn_options, 0);
#ifdef Libburner_raw_mode_which_i_do_not_likE
/* This yields higher CD capacity but hampers my IDE controller
with burning on one drive and reading on another simultaneously.
My burner does not obey the order --try_to_simulate in this mode.
*/
burn_write_opts_set_write_type(burn_options,
BURN_WRITE_RAW, BURN_BLOCK_RAW96R);
#else
/* This is by what cdrskin competes with cdrecord -sao which
i understand is the mode preferrably advised by Joerg Schilling */
burn_write_opts_set_write_type(burn_options,
BURN_WRITE_SAO, BURN_BLOCK_SAO);
#endif
if(simulate_burn)
printf("\n*** Will TRY to SIMULATE burning ***\n\n");
burn_write_opts_set_simulate(burn_options, simulate_burn);
burn_structure_print_disc(target_disc);
burn_drive_set_speed(drive, 0, 0);
burn_write_opts_set_underrun_proof(burn_options, 1);
printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n");
start_time = time(0);
burn_disc_write(burn_options, target_disc);
burn_write_opts_free(burn_options);
while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
usleep(1002);
while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
if( progress.sectors <= 0 || progress.sector == last_sector)
printf(
"Thank you for being patient since %d seconds.\n",
(int) (time(0) - start_time));
else
printf("Track %d : sector %d of %d\n", progress.track,
progress.sector, progress.sectors);
last_sector = progress.sector;
sleep(1);
}
printf("\n");
for (trackno = 0 ; trackno < source_adr_count; trackno++)
burn_track_free(tracklist[trackno]);
burn_session_free(session);
burn_disc_free(target_disc);
if(simulate_burn)
printf("\n*** Did TRY to SIMULATE burning ***\n\n");
return 0;
}
/** The setup parameters of libburn */
static char drive_adr[BURN_DRIVE_ADR_LEN]= {""};
static int driveno= 0;
static int do_blank= 0;
static char source_adr[99][4096];
static int source_adr_count= 0;
static off_t stdin_size= 650*1024*1024;
static int simulate_burn = 0;
static int all_tracks_type = BURN_MODE1;
/** Converts command line arguments into above setup parameters.
drive_adr[] must provide at least BURN_DRIVE_ADR_LEN bytes.
source_adr[] must provide at least 4096 bytes.
*/
int libburner_setup(int argc, char **argv)
{
int i, insuffient_parameters = 0, print_help = 0;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--audio")) {
all_tracks_type = BURN_AUDIO;
} else if (!strcmp(argv[i], "--blank_fast")) {
do_blank = 1;
} else if (!strcmp(argv[i], "--blank_full")) {
do_blank = 2;
} else if (!strcmp(argv[i], "--burn_for_real")) {
simulate_burn = 0;
} else if (!strcmp(argv[i], "--drive")) {
++i;
if (i >= argc) {
fprintf(stderr,"--drive requires an argument\n");
return 1;
} else if (strcmp(argv[i], "-") == 0) {
drive_adr[0] = 0;
driveno = -1;
} else if (isdigit(argv[i][0])) {
drive_adr[0] = 0;
driveno = atoi(argv[i]);
} else {
if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
fprintf(stderr,"--drive address too long (max. %d)\n",
BURN_DRIVE_ADR_LEN-1);
return 2;
}
strcpy(drive_adr, argv[i]);
}
} else if (!strcmp(argv[i], "--stdin_size")) {
++i;
if (i >= argc) {
fprintf(stderr,"--stdin_size requires an argument\n");
return 3;
} else
stdin_size = atoi(argv[i]);
if (stdin_size < 600*1024) /* minimum readable track size */
stdin_size = 600*1024;
} else if (!strcmp(argv[i], "--try_to_simulate")) {
simulate_burn = 1;
} else if (!strcmp(argv[i], "--help")) {
print_help = 1;
} else if (!strncmp(argv[i], "--",2)) {
fprintf(stderr, "Unidentified option: %s\n", argv[i]);
return 7;
} else {
if(strlen(argv[i]) >= 4096) {
fprintf(stderr, "Source address too long (max. %d)\n", 4096-1);
return 5;
}
if(source_adr_count >= 99) {
fprintf(stderr, "Too many tracks (max. 99)\n");
return 6;
}
strcpy(source_adr[source_adr_count], argv[i]);
source_adr_count++;
}
}
insuffient_parameters = 1;
if (driveno < 0)
insuffient_parameters = 0;
if (source_adr_count > 0)
insuffient_parameters = 0;
if (do_blank)
insuffient_parameters = 0;
if (print_help || insuffient_parameters ) {
printf("Usage: %s\n", argv[0]);
printf(" [--drive <address>|<driveno>|\"-\"]\n");
printf(" [--blank_fast|--blank_full] [--audio]\n");
printf(" [--try_to_simulate] [--stdin_size <bytes>]\n");
printf(" [<one or more imagefiles>|\"-\"]\n");
printf("Examples\n");
printf("A bus scan (needs rw-permissions to see a drive):\n");
printf(" %s --drive -\n",argv[0]);
printf("Burn a file to drive chosen by number:\n");
printf(" %s --drive 0 my_image_file\n",
argv[0]);
printf("Burn a file to drive chosen by persistent address:\n");
printf(" %s --drive /dev/hdc my_image_file\n", argv[0]);
printf("Blank a used CD-RW (is combinable with burning in one run):\n");
printf(" %s --drive /dev/hdc --blank_fast\n",argv[0]);
printf("Burn two audio tracks\n");
printf(" lame --decode -t /path/to/track1.mp3 track1.cd\n");
printf(" test/dewav /path/to/track2.wav -o track2.cd\n");
printf(" %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);
printf("Burn a compressed afio archive on-the-fly, pad up to 700 MB:\n");
printf(" ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
printf(" %s --drive /dev/hdc --stdin_size 734003200 -\n", argv[0]);
printf("To be read from *not mounted* CD via: afio -tvZ /dev/hdc\n");
printf("Program tar would need a clean EOF which our padded CD cannot deliver.\n");
if (insuffient_parameters)
return 6;
}
return 0;
}
int main(int argc, char **argv)
{
int ret;
ret = libburner_setup(argc, argv);
if (ret)
exit(ret);
printf("Initializing libburn.pykix.org ...\n");
if (burn_initialize())
printf("Done\n");
else {
printf("FAILED\n");
fprintf(stderr,"\nFATAL: Failed to initialize.\n");
exit(33);
}
/* Print messages of severity SORRY or more directly to stderr */
burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
/* Activate the default signal handler which eventually will try to
properly shutdown drive and library on aborting events. */
burn_set_signal_handling("libburner : ", NULL, 0);
/** Note: driveno might change its value in this call */
ret = libburner_aquire_drive(drive_adr, &driveno);
if (ret<=0) {
fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
{ ret = 34; goto finish_libburn; }
}
if (ret == 2)
{ ret = 0; goto release_drive; }
if (do_blank) {
ret = libburner_blank_disc(drive_list[driveno].drive,
do_blank == 1);
if (ret<=0)
{ ret = 36; goto release_drive; }
if (ret != 2 && source_adr_count > 0)
ret = libburner_regrab(drive_list[driveno].drive);
if (ret<=0) {
fprintf(stderr,
"FATAL: Cannot release and grab again drive after blanking\n");
{ ret = 37; goto finish_libburn; }
}
}
if (source_adr_count > 0) {
ret = libburner_payload(drive_list[driveno].drive,
source_adr, source_adr_count, stdin_size,
simulate_burn, all_tracks_type);
if (ret<=0)
{ ret = 38; goto release_drive; }
}
ret = 0;
release_drive:;
if (drive_is_grabbed)
burn_drive_release(drive_list[driveno].drive, 0);
finish_libburn:;
/* This app does not bother to know about exact scan state.
Better to accept a memory leak here. We are done anyway. */
/* burn_drive_info_free(drive_list); */
burn_finish();
exit(ret);
}
/* License and copyright aspects:
This all is provided under GPL.
Read. Try. Think. Play. Write yourself some code. Be free of my copyright.
Be also invited to study the code of cdrskin/cdrskin.c et al.
Clarification in my name and in the name of Mario Danic, copyright holder
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:
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.
History:
libburner is a compilation of my own contributions to test/burniso.c and
fresh code which replaced the remaining parts under copyright of
Derek Foreman.
My respect and my thanks to Derek for providing me a start back in 2005.
*/

View File

@ -1,126 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <libburn/libburn.h>
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
static struct burn_drive_info *drives;
static unsigned int n_drives;
void burn_files(struct burn_drive *drive, struct burn_disc *disc)
{
struct burn_write_opts *o;
enum burn_disc_status s;
if (!burn_drive_grab(drive, 1)) {
printf("Unable to open the drive!\n");
return;
}
while (burn_drive_get_status(drive, NULL))
usleep(1000);
while ((s = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
usleep(1000);
if (s != BURN_DISC_BLANK) {
burn_drive_release(drive, 0);
printf("Please insert blank media in the drive\n");
return;
}
o = burn_write_opts_new(drive);
burn_drive_set_speed(drive, 0, 2816);
burn_write_opts_set_perform_opc(o, 0);
burn_write_opts_set_write_type(o, BURN_WRITE_TAO, BURN_BLOCK_MODE1);
burn_write_opts_set_simulate(o, 1);
/* want failure on seggy while debugging :) */
burn_write_opts_set_underrun_proof(o, 0);
burn_structure_print_disc(disc);
burn_disc_write(o, disc);
burn_write_opts_free(o);
while (burn_drive_get_status(drive, NULL)) {
sleep(1);
}
printf("\n");
burn_drive_release(drive, 0);
burn_disc_free(disc);
}
void parse_args(int argc, char **argv, int *drive, struct burn_disc **disc)
{
int i, tmode = BURN_AUDIO;
int help = 1;
struct burn_session *session;
struct burn_track *tr;
struct burn_source *src;
*disc = burn_disc_create();
session = burn_session_create();
burn_disc_add_session(*disc, session, BURN_POS_END);
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--drive")) {
++i;
if (i >= argc)
printf("--drive requires an argument\n");
else
*drive = atoi(argv[i]);
} else if (!strcmp(argv[i], "--audio")) {
tmode = BURN_AUDIO;
} else if (!strcmp(argv[i], "--data")) {
tmode = BURN_MODE1;
} else if (!strcmp(argv[i], "--verbose")) {
++i;
if (i >= argc)
printf("--verbose requires an argument\n");
else
burn_set_verbosity(atoi(argv[i]));
} else if (!strcmp(argv[i], "--help")) {
help = 1; /* who cares */
} else {
help = 0;
printf("%s is a track\n", argv[i]);
tr = burn_track_create();
src = burn_file_source_new(argv[i], NULL);
burn_track_set_source(tr, src);
burn_source_free(src);
burn_track_define_data(tr, 0, 0, 1, tmode);
burn_session_add_track(session, tr, BURN_POS_END);
}
}
if (help) {
printf("Usage: %s [--drive <num>] [--verbose <level>] files\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
int main(int argc, char **argv)
{
int drive = 0;
struct burn_disc *disc;
parse_args(argc, argv, &drive, &disc);
printf("Initializing library...");
if (burn_initialize())
printf("Success\n");
else {
printf("Failed\n");
return 1;
}
printf("Scanning for devices...");
while (!burn_drive_scan(&drives, &n_drives)) ;
printf("Done\n");
burn_files(drives[drive].drive, disc);
burn_drive_info_free(drives);
burn_finish();
return 0;
}

View File

@ -1,78 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include "libburn/libburn.h"
#include "libburn/toc.h"
#include "libburn/mmc.h"
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <assert.h>
static struct burn_drive_info *drives;
static unsigned int n_drives;
int NEXT;
static void catch_int ()
{
NEXT = 1;
}
static void poll_drive(int d)
{
enum burn_disc_status s;
fprintf(stderr, "polling disc in %s - %s:\n",
drives[d].vendor, drives[d].product);
if (!burn_drive_grab(drives[d].drive, 1)) {
fprintf(stderr, "Unable to open the drive!\n");
return;
}
while (burn_drive_get_status(drives[d].drive, NULL))
usleep(1000);
while ((s = burn_disc_get_status(drives[d].drive))
== BURN_DISC_UNREADY)
usleep(1000);
while (NEXT == 0) {
sleep(2);
mmc_get_event(drives[d].drive);
}
burn_drive_release(drives[d].drive, 0);
}
int main()
{
int i;
struct sigaction newact;
struct sigaction oldact;
fprintf(stderr, "Initializing library...");
if (burn_initialize())
fprintf(stderr, "Success\n");
else {
printf("Failed\n");
return 1;
}
fprintf(stderr, "Scanning for devices...");
while (!burn_drive_scan(&drives, &n_drives)) ;
fprintf(stderr, "Done\n");
if (!drives) {
printf("No burner found\n");
return 1;
}
newact.sa_handler = catch_int;
sigaction(SIGINT, &newact, &oldact);
for (i = 0; i < n_drives; i++) {
NEXT=0;
poll_drive(i);
}
sigaction(SIGINT, &oldact, NULL);
burn_drive_info_free(drives);
burn_finish();
return 0;
}

View File

@ -1,54 +0,0 @@
/* THIS IS NOT A PROPER EXAMPLE */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <libburn/libburn.h>
static struct burn_drive_info *drives;
static unsigned int n_drives;
#warning this example is totally fried
int main()
{
#if 0
struct burn_drive *drive;
struct burn_read_opts o;
burn_initialize();
o.datafd =
open("/xp/burn/blah.data", O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR);
o.subfd =
open("/xp/burn/blah.sub", O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR);
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;
printf("Scanning for devices...");
while (!burn_drive_scan(&drives, &n_drives)) ;
printf("Done\n");
drive = drives[0].drive;
burn_drive_set_speed(drive, 0, 0);
if (!burn_drive_grab(drive, 1)) {
printf("Unable to open the drive!\n");
return EXIT_FAILURE;
}
while (burn_drive_get_status(drive, NULL))
usleep(1000);
burn_disc_read(drive, &o);
#endif
return EXIT_SUCCESS;
}

View File

@ -1,48 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libburn/libburn.h>
int main(int argc, char **argv)
{
int i;
const char *path;
struct burn_track *track;
struct burn_disc *disc;
struct burn_session *session;
struct burn_source *src;
disc = burn_disc_create();
session = burn_session_create();
burn_disc_add_session(disc, session, BURN_POS_END);
/* Define a source for all of the tracks */
path = strdup("/etc/hosts");
src = burn_file_source_new(path, NULL);
/* Add ten tracks to a session */
for (i = 0; i < 10; i++) {
track = burn_track_create();
burn_session_add_track(session, track, 0);
if (burn_track_set_source(track, src) != BURN_SOURCE_OK) {
printf("problem with the source\n");
return 0;
}
}
/* Add ten tracks to a session */
for (i = 0; i < 10; i++) {
track = burn_track_create();
burn_session_add_track(session, track, 0);
if (burn_track_set_source(track, src) != BURN_SOURCE_OK) {
printf("problem with the source\n");
return 0;
}
}
/* Delete a session */
burn_session_remove_track(session, track);
burn_structure_print_disc(disc);
return EXIT_SUCCESS;
}

View File

@ -1,103 +0,0 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <libburn/libburn.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
static struct burn_drive_info *drives;
static unsigned int n_drives;
static void show_tocs()
{
struct burn_session **sessions;
struct burn_track **tracks;
struct burn_disc *disc;
int nses, ntracks, hidefirst;
unsigned int i, j, k;
struct burn_toc_entry e;
enum burn_disc_status s;
for (i = 0; i < n_drives; ++i) {
fprintf(stderr, "TOC for disc in %s - %s:\n",
drives[i].vendor, drives[i].product);
if (!burn_drive_grab(drives[i].drive, 1)) {
fprintf(stderr, "Unable to open the drive!\n");
continue;
}
while (burn_drive_get_status(drives[i].drive, NULL))
usleep(1000);
while ((s = burn_disc_get_status(drives[i].drive))
== BURN_DISC_UNREADY)
usleep(1000);
if (s != BURN_DISC_FULL) {
burn_drive_release(drives[i].drive, 0);
fprintf(stderr, "No disc found!\n");
continue;
}
disc = burn_drive_get_disc(drives[i].drive);
sessions = burn_disc_get_sessions(disc, &nses);
for (k = 0; k < nses; ++k) {
tracks = burn_session_get_tracks(sessions[k],
&ntracks);
hidefirst = burn_session_get_hidefirst(sessions[k]);
if (hidefirst)
fprintf(stderr,
"track: GAP (%2d) lba: %9d (%9d) %02d:%02d:%02d adr: X control: X mode: %d\n",
k + 1, 0, 0, 0, 2, 0,
burn_track_get_mode(tracks[0]));
for (j = !!hidefirst; j < ntracks; ++j) {
burn_track_get_entry(tracks[j], &e);
fprintf(stderr,
"track: %3d (%2d) lba: %9d (%9d) %02d:%02d:%02d "
"adr: %d control: %d mode: %d\n",
e.point, e.session,
burn_msf_to_lba(e.pmin, e.psec,
e.pframe),
burn_msf_to_lba(e.pmin, e.psec,
e.pframe) * 4,
e.pmin, e.psec, e.pframe, e.adr,
e.control,
burn_track_get_mode(tracks[j]));
}
burn_session_get_leadout_entry(sessions[k], &e);
fprintf(stderr,
"track:lout (%2d) lba: %9d (%9d) %02d:%02d:%02d "
"adr: %d control: %d mode: %d\n",
k + 1, burn_msf_to_lba(e.pmin, e.psec,
e.pframe),
burn_msf_to_lba(e.pmin, e.psec,
e.pframe) * 4, e.pmin,
e.psec, e.pframe, e.adr, e.control, -1);
}
burn_disc_free(disc);
burn_drive_release(drives[i].drive, 0);
}
}
int main()
{
fprintf(stderr, "Initializing library...");
if (burn_initialize())
fprintf(stderr, "Success\n");
else {
printf("Failed\n");
return 1;
}
fprintf(stderr, "Scanning for devices...");
while (!burn_drive_scan(&drives, &n_drives)) ;
fprintf(stderr, "Done\n");
show_tocs();
burn_drive_info_free(drives);
burn_finish();
return 0;
}