Compare commits
117 Commits
ZeroThreeT
...
ZeroThreeS
Author | SHA1 | Date | |
---|---|---|---|
a997ee4ce9 | |||
f3fb4de138 | |||
f0cb747993 | |||
723060c08a | |||
660bf40a3c | |||
25ba84a7e2 | |||
6566771834 | |||
2d2a2f8c1b | |||
329f266cea | |||
dce1ba57f3 | |||
d3f08d4f96 | |||
ddb63509af | |||
96098b3f2d | |||
256139c9d6 | |||
fd5b681bc6 | |||
2a38890c5f | |||
2ec2a34f51 | |||
10e320911a | |||
9699880581 | |||
13b9f910e1 | |||
acaba76cda | |||
927a820aec | |||
3b9f66a765 | |||
5d2ad006a4 | |||
aa03717f24 | |||
ab5f39b8bb | |||
e1b8edb437 | |||
a78e6f9b29 | |||
047f9c75f5 | |||
159715ebaa | |||
f617567e03 | |||
10a7a9d5e8 | |||
76ed9570c9 | |||
4bc8e4caea | |||
1a054b54c9 | |||
76a9fa4fa2 | |||
4c85686aad | |||
a686340407 | |||
16c7cf1889 | |||
15b33422d0 | |||
649f67697a | |||
125e28160d | |||
eb860ee4b7 | |||
a8c69206fe | |||
26745b4064 | |||
962f68b1d6 | |||
cc5560fc86 | |||
5d65697697 | |||
749d12591e | |||
98f0dab87e | |||
17c87b78a6 | |||
ecbe1c0f39 | |||
9507587652 | |||
dba40c756b | |||
fd9e5dc935 | |||
2816d8b569 | |||
64233b0ccc | |||
9e1b3719d6 | |||
6086b59301 | |||
c345426299 | |||
05216162ef | |||
13e2b23ace | |||
820f0924f9 | |||
5b6aab575e | |||
bd529442ed | |||
33938c20eb | |||
71c490d0ae | |||
4458bb130a | |||
99172bdeb4 | |||
790c75be9c | |||
6a5e1b6bd5 | |||
49e0a6cb1a | |||
b6c7fd7478 | |||
e955d50198 | |||
794d1ee712 | |||
3b5c80e867 | |||
0c4cfdd359 | |||
f263443858 | |||
362a8faa61 | |||
2e361e50ed | |||
0ddeb01502 | |||
64ae333863 | |||
9f2c4b303d | |||
8182be7824 | |||
fa6849374a | |||
115f03cf63 | |||
b6475c3d84 | |||
afd54a1f87 | |||
4f3dd8614d | |||
7989d32834 | |||
0151358635 | |||
8c0e0a7a47 | |||
c570e4868d | |||
6ccd359c93 | |||
ca69e3f2ca | |||
d272450a70 | |||
a21c2a5138 | |||
73273b1643 | |||
4df7aa0f3b | |||
dbe2ee41ae | |||
72a2ef9f96 | |||
e639cd5bbb | |||
3ec93316e0 | |||
ff6a9fc92b | |||
636f5278ad | |||
e10bfe2d37 | |||
4da50dfad5 | |||
dc281902a5 | |||
4903bb9971 | |||
ba702bc9a8 | |||
c7804d390f | |||
9584adcc87 | |||
7154d8cb91 | |||
36b4f2ded5 | |||
1aed3f692c | |||
fdcb1a4014 | |||
384c47c710 |
@ -101,9 +101,9 @@ test_structest_CPPFLAGS = -Ilibburn
|
||||
test_structest_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_structest_SOURCES = test/structest.c
|
||||
|
||||
## cdrskin construction site - ts A60816 - A70116
|
||||
## cdrskin construction site - ts A60816 - A70312
|
||||
cdrskin_cdrskin_CPPFLAGS = -Ilibburn
|
||||
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_3_1
|
||||
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_3_6
|
||||
cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cdrskin_timestamp.h
|
||||
##
|
||||
|
14
README
14
README
@ -67,7 +67,7 @@ we would need : login on a development machine resp. a live OS on CD or DVD,
|
||||
advise from a system person about the equivalent of Linux sg or FreeBSD CAM,
|
||||
volunteers for testing of realistic use cases.
|
||||
|
||||
We have a workable code base for burning CD and most single layer DVD, though.
|
||||
We have a workable code base for burning CD and most single layer DVD.
|
||||
The burn API is quite comprehensively documented and can be used to build a
|
||||
presentable application.
|
||||
We have a functional binary which emulates parts of cdrecord in order to
|
||||
@ -190,15 +190,21 @@ Project history as far as known to me:
|
||||
by dvd+rw-tools' "poor man" writing facility for this class of media.
|
||||
Taking a bow towards Andy Polyakov.
|
||||
|
||||
- Upcoming release will cover sequential DVD-RW and DVD-R.
|
||||
- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
|
||||
multi-session and with DAO.
|
||||
|
||||
- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
|
||||
DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
|
||||
yet.
|
||||
|
||||
- 23th April 2000 version 0.3.6 follows the unanimous opinion of Linux kernel
|
||||
people that one should not use /dev/sg on kernel 2.6.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
the Free Software Foundation. To be exact: version 2 of that License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
@ -26,12 +26,12 @@ following possible.
|
||||
cdrskin. By Thomas Schmitt <scdbackup@gmx.net>
|
||||
Integrated sub project of libburnia.pykix.org but also published via:
|
||||
http://scdbackup.sourceforge.net/cdrskin_eng.html
|
||||
http://scdbackup.sourceforge.net/cdrskin-0.3.1.tar.gz
|
||||
http://scdbackup.sourceforge.net/cdrskin-0.3.6.pl00.tar.gz
|
||||
Copyright (C) 2006-2007 Thomas Schmitt
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
On top of libburn there is implemented cdrskin 0.3.1, a limited cdrecord
|
||||
On top of libburn there is implemented cdrskin 0.3.6, 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
|
||||
@ -59,16 +59,16 @@ systems, including 64 bit systems. (Further reports are welcome.)
|
||||
|
||||
Compilation, First Glimpse, Installation
|
||||
|
||||
Obtain cdrskin-0.3.1.tar.gz, take it to a directory of your choice and do:
|
||||
Obtain cdrskin-0.3.6.pl00.tar.gz, take it to a directory of your choice and do:
|
||||
|
||||
tar xzf cdrskin-0.3.1.tar.gz
|
||||
cd cdrskin-0.3.1
|
||||
tar xzf cdrskin-0.3.6.pl00.tar.gz
|
||||
cd cdrskin-0.3.6
|
||||
|
||||
Or obtain a libburnia.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.3.1 or libburn then execute:
|
||||
Within that toplevel directory of either cdrskin-0.3.6 or libburn then execute:
|
||||
|
||||
./configure
|
||||
make
|
||||
@ -126,16 +126,16 @@ 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.
|
||||
On Linux 2.4 this would be some /dev/sgN and on 2.6. some /dev/srM or /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'
|
||||
0 dev='/dev/sr0' rwrwr- : '_NEC' 'DVD_RW ND-4570A'
|
||||
1 dev='/dev/sr1' 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
|
||||
chmod a+rw /dev/sr0 /dev/sr1
|
||||
|
||||
I strongly discourage to run cdrskin with setuid root or via sudo !
|
||||
It is not checked for the necessary degree of hacker safety.
|
||||
@ -152,7 +152,7 @@ Get an overview of cdrecord style addresses of available devices
|
||||
cdrskin --devices
|
||||
|
||||
Adresses reported with dev=ATA need prefix "ATA:". Address examples:
|
||||
dev=0,1,0 dev=ATA:1,0,0 dev=/dev/sg1 dev=/dev/hdc
|
||||
dev=0,1,0 dev=ATA:1,0,0 dev=/dev/sg1 dev=/dev/hdc dev=/dev/sr0
|
||||
See also "Drive Addressing" below.
|
||||
|
||||
Obtain some info about the drive
|
||||
@ -174,13 +174,13 @@ Burn image file my_image.iso to media
|
||||
cdrskin -v dev=0,1,0 speed=12 fs=8m driveropts=burnfree padsize=300k \
|
||||
-eject my_image.iso
|
||||
|
||||
Write several sessions to the same CD or DVD-R[W]
|
||||
Write multi-session to the same CD , DVD-R[W] or DVD+R
|
||||
cdrskin dev=/dev/hdc padsize=300k -multi 1.iso
|
||||
cdrskin dev=/dev/hdc padsize=300k -multi -tao 2.iso
|
||||
cdrskin dev=/dev/hdc padsize=300k -multi -tao 3.iso
|
||||
cdrskin dev=/dev/hdc padsize=300k -tao 4.iso
|
||||
|
||||
Get CD or DVD-R[W] multi-session info for option -C of program mkisofs:
|
||||
Get multi-session info for option -C of program mkisofs:
|
||||
c_values=$(cdrskin dev=/dev/hdc -msinfo 2>/dev/null)
|
||||
mkisofs ... -C "$c_values" ...
|
||||
|
||||
@ -210,7 +210,7 @@ cdrskin -scanbus (and hopefully as listed with cdrecord -scanbus) :
|
||||
|
||||
or a device file address as listed by --devices with an accessible drive :
|
||||
|
||||
export SCDBACKUP_SCSI_ADR="/dev/sg1"
|
||||
export SCDBACKUP_SCSI_ADR="/dev/sr1"
|
||||
|
||||
Set usage of cdrskin with appropriate options rather than cdrecord :
|
||||
|
||||
@ -223,13 +223,11 @@ Run a backup :
|
||||
|
||||
Restrictions
|
||||
|
||||
The major restrictions are lifted now: audio, TAO, multi-session do work.
|
||||
|
||||
Many cdrecord options are still unsupported, though.
|
||||
Many cdrecord options are still unsupported.
|
||||
If you have use cases for them, please report your wishes and expectations.
|
||||
|
||||
DVD support is restricted to single layer overwriteable DVD (-RAM, +RW, -RW)
|
||||
for now.
|
||||
DVD support is restricted to single layer DVD for now. Double layer media
|
||||
are implemented but untested.
|
||||
|
||||
|
||||
|
||||
@ -244,9 +242,6 @@ Do not bother Joerg Schilling with any cdrskin problems.
|
||||
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.
|
||||
|
||||
Many thanks to Andy Polyakov for his dvd+rw-tools
|
||||
@ -277,8 +272,8 @@ the meaning of the components. A cdrecord-style address for cdrskin
|
||||
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 (emulated) SCSI where the device file /dev/s[rg]N 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
|
||||
@ -298,8 +293,8 @@ Component "scsibus" indicates the translation method. Defined busses are:
|
||||
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.
|
||||
So "1,1,0" is /dev/sg1 (resp. its /dev/sr*), "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
|
||||
@ -319,12 +314,12 @@ Old frontends which do not know dev=ATA or dev=ATAPI and which do ask their
|
||||
|
||||
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 \
|
||||
cdrskin dev_translation=+1,0,0+/dev/sr1 \
|
||||
dev_translation=+ATA:1,0,0+/dev/sr1 \
|
||||
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.
|
||||
/dev/sr1 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 "-".)
|
||||
|
||||
@ -336,7 +331,7 @@ and to make them default in menu
|
||||
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
|
||||
-v dev_translation=+1,0,0+/dev/sr1
|
||||
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.
|
||||
@ -475,6 +470,13 @@ Incremental Streaming afterwards. So blank=fast will do full blanking.
|
||||
blank=deformat_sequential_quickest is faster but might yield DAO-only media.
|
||||
|
||||
|
||||
DVD+R
|
||||
|
||||
From the view of cdrskin they behave much like DVD-R. Each track gets wrapped
|
||||
into an own session, though.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Special compilation variations
|
||||
|
||||
You may get a (super fat) statically linked binary by :
|
||||
|
@ -20,23 +20,25 @@ set -x
|
||||
# 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
|
||||
|
||||
# The top level directory in the SVN snapshot is named
|
||||
intermediate="./libburn_pykix"
|
||||
|
||||
# libburn source used: http://libburnia.pykix.org
|
||||
# Downloaded by:
|
||||
# $ svn co http://libburn-svn.pykix.org/libburn/trunk libburn_pykix
|
||||
# $ svn co http://libburnia-svn.pykix.org/libburn/tags/... $intermediate
|
||||
# packed up in a tarball just to save it from inadverted changes by
|
||||
# $ tar czf libburn_svn.tgz libburn_pykix
|
||||
original="./libburn_svn.tgz"
|
||||
# $ tar czf libburn_svn.tgz $intermediate
|
||||
original="./libburn_svn_release.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-develop , mainly in ./cdrskin
|
||||
# My changes are in $changes , mainly in $changes/cdrskin
|
||||
changes="./libburn-release"
|
||||
|
||||
changes="./libburn-develop"
|
||||
skin_release="0.3.0"
|
||||
skin_release="0.3.6"
|
||||
patch_level=".pl00"
|
||||
skin_rev="$skin_release""$patch_level"
|
||||
|
||||
@ -112,7 +114,8 @@ then
|
||||
fi
|
||||
cp -a "$cdrskin_dir" "$cdrskin_target"
|
||||
|
||||
# Remove copied binaries
|
||||
# Remove copied vim.swp and binaries
|
||||
rm "$cdrskin_target"/.*.swp
|
||||
rm "$cdrskin_target"/*.o
|
||||
rm "$cdrskin_target"/cdrfifo
|
||||
rm "$cdrskin_target"/cdrskin
|
||||
@ -190,6 +193,18 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
# Repair non-portable shell code output of ./bootstrap
|
||||
(
|
||||
cd "$compile_dir" || exit 1
|
||||
sed -e 's/^for ac_header in$/test -z 1 \&\& for ac_header in dummy/' \
|
||||
< ./configure > ./configure-repaired
|
||||
if test "$?" = 0
|
||||
then
|
||||
echo "$0: Empty 'for ac_header in' found in configure." >&2
|
||||
fi
|
||||
mv ./configure-repaired ./configure
|
||||
chmod a+rx,go-w,u+w ./configure
|
||||
)
|
||||
|
||||
# Pack it up to the new libburn+cdrskin-tarball
|
||||
tar czf "$cdrskin_tarball" "$target"
|
||||
@ -199,11 +214,11 @@ tar czf "$cdrskin_tarball" "$target"
|
||||
cd "$compile_dir" || exit 1
|
||||
./configure
|
||||
make
|
||||
"$compile_cmd" -do_strip
|
||||
"$compile_cmd" -O2 -do_strip
|
||||
cp "$compile_result" "../$bintarget_dynamic"
|
||||
if test -n "$compile_static_opts"
|
||||
then
|
||||
"$compile_cmd" $compile_static_opts -do_strip
|
||||
"$compile_cmd" $compile_static_opts -O2 -do_strip
|
||||
cp "$compile_result" "../$bintarget_static"
|
||||
fi
|
||||
"$man_to_html_cmd"
|
@ -20,23 +20,25 @@ set -x
|
||||
# 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
|
||||
|
||||
# The top level directory in the SVN snapshot is named
|
||||
intermediate="./libburn_pykix"
|
||||
|
||||
# libburn source used: http://libburnia.pykix.org
|
||||
# Downloaded by:
|
||||
# $ svn co http://libburn-svn.pykix.org/libburn/trunk libburn_pykix
|
||||
# $ svn co http://libburnia-svn.pykix.org/libburn/tags/... $intermediate
|
||||
# packed up in a tarball just to save it from inadverted changes by
|
||||
# $ tar czf libburn_svn.tgz libburn_pykix
|
||||
# $ tar czf libburn_svn.tgz $intermediate
|
||||
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-develop , mainly in ./cdrskin
|
||||
|
||||
# My changes are in $changes , mainly in $changes/cdrskin
|
||||
changes="./libburn-develop"
|
||||
skin_release="0.3.1"
|
||||
|
||||
skin_release="0.3.7"
|
||||
patch_level=""
|
||||
skin_rev="$skin_release""$patch_level"
|
||||
|
||||
@ -112,7 +114,8 @@ then
|
||||
fi
|
||||
cp -a "$cdrskin_dir" "$cdrskin_target"
|
||||
|
||||
# Remove copied binaries
|
||||
# Remove copied vim.swp and binaries
|
||||
rm "$cdrskin_target"/.*.swp
|
||||
rm "$cdrskin_target"/*.o
|
||||
rm "$cdrskin_target"/cdrfifo
|
||||
rm "$cdrskin_target"/cdrskin
|
||||
@ -190,6 +193,19 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
# Repair non-portable shell code output of ./bootstrap
|
||||
(
|
||||
cd "$compile_dir" || exit 1
|
||||
sed -e 's/^for ac_header in$/test -z 1 \&\& for ac_header in dummy/' \
|
||||
< ./configure > ./configure-repaired
|
||||
if test "$?" = 0
|
||||
then
|
||||
echo "$0: Empty 'for ac_header in' found in configure." >&2
|
||||
fi
|
||||
mv ./configure-repaired ./configure
|
||||
chmod a+rx,go-w,u+w ./configure
|
||||
)
|
||||
|
||||
|
||||
# Pack it up to the new libburn+cdrskin-tarball
|
||||
tar czf "$cdrskin_tarball" "$target"
|
||||
@ -199,11 +215,11 @@ tar czf "$cdrskin_tarball" "$target"
|
||||
cd "$compile_dir" || exit 1
|
||||
./configure
|
||||
make
|
||||
"$compile_cmd" -do_strip
|
||||
"$compile_cmd" -O2 -do_strip
|
||||
cp "$compile_result" "../$bintarget_dynamic"
|
||||
if test -n "$compile_static_opts"
|
||||
then
|
||||
"$compile_cmd" $compile_static_opts -do_strip
|
||||
"$compile_cmd" $compile_static_opts -O2 -do_strip
|
||||
cp "$compile_result" "../$bintarget_static"
|
||||
fi
|
||||
"$man_to_html_cmd"
|
@ -38,7 +38,9 @@
|
||||
#define Cdrfifo_ffd_maX 100
|
||||
|
||||
|
||||
/* 1= enable , 0= disable status messages to stderr */
|
||||
/* 1= enable , 0= disable status messages to stderr
|
||||
2= report each
|
||||
*/
|
||||
static int Cdrfifo_debuG= 0;
|
||||
|
||||
|
||||
@ -75,6 +77,8 @@ struct CdrfifO {
|
||||
double empty_counter;
|
||||
double full_counter;
|
||||
|
||||
/* eventual ISO-9660 image size obtained from first 64k of input */
|
||||
double iso_fs_size;
|
||||
|
||||
/* (sequential) fd chaining */
|
||||
/* fds: 0=source, 1=dest */
|
||||
@ -82,6 +86,8 @@ struct CdrfifO {
|
||||
|
||||
/* index of first byte in buffer which does not belong to predecessor fd */
|
||||
int follow_up_eop[Cdrfifo_ffd_maX];
|
||||
/* if follow_up_eop[i]==buffer_size : read_idx was 0 when this was set */
|
||||
int follow_up_was_full_buffer[Cdrfifo_ffd_maX];
|
||||
|
||||
/* index of first byte in buffer which belongs to [this] fd pair */
|
||||
int follow_up_sod[Cdrfifo_ffd_maX];
|
||||
@ -99,6 +105,9 @@ struct CdrfifO {
|
||||
/* (simultaneous) peer chaining */
|
||||
struct CdrfifO *next;
|
||||
struct CdrfifO *prev;
|
||||
|
||||
/* rank in peer chain */
|
||||
int chain_idx;
|
||||
};
|
||||
|
||||
|
||||
@ -152,14 +161,17 @@ int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
|
||||
o->get_counter= 0.0;
|
||||
o->empty_counter= 0.0;
|
||||
o->full_counter= 0.0;
|
||||
o->iso_fs_size= -1.0;
|
||||
for(i= 0; i<Cdrfifo_ffd_maX; i++) {
|
||||
o->follow_up_fds[i][0]= o->follow_up_fds[i][1]= -1;
|
||||
o->follow_up_eop[i]= o->follow_up_sod[i]= -1;
|
||||
o->follow_up_was_full_buffer[i]= 0;
|
||||
o->follow_up_in_limits[i]= -1.0;
|
||||
}
|
||||
o->follow_up_fd_counter= 0;
|
||||
o->follow_up_fd_idx= -1;
|
||||
o->next= o->prev= NULL;
|
||||
o->chain_idx= 0;
|
||||
o->buffer= TSOB_FELD(char,buffer_size);
|
||||
if(o->buffer==NULL)
|
||||
goto failed;
|
||||
@ -299,10 +311,16 @@ int Cdrfifo_attach_follow_up_fds(struct CdrfifO *o, int source_fd, int dest_fd,
|
||||
*/
|
||||
int Cdrfifo_attach_peer(struct CdrfifO *o, struct CdrfifO *next, int flag)
|
||||
{
|
||||
int idx;
|
||||
struct CdrfifO *s;
|
||||
|
||||
for(s= o;s->prev!=NULL;s= s->prev); /* determine start of o-chain */
|
||||
for(;o->next!=NULL;o= o->next); /* determine end of o-chain */
|
||||
for(;next->prev!=NULL;next= next->prev); /* determine start of next-chain */
|
||||
next->prev= o;
|
||||
o->next= next;
|
||||
for(idx= 0;s!=NULL;s= s->next)
|
||||
s->chain_idx= idx++;
|
||||
return(1);
|
||||
}
|
||||
|
||||
@ -375,6 +393,13 @@ int Cdrfifo_get_min_fill(struct CdrfifO *o, int *total_min_fill,
|
||||
}
|
||||
|
||||
|
||||
int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes, int flag)
|
||||
{
|
||||
*size_in_bytes= o->iso_fs_size;
|
||||
return(o->iso_fs_size>=2048);
|
||||
}
|
||||
|
||||
|
||||
/** Get counters which are mentioned by cdrecord at the end of burning.
|
||||
It still has to be examined wether they mean what i believe they do.
|
||||
*/
|
||||
@ -383,7 +408,7 @@ int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
|
||||
double *empty_counter, double *full_counter,
|
||||
int flag)
|
||||
{
|
||||
*put_counter= o->put_counter;;
|
||||
*put_counter= o->put_counter;
|
||||
*get_counter= o->get_counter;
|
||||
*empty_counter= o->empty_counter;
|
||||
*full_counter= o->full_counter;
|
||||
@ -408,10 +433,26 @@ int Cdrfifo_eop_adjust(struct CdrfifO *o,int *buffer_fill, int *eop_idx,
|
||||
for(i=0; i<=o->follow_up_fd_idx; i++) {
|
||||
if(o->follow_up_eop[i]>=0 && o->follow_up_eop[i]>=o->read_idx) {
|
||||
eop_is_near= 1;
|
||||
valid_fill= o->follow_up_eop[i]-o->read_idx;
|
||||
if(o->follow_up_eop[i]<o->buffer_size || o->read_idx>0) {
|
||||
valid_fill= o->follow_up_eop[i]-o->read_idx;
|
||||
o->follow_up_was_full_buffer[i]= 0;
|
||||
} else {
|
||||
/*
|
||||
If an input fd change hit exactly the buffer end then follow_up_eop
|
||||
points to buffer_size and not to 0. So it is time to switch output
|
||||
pipes unless this is immediately after follow_up_eop was set and
|
||||
read_idx was 0 (... if this is possible at all while write_idx is 0).
|
||||
follow_up_was_full_buffer was set in this case and gets invalid as
|
||||
soon as a non-0 read_idx is detected (see above).
|
||||
*/
|
||||
if(o->follow_up_was_full_buffer[i])
|
||||
valid_fill= o->buffer_size;
|
||||
else
|
||||
valid_fill= 0; /* the current pipe is completely served */
|
||||
}
|
||||
if(valid_fill==0)
|
||||
*eop_idx= i;
|
||||
else if(valid_fill<=o->chunk_size)
|
||||
else if(valid_fill<o->chunk_size)
|
||||
eop_is_near= 2; /* for debugging. to carry a break point */
|
||||
break;
|
||||
}
|
||||
@ -436,7 +477,7 @@ static int Cdrfifo_setup_try(struct CdrfifO *o, struct timeval start_tv,
|
||||
*/
|
||||
{
|
||||
int buffer_space,buffer_fill,eop_reached= -1,eop_is_near= 0,was_closed;
|
||||
int fd_buffer_fill;
|
||||
int fd_buffer_fill, eop_reached_counter= 0;
|
||||
struct timeval current_tv;
|
||||
struct timezone tz;
|
||||
double diff_time,diff_counter,limit,min_wait_time;
|
||||
@ -465,21 +506,26 @@ setup_try:;
|
||||
|
||||
if(eop_reached>=0) { /* switch to next output fd */
|
||||
o->dest_fd= o->follow_up_fds[eop_reached][1];
|
||||
if(Cdrfifo_debuG)
|
||||
fprintf(stderr,"\ncdrfifo %d: new fifo destination fd : %d\n",
|
||||
o->chain_idx,o->dest_fd);
|
||||
o->read_idx= o->follow_up_sod[eop_reached];
|
||||
o->follow_up_eop[eop_reached]= -1;
|
||||
eop_is_near= 0;
|
||||
eop_reached= -1;
|
||||
eop_reached_counter= 0;
|
||||
goto setup_try;
|
||||
} else {
|
||||
/* work is really done */
|
||||
if((!was_closed) && ((flag&1)||Cdrfifo_debuG))
|
||||
fprintf(stderr,
|
||||
"\ncdrfifo_debug: w=%d r=%d | b=%d s=%d | i=%.f o=%.f (done)\n",
|
||||
o->write_idx,o->read_idx,buffer_fill,buffer_space,
|
||||
"\ncdrfifo %d: w=%d r=%d | b=%d s=%d | i=%.f o=%.f (done)\n",
|
||||
o->chain_idx,o->write_idx,o->read_idx,buffer_fill,buffer_space,
|
||||
o->in_counter,o->out_counter);
|
||||
return(2);
|
||||
}
|
||||
}
|
||||
} else if(eop_reached>=0)
|
||||
eop_reached_counter++;
|
||||
if(o->interval_counter>0) {
|
||||
if(o->total_min_fill>buffer_fill && o->source_fd>=0)
|
||||
o->total_min_fill= buffer_fill;
|
||||
@ -581,7 +627,8 @@ return: <0 = error , 0 = idle , 1 = did some work
|
||||
if(ret==-1) {
|
||||
|
||||
/* >>> handle broken pipe */;
|
||||
fprintf(stderr,"\ncdrfifo: on write: errno=%d , \"%s\"\n",errno,
|
||||
fprintf(stderr,"\ncdrfifo %d: on write: errno=%d , \"%s\"\n",
|
||||
o->chain_idx,errno,
|
||||
errno==0?"-no error code available-":strerror(errno));
|
||||
|
||||
if(!(flag&4))
|
||||
@ -613,22 +660,31 @@ after_write:;
|
||||
if(ret==-1) {
|
||||
|
||||
/* >>> handle input error */;
|
||||
fprintf(stderr,"\ncdrfifo: on read: errno=%d , \"%s\"\n",errno,
|
||||
fprintf(stderr,"\ncdrfifo %d: on read: errno=%d , \"%s\"\n",
|
||||
o->chain_idx,errno,
|
||||
errno==0?"-no error code available-":strerror(errno));
|
||||
|
||||
o->source_fd= -1;
|
||||
} else if(ret==0) { /* eof */
|
||||
/* activate eventual follow-up source fd */
|
||||
if(Cdrfifo_debuG || (flag&1))
|
||||
fprintf(stderr,"\ncdrfifo: on read(%d,buffer,%d): eof\n",
|
||||
o->source_fd,can_read);
|
||||
fprintf(stderr,"\ncdrfifo %d: on read(%d,buffer,%d): eof\n",
|
||||
o->chain_idx,o->source_fd,can_read);
|
||||
if(o->follow_up_fd_idx+1 < o->follow_up_fd_counter) {
|
||||
idx= ++(o->follow_up_fd_idx);
|
||||
o->source_fd= o->follow_up_fds[idx][0];
|
||||
/* End-Of-Previous */
|
||||
if(o->write_idx==0)
|
||||
if(o->write_idx==0) {
|
||||
o->follow_up_eop[idx]= o->buffer_size;
|
||||
else
|
||||
|
||||
/* A70304 : can this happen ? */
|
||||
o->follow_up_was_full_buffer[idx]= (o->read_idx==0);
|
||||
|
||||
if(Cdrfifo_debuG || (flag&1))
|
||||
fprintf(stderr,"\ncdrfifo %d: write_idx 0 on eop: read_idx= %d\n",
|
||||
o->chain_idx,o->read_idx);
|
||||
|
||||
} else
|
||||
o->follow_up_eop[idx]= o->write_idx;
|
||||
/* Start-Of-Data . Try to start at next full chunk */
|
||||
sod= o->write_idx;
|
||||
@ -644,7 +700,8 @@ after_write:;
|
||||
o->fd_in_counter= 0;
|
||||
o->fd_in_limit= o->follow_up_in_limits[idx];
|
||||
if(Cdrfifo_debuG || (flag&1))
|
||||
fprintf(stderr,"\ncdrfio: new fifo source fd : %d\n",o->source_fd);
|
||||
fprintf(stderr,"\ncdrfifo %d: new fifo source fd : %d\n",
|
||||
o->chain_idx,o->source_fd);
|
||||
} else {
|
||||
o->source_fd= -1;
|
||||
}
|
||||
@ -777,13 +834,13 @@ ex:;
|
||||
} else
|
||||
elapsed= wait_usec;
|
||||
if(elapsed>=wait_usec) {
|
||||
if((flag&1)||Cdrfifo_debuG) {
|
||||
if((flag&1)||Cdrfifo_debuG>=2) {
|
||||
fprintf(stderr,"\n");
|
||||
for(ff= o; ff!=NULL; ff= ff->next) {
|
||||
buffer_space= Cdrfifo_tell_buffer_space(ff,0);
|
||||
fprintf(stderr,
|
||||
"cdrfifo_debug: w=%d r=%d | b=%d s=%d | i=%.f o=%.f\n",
|
||||
ff->write_idx,ff->read_idx,
|
||||
"cdrfifo %d: w=%d r=%d | b=%d s=%d | i=%.f o=%.f\n",
|
||||
ff->chain_idx,ff->write_idx,ff->read_idx,
|
||||
ff->buffer_size-buffer_space,buffer_space,
|
||||
ff->in_counter,ff->out_counter);
|
||||
}
|
||||
@ -823,6 +880,24 @@ int Cdrfifo_fill(struct CdrfifO *o, int size, int flag)
|
||||
if(ret==2)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef Cdrfifo_standalonE
|
||||
{ int Scan_for_iso_size(unsigned char data[2048], double *size_in_bytes,
|
||||
int flag);
|
||||
int i;
|
||||
double size;
|
||||
|
||||
/* try to obtain an ISO-9660 file system size */
|
||||
for(i= 0; i<32*2048 && i+2048<=fill; i+=2048) {
|
||||
ret= Scan_for_iso_size((unsigned char *) (o->buffer+i), &size, 0);
|
||||
if(ret<=0)
|
||||
continue;
|
||||
o->iso_fs_size= size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
o->total_min_fill= fill;
|
||||
o->interval_min_fill= fill;
|
||||
return(1);
|
||||
@ -875,6 +950,76 @@ double Scanf_io_size(char *text, int flag)
|
||||
}
|
||||
|
||||
|
||||
/* This is a hardcoded test mock-up for two simultaneous fifos of which the
|
||||
one runs with block size 2048 and feeds the other which runs with 2352.
|
||||
Both fifos have the same number of follow_up pipes (tracks) which shall
|
||||
be connected 1-to-1.
|
||||
*/
|
||||
int Test_mixed_bs(char **paths, int path_count,
|
||||
int fs_size, double speed_limit, double interval, int flag)
|
||||
/*
|
||||
bit0= debugging verbousity
|
||||
*/
|
||||
{
|
||||
int fd_in[100],fd_out[100],ret,pipe_fds[100][2],real_out[100];
|
||||
int i,iv,stall_counter= 0,cycle_counter= 0.0;
|
||||
char buf[10240], target_path[80];
|
||||
double in_counter, out_counter, prev_in= -1.0, prev_out= -1.0;
|
||||
struct CdrfifO *ff_in= NULL, *ff_out= NULL;
|
||||
|
||||
if(path_count<1)
|
||||
return(2);
|
||||
Cdrfifo_new(&ff_in,fd_in[0],fd_out[0],2048,fs_size,0);
|
||||
for(i= 0; i<path_count; i++) {
|
||||
fd_in[2*i]= open(paths[i],O_RDONLY);
|
||||
if(fd_in[2*i]==-1)
|
||||
return(0);
|
||||
if(pipe(pipe_fds[2*i])==-1)
|
||||
return(-1);
|
||||
fd_out[2*i]= pipe_fds[2*i][1];
|
||||
if(i==0)
|
||||
ret= Cdrfifo_new(&ff_in,fd_in[2*i],fd_out[2*i],2048,fs_size,0);
|
||||
else
|
||||
ret= Cdrfifo_attach_follow_up_fds(ff_in,fd_in[2*i],fd_out[2*i],0);
|
||||
if(ret<=0)
|
||||
return(ret);
|
||||
fd_in[2*i+1]= pipe_fds[2*i][0];
|
||||
sprintf(target_path,"/dvdbuffer/fifo_mixed_bs_test_%d",i);
|
||||
fd_out[2*i+1]= open(target_path,O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
|
||||
if(i==0)
|
||||
ret= Cdrfifo_new(&ff_out,fd_in[2*i+1],fd_out[2*i+1],2352,fs_size,0);
|
||||
else
|
||||
ret= Cdrfifo_attach_follow_up_fds(ff_out,fd_in[2*i+1],fd_out[2*i+1],0);
|
||||
if(ret<=0)
|
||||
return(ret);
|
||||
fprintf(stderr,"test_mixed_bs: %d : %2d fifo %2d pipe %2d fifo %2d : %s\n",
|
||||
i, fd_in[2*i],fd_out[2*i],fd_in[2*i+1],fd_out[2*i+1], target_path);
|
||||
}
|
||||
Cdrfifo_attach_peer(ff_in,ff_out,0);
|
||||
|
||||
|
||||
/* Let the fifos work */
|
||||
iv= interval*1e6;
|
||||
while(1) {
|
||||
ret= Cdrfifo_try_to_work(ff_in,iv,NULL,NULL,flag&1);
|
||||
if(ret<0 || ret==2) { /* <0 = error , 2 = work is done */
|
||||
fprintf(stderr,"\ncdrfifo %d: fifo ended work with ret=%d\n",
|
||||
ff_in->chain_idx,ret);
|
||||
if(ret<0)
|
||||
return(-7);
|
||||
break;
|
||||
}
|
||||
cycle_counter++;
|
||||
Cdrfifo_get_counters(ff_in, &in_counter, &out_counter, 0);
|
||||
if(prev_in == in_counter && prev_out == out_counter)
|
||||
stall_counter++;
|
||||
prev_in= in_counter;
|
||||
prev_out= out_counter;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* This is a hardcoded test mock-up for two simultaneous fifos of which the
|
||||
first one simulates the cdrskin fifo feeding libburn and the second one
|
||||
simulates libburn and the burner at given speed. Both have two fd pairs
|
||||
@ -933,7 +1078,8 @@ int Test_multi(int fs_size, double speed_limit, double interval, int flag)
|
||||
while(1) {
|
||||
ret= Cdrfifo_try_to_work(ff1,iv,NULL,NULL,flag&1);
|
||||
if(ret<0 || ret==2) { /* <0 = error , 2 = work is done */
|
||||
fprintf(stderr,"\ncdrfifo: fifo ended work with ret=%d\n",ret);
|
||||
fprintf(stderr,"\ncdrfifo %d: fifo ended work with ret=%d\n",
|
||||
ff1->chain_idx,ret);
|
||||
if(ret<0)
|
||||
return(-7);
|
||||
break;
|
||||
@ -992,6 +1138,13 @@ int main(int argc, char **argv)
|
||||
} else if(strncmp(argv[i],"vb=",3)==0) {
|
||||
sscanf(argv[i]+3,"%d",&verbous);
|
||||
|
||||
} else if(strcmp(argv[i],"-mixed_bs_test")==0) {
|
||||
|
||||
ret= Test_mixed_bs(argv+i+1,argc-i-1,
|
||||
(int) fs_value,speed_limit,interval,(verbous>=2));
|
||||
fprintf(stderr,"Test_mixed_bs(): ret= %d\n",ret);
|
||||
exit(ret<0);
|
||||
|
||||
} else if(strcmp(argv[i],"-multi_test")==0) {
|
||||
|
||||
if(speed_limit==0.0)
|
||||
@ -1035,7 +1188,7 @@ int main(int argc, char **argv)
|
||||
if(speed_limit!=0.0)
|
||||
Cdrfifo_set_speed_limit(ff,speed_limit,0);
|
||||
if(fill_buffer) {
|
||||
ret= Cdrfifo_fill(ff,0);
|
||||
ret= Cdrfifo_fill(ff,0,0);
|
||||
if(ret<=0) {
|
||||
fprintf(stderr,
|
||||
"cdrfifo: FATAL : initial filling of fifo buffer failed\n");
|
||||
|
@ -117,6 +117,11 @@ int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
|
||||
double *empty_counter, double *full_counter,
|
||||
int flag);
|
||||
|
||||
/** Inquire the eventually detected size of an eventual ISO-9660 file system
|
||||
@return 0=no ISO resp. size detected, 1=size_in_bytes is valid
|
||||
*/
|
||||
int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes,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
|
||||
|
@ -2,7 +2,7 @@
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH CDRSKIN 1 "February 8, 2007"
|
||||
.TH CDRSKIN 1 "April 22, 2007"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
@ -16,8 +16,8 @@
|
||||
.\" .sp <n> insert n+1 empty lines
|
||||
.\" for manpage-specific macros, see man(7)
|
||||
.SH NAME
|
||||
cdrskin \- burns preformatted data to CD-R, CD-RW, DVD-R, DVD-RW, DVD+RW,
|
||||
DVD-RAM via libburn.
|
||||
cdrskin \- burns preformatted data to CD-R[W], DVD-R[W], DVD+R[W], DVD-RAM
|
||||
via libburn.
|
||||
.SH SYNOPSIS
|
||||
.B cdrskin
|
||||
.RI [ options | track_source_addresses ]
|
||||
@ -44,7 +44,7 @@ or in Session at Once mode for seamless tracks.
|
||||
.br
|
||||
Multi session on CD (follow-up sessions in TAO only)
|
||||
.br
|
||||
and on DVD-RW or DVD-R (in Incremental write mode only).
|
||||
or on DVD-R[W] (in Incremental mode) or on DVD+R.
|
||||
.br
|
||||
Single session on DVD-RW or DVD-R (Disk-at-once)
|
||||
.br
|
||||
@ -54,6 +54,20 @@ Bus scan, burnfree, speed options, retrieving media info, padding, fifo.
|
||||
.br
|
||||
See section EXAMPLES at the end of this text.
|
||||
.PP
|
||||
.B General information paragraphs:
|
||||
.br
|
||||
Track recording model
|
||||
.br
|
||||
Write mode selection
|
||||
.br
|
||||
Recordable CD Media
|
||||
.br
|
||||
Sequentially Recordable DVD Media
|
||||
.br
|
||||
Overwriteable DVD Media
|
||||
.br
|
||||
Drive preparation and addressing
|
||||
.PP
|
||||
.B Track recording model:
|
||||
.br
|
||||
The input-output entities which get processed are called tracks.
|
||||
@ -96,6 +110,16 @@ have been developed for magnetic tapes. Only formats which mark a detectable
|
||||
end-of-archive in their data are suitable, though. Well tested are
|
||||
the archivers afio and star. Not suitable seems GNU tar.
|
||||
.PP
|
||||
.B Write mode selection:
|
||||
.br
|
||||
If none of the options -dao, -tao or -sao is given then the program will
|
||||
try to choose a write mode which matches the defined recording job,
|
||||
the capabilities of the drive and the state of the present media.
|
||||
.br
|
||||
So the mentioning of write modes in the following paragraphs and in the
|
||||
examples is not so much a demand that the user shall choose one explicitely,
|
||||
but rather an illustration of what to expect with particular media types.
|
||||
.PP
|
||||
.B Recordable CD Media:
|
||||
.br
|
||||
CD-R can be initially written only once and eventually extended until they
|
||||
@ -124,23 +148,18 @@ Multiple cycles of blanking and overwriting with random numbers might be.
|
||||
.PP
|
||||
.B Sequentially Recordable DVD Media:
|
||||
.br
|
||||
Currently only DVD-RW and DVD-R can be used for the Sequential recording model.
|
||||
Currently DVD-RW, DVD-R and DVD+R can be used for the Sequential recording
|
||||
model.
|
||||
.br
|
||||
DVD-RW must be in state "Sequential Recording".
|
||||
The media must be either blank or appendable.
|
||||
Newly purchased DVD-RW and DVD-R media are in this state.
|
||||
Used DVD-RW get into blank sequential state by option
|
||||
.B blank=deformat_sequential .
|
||||
.br
|
||||
Incremental Streaming is the default write mode if it is offered by the media.
|
||||
It may be selected explicitely by option
|
||||
.B -tao
|
||||
as it resembles much CD TAO by allowing track sources of
|
||||
unpredicted length and to keep media appendable by option
|
||||
.B -multi .
|
||||
The only restriction towards CD-R[W] is the lack of support for -audio tracks.
|
||||
Multiple tracks per session are permissible.
|
||||
With DVD-R[W] two write modes may be available:
|
||||
.br
|
||||
The other write mode, DAO, has many restrictions. It does not work with
|
||||
Mode DAO has many restrictions. It does not work with
|
||||
appendable media, allows no -multi and only a single track. The size of the
|
||||
track needs to be known in advance. So either its source has to be a disk file
|
||||
of recognizable size or the size has to be announced explicitely by options
|
||||
@ -148,16 +167,33 @@ of recognizable size or the size has to be announced explicitely by options
|
||||
or
|
||||
.B tao_to_sao_tsize= .
|
||||
.br
|
||||
DAO is the default mode for media which do not offer feature 21h Incremental
|
||||
Streaming. It may also be selected explicitely by option
|
||||
DAO is the only mode for media which do not offer feature 21h Incremental
|
||||
Streaming. DAO may also be selected explicitely by option
|
||||
.B -sao .
|
||||
.br
|
||||
Program growisofs uses DAO on sequential DVD-R[W] media for maximum
|
||||
DVD-ROM/-Video compatibility.
|
||||
.br
|
||||
The other mode, Incremental Streaming, is the default write mode if
|
||||
it is available and if the restrictions of DAO would prevent the job.
|
||||
Incremental Streaming may be selected explicitely by option
|
||||
.B -tao
|
||||
as it resembles much CD TAO by allowing track sources of
|
||||
unpredicted length and to keep media appendable by option
|
||||
.B -multi .
|
||||
The only restriction towards CD-R[W] is the lack of support for -audio tracks.
|
||||
Multiple tracks per session are permissible.
|
||||
.br
|
||||
The write modes for DVD+R resemble those with DVD-R except that with DVD+R
|
||||
each track gets wrapped in an own session. There is no -dummy writing with
|
||||
DVD+R.
|
||||
.br
|
||||
Quite deliberately write mode -sao insists in the tradition of a predicted
|
||||
track size and blank media, whereas -tao writes the tracks open ended and
|
||||
allows appendable media.
|
||||
.PP
|
||||
.B Overwriteable DVD Media:
|
||||
.br
|
||||
Currently only types DVD+RW, DVD-RW and DVD-RAM can be overwritten via cdrskin.
|
||||
Currently types DVD+RW, DVD-RW and DVD-RAM can be overwritten via cdrskin.
|
||||
.br
|
||||
DVD+RW and DVD-RAM media get treated as blank media regardless wether they
|
||||
hold data or not. They need no special initial formatting.
|
||||
@ -172,8 +208,8 @@ Overwriteable DVD recording model they need to get formatted to state
|
||||
can be done by option
|
||||
.B blank=format_overwrite .
|
||||
.br
|
||||
Several programs like dvd+rw-format, cdrecord, wodim, or cdrskin option
|
||||
blank=deformat_sequential can bring a DVD-RW out of overwriteable state so
|
||||
Several programs like dvd+rw-format, cdrecord, wodim, or cdrskin
|
||||
can bring a DVD-RW out of overwriteable state so
|
||||
that it has to be formatted again. If in doubt, just give it a try.
|
||||
.PP
|
||||
.B Drive preparation and addressing:
|
||||
@ -184,10 +220,12 @@ by a run of \fBcdrskin --devices\fP.
|
||||
.br
|
||||
On Linux, they are device files which traditionally do not offer
|
||||
w-permissions for normal users. Because libburn needs rw-permission,
|
||||
it might be only the superuser who is able to get this list without further
|
||||
it might be only the
|
||||
.B superuser
|
||||
who is able to get this list without further
|
||||
precautions.
|
||||
.br
|
||||
It is consensus that \fBchmod a+rw /dev/sg0\fP or \fBchmod a+rw /dev/hdc\fP
|
||||
It is consensus that \fBchmod a+rw /dev/sr0\fP or \fBchmod a+rw /dev/hdc\fP
|
||||
is less security sensitive than chmod u+s /usr/bin/cdrskin. The risk for the
|
||||
drive is somewhat higher but the overall system is much less at stake.
|
||||
.br
|
||||
@ -205,7 +243,7 @@ See option -scanbus for getting a list of cdrecord style addresses.
|
||||
.br
|
||||
Further are accepted on Linux: links to libburn-suitable device files,
|
||||
device files which have the same major and minor device number,
|
||||
and device files which have the same SCSI address parameters (e.g. /dev/sr0).
|
||||
and device files which have the same SCSI address parameters (e.g. /dev/sg0).
|
||||
.br
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
@ -279,6 +317,9 @@ complete "de-icing" so no reader slips on unwritten data areas.
|
||||
deformat_sequential
|
||||
Like blank=all but with the additional ability to blank overwriteable DVD-RW.
|
||||
This will destroy their formatting and make them sequentially recordable.
|
||||
Another peculiarity is the ability to blank media which appear already blank.
|
||||
This is similar to option -force but does not try to blank media other than
|
||||
recognizable CD-RW and DVD-RW.
|
||||
.br
|
||||
(Note: blank=deformat_sequential* are not original cdrecord options.)
|
||||
.TP
|
||||
@ -336,9 +377,10 @@ insecure about drive or media state. This includes the attempt to blank
|
||||
media which are classified as unknown or unsuitable, and the attempt to use
|
||||
write modes which libburn believes they are not supported by the drive.
|
||||
.br
|
||||
Another application is with blank=format_* to enforce re-formatting of media
|
||||
which appear to be sufficiently formatted already.
|
||||
Another application is to enforce blanking or re-formatting of media
|
||||
which appear to be in the desired blank or format state already.
|
||||
.br
|
||||
.B Caution:
|
||||
Use this only when in urgent need.
|
||||
.TP
|
||||
.BI fs= size
|
||||
@ -360,6 +402,22 @@ option fifo_start_at=size.
|
||||
.BI gracetime= seconds
|
||||
Set the grace time before starting to write. (Default is 0)
|
||||
.TP
|
||||
.BI -isosize
|
||||
The next track following this option will try to obtain its source size from
|
||||
the header information out of the first few blocks of the source data.
|
||||
If these blocks indicate an ISO-9660 filesystem then its declared size
|
||||
will be used under the assumption that it is a single session filesystem.
|
||||
.br
|
||||
If not, then the burn run will be aborted.
|
||||
.br
|
||||
The range of -isosize is exactly one track. Further tracks may be preceeded
|
||||
by further -isosize options, though. At least 15 blocks of padding will be
|
||||
added to each -isosize track. But be advised to rather use padsize=300k.
|
||||
.br
|
||||
This option can be performed on track sources which are regular files or block
|
||||
devices. For the first track of the session it can be performed on any type
|
||||
of source if there is a fifo of at least 64 kB. See option fs= .
|
||||
.TP
|
||||
.BI msifile= path
|
||||
Run option -msinfo and copy the result line into the file given by path.
|
||||
Unlike -msinfo this option does not redirect all normal output away from
|
||||
@ -370,8 +428,8 @@ Note: msifile=path is actually an option of wodim and not of cdrecord.
|
||||
.BI \-msinfo
|
||||
Retrieve multi-session info for preparing a follow-up session by option -C
|
||||
of programs mkisofs or genisoimage. Print result to standard output.
|
||||
This option redirects to stderr all
|
||||
message output besides its own result string, which consists of two numbers.
|
||||
This option redirects to stderr all message output except the one of option
|
||||
--tell_media_space and its own result string, which consists of two numbers.
|
||||
The result string shall be used as argument of option -C with said programs.
|
||||
It gives the start address of the most recent session and the predicted
|
||||
start address of the next session to be appended. The string is empty if
|
||||
@ -419,8 +477,8 @@ then behave strange or even go bad for the next few attempts to burn a CD.
|
||||
One should use it only if inavoidable.
|
||||
.TP
|
||||
.BI \-sao
|
||||
Write CD in Session At Once mode, resp. a sequential DVD-R[W] in Disc-at-once
|
||||
(DAO) mode.
|
||||
Write CD in Session At Once mode, a sequential DVD-R[W] in Disc-at-once
|
||||
(DAO) mode, or a DVD+R.
|
||||
.br
|
||||
With CD this mode is able to put several audio tracks on media without
|
||||
producing audible gaps between them.
|
||||
@ -428,6 +486,9 @@ producing audible gaps between them.
|
||||
With DVD-R[W] this mode can only write a single track.
|
||||
No -multi is allowed with DVD-R[W] -sao.
|
||||
.br
|
||||
-sao is permissible with overwriteable DVD and with DVD+R but actually only
|
||||
imposes restrictions without providing known advantages.
|
||||
.br
|
||||
-sao can only be used for tracks of fixely predicted size. This implies that
|
||||
track arguments which depict stdin or named pipes need to be preceeded by
|
||||
option tsize= or by option tao_to_sao_tsize=.
|
||||
@ -462,8 +523,9 @@ Less guesswork is needed if track sources are in format MS-WAVE in a file with
|
||||
suffix ".wav".
|
||||
.TP
|
||||
.BI \-tao
|
||||
Write CD in Track At Once (TAO) mode, resp. sequential DVD-R[W] in Incremental
|
||||
Streaming mode. This mode also applies pro-forma to overwriteable DVD media.
|
||||
Write CD in Track At Once (TAO) mode, sequential DVD-R[W] in Incremental
|
||||
Streaming mode, or DVD+R without traditional -sao restrictions.
|
||||
This mode also applies pro-forma to overwriteable DVD media.
|
||||
.br
|
||||
Mode -tao can be used with track sources of unpredictable size, like standard
|
||||
input or named pipes. It is also the only mode that can be used for writing
|
||||
@ -529,6 +591,20 @@ contain a "=" character.
|
||||
By default such arguments are seen as misspelled options. It is nevertheless
|
||||
not possible to use one of the options listed with --list_ignored_options.
|
||||
.TP
|
||||
.BI assert_write_lba= block_number | byte_address
|
||||
Abort if the write address given with this option is not the same as predicted
|
||||
immediately before the write session starts. This option can ensure that a
|
||||
start address which was presumed by a formatter like mkisofs -C is really used
|
||||
by the drive for writing.
|
||||
assert_write_lba=0 effectively demands blank media and excludes appendables.
|
||||
.br
|
||||
Block numbering is peculiar: If the last character of the option string is
|
||||
a letter [a-zA-Z] then the usual unit scaling by "s", "k", "m", etc. applies
|
||||
and the result is divided by 2048. Else the number value of the string is
|
||||
taken as plain block number with block size 2048 byte.
|
||||
(E.g ...=1000 or ...=1000s means block 1000, ...=1m means block
|
||||
512, ...=4096b means block number 2)
|
||||
.TP
|
||||
.BI \--demand_a_drive
|
||||
Exit with a nonzero value if no drive can be found during a bus scan.
|
||||
.TP
|
||||
@ -591,6 +667,25 @@ for best DVD-ROM compatibility.
|
||||
If the track source delivers less bytes than announced then the missing ones
|
||||
will be filled with zeros.
|
||||
.TP
|
||||
.BI --tell_media_space
|
||||
Prepare a recording session, do not perform it but rather inquire the
|
||||
maximum number of 2048 byte data blocks which may be written in
|
||||
the current state of media with the prepared setup. So this option disables
|
||||
recording of data. It does allow blanking, though, and will measure space
|
||||
afterwards.
|
||||
.br
|
||||
It is not mandatory to give track sources but their nature may influence
|
||||
the available capacity. So for most realistic results one may set up
|
||||
the full burn session and add --tell_media_space. But if one has to expect
|
||||
a cdrskin version prior to 0.3.3 no track source should be given in order
|
||||
not to start an involuntary burn session.
|
||||
In this case set at least -sao or -tao explicitely.
|
||||
.br
|
||||
The result gets printed to standard output. It is 0 or empty if no writing
|
||||
is possible with the given options.
|
||||
This option redirects to stderr all message output except its own result
|
||||
string and eventual output of -msinfo.
|
||||
.TP
|
||||
.BI write_start_address= byte_offset
|
||||
Set the address on media where to start writing the track. With DVD+RW or
|
||||
DVD-RAM byte_offset must be aligned to 2 KB blocks, but better is 32 kB.
|
||||
@ -607,6 +702,17 @@ but rather to shut it down and to wait until it has ended the final operations.
|
||||
This option is only needed for revoking eventual --ignore_signals or
|
||||
--no_abort_handler.
|
||||
.TP
|
||||
.BI \--allow_untested_media
|
||||
Enable the use of media profiles which have been implemented but not yet
|
||||
tested. Currently this applies to :
|
||||
.br
|
||||
Profile 0015h , DVD-R/DL Sequential (will not allow -multi).
|
||||
.br
|
||||
Profile 002Bh , DVD+R/DL.
|
||||
.br
|
||||
If you really test such media, then please report the outcome on
|
||||
libburn-hackers@pykix.org
|
||||
.TP
|
||||
.BI dev_translation= <sep><from><sep><to>
|
||||
Set drive address alias. This was necessary before cdrskin-0.2.4 to manually
|
||||
translate cdrecord addresses into cdrskin addresses.
|
||||
@ -616,7 +722,7 @@ translate cdrecord addresses into cdrskin addresses.
|
||||
dev=. <to> is the address to be used instead whenever <from> is given.
|
||||
More than one translation instruction can be given in one cdrskin run.
|
||||
.br
|
||||
E.g.: dev_translation=+ATA:1,0,0+/dev/sg1 dev_translation=+ATA:1,1,0+/dev/sg2
|
||||
E.g.: dev_translation=+ATA:1,0,0+/dev/sr1 dev_translation=+ATA:1,1,0+/dev/sr2
|
||||
.TP
|
||||
.BI \--drive_abort_on_busy
|
||||
Linux specific: Abort process if a busy drive is encountered.
|
||||
@ -625,14 +731,33 @@ Linux specific: Abort process if a busy drive is encountered.
|
||||
Linux specific: Try to wait for a busy drive to become free.
|
||||
This is not guaranteed to work with all drivers. Some need nonblocking i/o.
|
||||
.TP
|
||||
.BI \--drive_f_setlk
|
||||
Linux specific: Try to get exclusive lock on drive device file via fcntl(2).
|
||||
.TP
|
||||
.BI \--drive_not_exclusive
|
||||
Linux specific: Combine --drive_not_f_setlk and --drive_not_o_excl.
|
||||
.TP
|
||||
.BI \--drive_not_f_setlk
|
||||
Linux specific: Do not try to get exclusive lock on drive device file via
|
||||
fcntl(2).
|
||||
.TP
|
||||
.BI \--drive_not_o_excl
|
||||
Linux specific: Do not ask the operating system to prevent opening busy drives.
|
||||
Wether this leads to senseful behavior depends on operating system and kernel.
|
||||
.TP
|
||||
.BI drive_scsi_dev_family= sr | scd | sg
|
||||
Linux specific: Select a SCSI device file family to be used for drive command
|
||||
transactions. Normally this is /dev/sgN on kernel versions < 2.6 and /dev/srN
|
||||
on kernels >= 2.6 . This option allows to explicitely override that default
|
||||
in order to meet other programs at a common device file for each drive.
|
||||
On kernel 2.4 families sr and scd will find no drives.
|
||||
.br
|
||||
Device file family /dev/hdX on kernel >= 2.6 is not affected by this setting.
|
||||
.TP
|
||||
.BI \--drive_scsi_exclusive
|
||||
Linux specific:
|
||||
Try to exclusively reserve device files /dev/srN, /dev/scdM, /dev/stK of drive.
|
||||
this would be helpful to protect against collisions with program growisofs.
|
||||
Try to exclusively reserve device files /dev/srN, /dev/scdM, /dev/sgK of drives.
|
||||
This would be helpful to protect against collisions with program growisofs.
|
||||
Regrettably on Linux kernel 2.4 with ide-scsi emulation this seems not to
|
||||
work. Wether it becomes helpful with new Linux systems has to be evaluated.
|
||||
.TP
|
||||
@ -642,6 +767,18 @@ Disable fifo despite any fs=.
|
||||
.BI \--fifo_per_track
|
||||
Use a separate fifo for each track.
|
||||
.TP
|
||||
.BI \--fill_up_media
|
||||
Expand the last track of the session to occupy all remaining free space on
|
||||
the media.
|
||||
.br
|
||||
This option overrides option -multi. It will not fill up media if option -sao
|
||||
is given with CD media.
|
||||
.br
|
||||
.B Caution:
|
||||
This option might increase read compatibility with DVD-ROM drives but
|
||||
with some DVD recorders and media types it might also fail to produce readable
|
||||
media at all. "Your mileage may vary".
|
||||
.TP
|
||||
.BI grab_drive_and_wait= seconds
|
||||
Open the addressed drive, wait the given number of seconds, release the drive,
|
||||
and do normal work as indicated by the other options used. This option helps
|
||||
@ -670,7 +807,7 @@ Partly Linux specific:
|
||||
Such opening is needed for Bus,Target,Lun addresses unless option
|
||||
--old_pseudo_scsi_adr is given. It is also needed to resolve device file
|
||||
addresses which are not listed with cdrskin --devices but nevertheless point
|
||||
to a usable drive. (Like /dev/sr0 using the same SCSI address as /dev/sg0.)
|
||||
to a usable drive. (Like /dev/sg0 using the same SCSI address as /dev/sr0.)
|
||||
.TP
|
||||
.BI \--old_pseudo_scsi_adr
|
||||
Linux specific:
|
||||
@ -716,7 +853,7 @@ cdrskin -v dev=/dev/hdc speed=12 fs=8m \\
|
||||
.br
|
||||
-sao -eject padsize=300k my_image.iso
|
||||
.SS
|
||||
.B Write compressed afio archive on-the-fly:
|
||||
.B Write compressed afio archive on-the-fly (not possible with minimally blanked DVD-RW):
|
||||
.br
|
||||
find . | afio -oZ - | \\
|
||||
.br
|
||||
@ -724,7 +861,7 @@ cdrskin -v dev=0,1,0 fs=32m speed=8 \\
|
||||
.br
|
||||
-tao padsize=300k -
|
||||
.SS
|
||||
.B Write several sessions to the same CD or DVD-R[W]:
|
||||
.B Write multi-session to the same CD, DVD-R[W] or DVD+R:
|
||||
.br
|
||||
cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 1.iso
|
||||
.br
|
||||
@ -734,12 +871,20 @@ cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 3.iso
|
||||
.br
|
||||
cdrskin dev=/dev/hdc -v padsize=300k -tao 4.iso
|
||||
.SS
|
||||
.B Get CD or DVD-R[W] multi-session info for option -C of program mkisofs:
|
||||
.B Get multi-session info for option -C of program mkisofs:
|
||||
.br
|
||||
c_values=$(cdrskin dev=/dev/sr0 -msinfo 2>/dev/null)
|
||||
c_values=$(cdrskin dev=/dev/hdc -msinfo 2>/dev/null)
|
||||
.br
|
||||
mkisofs ... -C "$c_values" ...
|
||||
.SS
|
||||
.B Inquire free space on media for a -tao -multi run:
|
||||
.br
|
||||
x=$(cdrskin dev=/dev/sr0 -tao -multi \\
|
||||
.br
|
||||
--tell_media_space 2>/dev/null)
|
||||
.br
|
||||
echo "Available: $x blocks of 2048 data bytes"
|
||||
.SS
|
||||
.B Write audio tracks to CD:
|
||||
.br
|
||||
cdrskin -v dev=ATA:1,0,0 speed=48 -sao \\
|
||||
@ -783,7 +928,7 @@ fs=16m
|
||||
.br
|
||||
.SH SEE ALSO
|
||||
.TP
|
||||
Formatting track sources for cdrskin:
|
||||
Formatting data track sources for cdrskin:
|
||||
.br
|
||||
.BR mkisofs (8),
|
||||
.BR genisoimage (8),
|
||||
|
1294
cdrskin/cdrskin.c
1294
cdrskin/cdrskin.c
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
|
||||
<HEAD>
|
||||
<META NAME="description" CONTENT="cdrskin, a limited cdrecord compatibility wrapper for libburn">
|
||||
<META NAME="keywords" CONTENT="cdrskin, libburn, libburnia, burn, CD, linux, CDR, CD-R, CDRW, CD-RW, cdrecord, compatible, scdbackup, burning">
|
||||
<META NAME="keywords" CONTENT="cdrskin, libburn, libburnia, burn, CD, DVD, linux, recording, burning, CD-R, CD-RW, DVD-R, DVD-RW, DVD+RW, DVD+R, cdrecord, compatible, scdbackup">
|
||||
<META NAME="robots" CONTENT="follow">
|
||||
<TITLE>cdrskin homepage english</TITLE>
|
||||
</HEAD>
|
||||
@ -24,9 +24,8 @@
|
||||
|
||||
<P>
|
||||
<H2>Purpose:</H2>
|
||||
<UL>
|
||||
<LI>Burns preformatted data to CD-R, CD-RW, DVD-RAM, DVD+RW, DVD-RW</LI>
|
||||
</UL>
|
||||
Burns preformatted data to CD and single layer DVD media:<BR>
|
||||
CD-R, DVD-R, DVD+R, CD-RW, DVD-RW, DVD-RAM, DVD+RW
|
||||
</P>
|
||||
<P>
|
||||
|
||||
@ -34,9 +33,10 @@
|
||||
|
||||
<P>
|
||||
<H2>Hardware requirements:</H2>
|
||||
A CD recorder suitable for
|
||||
<A HREF="http://libburnia.pykix.org">libburnia.pykix.org</A>
|
||||
(SCSI or IDE/ATAPI writers compliant to mmc-3 standard).
|
||||
A CD/DVD recorder suitable for
|
||||
<A HREF="http://libburnia.pykix.org">libburnia.pykix.org</A> <BR>
|
||||
(SCSI , ATA , USB , or SATA writers compliant to standard MMC-3 for CD
|
||||
and to MMC-5 for DVD).
|
||||
<BR>
|
||||
</P>
|
||||
|
||||
@ -44,7 +44,7 @@ A CD recorder suitable for
|
||||
<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.4 an ATA 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>
|
||||
@ -56,9 +56,9 @@ A CD recorder suitable for
|
||||
GPL software included:<BR>
|
||||
</H2>
|
||||
<DL>
|
||||
<DT>libburn-0.3.0</DT>
|
||||
<DT>libburn-0.3.6</DT>
|
||||
<DD>(by Derek Foreman, Ben Jansens, and team of libburnia.pykix.org)</DD>
|
||||
<DD>transfers data to CD</DD>
|
||||
<DD>transfers data to CD and DVD</DD>
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
@ -88,41 +88,84 @@ 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>
|
||||
DVD are written in a pseudo -tao mode which is very different from the
|
||||
write mode used by cdrecord(-ProDVD).<BR>
|
||||
Most DVD types are written in pseudo -tao modes which are very different
|
||||
from the write mode DAO used by cdrecord(-ProDVD). With DVD-R[W] cdrskin
|
||||
can use this write mode, too.<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 an overview of drives and their addresses</DT>
|
||||
<DD>#<KBD> cdrskin -scanbus</KBD></DD>
|
||||
<DD>#<KBD> cdrskin dev=ATA -scanbus</KBD></DD>
|
||||
<DD>#<KBD> cdrskin --devices</KBD></DD>
|
||||
<DT>Being superuser avoids permission problems with /dev/srN resp. /dev/hdX .
|
||||
</DT>
|
||||
<DT>Ordinary users should then get granted rw access to the /dev files
|
||||
as listed by option --devices.</DT>
|
||||
<DT> </DT>
|
||||
|
||||
<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>Format DVD-RW before first use with cdrskin</DT>
|
||||
<DD>$ cdrskin -v dev=0,1,0 blank=format_overwrite -eject<DD>
|
||||
<DT>Write ISO-9660 filesystem image:</DT>
|
||||
<DD>$ cdrskin -v dev=/dev/hdc speed=12 fs=8m driveropts=burnfree -eject padsize=300k my_image.iso</DD>
|
||||
<DT>Write compressed afio archive on-the-fly :</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>
|
||||
<DD>$<KBD> cdrskin dev=0,1,0 -checkdrive</KBD></DD>
|
||||
<DD>$<KBD> cdrskin dev=ATA:1,0,0 -v -atip</KBD></DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -toc</KBD></DD>
|
||||
|
||||
<DT>Make used CD-RW or used unformatted DVD-RW writable again:</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/sg1 blank=fast -eject</KBD></DD>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/dvd blank=all -eject</KBD></DD>
|
||||
|
||||
<DT>Format DVD-RW to avoid need for blanking before re-use:</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/sr0 blank=format_overwrite</KBD></DD>
|
||||
|
||||
<DT>De-format DVD-RW to make it capable of multi-session again:</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/sr0 blank=deformat_sequential</KBD></DD>
|
||||
|
||||
<DT>Write ISO-9660 filesystem image as only one to blank or formatted media:
|
||||
</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/hdc speed=12 fs=8m \</KBD></DD>
|
||||
<DD><KBD> -sao -eject padsize=300k my_image.iso</KBD></DD>
|
||||
|
||||
<DT>Write compressed afio archive on-the-fly:</DT>
|
||||
<DD>$<KBD> find . | afio -oZ - | \</KBD></DD>
|
||||
<DD><KBD> cdrskin -v dev=0,1,0 fs=32m speed=8 \</KBD></DD>
|
||||
<DD><KBD> -tao padsize=300k -</KBD></DD>
|
||||
|
||||
<DT>Write several sessions to the same CD, DVD-R[W] or DVD+R:</DT>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 1.iso</KBD>
|
||||
</DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 2.iso</KBD>
|
||||
</DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 3.iso</KBD>
|
||||
</DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -tao 4.iso</KBD></DD>
|
||||
|
||||
<DT>Get multi-session info for option -C of program mkisofs:</DT>
|
||||
<DD>$<KBD> c_values=$(cdrskin dev=/dev/sr0 -msinfo 2>/dev/null)</KBD></DD>
|
||||
<DD>$<KBD> mkisofs ... -C "$c_values" ...</KBD></DD>
|
||||
|
||||
<DT>Inquire free space on media for a -tao -multi run:</DT>
|
||||
<DD>$<KBD> x=$(cdrskin dev=/dev/sr0 -tao -multi \</KBD></DD>
|
||||
<DD><KBD> --tell_media_space 2>/dev/null)</KBD></DD>
|
||||
<DD>$<KBD> echo "Available: $x blocks of 2048 data bytes"</KBD></DD>
|
||||
|
||||
<DT>Write audio tracks to CD:</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=ATA:1,0,0 speed=48 -sao \</KBD></DD>
|
||||
<DD><KBD> track1.wav track2.au -audio -swab track3.raw</KBD></DD>
|
||||
|
||||
<DT>Get overview of the cdrecord compatible options:</DT>
|
||||
<DD><A HREF="cdrskin_help">$ cdrskin -help</A></DD>
|
||||
<DD>$<KBD> <A HREF="cdrskin_help">cdrskin -help</A></KBD></DD>
|
||||
|
||||
<DT>Get overview of the non-cdrecord options:</DT>
|
||||
<DD><A HREF="cdrskin__help">$ cdrskin --help</A></DD>
|
||||
<DD>$<KBD> <A HREF="cdrskin__help">cdrskin --help</A></KBD></DD>
|
||||
|
||||
<DT>Read the detailed manual page:</DT>
|
||||
<DD><A HREF="man_1_cdrskin.html">$ man cdrskin</A></DD>
|
||||
<DD>$<KBD> <A HREF="man_1_cdrskin.html">man cdrskin</A></KBD></DD>
|
||||
</DL>
|
||||
|
||||
<DL>
|
||||
<DT>Read about the standard for which cdrskin is striving:</DT>
|
||||
<DD><A HREF="http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html">
|
||||
$ man cdrecord</A></DD>
|
||||
<DD>$<KBD>
|
||||
<A HREF="http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html">
|
||||
man cdrecord</A></KBD></DD>
|
||||
<DD><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.)
|
||||
@ -130,35 +173,13 @@ $ man cdrecord</A></DD>
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
<P>
|
||||
<H2>Known deficiencies:</H2>
|
||||
<UL>
|
||||
<DT></DT>
|
||||
<LI>
|
||||
Appending sessions to unclosed media is restricted to write mode TAO.
|
||||
</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.3.0.pl01.tar.gz">cdrskin-0.3.0.pl01.tar.gz</A>
|
||||
(540 KB).
|
||||
<DD><A HREF="cdrskin-0.3.6.pl00.tar.gz">cdrskin-0.3.6.pl00.tar.gz</A>
|
||||
(605 KB).
|
||||
</DD>
|
||||
<DD>
|
||||
The "stable" cdrskin tarballs are source code identical with "stable"
|
||||
@ -168,21 +189,21 @@ cdrskin is part of libburn - full libburn is provided with cdrskin releases.
|
||||
</DD>
|
||||
<DD> </DD>
|
||||
<DT>Download as single x86 binaries (untar and move to /usr/bin/cdrskin):</DT>
|
||||
<DD><A HREF="cdrskin_0.3.0.pl01-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.3.0.pl01-x86-suse9_0.tar.gz</A>, (75 KB),
|
||||
<DD><A HREF="cdrskin_0.3.6.pl00-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.3.6.pl00-x86-suse9_0.tar.gz</A>, (90 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.3.0.pl01-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.3.0.pl01-x86-suse9_0-static.tar.gz</A>, (275 KB), -static compiled,
|
||||
<DD><A HREF="cdrskin_0.3.6.pl00-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.3.6.pl00-x86-suse9_0-static.tar.gz</A>, (290 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="README_cdrskin">README</A> an 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><A HREF="man_1_cdrskin.html">man cdrskin</A> the manual page</DD>
|
||||
@ -202,46 +223,38 @@ cdrskin_0.3.0.pl01-x86-suse9_0-static.tar.gz</A>, (275 KB), -static compiled,
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
Enhancements towards previous stable version cdrskin-0.2.6:
|
||||
Enhancements towards previous stable version cdrskin-0.3.4:
|
||||
<UL>
|
||||
<LI>Improved recognition of unsuitable media types</LI>
|
||||
<LI>Ban of chmod u+s is replaced by a loud warning</LI>
|
||||
<LI>Detailed man page</LI>
|
||||
<LI>Burning to DVD+RW and DVD-RAM as non-multi, non-appending,
|
||||
single-track session</LI>
|
||||
<LI>Formatting and then burning to DVD-RW like to DVD+RW</LI>
|
||||
<LI>Emulation of new wodim option msifile=path</LI>
|
||||
<LI>Use of /dev/srN rather than /dev/sgN on Linux >= 2.6</LI>
|
||||
<LI>Option drive_scsi_dev_family=sr|scd|sg to select explicitely</LI>
|
||||
<LI>Option -isosize is supported now</LI>
|
||||
<LI>DVD+R now get finalized (if not -multi is given)</LI>
|
||||
</UL>
|
||||
</P>
|
||||
<P>
|
||||
Bug fix towards previous patch level 0:
|
||||
<UL>
|
||||
<LI>Tracks >= 2 GB were only possible via a pipe to stdin but not
|
||||
directly from a disk file</LI>
|
||||
</UL>
|
||||
</P>
|
||||
|
||||
<!--
|
||||
Bug fixes towards cdrskin-0.3.6.pl00:
|
||||
<UL>
|
||||
<LI>none yet</LI>
|
||||
</UL>
|
||||
-->
|
||||
|
||||
</P>
|
||||
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
<DL>
|
||||
<DT><H3>Development snapshot, version 0.3.1 :</H3></DT>
|
||||
<DD>Enhancements towards stable version 0.3.0:
|
||||
<DT><H3>Development snapshot, version 0.3.7 :</H3></DT>
|
||||
<DD>Enhancements towards stable version 0.3.6.pl00:
|
||||
<UL>
|
||||
<LI>Burnfree enabled by default</LI>
|
||||
<LI>Multi-session burning to DVD-R
|
||||
and sequential (i.e. unformatted) DVD-RW</LI>
|
||||
<LI>Option -toc with sequential DVD-R[W]</LI>
|
||||
<LI>Options -msinfo and msifile= with appendable DVD-R[W]</LI>
|
||||
<LI>Single session DAO write mode with DVD-R[W]</LI>
|
||||
<LI>-none yet-</LI>
|
||||
</UL>
|
||||
</DD>
|
||||
<DD> </DD>
|
||||
<DD><A HREF="README_cdrskin_devel">README 0.3.1</A>
|
||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.3.1 --help</A></DD>
|
||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.3.1 -help</A></DD>
|
||||
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.3.1)</A></DD>
|
||||
<DD><A HREF="README_cdrskin_devel">README 0.3.7</A>
|
||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.3.7 --help</A></DD>
|
||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.3.7 -help</A></DD>
|
||||
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.3.7)</A></DD>
|
||||
<DD> </DD>
|
||||
<DT>Maintainers of cdrskin unstable packages please use SVN of
|
||||
<A HREF="http://libburnia.pykix.org"> libburnia.pykix.org</A></DT>
|
||||
@ -261,15 +274,15 @@ admins with full system souvereignty.</DT>
|
||||
<A HREF="README_cdrskin_devel">upcoming README</A> ):
|
||||
</DD>
|
||||
<DD>
|
||||
<A HREF="cdrskin-0.3.1.tar.gz">cdrskin-0.3.1.tar.gz</A>
|
||||
(570 KB).
|
||||
<A HREF="cdrskin-0.3.7.tar.gz">cdrskin-0.3.7.tar.gz</A>
|
||||
(605 KB).
|
||||
</DD>
|
||||
<DD>Binary (untar and move to /usr/bin/cdrskin):</DD>
|
||||
<DD><A HREF="cdrskin_0.3.1-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.3.1-x86-suse9_0.tar.gz</A>, (80 KB).
|
||||
<DD><A HREF="cdrskin_0.3.7-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.3.7-x86-suse9_0.tar.gz</A>, (90 KB).
|
||||
</DD>
|
||||
<DD><A HREF="cdrskin_0.3.1-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.3.1-x86-suse9_0-static.tar.gz</A>, (280 KB)
|
||||
<DD><A HREF="cdrskin_0.3.7-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.3.7-x86-suse9_0-static.tar.gz</A>, (285 KB)
|
||||
</DD>
|
||||
</DL>
|
||||
</P>
|
||||
@ -297,13 +310,13 @@ provide libburn with invaluable examples on how to deal with DVD media.
|
||||
<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>
|
||||
<DT>(CD devices which offer no rw-permission are invisible to normal users.)
|
||||
</DT>
|
||||
<DD># <KBD><B>cdrskin --devices</B></KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD>0 dev='/dev/sg0' rwrwr- : 'TEAC' 'CD-ROM CD-532S'</KBD></DD>
|
||||
<DD><KBD>0 dev='/dev/sr0' rwrwr- : 'TEAC' 'CD-ROM CD-532S'</KBD></DD>
|
||||
<DD><KBD>1 dev='/dev/hdc' rwrw-- : 'LITE-ON' 'LTR-48125S'</KBD></DD>
|
||||
<DD># <KBD><B>chmod a+rw /dev/sg0 /dev/hdc</B></KBD></DD>
|
||||
<DD># <KBD><B>chmod a+rw /dev/sr0 /dev/hdc</B></KBD></DD>
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
@ -340,7 +353,7 @@ is a GUI frontend which uses cdrecord for CD burning.)
|
||||
<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.3.0 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
|
||||
<DD><KBD>cdrskin 0.3.6 : limited cdrecord compatibility wrapper for libburn</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.
|
||||
@ -399,8 +412,8 @@ Contact me. Let's see what we can achieve.
|
||||
<BR>
|
||||
<BR>
|
||||
libburn and cdrskin are now mature enough to substitute cdrecord in its
|
||||
major use cases of CD burning. It is possible to foist cdrskin on various
|
||||
software packages if it gets falsely named "cdrecord".
|
||||
major use cases of CD and DVD burning. It is possible to foist cdrskin on
|
||||
various software packages if it gets falsely named "cdrecord".
|
||||
I do not encourage this approach, but of course such a replacement
|
||||
opportunity is the goal of a cdrecord compatibility wrapper.
|
||||
<BR>
|
||||
|
@ -1 +1 @@
|
||||
#define Cdrskin_timestamP "2007.02.08.225208"
|
||||
#define Cdrskin_timestamP "2007.04.23.130001"
|
||||
|
@ -23,12 +23,21 @@ Deliberate deviations of cdrskin from cdrecord compatibility:
|
||||
|
||||
+ DVD track sources get not concateneated to a single track. In general DVD
|
||||
writing is quite different from cdrecord-ProDVD:
|
||||
DVD-RW "Disc-at-once" (-sao) is nearest to cdrecord-ProDVD's methods.
|
||||
DVD-RW "Incremental Streaming" (-tao) on unformatted media allows
|
||||
DVD-R[W] "Disc-at-once" (-sao) is nearest to cdrecord-ProDVD's methods.
|
||||
DVD-R[W] "Incremental Streaming" (-tao) on unformatted media allows
|
||||
multi-session and track sources of unpredictable size.
|
||||
Writing DVD-RAM, DVD+RW and "Restricted Overwrite" DVD-RW is like -tao on
|
||||
blank CD. Formatting is done via cdrskin-specific blank=format_overwrite
|
||||
and not with option -format.
|
||||
Writing DVD-RAM, DVD+RW and "Restricted Overwrite" DVD-RW is like single
|
||||
track -tao on blank CD. Formatting is done via cdrskin-specific
|
||||
blank=format_overwrite and not with option -format.
|
||||
|
||||
+ DVD-RW get blanked fast only with option blank=deformat_sequential_quickest .
|
||||
Option blank=fast is the same as blank=all in order to achieve media which
|
||||
are capable of Incremental Streaming.
|
||||
|
||||
+ It has not been evaluated how far -isosize is compatible with the original
|
||||
cdrecord option. man cdrecord forbids stdin as source, cdrskin allows it
|
||||
if a fifo is used.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Changelog
|
||||
@ -2901,55 +2910,772 @@ Described DVD-R[W] DAO mode
|
||||
------------------------------------ cycle - cdrskin-0.3.1 - 2007.02.06.200802
|
||||
* DVD-R[W] Disk-at-once writing
|
||||
|
||||
[]
|
||||
6 Feb 2007 [690]
|
||||
cdrskin/README
|
||||
cdrskin/changelog.txt
|
||||
cdrskin/cdrskin_eng.html
|
||||
Nect cdrskin-0.3.1 cycle
|
||||
Next cdrskin-0.3.1 cycle
|
||||
|
||||
2007.02.07.162836 [691]
|
||||
libburn/libburn.h
|
||||
libburn/drive.h
|
||||
libburn/drive.c
|
||||
libburn/options.c
|
||||
libburn/libdax_msgs.h
|
||||
New API function burn_write_opts_auto_write_type()
|
||||
|
||||
7 Feb 2007 [692]
|
||||
test/libburner.c
|
||||
Made use of burn_write_opts_auto_write_type()
|
||||
|
||||
7 Feb 2007 [693]
|
||||
test/libburner.c
|
||||
doc/comments
|
||||
Updated documentation aspects
|
||||
|
||||
8 Feb 2007 [694]
|
||||
README
|
||||
doc/comments
|
||||
cdrskin/cdrskin.1
|
||||
cdrskin/README
|
||||
Finally made tests with DVD-R. They burn indeed like DVD-RW.
|
||||
|
||||
2007.02.08.210744 [695]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
New option --prodvd_cli_compatible
|
||||
|
||||
8 Feb 2007 [696]
|
||||
cdrskin/wiki_plain.txt
|
||||
cdrskin/cdrskin_eng.html
|
||||
Mentioned DVD-R
|
||||
|
||||
2007.02.08.225208 [697]
|
||||
cdrskin/cdrskin.c
|
||||
Silenced compiler warning
|
||||
|
||||
|
||||
forceful blanking of blank media in burn_disc_erase()
|
||||
------------------------------------ cycle - cdrskin-0.3.1 - 2007.02.09.074058
|
||||
|
||||
9 Feb 2006 [698]
|
||||
cdrskin/cdrskin_eng.html
|
||||
Added special thanks towards Andy Polyakov
|
||||
|
||||
9 Feb 2006 [699]
|
||||
cdrskin/cdrskin.1
|
||||
doc/cookbook.txt
|
||||
Small corrections in documentation
|
||||
|
||||
10 Feb 2007 [tag 701] [705]
|
||||
- cdrskin/add_ts_changes_to_libburn_0_3_0
|
||||
- cdrskin/add_ts_changes_to_libburn_0_3_1
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_3_2
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_3_3
|
||||
Updated cdrskin tarball generator
|
||||
|
||||
2007.02.10.120001 [tag 702] [704]
|
||||
Makefile.am
|
||||
configure.ac
|
||||
README
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/README
|
||||
cdrskin/compile_cdrskin.sh
|
||||
cdrskin/cdrskin_timestamp.h
|
||||
cdrskin/wiki_plain.txt
|
||||
cdrskin/cdrskin_eng.html
|
||||
Made number transition and activated development documentation
|
||||
|
||||
10 Feb 2007 [tag 703] [707]
|
||||
cdrskin/changelog.txt
|
||||
Documented changes and 0.3.2 release timestamp
|
||||
|
||||
|
||||
----------------------------- release - cdrskin-0.3.2.pl00 - 2007.02.10.120001
|
||||
* Burnfree enabled by default
|
||||
* Multi-session recording on sequential DVD-R[W], including -toc, -msinfo
|
||||
* DVD-R[W] Disk-at-once recording
|
||||
|
||||
|
||||
10 Feb 2007 [706]
|
||||
libburn/mmc.c
|
||||
Added a comment about DVD-R
|
||||
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.3 - 2007.02.10.190528
|
||||
|
||||
|
||||
12 Feb 2007 [708]
|
||||
cdrskin/cdrskin.1
|
||||
Being exacting about on-the-fly and DVD-RW
|
||||
|
||||
|
||||
12 Feb 2007 [709]
|
||||
cdrskin/cdrskin_eng.html
|
||||
Updated list of keywords
|
||||
|
||||
2007.02.12.142245 [710]
|
||||
libburn/mmc.c
|
||||
Made profile 0010h DVD-ROM suitable,full,not erasable. So it delivers a TOC.
|
||||
|
||||
|
||||
2007.02.13.115459 [711]
|
||||
libburn/spc.c
|
||||
Set a suitable page 05h after spc_probe_write_modes()
|
||||
|
||||
2007.02.13.143718 [712]
|
||||
libburn/libburn.h
|
||||
libburn/transport.h
|
||||
libburn/mmc.c
|
||||
libburn/spc.c
|
||||
libburn/drive.c
|
||||
Mew API function burn_disc_available_space()
|
||||
|
||||
13 Feb 2007 [713]
|
||||
test/libburner.c
|
||||
Removed or updated outdated restriction statements
|
||||
|
||||
13 Feb 2007 [714]
|
||||
test/telltoc.c
|
||||
Applied new API function burn_disc_available_space()
|
||||
|
||||
2007.02.14.120213 [715]
|
||||
libburn/spc.c
|
||||
Removed outdated ifdef
|
||||
|
||||
14 Feb 2007 [716]
|
||||
test/telltoc.c
|
||||
Set the advised write mode before inquiring media space
|
||||
|
||||
2007.02.14.121440 [717]
|
||||
libburn/libdax_msgs.h
|
||||
libburn/mmc.c
|
||||
Handle eventual ridiculously high d->last_track_no
|
||||
|
||||
2007.02.14.122218 [718]
|
||||
libburn/mmc.h
|
||||
Forgotten part of revision 718
|
||||
|
||||
2007.02.14.202944 [719]
|
||||
libburn/libburn.h
|
||||
libburn/options.h
|
||||
libburn/options.c
|
||||
libburn/structure.h
|
||||
libburn/structure.c
|
||||
libburn/write.c
|
||||
libburn/drive.c
|
||||
Optional padding up to full media size when closing (incomplete yet)
|
||||
|
||||
2007.02.14.203635 [720]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
New options --fill_up_media and --tell_media_space
|
||||
|
||||
2007.02.15.201506 [722]
|
||||
libburn/options.c
|
||||
libburn/drive.c
|
||||
cdrskin/cdrskin.c
|
||||
libburn/write.c
|
||||
Took fill_up_media into respect with automatic write mode decisions
|
||||
|
||||
2007.02.15.201651 [723]
|
||||
libburn/transport.h
|
||||
libburn/mmc.c
|
||||
libburn/libdax_msgs.h
|
||||
Installed a guardian for predicted track end
|
||||
|
||||
2007.02.15.201757 [724]
|
||||
libburn/structure.c
|
||||
Corrected bug about open_ended filluped tracks
|
||||
|
||||
15 Feb 2007 [725]
|
||||
libburn/libburn.h
|
||||
cdrskin/cdrskin.1
|
||||
Clarifications about current state of fillup
|
||||
|
||||
2007.02.15.203448 [726]
|
||||
libburn/write.c
|
||||
Repaired debugging message spoiled by uninitialized variable
|
||||
|
||||
2007.02.16.111941 [728]
|
||||
libburn/write.c
|
||||
Corrected CD TAO bug introduced with DVD bug fix 724 and CD SAO change 655
|
||||
|
||||
2007.02.17.085118 [729]
|
||||
libburn/structure.c
|
||||
Another bug fix for revision 724
|
||||
|
||||
2007.02.17.085533 [730]
|
||||
libburn/async.c
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
test/libburner.c
|
||||
Allowed forceful blanking of blank media in burn_disc_erase()
|
||||
|
||||
17 Feb 2007 [731]
|
||||
test/libburner.c
|
||||
Removed unprecise unnecessary comment
|
||||
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.3 - 2007.02.17.121238
|
||||
* New option --tell_media_space tells the maximum size for the next burn
|
||||
|
||||
|
||||
2007.02.18.094414 [732]
|
||||
libburn/libburn.h
|
||||
Clarified usage comment with burn_drive_info_free() (see ticket 98)
|
||||
|
||||
18 Feb 2007 [733]
|
||||
cdrskin/cdrskin.1
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/changelog.txt
|
||||
Next cdrskin-0.3.3 cycle
|
||||
|
||||
|
||||
2007.02.18.094858 [734]
|
||||
libburn/mmc.h
|
||||
Adjusted maximum realistic number of tracks to MMC specs
|
||||
|
||||
2007.02.19.184132 [735]
|
||||
cdrskin/cdrskin.c
|
||||
Repaired slightly broken pacifier track size display with -audio
|
||||
|
||||
2007.02.19.225102 [736]
|
||||
libburn/libburn.h
|
||||
libburn/async.c
|
||||
libburn/structure.h
|
||||
libburn/structure.c
|
||||
libburn/write.h
|
||||
libburn/write.c
|
||||
libburn/drive.h
|
||||
libburn/drive.c
|
||||
libburn/options.c
|
||||
libburn/libdax_msgs.h
|
||||
Re-arranged checking and defaulting of write parameters
|
||||
=
|
||||
New API function burn_track_set_default_size()
|
||||
New API function burn_precheck_write()
|
||||
Make wide use of burn_disc_write_mode_demands()
|
||||
|
||||
2007.02.21.205244 [737]
|
||||
libburn/libburn.h
|
||||
libburn/async.c
|
||||
libburn/drive.c
|
||||
libburn/options.c
|
||||
libburn/structure.c
|
||||
libburn/write.c
|
||||
libburn/libdax_msgs.h
|
||||
cdrskin/cdrskin.c
|
||||
Moved tao_to_sao_tsize into libburn, let cdrskin use auto_write_type and precheck
|
||||
|
||||
21 Feb 2007 [738]
|
||||
cdrskin/add_ts_changes_to_libburn_0_3_3
|
||||
cdrskin/add_ts_changes_to_libburn_0_3_2
|
||||
Added -O2 to binary production
|
||||
|
||||
2007.02.22.072700 [739]
|
||||
libburn/libburn.h
|
||||
libburn/drive.c
|
||||
libburn/options.c
|
||||
Re-enabled overwriteable pseudo-pseudo-SAO with unpredicted track size
|
||||
|
||||
2007.02.22.073157 [740]
|
||||
libburn/mmc.c
|
||||
Disabled debugging messages about format descriptors
|
||||
|
||||
2007.02.22.094939 [741]
|
||||
libburn/libburn.h
|
||||
libburn/options.c
|
||||
libburn/write.c
|
||||
libburn/async.c
|
||||
test/libburner.c
|
||||
cdrskin/cdrskin.c
|
||||
Macro for length of rejection reasons string (old size is still safe)
|
||||
|
||||
2007.02.22.113016 [742]
|
||||
libburn/libburn.h
|
||||
libburn/drive.c
|
||||
Made burn_disc_available_space() take into respect burn_write_opts_set_start_byte()
|
||||
|
||||
2007.02.23.190937 [743]
|
||||
libburn/libburn.h
|
||||
libburn/drive.c
|
||||
libburn/mmc.c
|
||||
libburn/write.c
|
||||
doc/cookbook.txt
|
||||
Enabled DVD-R/DL Sequential via burn_allow_untested_profiles()
|
||||
|
||||
2007.02.23.191117 [744]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
Enabled DVD-R/DL Sequential via --allow_untested_media_types
|
||||
|
||||
2007.02.23.193427 [745]
|
||||
libburn/init.c
|
||||
Forgotten source file for revision 743
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.3 - 2007.02.24.102731
|
||||
|
||||
|
||||
2007.02.25.112733 [746]
|
||||
libburn/write.h
|
||||
libburn/write.c
|
||||
libburn/drive.c
|
||||
cdrskin/cdrskin.1
|
||||
Took into respect deliberate lack of DVD-R/DL multi session capability
|
||||
|
||||
2007.03.01.120945 [747]
|
||||
libburn/drive.c
|
||||
libburn/mmc.c
|
||||
libburn/write.c
|
||||
cdrskin/cdrskin.c
|
||||
doc/cookbook.txt
|
||||
Preparations for supporting DVD+R[/DL]
|
||||
|
||||
3 Mar 2007 [748]
|
||||
cdrskin/cdrskin.1
|
||||
Updated DVD-R[W] write mode description
|
||||
|
||||
2007.03.03.141240 [749]
|
||||
libburn/transport.h
|
||||
libburn/mmc.c
|
||||
Determine physical interface SCSI,ATA,SATA,USB,... (for future use)
|
||||
|
||||
2007.03.03.141435 [750]
|
||||
libburn/libburn.h
|
||||
libburn/write.c
|
||||
libburn/options.h
|
||||
libburn/options.c
|
||||
cdrskin/cdrskin.c
|
||||
Re-enabled -force with write modes which seem unavailable
|
||||
|
||||
2007.03.03.151812 [751]
|
||||
libburn/options.c
|
||||
Fixed bug introduced with rev 736ff which prevented audio CD burning
|
||||
|
||||
2007.03.04.184720 [752]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrfifo.c
|
||||
Fifo got stuck if sum of processed track sizes was exactly aligned to fifo size
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.3 - 2007.03.04.185202
|
||||
* Bug fix: Multi-track runs with fifo could stall in rare cases
|
||||
|
||||
5 Mar 2007 [753]
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/add_ts_changes_to_libburn_0_3_2
|
||||
Released cdrskin-0.3.2.pl01
|
||||
|
||||
2007.03.06.195203 [754]
|
||||
libburn/mmc.c
|
||||
libburn/write.c
|
||||
Enabled DVD+R, DVD+R DL via --allow_untested_media_types, always -multi for now
|
||||
|
||||
2007.03.06.205312 [755]
|
||||
libburn/mmc.c
|
||||
cdrskin/cdrskin.1
|
||||
doc/cookbook.txt
|
||||
doc/comments
|
||||
Enabled DVD+R as tested media (-multi is still always on)
|
||||
|
||||
2007.03.07.151514 [756]
|
||||
libburn/write.c
|
||||
cdrskin/cdrskin.1
|
||||
cdrskin/README
|
||||
doc/cookbook.txt
|
||||
Some adjustments for DVD+R recording
|
||||
|
||||
2007.03.07.151514 [756]
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/changelog.txt
|
||||
Next cdrskin-0.3.3 cycle
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.3 - 2007.03.07.155750
|
||||
* Multi-session burning to DVD+R
|
||||
|
||||
|
||||
8 Mar 2007 [757]
|
||||
cdrskin/cdrskin.1
|
||||
cdrskin/convert_man_to_html.sh
|
||||
cdrskin/wiki_plain.txt
|
||||
Polished documentation
|
||||
|
||||
2007.03.09.134622 [758]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
New option assert_write_lba=
|
||||
|
||||
10 Mar 2007 [759]
|
||||
cdrskin/cdrskin.1
|
||||
cdrskin/wiki_plain.txt
|
||||
Polished documentation
|
||||
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.3 - 2007.03.10.
|
||||
* New option assert_write_lba=
|
||||
|
||||
2007.03.12.110001 [tag 761]
|
||||
Makefile.am
|
||||
configure.ac
|
||||
README
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/README
|
||||
cdrskin/compile_cdrskin.sh
|
||||
cdrskin/cdrskin_timestamp.h
|
||||
cdrskin/cdrskin_eng.html
|
||||
Made number transition to 0.3.4 and activated development documentation
|
||||
|
||||
12 Mar 2007 [tag 762]
|
||||
- cdrskin/add_ts_changes_to_libburn_0_3_2
|
||||
- cdrskin/add_ts_changes_to_libburn_0_3_3
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_3_4
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_3_5
|
||||
Updated cdrskin tarball generator
|
||||
|
||||
12 Mar 2007 [tag 763]
|
||||
cdrskin/changelog.txt
|
||||
Documented most recent changes
|
||||
|
||||
12 Mar 2007 [tag 764]
|
||||
README
|
||||
Removed redundant sentence
|
||||
|
||||
----------------------------- release - cdrskin-0.3.4.pl00 - 2007.03.12.110001
|
||||
* Multi-session burning to DVD+R
|
||||
* New option --tell_media_space tells the maximum size for the next burn
|
||||
* New option assert_write_lba=
|
||||
* Bug fix: Multi-track runs with fifo could stall in rare cases
|
||||
|
||||
|
||||
2007.03.12.155600 [765]
|
||||
Makefile.am
|
||||
configure.ac
|
||||
README
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/README
|
||||
cdrskin/compile_cdrskin.sh
|
||||
cdrskin/cdrskin_timestamp.h
|
||||
cdrskin/cdrskin_eng.html
|
||||
Made number transition to 0.3.5
|
||||
|
||||
12 Mar 2007 [766]
|
||||
- cdrskin/add_ts_changes_to_libburn_0_3_2
|
||||
- cdrskin/add_ts_changes_to_libburn_0_3_3
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_3_4
|
||||
+ cdrskin/add_ts_changes_to_libburn_0_3_5
|
||||
Updated cdrskin tarball generator
|
||||
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.5 - 2007.03.12.160658
|
||||
|
||||
14 Mar 2007 [767]
|
||||
cdrskin/cdrskin_eng.html
|
||||
Corrected truncated sentence and file sizes
|
||||
|
||||
14 Mar 2007 [768]
|
||||
cdrskin/changelog.txt
|
||||
Next cdrskin-0.3.5 cycle
|
||||
|
||||
2007.03.14.133618 [769]
|
||||
libburn/libburn.h
|
||||
libburn/init.c
|
||||
libburn/sg-linux.c
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
New option drive_scsi_dev_family=sr|scd|sg
|
||||
|
||||
2007.03.15.194531 [770]
|
||||
libburn/drive.c
|
||||
React properly on drive stating that it cannot write any media
|
||||
|
||||
2007.03.15.195005 [771]
|
||||
libburn/spc.h
|
||||
libburn/spc.c
|
||||
libburn/sbc.c
|
||||
After loading tray wait for unit to become ready or to report some clear error
|
||||
|
||||
2007.03.15.195251 [772]
|
||||
cdrskin/cdrskin.c
|
||||
Moved manual device family decision to a sufficiently early stage
|
||||
|
||||
2007.03.15.195428 [773]
|
||||
libburn/mmc.c
|
||||
Kept mmc_get_configuration() from believing the announcement of 1 GB reply
|
||||
|
||||
2007.03.15.195534 [774]
|
||||
libburn/sg-linux.c
|
||||
Trying to recognize kernel >= 2.6 and use /dev/sr by default
|
||||
|
||||
15 Mar 2007 [775]
|
||||
cdrskin/cdrskin.1
|
||||
Updated drive_scsi_dev_family=
|
||||
|
||||
15 Mar 2007 [776]
|
||||
cdrskin/changelog.txt
|
||||
Next cdrskin-0.3.5 cycle
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.5 - 2007.03.16.001311
|
||||
* Usage of /dev/srN rather than /dev/sgN on Linux >= 2.6
|
||||
* New option drive_scsi_dev_family=sr|scd|sg
|
||||
|
||||
|
||||
18 Mar 2007 [777]
|
||||
cdrskin/cdrskin_eng.html
|
||||
Mentioned new sr behavior
|
||||
|
||||
2007.03.24.093238 [785]
|
||||
libburn/drive.c
|
||||
Fixed bug with burn_disc_available_space(...,NULL)
|
||||
|
||||
2007.03.24.093623 [786]
|
||||
cdrskin/cdrskin.c
|
||||
Warning of very small tsize= settings. (Proposal by Eduard Bloch)
|
||||
|
||||
2007.03.27.213543 [787]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrfifo.h
|
||||
cdrskin/cdrfifo.c
|
||||
Preparations for option -isosize via fifo (only a debug message yet)
|
||||
|
||||
2007.03.28.100934 [788]
|
||||
libburn/libburn.h
|
||||
libburn/structure.c
|
||||
cdrskin/cdrskin.c
|
||||
Enabled -isosize for first track by help of fifo and without seeking
|
||||
|
||||
2007.03.28.111739 [789]
|
||||
cdrskin/cdrskin.c
|
||||
Silenced error condition about -sao with stdin and -isosize
|
||||
|
||||
2007.03.28.160503 [790]
|
||||
cdrskin/cdrskin.c
|
||||
Enabled -isosize with S_IFREG or S_IFBLK files and without fifo
|
||||
|
||||
2007.03.28.182419 [791]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
Made fifo based -isosize read 64k first and the rest only at normal stage
|
||||
|
||||
2007.03.28.202802 [792]
|
||||
cdrskin/cdrskin.c
|
||||
Silenced error message if tsize= is smaller than source is willing to deliver
|
||||
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.5 - 2007.03.28.212322
|
||||
* Option -isosize is supported now
|
||||
|
||||
|
||||
29 Mar 2007 [793]
|
||||
cdrskin/cdrskin_eng.html
|
||||
cdrskin/changelog.txt
|
||||
Next cdrskin-0.3.5 cycle
|
||||
|
||||
2007.03.30.201034 [794]
|
||||
libburn/write.c
|
||||
cdrskin/cdrskin.1
|
||||
Allowed finalizing of DVD+R
|
||||
|
||||
2007.03.30.214657 [795]
|
||||
libburn/write.c
|
||||
Avoided unconditional finalizing of DVD+R
|
||||
|
||||
2007.04.03.140356 [796]
|
||||
libburn/sg-linux.c
|
||||
Added fcntl() locking to O_EXCL locking
|
||||
|
||||
2007.04.03.145637 [797]
|
||||
cdrskin/cdrskin.c
|
||||
Make --old_pseudo_scsi_adr -scanbus work with any drive_scsi_dev_family=
|
||||
|
||||
2007.04.03.145806 [798]
|
||||
libburn/libdax_msgs.h
|
||||
Added fcntl() locking to O_EXCL locking
|
||||
|
||||
2007.04.04.184341 [799]
|
||||
libburn/libburn.h
|
||||
libburn/init.c
|
||||
libburn/sg-linux.c
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
New cdrskin options --drive_not_f_setlk and --drive_not_o_excl
|
||||
|
||||
6 Apr 2007 [801]
|
||||
test/libburner.c
|
||||
Updated media list in introduction comment
|
||||
|
||||
2007.04.09.105543 [802]
|
||||
libburn/transport.h
|
||||
libburn/os-linux.h
|
||||
libburn/sg-linux.c
|
||||
cdrskin/cdrskin.1
|
||||
Cleaned up scsi sibling management, sketched grafting of DDLP
|
||||
|
||||
2007.04.09.111215 [803]
|
||||
libburn/sg-linux.c
|
||||
Reacted on compiler warning about last_rdev, fixed fresh typo bug
|
||||
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.5 - 2007.04.09.112127
|
||||
* DVD+R now get finalized (if not -multi is given)
|
||||
|
||||
|
||||
10 Apr 2007 [804]
|
||||
cdrskin/changelog.txt
|
||||
Next cdrskin-0.3.5 cycle
|
||||
|
||||
2007.04.10.081855 [805]
|
||||
libburn/init.c
|
||||
Fixed bug with drive_scsi_dev_family= introduced by revision 796 (fcntl lock)
|
||||
|
||||
2007.04.10.082229 [806]
|
||||
libburn/sg-linux.c
|
||||
Used O_EXCL|O_RDWR and fcntl() even within sg_obtain_scsi_adr()
|
||||
|
||||
2007.04.10.083119 [807]
|
||||
libburn/sg-linux.c
|
||||
Fixed bug in sg_open_scsi_siblings() introduced with revision 802
|
||||
|
||||
2007.04.10.144840 [808]
|
||||
libburn/spc.c
|
||||
libburn/libdax_msgs.h
|
||||
Avoided SIGSEGV with an old SCSI CD-ROM drive and its wild replies
|
||||
|
||||
12 Apr 2007 [810]
|
||||
README
|
||||
Clarified license. People who object shall please come forward now.
|
||||
|
||||
2007.04.13.171347 [815]
|
||||
libburn/sg-linux.c
|
||||
libburn/libdax_msgs.h
|
||||
Switched from O_NONBLOCK to O_NDELAY (see http://lkml.org/lkml/2007/4/11/141)
|
||||
|
||||
2007.04.13.173008 [816]
|
||||
cdrskin/cdrskin.c
|
||||
cdrskin/cdrskin.1
|
||||
Made use of fcntl(F_SETLK) switchable (and thus became more free with default)
|
||||
|
||||
15 Apr 2007 [819]
|
||||
+ libburn/ddlpa.h
|
||||
+ libburn/ddlpa.c
|
||||
Began test implementation of DDLP-A
|
||||
|
||||
15 Apr 2007 [820]
|
||||
libburn/ddlpa.h
|
||||
libburn/ddlpa.c
|
||||
Implemented ddlpa_lock_btl()
|
||||
|
||||
16 Apr 2007 [821]
|
||||
doc/cookbook.txt
|
||||
Finalized DVD+R cookbook
|
||||
|
||||
16 Apr 2007 [822]
|
||||
+ doc/ddlp.txt
|
||||
Emerging description of DDLP
|
||||
|
||||
16 Apr 2007 [823]
|
||||
doc/ddlp.txt
|
||||
libburn/ddlpa.h
|
||||
libburn/ddlpa.c
|
||||
Polished txt and finally threw out getter functions
|
||||
|
||||
16 Apr 2007 [824]
|
||||
libburn/ddlpa.h
|
||||
Corrected description of return values
|
||||
|
||||
18 Apr 2007 [825]
|
||||
+ test/open-cd-excl.c
|
||||
Program for probing access to device files. By Ted Ts'o with modifications by me.
|
||||
|
||||
18 Apr 2007 [826]
|
||||
doc/ddlp.txt
|
||||
Allowed for Friendly Programs: O_EXCL | O_RDONLY
|
||||
|
||||
18 Apr 2007 [827]
|
||||
libburn/ddlpa.h
|
||||
libburn/ddlpa.c
|
||||
Progress due to tests with test/open-cd-excl
|
||||
|
||||
2007.04.18.103734 [828]
|
||||
libburn/mmc.c
|
||||
Updated comments about DVD+R
|
||||
|
||||
18 Apr 2007 [829]
|
||||
test/open-cd-excl.c
|
||||
libburn/ddlpa.c
|
||||
doc/ddlp.txt
|
||||
Polished messages, comments and description of DDLP-A
|
||||
|
||||
18 Apr 2007 [830]
|
||||
test/open-cd-excl.c
|
||||
doc/ddlp.txt
|
||||
Adaptations to new test results and discussions
|
||||
|
||||
18 Apr 2007 [831]
|
||||
doc/ddlp.txt
|
||||
Corrected a list of standard paths
|
||||
|
||||
19 Apr 2007 [832] [833]
|
||||
doc/ddlp.txt
|
||||
Clarifications about motivation and duties of the participants
|
||||
|
||||
20 Apr 2007 [834]
|
||||
doc/ddlp.txt
|
||||
Beginning to develop DDLP-B
|
||||
|
||||
21 Apr 2007 [835]
|
||||
doc/ddlp.txt
|
||||
Declared failure of DDLP to entirely solve the concurrency problem
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.5 - 2007.04.22.112236
|
||||
|
||||
22 Apr 2007 []
|
||||
cdrskin/changelog.txt
|
||||
Next cdrskin-0.3.5 cycle
|
||||
|
||||
[]
|
||||
cdrskin/add_ts_changes_to_libburn_0_3_5
|
||||
cdrskin/add_ts_changes_to_libburn_0_3_4
|
||||
Repaired autotools bootstrap bug by help of sed
|
||||
|
||||
|
||||
===============================================================================
|
||||
TODO
|
||||
===============================================================================
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.5 -
|
||||
cdrskin/changelog.txt
|
||||
Next cdrskin-0.3.5 cycle
|
||||
|
||||
|
||||
|
||||
cdrskin: prevent usage of burn drive as track source
|
||||
|
||||
Think about cdrecord option minbuf= for simultaneous operation on hdc and hdd
|
||||
|
||||
|
||||
What about minimum track sizes ? (POWER OFF/ON , BUS RESET ?)
|
||||
|
||||
How to handle finalizing ?
|
||||
growisofs does not finalize multi-session DVD[+-]R unless padding up. Why ?
|
||||
|
||||
Check test/libburner and test/telltoc for consequences
|
||||
|
||||
Test with DVD-R
|
||||
|
||||
------------------------------------ cycle - cdrskin-0.3.1 -
|
||||
|
||||
Make wide use of mmc_four_char_to_int(), mmc_int_to_four_char()
|
||||
|
||||
Remove from README what is also written in the man page.
|
||||
|
||||
Think about cdrecord option minbuf= for simultaneous operation on hdc and hdd
|
||||
|
||||
After cooking: review of -do_diet ?
|
||||
|
||||
growisofs.c : _LINUX_CAPABILITY_VERSION CAP_SYS_RAWIO SYS_capset ?
|
||||
|
||||
Questions to post:
|
||||
A70211_to_cdwrite_growisofs_question_finalizing
|
||||
|
||||
|
||||
|
||||
Format DVD-RAM ?
|
||||
Disable error checking with DVD-RAM.
|
||||
|
||||
How to handle finalizing ?
|
||||
|
||||
Check wether current_profile is kept up to date with each possible media change
|
||||
|
||||
Make drive_info reflect DVD capabilities
|
||||
Make proper use of reflected capabilities (e.g. in burn_drive_inquire_media())
|
||||
|
||||
Rectify mmc_read_atip speed interpretation. 12x media are reported as 10x. I never heard of 6x media.
|
||||
|
||||
|
||||
Sequentially check option list for DVD compliance
|
||||
|
||||
|
||||
(Learn about multi-track with DVD-RW Restricted Overwrite.) My drives don't offer
|
||||
|
||||
|
||||
|
||||
----------------------------------------- long term intentions:
|
||||
|
||||
[]
|
||||
@ -2965,7 +3691,6 @@ Open O_EXCL all devices in address resolution chain
|
||||
(Might help with non-standard hdX device siblings)
|
||||
|
||||
[]
|
||||
Convert libburn_experimental: into LIBDAX_MSGS_SEV_DEBUG
|
||||
Convert burn_print() into libdax_msgs_submit()
|
||||
|
||||
[]
|
||||
@ -2975,7 +3700,8 @@ Test unlocking of single drive by burn_drive_grab(), burn_drive_release()
|
||||
[]
|
||||
Clear outdated persistent read buffer after small CD image was read (ticket 57)
|
||||
|
||||
[]
|
||||
Enable multi-session for write modes other than TAO
|
||||
|
||||
|
||||
===============================================================================
|
||||
This is the dirty end of the todo list.
|
||||
For most recent changelog entries scroll up about 100 lines.
|
||||
===============================================================================
|
||||
|
@ -7,7 +7,7 @@
|
||||
debug_opts=
|
||||
def_opts=
|
||||
largefile_opts="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1"
|
||||
libvers="-DCdrskin_libburn_0_3_1"
|
||||
libvers="-DCdrskin_libburn_0_3_6"
|
||||
cleanup_src_or_obj="libburn/cleanup.o"
|
||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
||||
@ -33,15 +33,15 @@ do
|
||||
libdax_audioxtr_o=
|
||||
libdax_msgs_o="libburn/message.o"
|
||||
cleanup_src_or_obj="-DCleanup_has_no_libburn_os_H cdrskin/cleanup.c"
|
||||
elif test "$i" = "-libburn_0_3_0"
|
||||
elif test "$i" = "-libburn_0_3_6"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_0_3_0"
|
||||
libvers="-DCdrskin_libburn_0_3_6"
|
||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
||||
cleanup_src_or_obj="libburn/cleanup.o"
|
||||
elif test "$i" = "-libburn_svn"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_0_3_1"
|
||||
libvers="-DCdrskin_libburn_0_3_7"
|
||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
||||
cleanup_src_or_obj="libburn/cleanup.o"
|
||||
@ -79,7 +79,7 @@ do
|
||||
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_3_0 set macro to match libburn-0.3.0."
|
||||
echo " -libburn_0_3_6 set macro to match libburn-0.3.6 (default)."
|
||||
echo " -libburn_svn 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."
|
||||
|
@ -43,12 +43,15 @@ then
|
||||
-e 's/<h1 align=center>CDRSKIN<\/h1>/<h1 align=center>man 1 cdrskin<\/h1>/' \
|
||||
-e 's/<body>/<body BGCOLOR="#F5DEB3" TEXT=#000000 LINK=#0000A0 VLINK=#800000>/' \
|
||||
-e 's/<b>Overview of features:<\/b>/\ <BR><b>Overview of features:<\/b>/' \
|
||||
-e 's/<b>General information paragraphs:<\/b>/\ <BR><b>General information paragraphs:<\/b>/' \
|
||||
-e 's/<b>Track recording model:<\/b>/\ <BR><b>Track recording model:<\/b>/' \
|
||||
-e 's/In general there are two types of tracks: data and audio./\ <BR>In general there are two types of tracks: data and audio./' \
|
||||
-e 's/While audio tracks just contain a given/\ <BR>While audio tracks just contain a given/' \
|
||||
-e 's/<b>Write mode selection:<\/b>/\ <BR><b>Write mode selection:<\/b>/' \
|
||||
-e 's/<b>Recordable CD Media:<\/b>/\ <BR><b>Recordable CD Media:<\/b>/' \
|
||||
-e 's/<b>Overwriteable DVD Media:<\/b>/\ <BR><b>Overwriteable DVD Media:<\/b>/' \
|
||||
-e 's/<b>Sequentially Recordable DVD Media:<\/b>/\ <BR><b>Sequentially Recordable DVD Media:<\/b>/' \
|
||||
-e 's/The write modes for DVD+R/\ <BR>The write modes for DVD+R/' \
|
||||
-e 's/<b>Drive preparation and addressing:<\/b>/\ <BR><b>Drive preparation and addressing:<\/b>/' \
|
||||
-e 's/If you only got one CD capable drive/\ <BR>If you only got one CD capable drive/' \
|
||||
-e 's/^Alphabetical list of options/\ <BR>Alphabetical list of options/' \
|
||||
@ -60,7 +63,7 @@ then
|
||||
|
||||
chmod u+rw,go+r,go-w "$htmlpage"
|
||||
echo "Emerged file:"
|
||||
ls -l "$htmlpage"
|
||||
ls -lL "$htmlpage"
|
||||
|
||||
else
|
||||
|
||||
|
@ -10,9 +10,9 @@ 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 this way.
|
||||
Overwriteable media DVD-RAM, DVD+RW and DVD-RW are handled differently than
|
||||
with cdrecord-ProDVD in order to offer TAO-like single track recording.
|
||||
The current development version handles sequential DVD-R[W] like CD-R[W]
|
||||
with TAO and multi-session. Additionally it offers cdrecord-like mode DAO with
|
||||
DVD-R[W].
|
||||
Sequential DVD-R[W] and DVD+R are handled like CD-R[W] with TAO and
|
||||
multi-session. Additionally cdrskin offers cdrecord-ProDVD-like mode DAO
|
||||
with DVD-R[W].
|
||||
|
||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
||||
Many bytes have been copied from the message output of cdrecord
|
||||
@ -23,13 +23,9 @@ About libburn API for burning CD: http://libburnia-api.pykix.org
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Appending sessions to an unclosed CD or DVD-R[W] is restricted to write mode
|
||||
TAO. (Users who have a burner which succeeds with a follow-up session on CD via
|
||||
cdrecord -sao : please contact us.)
|
||||
|
||||
For DVD types other than DVD-RAM, DVD+RW, DVD-RW, DVD-R and for appending
|
||||
sessions to ISO filesystems on DVD other than DVD-RW, DVD-R see the advise
|
||||
to use dvd+rw-tools at the end of this text.
|
||||
For dual layer DVD types and for appending sessions to ISO filesystems on
|
||||
DVD other than DVD-RW, DVD-R, DVD+R see the advise to use dvd+rw-tools at
|
||||
the end of this text.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
@ -71,7 +67,7 @@ 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'
|
||||
0 dev='/dev/sr0' 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.
|
||||
@ -87,10 +83,9 @@ has to offer both, r- and w-permission.
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
The DVD capabilities of cdrskin differ from those of cdrecord-ProDVD. cdrskin
|
||||
lacks of support for DVD+R and for dual layer DVD media. On the other hand it
|
||||
offers TAO-like multi-session with DVD-R[W] and TAO-like single session with
|
||||
overwriteable DVD media. It also offers DAO on DVD-R[W] which is probably the
|
||||
same as the traditional cdrecord-ProDVD write mode.
|
||||
offers TAO-like multi-session with DVD-R[W], DVD+R and TAO-like single session
|
||||
with overwriteable DVD media. It also offers DAO on DVD-R[W] which is probably
|
||||
the same as the traditional cdrecord-ProDVD write mode.
|
||||
|
||||
Non-cdrecord blank mode blank=format_overwrite brings a DVD-RW
|
||||
disc from its initial profile "Sequential Recording" into profile state
|
||||
@ -124,6 +119,29 @@ multi-session. (The default behavior of cdrskin deems me to be preferrable.)
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
assert_write_lba=<lba> allows to ensure that the start block address which
|
||||
was used with the formatter program (e.g. mkisofs -C) matches the start block
|
||||
address which will be used by the upcoming burn.
|
||||
|
||||
E.g. cdrskin aborts with an error message if
|
||||
{{{
|
||||
assert_write_lba=0
|
||||
}}}
|
||||
is given but an appendable media is to be burned which would start ati
|
||||
block 68432.
|
||||
|
||||
|
||||
An ISO-9660 file system image must be prepared according to a particular
|
||||
block address on media. If the prepared address and the real address on media
|
||||
do not match then the filesystem will not be mountable or may even cause system
|
||||
trouble.
|
||||
|
||||
A sequential archive format like afio or star will not necessarily need such
|
||||
a coordination of addresses. It might nevertheless be confusing to a reader
|
||||
if the archive does not start at block 0.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
fifo_start_at=<num> 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
|
||||
@ -210,10 +228,10 @@ for an illustrated example with K3b 0.10 .
|
||||
|
||||
DVD advise:
|
||||
|
||||
For burning of DVD media other than DVD-RAM, DVD+RW, DVD-RW, DVD-R, 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-RAM, DVD+RW, DVD+R,
|
||||
DVD-RW, DVD-R and are also capable of dual layer and even BD discs.
|
||||
For burning of DVD media other than DVD-RAM, DVD+RW, DVD+R, DVD-RW, DVD-R,
|
||||
the cdrskin project currently advises to use Andy Polyakov's dvd+rw-tools
|
||||
which despite their historic name are capable of all the media above
|
||||
and also do dual layer and even BD discs.
|
||||
|
||||
http://fy.chalmers.se/~appro/linux/DVD+RW/tools
|
||||
|
||||
@ -228,10 +246,12 @@ image and finally manipulates the start sectors of this existing image.
|
||||
So for growable ISO filesystems on DVD-RAM or DVD+RW growisofs is the only
|
||||
choice, currently.
|
||||
|
||||
With sequential DVD-R[W] the development version of cdrskin can offer
|
||||
multi-session together with associated options blank=, -multi, -msinfo and
|
||||
-toc. Thus sequential DVD-RW behave much like large CD-RW with possibly more
|
||||
than 99 tracks.
|
||||
|
||||
cdrskin can offer DVD multi-session only with sequential DVD-R[W] and with
|
||||
DVD+R.
|
||||
Associated options blank=, -multi, -msinfo and -toc are available in this case.
|
||||
Thus sequential DVD-RW behave much like large CD-RW with possibly more than 99
|
||||
tracks.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
AC_INIT([libburn], [0.3.1], [http://libburnia.pykix.org])
|
||||
AC_INIT([libburn], [0.3.6], [http://libburnia.pykix.org])
|
||||
AC_PREREQ([2.50])
|
||||
dnl AC_CONFIG_HEADER([config.h])
|
||||
|
||||
@ -19,7 +19,7 @@ dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
|
||||
dnl
|
||||
BURN_MAJOR_VERSION=0
|
||||
BURN_MINOR_VERSION=3
|
||||
BURN_MICRO_VERSION=1
|
||||
BURN_MICRO_VERSION=6
|
||||
BURN_INTERFACE_AGE=0
|
||||
BURN_BINARY_AGE=0
|
||||
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
|
||||
|
10
doc/comments
10
doc/comments
@ -6,9 +6,11 @@
|
||||
@section intro Introduction
|
||||
|
||||
Libburnia is an open-source project for reading, mastering and writing
|
||||
optical discs. For now this means CD-R, CD-RW, DVD-RAM, DVD+RW, DVD-RW, DVD-R.
|
||||
optical discs.
|
||||
For now this means CD-R, CD-RW, DVD-RAM, DVD+RW, DVD+R, DVD-RW, DVD-R.
|
||||
|
||||
Not supported yet are DVD+R, any dual layer media, HD-DVD, BD (blue ray).
|
||||
Not supported yet are dual layer media, HD-DVD, BD (blue ray). Testers for
|
||||
dual layer DVD+/-R are wanted, though.
|
||||
|
||||
The project comprises of several more or less interdependent parts which
|
||||
together strive to be a usable foundation for application development.
|
||||
@ -31,7 +33,7 @@ scope by help of existing cdrecord frontends.
|
||||
|
||||
- libburn is the library by which preformatted data get onto optical media.
|
||||
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
|
||||
/dev/hdX (e.g. on kernel 2.6).
|
||||
/dev/srM or /dev/hdX (e.g. on kernel 2.6).
|
||||
libburn is the foundation of our cdrecord emulation. Its code is
|
||||
independent of cdrecord. Its DVD capabilities are learned from
|
||||
studying the code of dvd+rw-tools and MMC-5 specs. No code but only
|
||||
@ -89,7 +91,7 @@ languages and development tools.
|
||||
libburner is a minimal demo application for the library libburn
|
||||
(see: libburn/libburn.h) as provided on http://libburn.pykix.org .
|
||||
It can list the available devices, can blank a CD-RW or DVD-RW and
|
||||
can burn to CD-R, CD-RW, DVD-RAM, DVD+RW, DVD-RW, DVD-R.
|
||||
can burn to recordable CD and recordable single layer DVD.
|
||||
|
||||
It's main purpose, nevertheless, is to show you how to use libburn and also
|
||||
to serve the libburnia team as reference application. libburner does indeed
|
||||
|
137
doc/cookbook.txt
137
doc/cookbook.txt
@ -5,7 +5,7 @@ Content:
|
||||
- SAO CD Cookbook (CD-R, CD-RW, pure audio or pure data only)
|
||||
- Overwriteable DVD Cookbook (DVD-RAM, DVD+RW, DVD-RW)
|
||||
- Sequential DVD-R[W] Cookbook
|
||||
|
||||
- DVD+R Cookbook
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
TAO Multi-Session CD Cookbook
|
||||
@ -689,6 +689,7 @@ Media type can be recognized by Current Profile from 46h GET CONFIGURATION.
|
||||
DVD-R 0011h
|
||||
DVD-RW Restricted Overwrite 0013h
|
||||
DVD-RW Sequential Recording 0014h
|
||||
(DVD-R/DL Sequential Recording 0015h untested, might be single-session only)
|
||||
|
||||
There are two approaches for writing to sequential DVD-R[W]: DAO and
|
||||
Incremental. Not all media and drives offer Incremental which allows
|
||||
@ -701,6 +702,8 @@ track and it demands an exactly predicted track size.
|
||||
- DAO writing
|
||||
- Obtaining DVD-R[W] multi-session info for extending ISO-9660 filesystems
|
||||
- Obtaining a Table Of Content from DVD-R[W]
|
||||
- Hearsay about DVD-R/DL (Dual Layer)
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
About overwriteable, blank, appendable and finalized DVD-R[W] media :
|
||||
@ -870,6 +873,7 @@ No further finalization is necessary. (I.e. no 5Bh CLOSE TRACK SESSION.)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Obtaining DVD-R[W] multi-session info for extending ISO-9660 filesystems :
|
||||
(valid for DVD+R too)
|
||||
|
||||
Like with CD it is necessary to obtain the two numbers for mkisofs option -C
|
||||
in order to prepare a ISO-9660 filesystem image which by its inner pointers
|
||||
@ -922,7 +926,8 @@ Session from 51h READ DISC INFORMATION.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Obtaining a Table Of Content from DVD-R[W] :
|
||||
Obtaining a Table Of Content from DVD-R[W]:
|
||||
(valid for DVD+R too)
|
||||
|
||||
The raw TOC entries from 43h READ TOC/PMA/ATIP Format 0010b as described with
|
||||
CD media are not available with non-CD.
|
||||
@ -962,5 +967,133 @@ model. Their start address is computed from the start and size of the last
|
||||
track of the session.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Hearsay about DVD-R/DL (Dual Layer) :
|
||||
|
||||
DVD-R/DL can assume profile 0015h DVD-R Dual Layer Sequential which is supposed
|
||||
to behave like DVD-R or 0016h DVD-R Dual Layer Jump which has no counterpart
|
||||
with DVD-R.
|
||||
|
||||
A half-sentence in mmc5r03c.pdf 6.3.3.3.3 might indicate that closing a session
|
||||
by 5Bh CLOSE TRACK SESSION Close Function 010b overrides the multi-session bits
|
||||
in mode page 05h.
|
||||
growisofs applies this function in case of not DAO, though. A comment in
|
||||
growisofs_mmc.cpp states: "// DVD-R DL Seq has no notion of multi-session".
|
||||
I am not reading this from the specs - but not explicitely the contrary either.
|
||||
|
||||
For now libburn will close the session but there is a macro prepared in
|
||||
libburn/write.c Libburn_dvd_r_dl_multi_no_close_sessioN which will suppress
|
||||
close session if multi-session is demanded.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
INCOMPLETE YET
|
||||
|
||||
DVD+R Cookbook
|
||||
-------------------------------------------------------------------------------
|
||||
Inspired by reading mmc5r03c.pdf from http://www.t10.org/ftp/t10/drafts/mmc5/
|
||||
backed by Andy Polyakov's http://fy.chalmers.se/~appro/linux/DVD+RW/tools ,
|
||||
|
||||
For libburnia.pykix.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Media type can be recognized by Current Profile from 46h GET CONFIGURATION.
|
||||
(mmc5r03c.pdf 6.6.2.1)
|
||||
DVD+R 001bh
|
||||
DVD+R/DL 002bh
|
||||
|
||||
- About empty, appendable and finalized DVD+R
|
||||
- Writing a Pseudo Session to DVD+R
|
||||
- >>> Hearsay about DVD+R/DL (Dual Layer) :
|
||||
|
||||
The following two chapters of the Sequential DVD-R[W] Cookbook are valid for
|
||||
DVD+R media too:
|
||||
- Obtaining DVD-R[W] multi-session info for extending ISO-9660 filesystems
|
||||
- Obtaining a Table Of Content from DVD-R[W]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
About blank, appendable and finalized DVD+R :
|
||||
|
||||
In the beginning a DVD+R holds an empty session and the Incomplete Fragment.
|
||||
From these one may spawn reserved fragments or one may write directly to
|
||||
the incomplete fragment. As soon as this is done the empty session becomes the
|
||||
open session which finally needs to get closed. By closing fragments and
|
||||
session a new empty session with empty Incomplete Fragment gets spawned.
|
||||
So the disc stays appendable.
|
||||
|
||||
A DVD+R may hold 153 closed sessions with a single track each.
|
||||
The open session may hold up to 15 open fragments. But on closure of the
|
||||
session those fragments together form a single logical track. So one will
|
||||
usually only use a single fragment for sequential writing.
|
||||
(mmc5r03c.pdf 4.3.6.2)
|
||||
|
||||
The disc may get finalized by another close command so that no more data can
|
||||
be written.
|
||||
(mmc5r03c.pdf 6.3.3.4.4)
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Writing a Pseudo Session to DVD+R :
|
||||
|
||||
Session writing has to be pseudo because only one logical track per session
|
||||
can be distinguished. So actually there have to be written multiple sessions
|
||||
to mark multiple tracks. The pseudo session cannot get marked on disc and thus
|
||||
the tracks of a pseudo session cannot be grouped accordingly in a TOC.
|
||||
|
||||
Speed can be influenced by B6h SET STREAMING , speed capabilities can be
|
||||
inquired by ACh GET PERFORMANCE. It is advised to set only speeds and sizes
|
||||
which are returned by ACh.
|
||||
(mmc5r03c.pdf 6.39 SET STREAMING, 6.8 GET PERFORMANCE)
|
||||
|
||||
No mode page 05h is to be sent.
|
||||
growisofs sends a page but the specs clearly state that one shall not do.
|
||||
(mmc5r03c.pdf 7.5.3)
|
||||
|
||||
It is optional wether a track size is reserved in advance or not. Eventually
|
||||
this is done by 53h RESERVE TRACK, RMZ=ARSV=0. Reservation size should better
|
||||
already be aligned to 32 KiB.
|
||||
(mmc5r03c.pdf 6.31)
|
||||
The specs promise to pad up the track if not enough data get written.
|
||||
(mmc5r03c.pdf 6.3.3.4.2)
|
||||
|
||||
Next Writeable Address is fetched from the reply of 52h READ TRACK INFORMATION
|
||||
with track number FFh.
|
||||
(mmc5r03c.pdf 6.27)
|
||||
Since the fixely set write type is 16-block packet, full 32 kB buffers have
|
||||
to be transmitted via 2Ah WRITE.
|
||||
(mmc5r03c.pdf 4.3.6.2.2)
|
||||
|
||||
When writing is done, it is mandatory to force the drive's buffer to media by
|
||||
35h SYNCHRONIZE CACHE.
|
||||
(mmc5r03c.pdf 6.41)
|
||||
|
||||
The written fragment (i.e. track-to-be) has to be closed by 5Bh CLOSE TRACK
|
||||
SESSION Close Function 001b.
|
||||
(mmc5r03c.pdf 6.3.3.4.2)
|
||||
libburn obtains the necessary logical track number from Last Track Number in
|
||||
Last Session from the reply of 51h READ DISC INFORMATION requesting
|
||||
Data Type 000b.
|
||||
(mmc5r03c.pdf 6.22)
|
||||
|
||||
After each track 5Bh CLOSE TRACK SESSION Close Function 010b with Logical Track
|
||||
Number 0 closes the DVD+R session but keeps the media appendable.
|
||||
(mmc5r03c.pdf 6.3.3.4.3)
|
||||
If the media shall not stay appendable then the last DVD+R session is to be
|
||||
closed by Close Function 101b rather than 010b. This finalizes the media
|
||||
"with minimal radius".
|
||||
(mmc5r03c.pdf 6.3.3.4.4)
|
||||
|
||||
Note: growisofs has code for that gesture but explicitly avoids to use it.
|
||||
Instead it recommends to fill up the media with zeros.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Hearsay about DVD+R/DL (Dual Layer) :
|
||||
|
||||
>>>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
388
doc/ddlp.txt
Normal file
388
doc/ddlp.txt
Normal file
@ -0,0 +1,388 @@
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Users of modern desktop Linux installations report misburns with CD/DVD
|
||||
recording due to concurrency problems.
|
||||
|
||||
This text describes two locking protocols which have been developed by our
|
||||
best possible effort. But finally they rather serve as repelling example of
|
||||
what would be needed in user space to achieve an insufficient partial solution.
|
||||
|
||||
Ted Ts'o was so friendly to help as critic with his own use cases. It turned
|
||||
out that we cannot imagine a way in user space how to cover reliably the needs
|
||||
of callers of libblkid and the needs of our burn programs.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Content:
|
||||
|
||||
The "Delicate Device Locking Protocol" shall demonstrate our sincere
|
||||
consideration of the problem.
|
||||
|
||||
"What are the Stumble Stones ?" lists reasons why the effort finally failed.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
Delicate Device Locking Protocol
|
||||
(a joint sub project of cdrkit and libburnia)
|
||||
(contact: scdbackup@gmx.net )
|
||||
|
||||
Our projects provide programs which allow recording of data on CD or DVD.
|
||||
We encounter an increasing number of bug reports about spoiled burn runs and
|
||||
wasted media which obviously have one common cause: interference by other
|
||||
programs which access the drive's device files.
|
||||
There is some riddling about which gestures exactly are dangerous for
|
||||
ongoing recordings or can cause weirdly misformatted drive replies to MMC
|
||||
commands.
|
||||
We do know, nevertheless, that these effects do not occur if no other program
|
||||
accesses a device file of the drive while our programs use it.
|
||||
|
||||
DDLP shall help to avoid collisions between programs in the process of
|
||||
recording to a CD or DVD drive and other programs which access that drive.
|
||||
The protocol intends to provide advisory locking. So any good-willing program
|
||||
has to take some extra precautions to participate.
|
||||
|
||||
If a program does not feel vulnerable to disturbance, then the precautions
|
||||
impose much less effort than if the program feels the need for protection.
|
||||
|
||||
Two locking strategies are specified:
|
||||
DDLP-A operates on device files only. It is very Linux specific.
|
||||
DDLP-B adds proxy lock files, inspired by FHS /var/lock standard.
|
||||
|
||||
|
||||
DDLP-A
|
||||
|
||||
This protocol relies on the hardly documented feature open(O_EXCL | O_RDWR)
|
||||
with Linux device files and on POSIX compliant fcntl(F_SETLK).
|
||||
|
||||
Other than the original meaning of O_EXCL with creating regular files, the
|
||||
effect on device files is mutual exclusion of access. I.e. if one
|
||||
filedescriptor is open on that combination of major-minor device number, then
|
||||
no other open(O_EXCL) will succeed. But open() without O_EXCL would succeed.
|
||||
So this is advisory and exclusive locking.
|
||||
With kernel 2.6 it seems to work on all device drivers which might get used
|
||||
to access a CD/DVD drive.
|
||||
|
||||
The vulnerable programs shall not start their operation before they occupied a
|
||||
wide collection of drive representations.
|
||||
Non-vulnerable programs shall take care to detect the occupation of _one_ such
|
||||
representation.
|
||||
|
||||
So for Friendly Programs
|
||||
|
||||
A program which does not feel vulnerable to disturbance is urged to access
|
||||
CD/DVD drives by opening a file descriptor which will uphold the lock
|
||||
as long as it does not get closed. There are two alternative ways to achieve
|
||||
this.
|
||||
Very reliable is
|
||||
|
||||
open( some_path , O_EXCL | ...)
|
||||
|
||||
But O_EXCL imposes restrictions and interferences:
|
||||
- O_EXCL | O_RDONLY does not succeed with /dev/sg* !
|
||||
- O_EXCL cannot provide shared locks for programs which only want to lock
|
||||
against burn programs but not against their own peers.
|
||||
- O_EXCL keeps from obtaining information by harmless activities.
|
||||
- O_EXCL already has a meaning with devices which are mounted as filesystems.
|
||||
This priority meaning is more liberal than the one needed for CD/DV recording
|
||||
protection.
|
||||
|
||||
So it may be necessary to use a cautious open() without O_EXCL and to aquire
|
||||
a POSIX lock via fcntl(). "Cautious" means to add O_NDELAY to the flags of
|
||||
open(), because this is declared to avoid side effects within open().
|
||||
|
||||
With this gesture it is important to use the paths expected by our burn
|
||||
programs: /dev/sr[0..255] /dev/scd[0..255] /dev/sg[0..255] /dev/hd[a..z]
|
||||
because fcntl(F_SETLK) does not lock the device but only a device-inode.
|
||||
|
||||
std_path = one of the standard device files:
|
||||
/dev/sr[0..255] /dev/scd[0..255] /dev/sg[0..255] /dev/hd[a..z]
|
||||
or a symbolic link pointing to one of them.
|
||||
open( std_path , ... | O_NDELAY)
|
||||
fcntl(F_SETLK) and close() on failure
|
||||
... eventually disable O_NDELAY by fcntl(F_SETFL) ...
|
||||
|
||||
There is a pitfall mentioned in man 2 fcntl :
|
||||
"locks are automatically released [...] if it closes any file descriptor
|
||||
referring to a file on which locks are held. This is bad [...]"
|
||||
So you may have to re-lock after some temporary fd got closed.
|
||||
|
||||
|
||||
Vulnerable Programs
|
||||
|
||||
For programs which do feel vulnerable, O_EXCL would suffice for the /dev/hd*
|
||||
device file family and their driver. But USB and SATA recorders appear with
|
||||
at least two different major-minor combinations simultaneously.
|
||||
One as /dev/sr* alias /dev/scd*, the other as /dev/sg*.
|
||||
The same is true for ide-scsi or recorders attached to SCSI controllers.
|
||||
|
||||
So, in order to lock any access to the recorder, one has to open(O_EXCL)
|
||||
not only the device file that is intended for accessing the recorder but also
|
||||
a device file of any other major-minor representation of the recorder.
|
||||
This is done via the SCSI address parameter vector (Host,Channel,Id,Lun)
|
||||
and a search on standard device file paths /dev/sr* /dev/scd* /dev/sg*.
|
||||
In this text the alternative device representations are called "siblings".
|
||||
|
||||
For finding them, it is necessary to apply open() to many device files which
|
||||
might be occupied by delicate operations. On the other hand it is very
|
||||
important to occupy all reasonable representations of the drive.
|
||||
So the reading of the (Host,Channel,Id,Lun) parameters demands an
|
||||
open(O_RDONLY | O_NDELAY) _without_ fcntl() in order to find the outmost
|
||||
number of representations among the standard device files. Only ioctls
|
||||
SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER are applied.
|
||||
Hopefully this gesture is unable to cause harmful side effects on kernel 2.6.
|
||||
|
||||
At least one file of each class sr, scd and sg should be found to regard
|
||||
the occupation as satisfying. Thus corresponding sr-scd-sg triplets should have
|
||||
matching ownerships and access permissions.
|
||||
One will have to help the sysadmins to find those triplets.
|
||||
|
||||
A spicy detail is that sr and scd may be distinct device files for the same
|
||||
major-minor combination. In this case fcntl() locks on both are needed
|
||||
but O_EXCL can only be applied to one of them.
|
||||
|
||||
|
||||
An open and free implementation ddlpa.[ch] is provided as
|
||||
http://libburnia.pykix.org/browser/libburn/trunk/libburn/ddlpa.h?format=txt
|
||||
http://libburnia.pykix.org/browser/libburn/trunk/libburn/ddlpa.c?format=txt
|
||||
The current version of this text is
|
||||
http://libburnia.pykix.org/browser/libburn/trunk/doc/ddlp.txt?format=txt
|
||||
|
||||
Put ddlpa.h and ddlpa.c into the same directory and compile as test program by
|
||||
cc -g -Wall -DDDLPA_C_STANDALONE -o ddlpa ddlpa.c
|
||||
|
||||
Use it to occupy a drive's representations for a given number of seconds
|
||||
./ddlpa /dev/sr0 300
|
||||
|
||||
It should do no harm to any of your running activities.
|
||||
If it does: Please, please alert us.
|
||||
|
||||
Your own programs should not be able to circumvent the occupation if they
|
||||
obey above rules for Friendly Programs.
|
||||
Of course ./ddlpa should be unable to circumvent itself.
|
||||
|
||||
A successfull occupation looks like
|
||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/scd0") = "/dev/sr0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sr0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/scd0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sg0"
|
||||
DDLPA_DEBUG: ddlpa_occupy() : '/dev/scd0'
|
||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/sg0'
|
||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/sr0'
|
||||
---------------------------------------------- Lock gained
|
||||
ddlpa: opened /dev/sr0
|
||||
ddlpa: opened siblings: /dev/scd0 /dev/sg0
|
||||
slept 1 seconds of 300
|
||||
|
||||
Now an attempt via device file alias /dev/NEC must fail:
|
||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/NEC") = "/dev/sg0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sr0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/scd0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sg0"
|
||||
Cannot exclusively open '/dev/sg0'
|
||||
Reason given : Failed to open O_RDWR | O_NDELAY | O_EXCL : '/dev/sr0'
|
||||
Error condition : 16 'Device or resource busy'
|
||||
|
||||
With hdc, of course, things are trivial
|
||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/hdc") = "/dev/hdc"
|
||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/hdc'
|
||||
---------------------------------------------- Lock gained
|
||||
ddlpa: opened /dev/hdc
|
||||
slept 1 seconds of 1
|
||||
|
||||
|
||||
Ted Ts'o provided program open-cd-excl which allows to explore open(2) on
|
||||
device files with combinations of read-write, O_EXCL, and fcntl().
|
||||
(This does not mean that Ted endorsed our project yet. He helps exploring.)
|
||||
|
||||
Friendly in the sense of DDLP-A would be any run which uses at least one of
|
||||
the options -e (i.e. O_EXCL) or -f (i.e. F_SETLK, applied to a file
|
||||
descriptor which was obtained from a standard device file path).
|
||||
The code is available under GPL at
|
||||
http://libburnia.pykix.org/browser/libburn/trunk/test/open-cd-excl.c?format=txt
|
||||
To be compiled by
|
||||
cc -g -Wall -o open-cd-excl open-cd-excl.c
|
||||
|
||||
Options:
|
||||
-e : open O_EXCL
|
||||
-f : aquire lock by fcntl(F_SETLK) after sucessful open
|
||||
-i : do not wait in case of success but exit 0 immediately
|
||||
-r : open O_RDONLY , with -f use F_RDLCK
|
||||
-w : open O_RDWR , with -f use F_WRLCK
|
||||
plus the path of the devce file to open.
|
||||
|
||||
Friendly Programs would use gestures like:
|
||||
./open-cd-excl -e -r /dev/sr0
|
||||
./open-cd-excl -e -w /dev/sg1
|
||||
./open-cd-excl -e -w /dev/black-drive
|
||||
./open-cd-excl -f -r /dev/sg1
|
||||
./open-cd-excl -e -f -w /dev/sr0
|
||||
|
||||
Ignorant programs would use and cause potential trouble by:
|
||||
./open-cd-excl -r /dev/sr0
|
||||
./open-cd-excl -w /dev/sg1
|
||||
./open-cd-excl -f -w /dev/black-drive
|
||||
where "/dev/black-drive" is _not_ a symbolic link to
|
||||
any of /dev/sr* /dev/scd* /dev/sg* /dev/hd*, but has an own inode.
|
||||
|
||||
Prone to failure without further reason is:
|
||||
./open-cd-excl -e -r /dev/sg1
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
DDLP-B
|
||||
|
||||
This protocol relies on proxy lock files in some filesystem directory. It can
|
||||
be embedded into DDLP-A or it can be used be used standalone, outside DDLP-A.
|
||||
|
||||
DDLP-A shall be kept by DDLP-B from trying to access any device file which
|
||||
might already be in use. There is a problematic gesture in DDLP-A when SCSI
|
||||
address parameters are to be retrieved. For now this gesture seems to be
|
||||
harmless. But one never knows.
|
||||
Vice versa DDLP-B may get from DDLP-A the service to search for SCSI device
|
||||
file siblings. So they are best as a couple.
|
||||
|
||||
But they are not perfect. Not even as couple. fcntl() locking is flawed.
|
||||
|
||||
|
||||
There is a proxy file locking protocol described in FHS:
|
||||
http://www.pathname.com/fhs/pub/fhs-2.3.html#VARLOCKLOCKFILES
|
||||
|
||||
But it has shortcommings (see below). Decisive obstacle for its usage are the
|
||||
possibility for stale locks and the lack of shared locks.
|
||||
|
||||
DDLP-B rather defines a "path prefix" which is advised to be
|
||||
/tmp/ddlpb-lock-
|
||||
This prefix will get appended "device specific suffixes" and then form the path
|
||||
of a "lockfile".
|
||||
Not the existence of a lockfile but its occupation by an fcntl(F_SETLK) will
|
||||
constitute a lock. Lockfiles may get prepared by the sysadmin in directories
|
||||
where normal users are not allowed to create new files. Their rw-permissions
|
||||
then act as additional access restriction to the device files.
|
||||
The use of fcntl(F_SETLK) will prevent any stale locks after the process ended.
|
||||
It will also allow to obtain shared locks as well as exclusive locks.
|
||||
|
||||
There are two classes of device specific suffixes:
|
||||
|
||||
- Device file path suffix. Absolute paths only. "/" gets replaced by "_-".
|
||||
Eventual "_-" in path gets replaced by "_-_-". The leading group of "_-"
|
||||
is always interpreted as a group of "/", though. E.g.:
|
||||
/dev/sr0 <-> "_-dev_-sr0"
|
||||
/mydevs/burner/nec <-> "_-mydevs_-burners_-nec"
|
||||
/dev/rare_-name <-> "_-dev_-rare_-_-name"
|
||||
///strange/dev/x <-> "_-_-_-strange_-dev_-x"
|
||||
|
||||
- st_rdev suffix. A hex representation of struct stat.st_rdev. Capital letters.
|
||||
The number of characters is pare with at most one leading 0. I.e. bytewise
|
||||
printf("%2.2X") beginning with the highest order byte that is not zero.
|
||||
E.g. : "0B01", "2200", "01000000000004001"
|
||||
|
||||
If a lockfile does not exist and cannot be created then this shall not keep
|
||||
a program from working on a device. But if a lockfile exists and if permissions
|
||||
or locking state do not allow to obtain a lock of the appropirate type, then
|
||||
this shall prevent any opening of device file in question resp. shall cause
|
||||
immediate close(2) of an already opened device file.
|
||||
|
||||
The vulnerable programs shall not start their operation before they locked a
|
||||
wide collection of drive representations.
|
||||
|
||||
Non-vulnerable programs shall take care to lock the suffix resulting from the
|
||||
path they will be using and the suffix from the st_rdev from that path.
|
||||
The latter is to be obtained by call stat(2).
|
||||
|
||||
Locks get upheld as long as their file descriptor is not closed or no other
|
||||
incident as described in man 2 fcntl releases the lock.
|
||||
|
||||
So with shared locks there are no imandatory further activities after they
|
||||
have been obtained.
|
||||
|
||||
In case of exclusive locks, the file has to have been opened for writing and
|
||||
must be truncated to 0 bytes length immediately after obtaining the lock.
|
||||
When releasing an exclusive lock it is a nice gesture to
|
||||
already do this truncation.
|
||||
Then a /var/lock/ compatible first line has to be written.
|
||||
E.g. by: printf("%10u\n",(unsigned) getpid()) yielding " 1230\n".
|
||||
|
||||
Any further lines are optional. They shall have the form Name=Value and must
|
||||
be printable cleartext. If such further lines exist, then the last one must
|
||||
have the name "endmark".
|
||||
Defined Names are:
|
||||
hostid =hostname of the machine where the process number of line 1 is valid
|
||||
start =start time of lock in seconds since 1970. E.g: 1177147634.592410
|
||||
program =self chosen name of the program which obtained the lock
|
||||
argv0 =argv[0] of that program
|
||||
mainpath =device file path which will be used for operations by that program
|
||||
path =device file path which lead to the lock
|
||||
st_rdev =st_rdev suffix which is associated with path
|
||||
scsi_hcil=eventual SCSI parameters Host,Channel,Id,Lun
|
||||
scsi_bus =eventual SCSI parameter Bus
|
||||
endmark =declares the info as complete.
|
||||
Any undefined name or a line without "=" shall be handled as comment.
|
||||
"=" in the value is allowed. Any line beginning with an "=" character is an
|
||||
extension of the previous value.
|
||||
|
||||
If programs encounter an exclusive lock, they are invited to read the content
|
||||
of the lockfile anyway. But they should be aware that the info might be in the
|
||||
progress of emerging. There is a race condition possible in the short time
|
||||
between obtaining the exclusive lock and erasing the file content.
|
||||
If it is not crucial to obtain most accurate info then one may take the newline
|
||||
of the first line as indicator of a valid process number and the "endmark"
|
||||
name as indicator that the preceding lines are valid.
|
||||
Very cautious readers should obtain the info twice with a decent waiting period
|
||||
inbetween. Only if both results are identical they should be considered valid.
|
||||
|
||||
|
||||
There is no implementation of DDLP-B yet.
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
What are the Stumble Stones ?
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Any of the considered locking mechanisms has decisive shortcommings
|
||||
which keeps it from being the solution to all known legitimate use cases.
|
||||
|
||||
The attempt has failed to compose a waterproof locking mechanism from means of
|
||||
POSIX, FHS and from hardly documented Linux open(O_EXCL) on device files.
|
||||
The resulting mechanisms would need about 1000 lines of code and still do
|
||||
not close all gaps resp. cover the well motivated use cases.
|
||||
This attempt you see above: DDLP-A and DDLP-B.
|
||||
|
||||
|
||||
Summary of the reasons why the established locking mechanisms do not suffice:
|
||||
|
||||
None of the mechanisms can take care of the double device driver identity
|
||||
sr versus sg. To deduce the one device file from the other involves the need
|
||||
to open many other (possibly unrelated) device files with the risk to disturb
|
||||
them.
|
||||
This hard to solve problem is aggravated by the following facts.
|
||||
|
||||
Shortcommings of Linux specific open(O_EXCL) :
|
||||
|
||||
- O_EXCL | O_RDONLY does not succeed with /dev/sg*
|
||||
- O_EXCL cannot provide shared locks for programs which only want to lock
|
||||
against burn programs but not against their own peers.
|
||||
- O_EXCL keeps from obtaining information by harmless activities.
|
||||
- O_EXCL already has a meaning with devices which are mounted as filesystems.
|
||||
This priority meaning is more liberal than the one needed for CD/DV recording
|
||||
protection.
|
||||
|
||||
Shortcommings of POSIX fcntl(F_SETLK) :
|
||||
|
||||
- fcntl() demands an open file descriptor. open(2) might have side effects.
|
||||
- fcntl() locks can be released inadvertedly by submodules which just open and
|
||||
close the same file (inode ?) without refering to fcntl locks in any way.
|
||||
See man 2 fcntl "This is bad:".
|
||||
Stacking of software modules is a widely used design pattern. But fcntl()
|
||||
cannot cope with that.
|
||||
|
||||
Shortcommings of FHS /var/lock/ :
|
||||
|
||||
- Stale locks are possible.
|
||||
- It is necessary to create a file (using the _old_ meaning of O_EXCL flag ?)
|
||||
but /var/lock/ might not be available early during system start and it often
|
||||
has restrictive permission settings.
|
||||
- There is no way to indicate a difference between exclusive and shared locks.
|
||||
- The FHS prescription relies entirely on the basename of the device file path.
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
#include <a ssert.h>
|
||||
@ -236,10 +237,17 @@ void burn_disc_erase(struct burn_drive *drive, int fast)
|
||||
/* ts A70103 moved up from burn_disc_erase_sync() */
|
||||
/* ts A60825 : allow on parole to blank appendable CDs */
|
||||
/* ts A70131 : allow blanking of overwriteable DVD-RW (profile 0x13) */
|
||||
if ( ! (drive->status == BURN_DISC_FULL ||
|
||||
(drive->status == BURN_DISC_APPENDABLE &&
|
||||
! libburn_back_hack_42) ||
|
||||
drive->current_profile == 0x13 ) ) {
|
||||
/* ts A70216 : allow blanking of CD-RW or DVD-RW in any regular state
|
||||
and of any kind of full media */
|
||||
if ((drive->current_profile != 0x0a &&
|
||||
drive->current_profile != 0x13 &&
|
||||
drive->current_profile != 0x14 &&
|
||||
drive->status != BURN_DISC_FULL)
|
||||
||
|
||||
(drive->status != BURN_DISC_FULL &&
|
||||
drive->status != BURN_DISC_APPENDABLE &&
|
||||
drive->status != BURN_DISC_BLANK)
|
||||
) {
|
||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
||||
0x00020130,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
@ -325,7 +333,11 @@ static void *write_disc_worker_func(struct w_list *w)
|
||||
void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
{
|
||||
struct write_opts o;
|
||||
char reasons[BURN_REASONS_LEN+80];
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
int i, j, mode, mixed_mode = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/* For the next lines any return indicates failure */
|
||||
opts->drive->cancel = 1;
|
||||
@ -353,10 +365,37 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
"Drive capabilities not inquired yet", 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ts A70219 : intended to replace all further tests here and many
|
||||
tests in burn_*_write_sync()
|
||||
*/
|
||||
strcpy(reasons, "Write job parameters are unsuitable:\n");
|
||||
if (burn_precheck_write(opts, disc, reasons + strlen(reasons), 1)
|
||||
== BURN_WRITE_NONE) {
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
opts->drive->global_index, 0x00020139,
|
||||
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
|
||||
reasons, 0, 0);
|
||||
#else
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
opts->drive->global_index, 0x00020139,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
reasons, 0, 0);
|
||||
return;
|
||||
#endif /* Libburn_precheck_write_ruleS */
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* <<< covered burn_precheck_write() */
|
||||
/* ts A61009 : obsolete Assert in sector_headers() */
|
||||
if (! burn_disc_write_is_ok(opts, disc)) /* issues own msgs */
|
||||
if (! burn_disc_write_is_ok(opts, disc, 0)) /* issues own msgs */
|
||||
return;
|
||||
|
||||
/* <<< covered burn_precheck_write() */
|
||||
/* ts A70122 : libburn SAO code mishandles mode changes */
|
||||
for (i = 0; i < disc->sessions; i++) {
|
||||
if (disc->session[i]->tracks <= 0)
|
||||
@ -373,6 +412,7 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
"Cannot mix data and audio in SAO mode", 0, 0);
|
||||
return;
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
opts->drive->cancel = 0; /* End of the return = failure area */
|
||||
|
||||
|
614
libburn/ddlpa.c
Normal file
614
libburn/ddlpa.c
Normal file
@ -0,0 +1,614 @@
|
||||
|
||||
/* ddlpa
|
||||
Implementation of Delicate Device Locking Protocol level A.
|
||||
Copyright (C) 2007 Thomas Schmitt <scdbackup@gmx.net>
|
||||
Provided under any of the following licenses: GPL, LGPL, BSD. Choose one.
|
||||
|
||||
|
||||
Compile as test program:
|
||||
|
||||
cc -g -Wall \
|
||||
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
|
||||
-DDDLPA_C_STANDALONE -o ddlpa ddlpa.c
|
||||
|
||||
The system macros enable 64-bit off_t and open(2) flag O_LARGEFILE, which
|
||||
are not absolutely necessary but explicitely take into respect that
|
||||
our devices can offer more than 2 GB of addressable data.
|
||||
|
||||
Run test program:
|
||||
|
||||
./ddlpa /dev/sr0 15
|
||||
./ddlpa 0,0,0 15
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
||||
|
||||
/* All callers of ddlpa must do this */
|
||||
#include "ddlpa.h"
|
||||
|
||||
|
||||
/* 1 = Enable progress message on stderr, 0 = normal silent operation */
|
||||
static int ddlpa_debug_mode = 1;
|
||||
|
||||
|
||||
/* #define _GNU_SOURCE or _LARGEFILE64_SOURCE to get real O_LARGEFILE */
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
|
||||
/* ----------------------- private -------------------- */
|
||||
|
||||
|
||||
static int ddlpa_new(struct ddlpa_lock **lck, int o_flags, int ddlpa_flags)
|
||||
{
|
||||
int i;
|
||||
struct ddlpa_lock *o;
|
||||
|
||||
o = *lck = (struct ddlpa_lock *) malloc(sizeof(struct ddlpa_lock));
|
||||
if (o == NULL)
|
||||
return ENOMEM;
|
||||
for (i = 0; i < sizeof(struct ddlpa_lock); i++)
|
||||
((char *) o)[i] = 0;
|
||||
o->path = NULL;
|
||||
o->fd = -1;
|
||||
for (i = 0; i < DDLPA_MAX_SIBLINGS; i++)
|
||||
o->sibling_fds[i] = -1;
|
||||
o->errmsg = NULL;
|
||||
|
||||
o->o_flags = o_flags;
|
||||
o->ddlpa_flags = ddlpa_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_enumerate(struct ddlpa_lock *o, int *idx,
|
||||
char path[DDLPA_MAX_STD_LEN + 1])
|
||||
{
|
||||
if (*idx < 0)
|
||||
*idx = 0;
|
||||
|
||||
if (*idx < 26)
|
||||
sprintf(path, "/dev/hd%c", 'a' + *idx);
|
||||
else if (*idx < 256 + 26)
|
||||
sprintf(path, "/dev/sr%d", *idx - 26);
|
||||
else if (*idx < 2 * 256 + 26)
|
||||
sprintf(path, "/dev/scd%d", *idx - 256 - 26);
|
||||
else if (*idx < 3 * 256 + 26)
|
||||
sprintf(path, "/dev/sg%d", *idx - 2 * 256 - 26);
|
||||
else
|
||||
return 1;
|
||||
(*idx)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_std_by_rdev(struct ddlpa_lock *o)
|
||||
{
|
||||
int idx = 0;
|
||||
char try_path[DDLPA_MAX_STD_LEN+1];
|
||||
struct stat path_stbuf, try_stbuf;
|
||||
|
||||
if (!o->path_is_valid)
|
||||
return EFAULT;
|
||||
if (stat(o->path, &path_stbuf) == -1)
|
||||
return errno;
|
||||
|
||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
||||
if (stat(try_path, &try_stbuf) == -1)
|
||||
continue;
|
||||
if (path_stbuf.st_rdev != try_stbuf.st_rdev)
|
||||
continue;
|
||||
strcpy(o->std_path, try_path);
|
||||
|
||||
if (ddlpa_debug_mode)
|
||||
fprintf(stderr,
|
||||
"DDLPA_DEBUG: ddlpa_std_by_rdev(\"%s\") = \"%s\"\n",
|
||||
o->path, o->std_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
|
||||
/* Caution : these tests are valid only with standard paths */
|
||||
|
||||
static int ddlpa_is_scsi(struct ddlpa_lock *o, char *path)
|
||||
{
|
||||
return (strncmp(path, "/dev/s", 6) == 0);
|
||||
}
|
||||
|
||||
static int ddlpa_is_sg(struct ddlpa_lock *o, char *path)
|
||||
{
|
||||
return (strncmp(path, "/dev/sg", 7) == 0);
|
||||
}
|
||||
|
||||
static int ddlpa_is_sr(struct ddlpa_lock *o, char *path)
|
||||
{
|
||||
return (strncmp(path, "/dev/sr", 7) == 0);
|
||||
}
|
||||
|
||||
static int ddlpa_is_scd(struct ddlpa_lock *o, char *path)
|
||||
{
|
||||
return (strncmp(path, "/dev/scd", 8) == 0);
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_fcntl_lock(struct ddlpa_lock *o, int fd, int l_type)
|
||||
{
|
||||
struct flock lockthing;
|
||||
int ret;
|
||||
|
||||
memset(&lockthing, 0, sizeof(lockthing));
|
||||
lockthing.l_type = l_type;
|
||||
lockthing.l_whence = SEEK_SET;
|
||||
lockthing.l_start = 0;
|
||||
lockthing.l_len = 0;
|
||||
ret = fcntl(fd, F_SETLK, &lockthing);
|
||||
if (ret == -1)
|
||||
return EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_occupy(struct ddlpa_lock *o, char *path, int *fd,
|
||||
int no_o_excl)
|
||||
{
|
||||
int ret, o_flags, o_rw, l_type;
|
||||
char *o_rwtext;
|
||||
|
||||
o_flags = o->o_flags | O_NDELAY;
|
||||
if(!no_o_excl)
|
||||
o_flags |= O_EXCL;
|
||||
o_rw = (o_flags) & (O_RDONLY | O_WRONLY | O_RDWR);
|
||||
o_rwtext = (o_rw == O_RDONLY ? "O_RDONLY" :
|
||||
(o_rw == O_WRONLY ? "O_WRONLY" :
|
||||
(o_rw == O_RDWR ? "O_RDWR " : "O_?rw-mode?")));
|
||||
|
||||
*fd = open(path, o_flags);
|
||||
if (*fd == -1) {
|
||||
o->errmsg = malloc(strlen(path)+160);
|
||||
if (o->errmsg)
|
||||
sprintf(o->errmsg,
|
||||
"Failed to open %s | O_NDELAY %s: '%s'",
|
||||
o_rwtext,
|
||||
(o_flags & O_EXCL ? "| O_EXCL " : ""), path);
|
||||
return (errno ? errno : EBUSY);
|
||||
}
|
||||
if (o_rw == O_RDWR || o_rw == O_WRONLY)
|
||||
l_type = F_WRLCK;
|
||||
else
|
||||
l_type = F_RDLCK;
|
||||
ret = ddlpa_fcntl_lock(o, *fd, l_type);
|
||||
if (ret) {
|
||||
o->errmsg = malloc(strlen(path)+160);
|
||||
if (o->errmsg)
|
||||
sprintf(o->errmsg,
|
||||
"Failed to lock fcntl(F_WRLCK) : '%s'",path);
|
||||
close(*fd);
|
||||
*fd = -1;
|
||||
return ret;
|
||||
}
|
||||
if (ddlpa_debug_mode)
|
||||
fprintf(stderr, "DDLPA_DEBUG: ddlpa_occupy() %s %s: '%s'\n",
|
||||
o_rwtext,
|
||||
(no_o_excl ? " " : "O_EXCL "), path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_obtain_scsi_adr(struct ddlpa_lock *o, char *path,
|
||||
int *bus, int *host, int *channel, int *id, int *lun)
|
||||
{
|
||||
int fd, ret, open_mode = O_RDONLY | O_NDELAY;
|
||||
struct my_scsi_idlun {
|
||||
int x;
|
||||
int host_unique_id;
|
||||
};
|
||||
struct my_scsi_idlun idlun;
|
||||
|
||||
fd = open(path, open_mode);
|
||||
if (fd == -1)
|
||||
return (errno ? errno : EBUSY);
|
||||
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, bus) == -1)
|
||||
*bus = -1;
|
||||
ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
|
||||
close(fd);
|
||||
if (ret == -1)
|
||||
return (errno ? errno : EIO);
|
||||
*host = (idlun.x >> 24) & 255;
|
||||
*channel = (idlun.x >> 16) & 255;
|
||||
*id = (idlun.x) & 255;
|
||||
*lun = (idlun.x >> 8 ) & 255;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_collect_siblings(struct ddlpa_lock *o)
|
||||
{
|
||||
int idx = 0, ret, have_sg = 0, have_sr = 0, have_scd = 0;
|
||||
dev_t path_dev;
|
||||
ino_t path_inode;
|
||||
struct stat stbuf;
|
||||
char *path, try_path[DDLPA_MAX_STD_LEN+1];
|
||||
int t_bus, t_host, t_channel, t_id, t_lun;
|
||||
|
||||
if (o->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
||||
path = o->path;
|
||||
else
|
||||
path = o->std_path;
|
||||
if (path[0] == 0 || o->num_siblings != 0)
|
||||
return EFAULT;
|
||||
if (!ddlpa_is_scsi(o, o->std_path))
|
||||
return EFAULT;
|
||||
|
||||
if (stat(path, &stbuf) == -1)
|
||||
return errno;
|
||||
path_inode = stbuf.st_ino;
|
||||
path_dev = stbuf.st_dev;
|
||||
o->rdev = stbuf.st_rdev;
|
||||
o->dev = stbuf.st_dev;
|
||||
o->ino = stbuf.st_ino;
|
||||
ret = ddlpa_obtain_scsi_adr(o, path,
|
||||
&(o->bus), &(o->host), &(o->channel),
|
||||
&(o->id), &(o->lun));
|
||||
if (ret) {
|
||||
o->errmsg = strdup(
|
||||
"Cannot obtain SCSI parameters host,channel,id,lun");
|
||||
return ret;
|
||||
}
|
||||
o->hcilb_is_valid = 1;
|
||||
|
||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
||||
if (!ddlpa_is_scsi(o, try_path))
|
||||
continue;
|
||||
if (stat(try_path, &stbuf) == -1)
|
||||
continue;
|
||||
ret = ddlpa_obtain_scsi_adr(o, try_path,
|
||||
&t_bus, &t_host, &t_channel, &t_id, &t_lun);
|
||||
if (ret) {
|
||||
|
||||
/* >>> interpret error, memorize busy, no permission */
|
||||
|
||||
continue;
|
||||
}
|
||||
if (t_host != o->host || t_channel != o->channel ||
|
||||
t_id != o->id || t_lun != o->lun)
|
||||
continue;
|
||||
|
||||
if (o->num_siblings >= DDLPA_MAX_SIBLINGS) {
|
||||
o->errmsg =
|
||||
strdup("Too many matching device files found");
|
||||
return ERANGE;
|
||||
}
|
||||
if (ddlpa_is_sg(o, try_path))
|
||||
have_sg = 1;
|
||||
else if (ddlpa_is_sr(o, try_path))
|
||||
have_sr = 1;
|
||||
else if (ddlpa_is_scd(o, try_path))
|
||||
have_scd = 1;
|
||||
strcpy(o->sibling_paths[o->num_siblings], try_path);
|
||||
o->sibling_rdevs[o->num_siblings] = stbuf.st_rdev;
|
||||
o->sibling_devs[o->num_siblings] = stbuf.st_dev;
|
||||
o->sibling_inodes[o->num_siblings] = stbuf.st_ino;
|
||||
|
||||
if (ddlpa_debug_mode)
|
||||
fprintf(stderr,
|
||||
"DDLPA_DEBUG: ddlpa_collect_siblings() found \"%s\"\n",
|
||||
try_path);
|
||||
|
||||
(o->num_siblings)++;
|
||||
}
|
||||
if (have_sg && have_sr && have_scd)
|
||||
return 0;
|
||||
if (o->ddlpa_flags & DDLPA_ALLOW_MISSING_SGRCD)
|
||||
return 0;
|
||||
|
||||
o->errmsg = strdup("Did not find enough siblings");
|
||||
|
||||
/* >>> add more info about busy and forbidden paths */
|
||||
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_std_by_btl(struct ddlpa_lock *o)
|
||||
{
|
||||
int idx = 0, ret;
|
||||
char try_path[DDLPA_MAX_STD_LEN+1];
|
||||
int t_bus, t_host, t_channel, t_id, t_lun;
|
||||
|
||||
if (!o->inbtl_is_valid)
|
||||
return EFAULT;
|
||||
|
||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
||||
if (!ddlpa_is_sr(o, try_path))
|
||||
continue;
|
||||
ret = ddlpa_obtain_scsi_adr(o, try_path,
|
||||
&t_bus, &t_host, &t_channel, &t_id, &t_lun);
|
||||
if (ret) {
|
||||
|
||||
/* >>> interpret error, memorize busy, no permission */
|
||||
|
||||
continue;
|
||||
}
|
||||
if (t_bus != o->in_bus || t_id != o->in_target ||
|
||||
t_lun != o->in_lun)
|
||||
continue;
|
||||
strcpy(o->std_path, try_path);
|
||||
|
||||
if (ddlpa_debug_mode)
|
||||
fprintf(stderr,
|
||||
"DDLPA_DEBUG: ddlpa_std_by_btl(%d,%d,%d) = \"%s\"\n",
|
||||
t_bus, t_id, t_lun, o->std_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* >>> add more info about busy and forbidden paths */
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_open_all(struct ddlpa_lock *o)
|
||||
{
|
||||
int i, j, ret, no_o_excl;
|
||||
|
||||
if (ddlpa_is_scsi(o, o->std_path)) {
|
||||
ret = ddlpa_collect_siblings(o);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (i = 0; i < o->num_siblings; i++) {
|
||||
|
||||
/* Watch out for the main personality of the drive. */
|
||||
/* No need to occupy identical path or softlink path */
|
||||
if (o->sibling_devs[i] == o->dev &&
|
||||
o->sibling_inodes[i] == o->ino)
|
||||
continue;
|
||||
/* There may be the same rdev but different inode. */
|
||||
no_o_excl = (o->sibling_rdevs[i] == o->rdev);
|
||||
|
||||
/* Look for multiply registered device drivers with
|
||||
distinct inodes. */
|
||||
for (j = 0; j < i; j++) {
|
||||
if (o->sibling_devs[j] == o->sibling_devs[i] &&
|
||||
o->sibling_inodes[j] == o->sibling_inodes[i])
|
||||
break;
|
||||
if (o->sibling_rdevs[j] == o->sibling_rdevs[i])
|
||||
no_o_excl = 1;
|
||||
}
|
||||
if (j < i)
|
||||
continue; /* inode is already occupied */
|
||||
|
||||
ret = ddlpa_occupy(o, o->sibling_paths[i],
|
||||
&(o->sibling_fds[i]), no_o_excl);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (o->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
||||
ret = ddlpa_occupy(o, o->path, &(o->fd), 0);
|
||||
else
|
||||
ret = ddlpa_occupy(o, o->std_path, &(o->fd), 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* >>> use fcntl() to adjust O_NONBLOCK */;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------- public -------------------- */
|
||||
|
||||
|
||||
int ddlpa_destroy(struct ddlpa_lock **lockbundle)
|
||||
{
|
||||
struct ddlpa_lock *o;
|
||||
int i;
|
||||
|
||||
o= *lockbundle;
|
||||
if (o == NULL)
|
||||
return 0;
|
||||
for (i = 0; i < o->num_siblings; i++)
|
||||
if (o->sibling_fds[i] != -1)
|
||||
close(o->sibling_fds[i]);
|
||||
if(o->fd != -1)
|
||||
close(o->fd);
|
||||
if (o->path != NULL)
|
||||
free(o->path);
|
||||
if (o->errmsg != NULL)
|
||||
free(o->errmsg);
|
||||
free((char *) o);
|
||||
*lockbundle = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ddlpa_lock_path(char *path, int o_flags, int ddlpa_flags,
|
||||
struct ddlpa_lock **lockbundle, char **errmsg)
|
||||
{
|
||||
struct ddlpa_lock *o;
|
||||
int ret;
|
||||
|
||||
*errmsg = NULL;
|
||||
if (ddlpa_new(&o, o_flags, ddlpa_flags))
|
||||
return ENOMEM;
|
||||
*lockbundle = o;
|
||||
|
||||
o->path = strdup(path);
|
||||
if (o->path == NULL)
|
||||
return ENOMEM;
|
||||
o->path_is_valid = 1;
|
||||
|
||||
ret = ddlpa_std_by_rdev(o);
|
||||
if (ret) {
|
||||
*errmsg = strdup(
|
||||
"Cannot find equivalent of given path among standard paths");
|
||||
return ret;
|
||||
}
|
||||
ret = ddlpa_open_all(o);
|
||||
if (ret) {
|
||||
*errmsg = o->errmsg;
|
||||
o->errmsg = NULL;
|
||||
ddlpa_destroy(&o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int ddlpa_lock_btl(int bus, int target, int lun,
|
||||
int o_flags, int ddlpa_flags,
|
||||
struct ddlpa_lock **lockbundle, char **errmsg)
|
||||
{
|
||||
struct ddlpa_lock *o;
|
||||
int ret;
|
||||
|
||||
*errmsg = NULL;
|
||||
ddlpa_flags &= ~DDLPA_OPEN_GIVEN_PATH;
|
||||
if (ddlpa_new(&o, o_flags, ddlpa_flags))
|
||||
return ENOMEM;
|
||||
*lockbundle = o;
|
||||
|
||||
o->in_bus = bus;
|
||||
o->in_target = target;
|
||||
o->in_lun = lun;
|
||||
o->inbtl_is_valid = 1;
|
||||
ret = ddlpa_std_by_btl(o);
|
||||
if (ret) {
|
||||
*errmsg = strdup(
|
||||
"Cannot find /dev/sr* with given Bus,Target,Lun");
|
||||
return ret;
|
||||
}
|
||||
ret = ddlpa_open_all(o);
|
||||
if (ret) {
|
||||
*errmsg = o->errmsg;
|
||||
o->errmsg = NULL;
|
||||
ddlpa_destroy(&o);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DDLPA_C_STANDALONE
|
||||
|
||||
/* ----------------------------- Test / Demo -------------------------- */
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ddlpa_lock *lck = NULL;
|
||||
char *errmsg = NULL, *opened_path = NULL, *my_path = NULL;
|
||||
int i, ret, fd = -1, duration = -1, bus = -1, target = -1, lun = -1;
|
||||
|
||||
if (argc < 3) {
|
||||
usage:;
|
||||
fprintf(stderr, "usage: %s device_path duration\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
my_path = argv[1];
|
||||
sscanf(argv[2], "%d", &duration);
|
||||
if (duration < 0)
|
||||
goto usage;
|
||||
|
||||
|
||||
/* For our purpose, only O_RDWR is a suitable access mode.
|
||||
But in order to allow experiments, o_flags are freely adjustable.
|
||||
|
||||
Warning: Do _not_ set an own O_EXCL flag with the following calls !
|
||||
|
||||
(This freedom to fail may get removed in a final version.)
|
||||
*/
|
||||
if (my_path[0] != '/' && my_path[0] != '.' &&
|
||||
strchr(my_path, ',') != NULL) {
|
||||
/*
|
||||
cdrecord style dev=Bus,Target,Lun
|
||||
*/
|
||||
|
||||
sscanf(my_path, "%d,%d,%d", &bus, &target, &lun);
|
||||
ret = ddlpa_lock_btl(bus, target, lun, O_RDWR | O_LARGEFILE,
|
||||
0, &lck, &errmsg);
|
||||
} else {
|
||||
/*
|
||||
This substitutes for:
|
||||
fd = open(my_path, O_RDWR | O_EXCL | O_LARGEFILE);
|
||||
|
||||
*/
|
||||
|
||||
ret = ddlpa_lock_path(my_path, O_RDWR | O_LARGEFILE,
|
||||
0, &lck, &errmsg);
|
||||
}
|
||||
if (ret) {
|
||||
fprintf(stderr, "Cannot exclusively open '%s'\n", my_path);
|
||||
if (errmsg != NULL)
|
||||
fprintf(stderr, "Reason given : %s\n",
|
||||
errmsg);
|
||||
free(errmsg);
|
||||
fprintf(stderr, "Error condition : %d '%s'\n",
|
||||
ret, strerror(ret));
|
||||
exit(2);
|
||||
}
|
||||
fd = lck->fd;
|
||||
|
||||
printf("---------------------------------------------- Lock gained\n");
|
||||
|
||||
|
||||
/* Use fd for the usual operations on the device depicted by my_path.
|
||||
*/
|
||||
|
||||
|
||||
/* This prints an overview of the impact of the lock */
|
||||
if (lck->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
||||
opened_path = lck->path;
|
||||
else
|
||||
opened_path = lck->std_path;
|
||||
printf("ddlpa: opened %s", opened_path);
|
||||
|
||||
if (strcmp(opened_path, lck->std_path) != 0)
|
||||
printf(" (an alias of '%s')", lck->std_path);
|
||||
printf("\n");
|
||||
if (lck->num_siblings > 0) {
|
||||
printf("ddlpa: opened siblings:");
|
||||
for (i = 0; i < lck->num_siblings; i++)
|
||||
if (lck->sibling_fds[i] != -1)
|
||||
printf(" %s", lck->sibling_paths[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
/* This example waits a while. So other lock candidates can collide. */
|
||||
for (i = 0; i < duration; i++) {
|
||||
sleep(1);
|
||||
fprintf(stderr, "\rslept %d seconds of %d", i + 1, duration);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
|
||||
/* When finally done with the drive, this substitutes for:
|
||||
close(fd);
|
||||
*/
|
||||
if (ddlpa_destroy(&lck)) {
|
||||
/* Well, man 2 close says it can fail. */
|
||||
exit(3);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
#endif /* DDLPA_C_STANDALONE */
|
||||
|
107
libburn/ddlpa.h
Normal file
107
libburn/ddlpa.h
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
/* ddlpa
|
||||
Implementation of Delicate Device Locking Protocol level A.
|
||||
Copyright (C) 2007 Thomas Schmitt <scdbackup@gmx.net>
|
||||
Provided under any of the following licenses: GPL, LGPL, BSD. Choose one.
|
||||
|
||||
See ../doc/ddlp.txt for a description of the protocol.
|
||||
*/
|
||||
|
||||
#ifndef DDLPA_H_INCLUDED
|
||||
#define DDLPA_H_INCLUDED 1
|
||||
|
||||
|
||||
/* An upper limit for the length of standard paths and sibling paths */
|
||||
#define DDLPA_MAX_STD_LEN 15
|
||||
|
||||
/* An upper limit for the number of siblings */
|
||||
#define DDLPA_MAX_SIBLINGS 5
|
||||
|
||||
struct ddlpa_lock {
|
||||
|
||||
/* Recorded input parameters of locking call */
|
||||
char *path;
|
||||
int path_is_valid;
|
||||
int in_bus, in_target, in_lun;
|
||||
int inbtl_is_valid;
|
||||
int ddlpa_flags;
|
||||
int o_flags;
|
||||
|
||||
/* Result of locking call */
|
||||
char std_path[DDLPA_MAX_STD_LEN + 1];
|
||||
int fd;
|
||||
dev_t rdev;
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
int host, channel, id, lun, bus;
|
||||
int hcilb_is_valid;
|
||||
int num_siblings;
|
||||
char sibling_paths[DDLPA_MAX_SIBLINGS][DDLPA_MAX_STD_LEN + 1];
|
||||
int sibling_fds[DDLPA_MAX_SIBLINGS];
|
||||
dev_t sibling_rdevs[DDLPA_MAX_SIBLINGS];
|
||||
dev_t sibling_devs[DDLPA_MAX_SIBLINGS];
|
||||
ino_t sibling_inodes[DDLPA_MAX_SIBLINGS];
|
||||
|
||||
/* Is NULL if all goes well. Else it may contain a text message. */
|
||||
char *errmsg;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Lock a recorder by naming a device file path. Allocate a new container.
|
||||
@param path Gives the file system path of the recorder
|
||||
as known to the calling program.
|
||||
@param o_flags flags for open(2). Do not use O_EXCL here because this
|
||||
is done automatically whenever appropriate.
|
||||
Advised is O_RDWR | O_LARGEFILE, eventually | O_NDELAY.
|
||||
@param ddlpa_flags 0 = default behavior: the standard path will be opened
|
||||
and treated by fcntl(F_SETLK)
|
||||
DDLPA_OPEN_GIVEN_PATH causes the input parameter "path"
|
||||
to be used with open(2) and fcntl(2).
|
||||
DDLPA_ALLOW_MISSING_SGRCD allows to grant a lock
|
||||
although not all three, a sg, a sr and a scd device
|
||||
file have been found during sibling search. Normally
|
||||
this is counted as failure due to EBUSY.
|
||||
@param lockbundle gets allocated and then represents the locking state
|
||||
@param errmsg if *errmsg is not NULL after the call, it contains an
|
||||
error message. Then to be released by free(3).
|
||||
It is NULL in case of success or lack of memory.
|
||||
@return 0=success , else an errno compatible error number
|
||||
*/
|
||||
int ddlpa_lock_path(char *path, int o_flags, int ddlpa_flags,
|
||||
struct ddlpa_lock **lockbundle, char **errmsg);
|
||||
|
||||
|
||||
/** Lock a recorder by naming a Bus,Target,Lun number triple.
|
||||
Allocate a new container.
|
||||
@param bus parameter to match ioctl(SCSI_IOCTL_GET_BUS_NUMBER)
|
||||
@param target parameter to match ioctl(SCSI_IOCTL_GET_IDLUN) &0xff
|
||||
@param lun parameter to match ioctl(SCSI_IOCTL_GET_IDLUN) &0xff00
|
||||
@param o_flags see ddlpa_lock_path().
|
||||
@param ddlpa_flags see ddlpa_lock_path(). Flag DDLPA_OPEN_GIVEN_PATH
|
||||
will be ignored.
|
||||
@param lockbundle see ddlpa_lock_path().
|
||||
@param errmsg see ddlpa_lock_path().
|
||||
@return 0=success , else an errno compatible error number
|
||||
*/
|
||||
int ddlpa_lock_btl(int bus, int target, int lun,
|
||||
int o_flags, int ddlpa_flags,
|
||||
struct ddlpa_lock **lockbundle, char **errmsg);
|
||||
|
||||
|
||||
/** Release the lock by closing all filedescriptors and freeing memory.
|
||||
@param lockbundle the lock which is to be released.
|
||||
*lockbundle will be set to NULL by this call.
|
||||
@return 0=success , 1=failure
|
||||
*/
|
||||
int ddlpa_destroy(struct ddlpa_lock **lockbundle);
|
||||
|
||||
|
||||
|
||||
/** Definitions of macros used in above functions */
|
||||
|
||||
#define DDLPA_OPEN_GIVEN_PATH 1
|
||||
#define DDLPA_ALLOW_MISSING_SGRCD 2
|
||||
|
||||
|
||||
#endif /* DDLPA_H_INCLUDED */
|
@ -29,6 +29,12 @@
|
||||
/* ts A70107 : to get BE_CANCELLED */
|
||||
#include "error.h"
|
||||
|
||||
/* ts A70219 : for burn_disc_get_write_mode_demands() */
|
||||
#include "options.h"
|
||||
|
||||
/* A70225 : to learn about eventual Libburn_dvd_r_dl_multi_no_close_sessioN */
|
||||
#include "write.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
@ -200,6 +206,9 @@ int burn_drive_inquire_media(struct burn_drive *d)
|
||||
} else {
|
||||
if (d->current_profile == -1 || d->current_is_cd_profile)
|
||||
d->read_toc(d);
|
||||
|
||||
/* ts A70314 */
|
||||
d->status = BURN_DISC_UNSUITABLE;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -1402,7 +1411,7 @@ int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
|
||||
0, 0);
|
||||
return -1;
|
||||
}
|
||||
if (o!=NULL)
|
||||
if (o != NULL)
|
||||
d->send_write_parameters(d, o);
|
||||
ret = d->get_nwa(d, trackno, lba, nwa);
|
||||
return ret;
|
||||
@ -1435,6 +1444,31 @@ int burn_disc_get_msc1(struct burn_drive *d, int *start)
|
||||
}
|
||||
|
||||
|
||||
/* ts A70213 : new API function */
|
||||
off_t burn_disc_available_space(struct burn_drive *d,
|
||||
struct burn_write_opts *o)
|
||||
{
|
||||
int lba, nwa;
|
||||
|
||||
if (burn_drive_is_released(d))
|
||||
goto ex;
|
||||
if (d->busy != BURN_DRIVE_IDLE)
|
||||
goto ex;
|
||||
if (o != NULL)
|
||||
d->send_write_parameters(d, o);
|
||||
d->get_nwa(d, -1, &lba, &nwa);
|
||||
ex:;
|
||||
if (o != NULL) {
|
||||
if (o->start_byte > 0) {
|
||||
if (o->start_byte > d->media_capacity_remaining)
|
||||
return 0;
|
||||
return d->media_capacity_remaining - o->start_byte;
|
||||
}
|
||||
}
|
||||
return d->media_capacity_remaining;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61202 : New API function */
|
||||
int burn_disc_get_profile(struct burn_drive *d, int *pno, char name[80])
|
||||
{
|
||||
@ -1615,14 +1649,19 @@ int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt,
|
||||
}
|
||||
if (wt == BURN_WRITE_RAW)
|
||||
o->multi_session = o->multi_track = 0;
|
||||
} else if (d->current_profile == 0x11 || d->current_profile == 0x14) {
|
||||
/* DVD-R , sequential DVD-RW */
|
||||
} else if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
|
||||
d->current_profile == 0x15) {
|
||||
/* DVD-R , sequential DVD-RW , DVD-R/DL Sequential */
|
||||
if (s == BURN_DISC_BLANK) {
|
||||
o->might_do_sao = 1;
|
||||
o->advised_write_mode = BURN_WRITE_SAO;
|
||||
}
|
||||
if (d->current_has_feat21h) {
|
||||
o->multi_session = o->multi_track = 1;
|
||||
#ifndef Libburn_dvd_r_dl_multi_no_close_sessioN
|
||||
if (d->current_profile != 0x15)
|
||||
#endif
|
||||
o->multi_session = 1;
|
||||
o->multi_track = 1;
|
||||
o->might_do_tao = 2;
|
||||
o->advised_write_mode = BURN_WRITE_TAO;
|
||||
}
|
||||
@ -1657,8 +1696,15 @@ int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt,
|
||||
d->best_format_size - 2048;
|
||||
}
|
||||
}
|
||||
o->might_do_sao = 4;
|
||||
o->might_do_tao = 2;
|
||||
o->advised_write_mode = BURN_WRITE_TAO;
|
||||
} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
|
||||
/* DVD+R , DVD+R/DL */
|
||||
o->multi_session = o->multi_track = 1;
|
||||
o->might_do_tao = 2;
|
||||
o->might_do_sao = 1;
|
||||
o->advised_write_mode = BURN_WRITE_TAO;
|
||||
} else /* unknown media */
|
||||
return 0;
|
||||
|
||||
@ -1686,15 +1732,25 @@ int burn_disc_free_multi_caps(struct burn_multi_caps **caps)
|
||||
}
|
||||
|
||||
|
||||
/* ts A70207 : evaluate write mode related peculiarities of a disc */
|
||||
/* ts A70207 : evaluate write mode related peculiarities of a disc
|
||||
@param flag bit0= fill_up_media is active
|
||||
*/
|
||||
int burn_disc_get_write_mode_demands(struct burn_disc *disc,
|
||||
struct burn_write_opts *opts,
|
||||
struct burn_disc_mode_demands *result, int flag)
|
||||
{
|
||||
struct burn_session *session;
|
||||
struct burn_track *track;
|
||||
int i, j, mode;
|
||||
int i, j, mode, unknown_track_sizes = 0, last_track_is_unknown = 0;
|
||||
enum burn_disc_status s;
|
||||
|
||||
|
||||
memset((char *) result, 0, sizeof(struct burn_disc_mode_demands));
|
||||
if (disc == NULL)
|
||||
return 2;
|
||||
s = burn_disc_get_status(opts->drive);
|
||||
if (s == BURN_DISC_APPENDABLE || disc->sessions > 1)
|
||||
result->will_append = 1;
|
||||
if (disc->sessions > 1)
|
||||
result->multi_session = 1;
|
||||
for (i = 0; i < disc->sessions; i++) {
|
||||
@ -1706,15 +1762,33 @@ int burn_disc_get_write_mode_demands(struct burn_disc *disc,
|
||||
result->multi_track = 1;
|
||||
for (j = 0; j < session->tracks; j++) {
|
||||
track = session->track[j];
|
||||
if (burn_track_is_open_ended(track))
|
||||
result->unknown_track_size = 1;
|
||||
if (burn_track_is_open_ended(track)) {
|
||||
if (burn_track_get_default_size(track) > 0) {
|
||||
if (result->unknown_track_size == 0)
|
||||
result->unknown_track_size = 2;
|
||||
} else
|
||||
result->unknown_track_size = 1;
|
||||
unknown_track_sizes++;
|
||||
last_track_is_unknown = 1;
|
||||
} else
|
||||
last_track_is_unknown = 0;
|
||||
if (mode != track->mode)
|
||||
result->mixed_mode = 1;
|
||||
if (track->mode != BURN_MODE1)
|
||||
result->exotic_track = 1;
|
||||
if (track->mode == BURN_AUDIO)
|
||||
if (track->mode == BURN_MODE1) {
|
||||
result->block_types |= BURN_BLOCK_MODE1;
|
||||
} else if (track->mode == BURN_AUDIO) {
|
||||
result->audio = 1;
|
||||
result->block_types |= BURN_BLOCK_RAW0;
|
||||
result->exotic_track = 1;
|
||||
} else {
|
||||
result->block_types |= opts->block_type;
|
||||
result->exotic_track = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag&1) {/* fill_up_media will define the size of the last track */
|
||||
if (unknown_track_sizes == 1 && last_track_is_unknown)
|
||||
result->unknown_track_size = 0;
|
||||
}
|
||||
return (disc->sessions > 0);
|
||||
}
|
||||
|
@ -100,12 +100,15 @@ void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag);
|
||||
struct burn_disc_mode_demands {
|
||||
int multi_session;
|
||||
int multi_track;
|
||||
int unknown_track_size;
|
||||
int unknown_track_size; /* 0=known, 1=unknown, 2=unknown+defaulted */
|
||||
int mixed_mode;
|
||||
int audio;
|
||||
int exotic_track;
|
||||
int block_types;
|
||||
int will_append; /* because of media state or multi session disc */
|
||||
};
|
||||
int burn_disc_get_write_mode_demands(struct burn_disc *disc,
|
||||
struct burn_disc_mode_demands *result, int flag);
|
||||
struct burn_write_opts *opts,
|
||||
struct burn_disc_mode_demands *result, int flag);
|
||||
|
||||
#endif /* __DRIVE */
|
||||
|
@ -26,9 +26,22 @@ 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 */
|
||||
/* ts A60813 : Linux: wether to use O_EXCL on open() of device files */
|
||||
int burn_sg_open_o_excl = 1;
|
||||
|
||||
/* ts A70403 : Linux: wether to use fcntl(,F_SETLK,)
|
||||
after open() of device files */
|
||||
int burn_sg_fcntl_f_setlk = 1;
|
||||
|
||||
/* ts A70314 : Linux: what device family to use :
|
||||
0= default family
|
||||
1= sr
|
||||
2= scd
|
||||
(3= st)
|
||||
4= sg
|
||||
*/
|
||||
int burn_sg_use_family = 0;
|
||||
|
||||
/* 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
|
||||
@ -50,6 +63,10 @@ static char abort_message_prefix[81] = {"libburn : "};
|
||||
static pid_t abort_control_pid= 0;
|
||||
|
||||
|
||||
/* ts A70223 : wether implemented untested profiles are supported */
|
||||
int burn_support_untested_profiles = 0;
|
||||
|
||||
|
||||
/* ts A60925 : ticket 74 */
|
||||
/** Create the messenger object for libburn. */
|
||||
int burn_msgs_initialize(void)
|
||||
@ -73,6 +90,7 @@ int burn_initialize(void)
|
||||
|
||||
if (burn_running)
|
||||
return 1;
|
||||
burn_support_untested_profiles = 0;
|
||||
ret = burn_msgs_initialize();
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
@ -114,10 +132,11 @@ void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy)
|
||||
/* 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;
|
||||
burn_sg_open_o_excl = exclusive & 3;
|
||||
burn_sg_fcntl_f_setlk = !!(exclusive & 32);
|
||||
burn_sg_use_family = (exclusive >> 2) & 7;
|
||||
burn_sg_open_o_nonblock = !blocking;
|
||||
burn_sg_open_abort_busy = !!abort_on_busy;
|
||||
}
|
||||
|
||||
|
||||
@ -274,3 +293,10 @@ void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
|
||||
Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler, mode|4);
|
||||
}
|
||||
|
||||
|
||||
/* ts A70223 : API */
|
||||
void burn_allow_untested_profiles(int yes)
|
||||
{
|
||||
burn_support_untested_profiles = !!yes;
|
||||
}
|
||||
|
||||
|
@ -572,13 +572,22 @@ void burn_set_verbosity(int level);
|
||||
after burn_initialize() and before any bus scan. But not mandatory at all.
|
||||
Parameter value 1 enables a feature, 0 disables.
|
||||
Default is (1,0,0). Have a good reason before you change it.
|
||||
@param exclusive 1 = Try to open only devices which are not marked as busy
|
||||
@param exclusive Linux only:
|
||||
0 = no attempt to make drive access exclusive.
|
||||
1 = Try to open only devices which are not marked as busy
|
||||
and try to mark them busy if opened sucessfully. (O_EXCL)
|
||||
There are kernels which simply don't care about O_EXCL.
|
||||
Some have it off, some have it on, some are switchable.
|
||||
2 = in case of a SCSI device, also try to open exclusively
|
||||
the matching /dev/sr, /dev/scd and /dev/st .
|
||||
0 = no attempt to make drive access exclusive.
|
||||
the matching /dev/sr, /dev/scd and /dev/st .
|
||||
One may select a device SCSI file family by adding
|
||||
0 = default family
|
||||
4 = /dev/sr%d
|
||||
8 = /dev/scd%d
|
||||
16 = /dev/sg%d
|
||||
Do not use other values !
|
||||
Add 32 to demand an exclusive lock by fcntl(,F_SETLK,)
|
||||
after open() has succeeded.
|
||||
@param blocking Try to wait for drives which do not open immediately but
|
||||
also do not return an error as well. (O_NONBLOCK)
|
||||
This might stall indefinitely with /dev/hdX hard disks.
|
||||
@ -589,6 +598,19 @@ void burn_set_verbosity(int level);
|
||||
void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy);
|
||||
|
||||
|
||||
/* ts A70223 */
|
||||
/** Allows the use of media types which are implemented in libburn but not yet
|
||||
tested. The list of those untested profiles is subject to change.
|
||||
Currently it contains: 0x15 "DVD-R/DL Sequential".
|
||||
If you really test such media, then please report the outcome on
|
||||
libburn-hackers@pykix.org
|
||||
If ever then this call should be done soon after burn_initialize() before
|
||||
any drive scanning.
|
||||
@param yes 1=allow all implemented profiles, 0=only tested media (default)
|
||||
*/
|
||||
void burn_allow_untested_profiles(int yes);
|
||||
|
||||
|
||||
/* ts A60823 */
|
||||
/** Aquire a drive with known persistent address.This is the sysadmin friendly
|
||||
way to open one drive and to leave all others untouched. It bundles
|
||||
@ -674,7 +696,9 @@ int burn_drive_scan(struct burn_drive_info *drive_infos[],
|
||||
int burn_drive_info_forget(struct burn_drive_info *drive_info, int force);
|
||||
|
||||
|
||||
/** Free a burn_drive_info array returned by burn_drive_scan
|
||||
/** When no longer needed, free a whole burn_drive_info array which was
|
||||
returned by burn_drive_scan().
|
||||
For freeing single drive array elements use burn_drive_info_forget().
|
||||
*/
|
||||
void burn_drive_info_free(struct burn_drive_info drive_infos[]);
|
||||
|
||||
@ -750,8 +774,8 @@ int burn_drive_grab(struct burn_drive *drive, int load);
|
||||
|
||||
|
||||
/** Release a drive. This should not be done until the drive is no longer
|
||||
busy (see burn_drive_get_status). The drive is (O_EXCL) unlocked
|
||||
afterwards.
|
||||
busy (see burn_drive_get_status).
|
||||
Linux: The drive is unlocked afterwards. (O_EXCL , F_SETLK).
|
||||
@param drive The drive to release.
|
||||
@param eject Nonzero to make the drive eject the disc in it.
|
||||
*/
|
||||
@ -838,11 +862,32 @@ int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
|
||||
*/
|
||||
int burn_disc_get_msc1(struct burn_drive *d, int *start_lba);
|
||||
|
||||
|
||||
/* ts A70213 */
|
||||
/** Return the best possible estimation of the currently available capacity of
|
||||
the media. This might depend on particular write option settings. For
|
||||
inquiring the space with such a set of options, the drive has to be
|
||||
grabbed and BURN_DRIVE_IDLE. If not, then one will only get a canned value
|
||||
from the most recent automatic inquiry (e.g. during last drive grabbing).
|
||||
An eventual start address from burn_write_opts_set_start_byte() will be
|
||||
subtracted from the obtained capacity estimation. Negative results get
|
||||
defaulted to 0.
|
||||
@param d The drive to query.
|
||||
@param o If not NULL: write parameters to be set on drive before query
|
||||
@return number of most probably available free bytes
|
||||
*/
|
||||
off_t burn_disc_available_space(struct burn_drive *d,
|
||||
struct burn_write_opts *o);
|
||||
|
||||
|
||||
/* ts A61202 */
|
||||
/** Tells the MMC Profile identifier of the loaded media. The drive must be
|
||||
grabbed in order to get a non-zero result.
|
||||
libburn currently writes only to profiles 0x09 "CD-R", 0x0a "CD-RW",
|
||||
0x12 "DVD-RAM", 0x13 "DVD-RW restricted overwrite" or 0x1a "DVD+RW".
|
||||
0x11 "DVD-R", 0x12 "DVD-RAM", 0x13 "DVD-RW restricted overwrite",
|
||||
0x14 "DVD-RW Sequential Recording" or 0x1a "DVD+RW".
|
||||
If enabled by burn_allow_untested_profiles() it also writes to profile
|
||||
0x15 "DVD-R/DL Sequential Recording".
|
||||
@param d The drive where the media is inserted.
|
||||
@param pno Profile Number as of mmc5r03c.pdf, table 89
|
||||
@param name Profile Name (e.g "CD-RW", unknown profiles have empty name)
|
||||
@ -895,6 +940,7 @@ void burn_read_opts_free(struct burn_read_opts *opts);
|
||||
@param drive The drive with which to erase a disc.
|
||||
@param fast Nonzero to do a fast erase, where only the disc's headers are
|
||||
erased; zero to erase the entire disc.
|
||||
With DVD-RW, fast blanking yields media capable only of DAO.
|
||||
*/
|
||||
void burn_disc_erase(struct burn_drive *drive, int fast);
|
||||
|
||||
@ -979,9 +1025,35 @@ int burn_disc_get_format_descr(struct burn_drive *drive, int index,
|
||||
*/
|
||||
void burn_disc_read(struct burn_drive *drive, const struct burn_read_opts *o);
|
||||
|
||||
|
||||
|
||||
/* ts A70222 */
|
||||
/** The length of a rejection reasons string for burn_precheck_write() and
|
||||
burn_write_opts_auto_write_type() .
|
||||
*/
|
||||
#define BURN_REASONS_LEN 4096
|
||||
|
||||
|
||||
/* ts A70219 */
|
||||
/** Examines a completed setup for burn_disc_write() wether it is permissible
|
||||
with drive and media. This function is called by burn_disc_write() but
|
||||
an application might be interested in this check in advance.
|
||||
@param o The options for the writing operation.
|
||||
@param disc The descrition of the disc to be created
|
||||
@param reasons Eventually returns a list of rejection reason statements
|
||||
@param silent 1= do not issue error messages , 0= report problems
|
||||
@return 1 ok, -1= no recordable media detected, 0= other failure
|
||||
*/
|
||||
int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
|
||||
char reasons[BURN_REASONS_LEN], int silent);
|
||||
|
||||
/* <<< enabling switch for internal usage and trust in this function */
|
||||
#define Libburn_precheck_write_ruleS 1
|
||||
|
||||
|
||||
/** Write a disc in the drive. The drive must be grabbed successfully before
|
||||
calling this function. Always ensure that the drive reports a status of
|
||||
BURN_DISC_BLANK before calling this function.
|
||||
BURN_DISC_BLANK ot BURN_DISC_APPENDABLE before calling this function.
|
||||
Note: write_type BURN_WRITE_SAO is currently not capable of writing a mix
|
||||
of data and audio tracks. You must use BURN_WRITE_TAO for such sessions.
|
||||
To be set by burn_write_opts_set_write_type().
|
||||
@ -1159,6 +1231,19 @@ struct burn_disc *burn_drive_get_disc(struct burn_drive *d);
|
||||
enum burn_source_status burn_track_set_source(struct burn_track *t,
|
||||
struct burn_source *s);
|
||||
|
||||
|
||||
/* ts A70218 */
|
||||
/** Set a default track size to be used only if the track turns out to be of
|
||||
unpredictable length and if the effective write type demands a fixed size.
|
||||
This can be useful to enable write types CD SAO or DVD DAO together with
|
||||
a track source like stdin. If the track source delivers fewer bytes than
|
||||
announced then the track will be padded up with zeros.
|
||||
@param t The track to change
|
||||
@param size The size to set
|
||||
@return 0=failure 1=sucess
|
||||
*/
|
||||
int burn_track_set_default_size(struct burn_track *t, off_t size);
|
||||
|
||||
/** Free a burn_source (decrease its refcount and maybe free it)
|
||||
@param s Source to free
|
||||
*/
|
||||
@ -1178,6 +1263,17 @@ struct burn_source *burn_file_source_new(const char *path,
|
||||
*/
|
||||
struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size);
|
||||
|
||||
|
||||
/* ts A70328 */
|
||||
/** Sets a fixed track size after the data source object has already been
|
||||
created.
|
||||
@param t The track to poperate on
|
||||
@param size the number of bytes to use as track size
|
||||
@return <=0 indicates failure , >0 success
|
||||
*/
|
||||
int burn_track_set_size(struct burn_track *t, off_t size);
|
||||
|
||||
|
||||
/** Tells how long a track will be on disc
|
||||
>>> NOTE: Not reliable with tracks of undefined length
|
||||
*/
|
||||
@ -1215,6 +1311,7 @@ int burn_write_opts_set_write_type(struct burn_write_opts *opts,
|
||||
enum burn_write_types write_type,
|
||||
int block_type);
|
||||
|
||||
|
||||
/* ts A70207 */
|
||||
/** As an alternative to burn_write_opts_set_write_type() this function tries
|
||||
to find a suitable write type and block type for a given write job
|
||||
@ -1223,12 +1320,15 @@ int burn_write_opts_set_write_type(struct burn_write_opts *opts,
|
||||
@param opts The nearly complete write opts to change
|
||||
@param disc The already composed session and track model
|
||||
@param reasons This text string collects reasons for decision resp. failure
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@param flag Bitfield for control purposes:
|
||||
bit0= do not choose type but check the one that is already set
|
||||
bit1= do not issue error messages via burn_msgs queue
|
||||
(is automatically set with bit0)
|
||||
@return Chosen write type. BURN_WRITE_NONE on failure.
|
||||
*/
|
||||
enum burn_write_types burn_write_opts_auto_write_type(
|
||||
struct burn_write_opts *opts, struct burn_disc *disc,
|
||||
char reasons[1024], int flag);
|
||||
char reasons[BURN_REASONS_LEN], int flag);
|
||||
|
||||
|
||||
/** Supplies toc entries for writing - not normally required for cd mastering
|
||||
@ -1295,6 +1395,28 @@ void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi);
|
||||
void burn_write_opts_set_start_byte(struct burn_write_opts *opts, off_t value);
|
||||
|
||||
|
||||
/* ts A70213 */
|
||||
/** Caution: still immature and likely to change. Problems arose with
|
||||
sequential DVD-RW on one drive.
|
||||
|
||||
Controls wether the whole available space of the media shall be filled up
|
||||
by the last track of the last session.
|
||||
@param opts The write opts to change
|
||||
@param fill_up_media If 1 : fill up by last track, if 0 = do not fill up
|
||||
*/
|
||||
void burn_write_opts_set_fillup(struct burn_write_opts *opts,
|
||||
int fill_up_media);
|
||||
|
||||
|
||||
/* ts A70303 */
|
||||
/** Eventually makes libburn ignore the failure of some conformance checks:
|
||||
- the check wether CD write+block type is supported by the drive
|
||||
@param opts The write opts to change
|
||||
@param use_force 1=ignore above checks, 0=refuse work on failed check
|
||||
*/
|
||||
void burn_write_opts_set_force(struct burn_write_opts *opts, int use_force);
|
||||
|
||||
|
||||
/** Sets whether to read in raw mode or not
|
||||
@param opts The read opts to change
|
||||
@param raw_mode If non-zero, reading will be done in raw mode, so that everything in the data tracks on the
|
||||
@ -1414,7 +1536,7 @@ struct burn_multi_caps {
|
||||
of multi-session by keeping a disc appendable. But .might_do_sao
|
||||
will be 0 afterwards, when checking the appendable media.)
|
||||
1= media may be kept appendable by burn_write_opts_set_multi(o,1)
|
||||
0= media will not be apendable appendable
|
||||
0= media will not be appendable
|
||||
*/
|
||||
int multi_session;
|
||||
|
||||
@ -1450,6 +1572,8 @@ struct burn_multi_caps {
|
||||
off_t start_range_high;
|
||||
|
||||
/** Potential availability of write modes
|
||||
4= needs no size prediction, not to be chosen automatically
|
||||
3= needs size prediction, not to be chosen automatically
|
||||
2= available, no size prediction necessary
|
||||
1= available, needs exact size prediction
|
||||
0= not available
|
||||
@ -1460,7 +1584,9 @@ struct burn_multi_caps {
|
||||
int might_do_sao;
|
||||
int might_do_raw;
|
||||
|
||||
/** Advised write mode.
|
||||
/** Generally advised write mode.
|
||||
Not necessarily the one chosen by burn_write_opts_auto_write_type()
|
||||
because the burn_disc structure might impose particular demands.
|
||||
*/
|
||||
enum burn_write_types advised_write_mode;
|
||||
|
||||
@ -1492,7 +1618,7 @@ int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt,
|
||||
struct burn_multi_caps **caps, int flag);
|
||||
|
||||
/** Removes from memory a multi session info structure which was returned by
|
||||
burn_disc_get_multi_caps(). The pointer *caps gets set o NULL.
|
||||
burn_disc_get_multi_caps(). The pointer *caps gets set to NULL.
|
||||
@param caps the info structure to dispose (note: pointer to pointer)
|
||||
@return 0 : *caps was already NULL, 1 : memory object was disposed
|
||||
*/
|
||||
|
@ -300,9 +300,10 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
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
|
||||
0x00020005 (SORRY,HIGH) = Failed to open device
|
||||
0x00020006 (FATAL,HIGH) = Too many scsi siblings
|
||||
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
|
||||
0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock
|
||||
|
||||
General library operations:
|
||||
|
||||
@ -350,17 +351,23 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
0x00020129 (SORRY,HIGH) = Will not format media type
|
||||
0x0002012a (FATAL,HIGH) = Cannot inquire write mode capabilities
|
||||
0x0002012b (FATAL,HIGH) = Drive offers no suitable write mode with this job
|
||||
|
||||
0x0002012c (SORRY,HIGH) = Too many logical tracks recorded
|
||||
0x0002012d (FATAL,HIGH) = Exceeding range of permissible write addresses
|
||||
0x0002012e (NOTE,HIGH) = Activated track default size
|
||||
0x0002012f (SORRY,HIGH) = SAO is restricted to single fixed size session
|
||||
0x00020130 (SORRY,HIGH) = Drive and media state unsuitable for blanking
|
||||
0x00020131 (SORRY,HIGH) = No suitable formatting type offered by drive
|
||||
0x00020132 (SORRY,HIGH) = Selected format is not suitable for libburn
|
||||
0x00020133 (SORRY,HIGH) = Cannot mix data and audio in SAO mode
|
||||
0x00020134 (NOTE,HIGH) = Defaulted TAO to DAO
|
||||
0x00020135 (SORRY,HIGH) = Cannot perform TAO, job unsuitable for DAO
|
||||
0x00020136 (SORRY,HIGH) = DAO Burning restricted to single fixed size track
|
||||
0x00020136 (SORRY,HIGH) = DAO burning restricted to single fixed size track
|
||||
0x00020137 (HINT,HIGH) = TAO would be possible
|
||||
0x00020138 (FATAL,HIGH) = Cannot reserve track
|
||||
|
||||
0x00020139 (SORRY,HIGH) = Write job parameters are unsuitable
|
||||
0x0002013a (FATAL,HIGH) = No suitable media detected
|
||||
0x0002013b
|
||||
0x0002013c (SORRY,HIGH) = Malformed capabilities page 2Ah received
|
||||
|
||||
libdax_audioxtr:
|
||||
0x00020200 (SORRY,HIGH) = Cannot open audio source file
|
||||
|
316
libburn/mmc.c
316
libburn/mmc.c
@ -21,6 +21,10 @@
|
||||
#include "options.h"
|
||||
|
||||
|
||||
/* ts A70223 : in init.c */
|
||||
extern int burn_support_untested_profiles;
|
||||
|
||||
|
||||
#ifdef Libburn_log_in_and_out_streaM
|
||||
/* <<< ts A61031 */
|
||||
#include <sys/types.h>
|
||||
@ -43,13 +47,13 @@ extern struct libdax_msgs *libdax_messenger;
|
||||
/* ts A70112 */
|
||||
#define Libburn_support_dvd_raM 1
|
||||
|
||||
|
||||
/* ts A70129 >>> EXPERIMENTAL UNTESTED
|
||||
*/
|
||||
/* ts A70129 */
|
||||
#define Libburn_support_dvd_r_seQ 1
|
||||
|
||||
/* ts A70306 */
|
||||
#define Libburn_support_dvd_plus_R 1
|
||||
|
||||
/* Progress report:
|
||||
/* DVD progress report:
|
||||
ts A61219 : It seems to work with a used (i.e. thoroughly formatted) DVD+RW.
|
||||
Error messages of class DEBUG appear because of inability to
|
||||
read TOC or track info. Nevertheless, the written images verify.
|
||||
@ -83,9 +87,9 @@ extern struct libdax_msgs *libdax_messenger;
|
||||
with unpredicted size, multi-track, multi-session.
|
||||
ts A70205 : Beginning to implement DVD-R[W] DAO : single track and session,
|
||||
size prediction mandatory.
|
||||
|
||||
Todo:
|
||||
Determine first free lba for appending data on overwriteables.
|
||||
ts A70208 : Finally made tests with DVD-R. Worked exactly as new DVD-RW.
|
||||
ts A70306 : Implemented DVD+R (always -multi for now)
|
||||
ts A70330 : Allowed finalizing of DVD+R.
|
||||
*/
|
||||
|
||||
|
||||
@ -162,8 +166,7 @@ int mmc_function_spy_ctrl(int do_tell)
|
||||
/* ts A70201 */
|
||||
int mmc_four_char_to_int(unsigned char *data)
|
||||
{
|
||||
return (data[0] << 24) | (data[1] << 16) |
|
||||
(data[2] << 8) | data[3];
|
||||
return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
||||
}
|
||||
|
||||
|
||||
@ -238,7 +241,6 @@ int mmc_reserve_track(struct burn_drive *d, off_t size)
|
||||
int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf)
|
||||
{
|
||||
struct command c;
|
||||
int i;
|
||||
|
||||
mmc_function_spy("mmc_read_track_info");
|
||||
c.retry = 1;
|
||||
@ -250,14 +252,16 @@ int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf)
|
||||
d->current_profile == 0x12 )
|
||||
/* DVD+RW , DVD-RW restricted overwrite , DVD-RAM */
|
||||
trackno = 1;
|
||||
else if (d->current_profile == 0x11 ||
|
||||
d->current_profile == 0x14) /* DVD-R[W] Sequential */
|
||||
else if (d->current_profile == 0x10 ||
|
||||
d->current_profile == 0x11 ||
|
||||
d->current_profile == 0x14 ||
|
||||
d->current_profile == 0x15)
|
||||
/* DVD-ROM , DVD-R[W] Sequential */
|
||||
trackno = d->last_track_no;
|
||||
else /* mmc5r03c.pdf: valid only for CD, DVD+R, DVD+R DL */
|
||||
trackno = 0xFF;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
c.opcode[2 + i] = (trackno >> (24 - 8 * i)) & 0xff;
|
||||
mmc_int_to_four_char(c.opcode + 2, trackno);
|
||||
c.page = buf;
|
||||
memset(buf->data, 0, BUFFER_SIZE);
|
||||
c.dir = FROM_DRIVE;
|
||||
@ -274,58 +278,22 @@ int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf)
|
||||
int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
|
||||
{
|
||||
struct buffer buf;
|
||||
int ret;
|
||||
|
||||
#ifdef Libburn_get_nwa_standalonE
|
||||
struct command c;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
int ret, num;
|
||||
unsigned char *data;
|
||||
|
||||
mmc_function_spy("mmc_get_nwa");
|
||||
if(trackno<=0) {
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
||||
d->current_profile == 0x12 )
|
||||
/* DVD+RW , DVD-RW restricted overwrite , DVD-RAM */
|
||||
trackno = 1;
|
||||
else if (d->current_profile == 0x11 ||
|
||||
d->current_profile == 0x14) /* DVD-R[W] Sequential */
|
||||
trackno = d->last_track_no;
|
||||
else /* mmc5r03c.pdf: valid only for CD, DVD+R, DVD+R DL */
|
||||
trackno = 0xFF;
|
||||
}
|
||||
|
||||
#ifdef Libburn_get_nwa_standalonE
|
||||
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(MMC_TRACK_INFO);
|
||||
memcpy(c.opcode, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO));
|
||||
c.opcode[1] = 1;
|
||||
for (i = 0; i < 4; i++)
|
||||
c.opcode[2 + i] = (trackno >> (24 - 8 * i)) & 0xff;
|
||||
c.page = &buf;
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
data = c.page->data;
|
||||
|
||||
#else /* Libburn_get_nwa_standalonE */
|
||||
|
||||
ret = mmc_read_track_info(d, trackno, &buf);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
data = buf.data;
|
||||
|
||||
#endif /* ! Libburn_get_nwa_standalonE */
|
||||
|
||||
|
||||
*lba = (data[8] << 24) + (data[9] << 16)
|
||||
+ (data[10] << 8) + data[11];
|
||||
*nwa = (data[12] << 24) + (data[13] << 16)
|
||||
+ (data[14] << 8) + data[15];
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13) {
|
||||
/* DVD+RW or DVD-RW restricted overwrite */
|
||||
*lba = *nwa = 0;
|
||||
*lba = mmc_four_char_to_int(data + 8);
|
||||
*nwa = mmc_four_char_to_int(data + 12);
|
||||
num = mmc_four_char_to_int(data + 16);
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
||||
d->current_profile == 0x12) {
|
||||
/* overwriteable */
|
||||
*lba = *nwa = num = 0;
|
||||
} else if (!(data[7]&1)) {
|
||||
/* ts A61106 : MMC-1 Table 142 : NWA_V = NWA Valid Flag */
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
@ -333,6 +301,17 @@ int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
|
||||
"mmc_get_nwa: Track Info Block: NWA_V == 0", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
if (num > 0) {
|
||||
d->media_capacity_remaining = ((off_t) num) * ((off_t) 2048);
|
||||
d->media_lba_limit = *nwa + num;
|
||||
} else
|
||||
d->media_lba_limit = 0;
|
||||
|
||||
/*
|
||||
fprintf(stderr, "LIBBURN_DEBUG: media_lba_limit= %d\n",
|
||||
d->media_lba_limit);
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -378,6 +357,11 @@ void mmc_close_session(struct burn_write_opts *o)
|
||||
mmc_close(d, 1, 0);
|
||||
}
|
||||
|
||||
/* ts A70227 : extended meaning of session to address all possible values
|
||||
of 5Bh CLOSE TRACK SESSION to address any Close Function.
|
||||
@param session contains the two high bits of Close Function
|
||||
@param track if not 0: sets the lowest bit of Close Function
|
||||
*/
|
||||
void mmc_close(struct burn_drive *d, int session, int track)
|
||||
{
|
||||
struct command c;
|
||||
@ -388,8 +372,8 @@ void mmc_close(struct burn_drive *d, int session, int track)
|
||||
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;
|
||||
/* (ts A61030 : shifted !!session rather than or-ing plain session ) */
|
||||
c.opcode[2] = ((session & 3) << 1) | !!track;
|
||||
c.opcode[4] = track >> 8;
|
||||
c.opcode[5] = track & 0xFF;
|
||||
c.page = NULL;
|
||||
@ -434,14 +418,8 @@ void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf)
|
||||
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;
|
||||
mmc_int_to_four_char(c.opcode + 2, start);
|
||||
mmc_int_to_four_char(c.opcode + 6, len);
|
||||
c.page = buf;
|
||||
c.dir = TO_DRIVE;
|
||||
|
||||
@ -470,6 +448,21 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
|
||||
if (cancelled)
|
||||
return BE_CANCELLED;
|
||||
|
||||
/* ts A70215 */
|
||||
if (d->media_lba_limit > 0 && start >= d->media_lba_limit) {
|
||||
char msg[160];
|
||||
|
||||
sprintf(msg,
|
||||
"Exceeding range of permissible write addresses (%d >= %d)",
|
||||
start, d->media_lba_limit);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002012d,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
d->cancel = 1; /* No need for mutexing because atomic */
|
||||
return BE_CANCELLED;
|
||||
}
|
||||
|
||||
len = buf->sectors;
|
||||
|
||||
/* ts A61009 : buffer fill problems are to be handled by caller */
|
||||
@ -479,10 +472,7 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
|
||||
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;
|
||||
mmc_int_to_four_char(c.opcode + 2, start);
|
||||
c.opcode[6] = 0;
|
||||
c.opcode[7] = (len >> 8) & 0xFF;
|
||||
c.opcode[8] = len & 0xFF;
|
||||
@ -545,8 +535,7 @@ int mmc_fake_toc_entry(struct burn_toc_entry *entry, int session_number,
|
||||
entry->tno = 0;
|
||||
entry->point = track_number & 0xff;
|
||||
entry->point_msb = (track_number >> 8) & 0xff;
|
||||
num = (size_data[0] << 24) | (size_data[1] << 16) |
|
||||
(size_data[2] << 8) | size_data[3];
|
||||
num = mmc_four_char_to_int(size_data);
|
||||
entry->track_blocks = num;
|
||||
burn_lba_to_msf(num, &min, &sec, &frames);
|
||||
if (min > 255) {
|
||||
@ -558,8 +547,7 @@ int mmc_fake_toc_entry(struct burn_toc_entry *entry, int session_number,
|
||||
entry->sec = sec;
|
||||
entry->frame = frames;
|
||||
entry->zero = 0;
|
||||
num = (start_data[0] << 24) | (start_data[1] << 16) |
|
||||
(start_data[2] << 8) | start_data[3];
|
||||
num = mmc_four_char_to_int(start_data);
|
||||
entry->start_lba = num;
|
||||
burn_lba_to_msf(num, &min, &sec, &frames);
|
||||
if (min > 255) {
|
||||
@ -584,10 +572,21 @@ int mmc_fake_toc(struct burn_drive *d)
|
||||
struct buffer buf;
|
||||
int i, session_number, prev_session = -1, ret, lba;
|
||||
unsigned char *tdata, size_data[4], start_data[4];
|
||||
char msg[160];
|
||||
|
||||
if (d->last_track_no <= 0 || d->complete_sessions <= 0 ||
|
||||
d->status == BURN_DISC_BLANK)
|
||||
return 2;
|
||||
if (d->last_track_no > BURN_MMC_FAKE_TOC_MAX_SIZE) {
|
||||
sprintf(msg,
|
||||
"Too many logical tracks recorded (%d , max. %d)\n",
|
||||
d->last_track_no, BURN_MMC_FAKE_TOC_MAX_SIZE);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002012c,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
return 0;
|
||||
}
|
||||
d->disc = burn_disc_create();
|
||||
if (d->disc == NULL)
|
||||
return -1;
|
||||
@ -620,10 +619,8 @@ int mmc_fake_toc(struct burn_drive *d)
|
||||
*/
|
||||
for (i = 0; i < d->last_track_no; i++) {
|
||||
ret = mmc_read_track_info(d, i+1, &buf);
|
||||
if (ret < 0)
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
if (ret == 0)
|
||||
continue;
|
||||
tdata = buf.data;
|
||||
session_number = (tdata[33] << 8) | tdata[3];
|
||||
if (session_number <= 0)
|
||||
@ -643,8 +640,16 @@ int mmc_fake_toc(struct burn_drive *d)
|
||||
entry;
|
||||
}
|
||||
|
||||
if (session_number > d->disc->sessions)
|
||||
if (session_number > d->disc->sessions) {
|
||||
if (i == d->last_track_no - 1) {
|
||||
/* ts A70212 : Last track field Free Blocks */
|
||||
d->media_capacity_remaining =
|
||||
((off_t) mmc_four_char_to_int(tdata + 16)) *
|
||||
((off_t) 2048);
|
||||
d->media_lba_limit = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
entry = &(d->toc_entry[i + session_number - 1]);
|
||||
track = burn_track_create();
|
||||
@ -916,13 +921,17 @@ void mmc_read_disc_info(struct burn_drive *d)
|
||||
struct command c;
|
||||
char msg[160];
|
||||
/* ts A70131 : had to move mmc_read_toc() to end of function */
|
||||
int do_read_toc = 0, session_state;
|
||||
int do_read_toc = 0, session_state, disc_status;
|
||||
|
||||
/* ts A61020 */
|
||||
d->start_lba = d->end_lba = -2000000000;
|
||||
d->erasable = 0;
|
||||
d->last_track_no = 1;
|
||||
|
||||
/* ts A70212 - A70215 */
|
||||
d->media_capacity_remaining = 0;
|
||||
d->media_lba_limit = 0;
|
||||
|
||||
/* ts A61202 */
|
||||
d->toc_entries = 0;
|
||||
if (d->status == BURN_DISC_EMPTY)
|
||||
@ -948,7 +957,12 @@ void mmc_read_disc_info(struct burn_drive *d)
|
||||
data = c.page->data;
|
||||
d->erasable = !!(data[2] & 16);
|
||||
|
||||
switch (data[2] & 3) {
|
||||
disc_status = data[2] & 3;
|
||||
if (d->current_profile == 0x10) { /* DVD-ROM */
|
||||
disc_status = 2; /* always full and finalized */
|
||||
d->erasable = 0; /* never erasable */
|
||||
}
|
||||
switch (disc_status) {
|
||||
case 0:
|
||||
d->toc_entries = 0;
|
||||
d->start_lba = burn_msf_to_lba(data[17], data[18], data[19]);
|
||||
@ -965,14 +979,8 @@ void mmc_read_disc_info(struct burn_drive *d)
|
||||
case 1:
|
||||
d->status = BURN_DISC_APPENDABLE;
|
||||
case 2:
|
||||
if ((data[2] & 3) == 2) {
|
||||
if (disc_status == 2)
|
||||
d->status = BURN_DISC_FULL;
|
||||
#ifdef Libburn_support_dvd_r_seQ
|
||||
/* offers no feature 0021h now but might do if blank */
|
||||
if (d->current_profile == 0x14) /* DVD-RW */
|
||||
d->current_is_supported_profile = 1;
|
||||
#endif
|
||||
}
|
||||
do_read_toc = 1;
|
||||
break;
|
||||
}
|
||||
@ -1006,6 +1014,15 @@ void mmc_read_disc_info(struct burn_drive *d)
|
||||
*/
|
||||
d->bg_format_status = data[7] & 3;
|
||||
|
||||
/* Preliminarily declare blank:
|
||||
ts A61219 : DVD+RW (is not bg_format_status==0 "blank")
|
||||
ts A61229 : same for DVD-RW Restricted overwrite
|
||||
ts A70112 : same for DVD-RAM
|
||||
*/
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
||||
d->current_profile == 0x12)
|
||||
d->status = BURN_DISC_BLANK;
|
||||
|
||||
if (d->status == BURN_DISC_BLANK) {
|
||||
d->last_track_no = 1; /* The "incomplete track" */
|
||||
d->complete_sessions = 0;
|
||||
@ -1023,15 +1040,6 @@ void mmc_read_disc_info(struct burn_drive *d)
|
||||
d->last_track_no = (data[11] << 8) | data[6];
|
||||
}
|
||||
|
||||
/* Preliminarily declare blank:
|
||||
ts A61219 : DVD+RW (is not bg_format_status==0 "blank")
|
||||
ts A61229 : same for DVD-RW Restricted overwrite
|
||||
ts A70112 : same for DVD-RAM
|
||||
*/
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
||||
d->current_profile == 0x12)
|
||||
d->status = BURN_DISC_BLANK;
|
||||
|
||||
if (do_read_toc)
|
||||
mmc_read_toc(d);
|
||||
}
|
||||
@ -1482,6 +1490,8 @@ void mmc_get_configuration(struct burn_drive *d)
|
||||
int len, cp, descr_len = 0, feature_code, prf_number, only_current = 1;
|
||||
unsigned char *descr, *prf, *up_to, *prf_end;
|
||||
struct command c;
|
||||
int phys_if_std = 0;
|
||||
char *phys_name = "";
|
||||
|
||||
d->current_profile = 0;
|
||||
d->current_profile_text[0] = 0;
|
||||
@ -1503,12 +1513,9 @@ void mmc_get_configuration(struct burn_drive *d)
|
||||
|
||||
if (c.error)
|
||||
return;
|
||||
len = (c.page->data[0] << 24)
|
||||
| (c.page->data[1] << 16)
|
||||
| (c.page->data[2] << 8)
|
||||
| c.page->data[3];
|
||||
len = mmc_four_char_to_int(c.page->data);
|
||||
|
||||
if (len<8)
|
||||
if (len < 8 || len > 4096)
|
||||
return;
|
||||
cp = (c.page->data[6]<<8) | c.page->data[7];
|
||||
d->current_profile = cp;
|
||||
@ -1529,7 +1536,14 @@ void mmc_get_configuration(struct burn_drive *d)
|
||||
d->current_is_supported_profile = 1;
|
||||
#endif
|
||||
#ifdef Libburn_support_dvd_r_seQ
|
||||
if (cp == 0x11 || cp == 0x14)
|
||||
if (cp == 0x10 || cp == 0x11 || cp == 0x14) /* DVD-ROM,DVD-R,DVD-RW */
|
||||
d->current_is_supported_profile = 1;
|
||||
if (cp == 0x15 && burn_support_untested_profiles) /* DVD-R/DL */
|
||||
d->current_is_supported_profile = 1;
|
||||
#endif
|
||||
#ifdef Libburn_support_dvd_plus_R
|
||||
if (cp == 0x1b || (cp == 0x2b && burn_support_untested_profiles))
|
||||
/* DVD+R , DVD+R/DL */
|
||||
d->current_is_supported_profile = 1;
|
||||
#endif
|
||||
|
||||
@ -1608,28 +1622,29 @@ void mmc_get_configuration(struct burn_drive *d)
|
||||
!!(descr[4] & 2));
|
||||
#endif /* Libburn_print_feature_descriptorS */
|
||||
|
||||
#ifdef Libburn_print_feature_descriptorS
|
||||
} else if (feature_code == 0x01) {
|
||||
int pys_if_std = 0;
|
||||
char *phys_name = "";
|
||||
|
||||
pys_if_std = (descr[4] << 24) | (descr[5] << 16) |
|
||||
phys_if_std = (descr[4] << 24) | (descr[5] << 16) |
|
||||
(descr[6] << 8) | descr[9];
|
||||
if (pys_if_std == 1)
|
||||
if (phys_if_std == 1)
|
||||
phys_name = "SCSI Family";
|
||||
else if(pys_if_std == 2)
|
||||
else if(phys_if_std == 2)
|
||||
phys_name = "ATAPI";
|
||||
else if(pys_if_std == 3 || pys_if_std == 4 ||
|
||||
pys_if_std == 6)
|
||||
else if(phys_if_std == 3 || phys_if_std == 4 ||
|
||||
phys_if_std == 6)
|
||||
phys_name = "IEEE 1394 FireWire";
|
||||
else if(pys_if_std == 7)
|
||||
else if(phys_if_std == 7)
|
||||
phys_name = "Serial ATAPI";
|
||||
else if(pys_if_std == 7)
|
||||
else if(phys_if_std == 8)
|
||||
phys_name = "USB";
|
||||
|
||||
d->phys_if_std = phys_if_std;
|
||||
strcpy(d->phys_if_name, phys_name);
|
||||
|
||||
#ifdef Libburn_print_feature_descriptorS
|
||||
|
||||
fprintf(stderr,
|
||||
"LIBBURN_EXPERIMENTAL : Phys. Interface Standard %Xh \"%s\"\n",
|
||||
pys_if_std, phys_name);
|
||||
phys_if_std, phys_name);
|
||||
|
||||
} else if (feature_code == 0x107) {
|
||||
|
||||
@ -1665,10 +1680,12 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
|
||||
{
|
||||
struct buffer buf;
|
||||
int len, type, score, num_descr, max_score = -2000000000, i, sign = 1;
|
||||
off_t size;
|
||||
off_t size, num_blocks;
|
||||
struct command c;
|
||||
unsigned char *dpt;
|
||||
/* <<<
|
||||
char msg[160];
|
||||
*/
|
||||
|
||||
mmc_function_spy("mmc_read_format_capacities");
|
||||
|
||||
@ -1679,7 +1696,7 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
|
||||
d->best_format_size = 0;
|
||||
|
||||
memcpy(c.opcode, MMC_READ_FORMAT_CAPACITIES,
|
||||
sizeof(MMC_GET_CONFIGURATION));
|
||||
sizeof(MMC_READ_FORMAT_CAPACITIES));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(MMC_READ_FORMAT_CAPACITIES);
|
||||
c.opcode[7]= 0x02;
|
||||
@ -1704,12 +1721,14 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
|
||||
+ (dpt[1] << 16) + (dpt[2] << 8) + dpt[3];
|
||||
d->format_curr_blsas = (dpt[5] << 16) + (dpt[6] << 8) + dpt[7];
|
||||
|
||||
/* <<<
|
||||
sprintf(msg,
|
||||
"Current/Maximum Capacity Descriptor : type = %d : %.f",
|
||||
d->format_descr_type, (double) d->format_curr_max_size);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msg, 0, 0);
|
||||
*/
|
||||
|
||||
d->format_curr_max_size *= (off_t) 2048;
|
||||
|
||||
@ -1720,9 +1739,8 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
|
||||
num_descr = (len - 8) / 8;
|
||||
for (i = 0; i < num_descr; i++) {
|
||||
dpt = c.page->data + 12 + 8 * i;
|
||||
size = (((off_t) dpt[0]) << 24)
|
||||
+ (dpt[1] << 16) + (dpt[2] << 8) + dpt[3];
|
||||
size *= (off_t) 2048;
|
||||
num_blocks = mmc_four_char_to_int(dpt);
|
||||
size = num_blocks * (off_t) 2048;
|
||||
type = dpt[4] >> 2;
|
||||
|
||||
if (i < 32) {
|
||||
@ -1733,24 +1751,37 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
|
||||
d->num_format_descr = i + 1;
|
||||
}
|
||||
|
||||
/* <<<
|
||||
sprintf(msg, "Capacity Descriptor %2.2Xh %.fs = %.1f MB",type,
|
||||
((double) size)/2048.0, ((double) size)/1024.0/1024.0);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msg, 0, 0);
|
||||
*/
|
||||
|
||||
/* Criterion is proximity to quick intermediate state */
|
||||
if (type == 0x00) { /* full format (with lead out) */
|
||||
score = 1 * sign;
|
||||
if(d->current_profile == 0x12 &&
|
||||
d->media_capacity_remaining == 0) {
|
||||
d->media_capacity_remaining = size;
|
||||
d->media_lba_limit = num_blocks;
|
||||
}
|
||||
} else if (type == 0x10) { /* DVD-RW full format */
|
||||
score = 10 * sign;
|
||||
} else if(type == 0x13) { /* DVD-RW quick grow last session */
|
||||
score = 100 * sign;
|
||||
} else if(type == 0x15) { /* DVD-RW Quick */
|
||||
score = 50 * sign;
|
||||
if(d->current_profile == 0x13) {
|
||||
d->media_capacity_remaining = size;
|
||||
d->media_lba_limit = num_blocks;
|
||||
}
|
||||
} else if(type == 0x26) { /* DVD+RW */
|
||||
score = 1 * sign;
|
||||
d->media_capacity_remaining = size;
|
||||
d->media_lba_limit = num_blocks;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@ -1763,12 +1794,14 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
|
||||
}
|
||||
}
|
||||
|
||||
/* <<<
|
||||
sprintf(msg,
|
||||
"best_format_type = %2.2Xh , best_format_size = %.f",
|
||||
d->best_format_type, (double) d->best_format_size);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msg, 0, 0);
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -1869,8 +1902,8 @@ int mmc_format_unit(struct burn_drive *d, off_t size, int flag)
|
||||
c.page->data[1] = 0x02; /* Immed */
|
||||
c.page->data[3] = 8; /* Format descriptor length */
|
||||
num_of_blocks = size / 2048;
|
||||
for (i = 0; i < 4; i++)
|
||||
c.page->data[4 + i] = (num_of_blocks >> (24 - 8 * i)) & 0xff;
|
||||
mmc_int_to_four_char(c.page->data + 4, num_of_blocks);
|
||||
|
||||
if (flag & 128) { /* explicitely chosen format descriptor */
|
||||
/* use case: the app knows what to do */
|
||||
|
||||
@ -1900,9 +1933,7 @@ selected_not_suitable:;
|
||||
if (flag & 4) {
|
||||
num_of_blocks =
|
||||
d->format_descriptors[index].size / 2048;
|
||||
for (i = 0; i < 4; i++)
|
||||
c.page->data[4 + i] =
|
||||
(num_of_blocks >> (24 - 8 * i)) & 0xff;
|
||||
mmc_int_to_four_char(c.page->data + 4, num_of_blocks);
|
||||
}
|
||||
if (format_type != 0x26)
|
||||
for (i = 0; i < 3; i++)
|
||||
@ -1977,9 +2008,8 @@ selected_not_suitable:;
|
||||
num_of_blocks = diff;
|
||||
}
|
||||
if (num_of_blocks > 0)
|
||||
for (i = 0; i < 4; i++)
|
||||
c.page->data[4 + i] =
|
||||
(num_of_blocks >> (24 - 8 * i)) & 0xff;
|
||||
mmc_int_to_four_char(c.page->data + 4,
|
||||
num_of_blocks);
|
||||
}
|
||||
/* 6.5.4.2.8 , DVD-RW Quick Grow Last Border */
|
||||
format_type = 0x13;
|
||||
@ -2003,9 +2033,8 @@ selected_not_suitable:;
|
||||
if ((flag & 4)
|
||||
|| d->best_format_type == full_format_type) {
|
||||
num_of_blocks = d->best_format_size / 2048;
|
||||
for (i = 0; i < 4; i++)
|
||||
c.page->data[4 + i] =
|
||||
(num_of_blocks >> (24 - 8 * i)) & 0xff;
|
||||
mmc_int_to_four_char(c.page->data + 4,
|
||||
num_of_blocks);
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -2208,11 +2237,16 @@ int mmc_setup_drive(struct burn_drive *d)
|
||||
d->format_unit = mmc_format_unit;
|
||||
d->read_format_capacities = mmc_read_format_capacities;
|
||||
|
||||
|
||||
/* ts A70302 */
|
||||
d->phys_if_std = -1;
|
||||
d->phys_if_name[0] = 0;
|
||||
|
||||
/* ts A61020 */
|
||||
d->start_lba = -2000000000;
|
||||
d->end_lba = -2000000000;
|
||||
|
||||
/* ts A61201 - A70128 */
|
||||
/* ts A61201 - A70223*/
|
||||
d->erasable = 0;
|
||||
d->current_profile = -1;
|
||||
d->current_profile_text[0] = 0;
|
||||
@ -2226,6 +2260,8 @@ int mmc_setup_drive(struct burn_drive *d)
|
||||
d->num_format_descr = 0;
|
||||
d->complete_sessions = 0;
|
||||
d->last_track_no = 1;
|
||||
d->media_capacity_remaining = 0;
|
||||
d->media_lba_limit = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -2257,9 +2293,10 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
|
||||
/* Link size dummy */
|
||||
pd[5] = 0;
|
||||
|
||||
} else if ((d->current_profile == 0x14 || d->current_profile == 0x11)
|
||||
} else if ((d->current_profile == 0x14 || d->current_profile == 0x11 ||
|
||||
d->current_profile == 0x15)
|
||||
&& o->write_type == BURN_WRITE_SAO) {
|
||||
/* ts A70205 : DVD-R[W} : Disc-at-once, DAO */
|
||||
/* ts A70205 : DVD-R[W][/DL] : Disc-at-once, DAO */
|
||||
/* Learned from dvd+rw-tools and mmc5r03c.pdf .
|
||||
See doc/cookbook.txt for more detailed references. */
|
||||
|
||||
@ -2272,8 +2309,9 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
|
||||
/* Data Block Type = 8 */
|
||||
pd[4] = 8;
|
||||
|
||||
} else if (d->current_profile == 0x14 || d->current_profile == 0x11) {
|
||||
/* ts A70128 : DVD-R[W] Incremental Streaming */
|
||||
} else if (d->current_profile == 0x14 || d->current_profile == 0x11 ||
|
||||
d->current_profile == 0x15) {
|
||||
/* ts A70128 : DVD-R[W][/DL] Incremental Streaming */
|
||||
/* Learned from transport.hxx : page05_setup()
|
||||
and mmc5r03c.pdf 7.5, 4.2.3.4 Table 17
|
||||
and spc3r23.pdf 6.8, 7.4.3 */
|
||||
@ -2305,6 +2343,10 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
|
||||
/* Packet Size */
|
||||
pd[13] = 16;
|
||||
|
||||
} else if (d->current_profile == 0x1a || d->current_profile == 0x1b ||
|
||||
d->current_profile == 0x2b || d->current_profile == 0x12) {
|
||||
/* not with DVD+R[W][/DL] or DVD-RAM */;
|
||||
return 0;
|
||||
} else {
|
||||
/* Traditional setup for CD */
|
||||
|
||||
|
@ -69,4 +69,7 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
|
||||
unsigned char *pd);
|
||||
|
||||
|
||||
/* mmc5r03c.pdf 4.3.4.4.1 d) "The maximum number of RZones is 2 302." */
|
||||
#define BURN_MMC_FAKE_TOC_MAX_SIZE 2302
|
||||
|
||||
#endif /*__MMC*/
|
||||
|
@ -36,6 +36,8 @@ struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive)
|
||||
opts->obs = -1;
|
||||
opts->obs_pad = 0;
|
||||
opts->start_byte = -1;
|
||||
opts->fill_up_media = 0;
|
||||
opts->force_is_set = 0;
|
||||
opts->has_mediacatalog = 0;
|
||||
opts->format = BURN_CDROM;
|
||||
opts->multi = 0;
|
||||
@ -172,92 +174,187 @@ void burn_write_opts_set_start_byte(struct burn_write_opts *opts, off_t value)
|
||||
|
||||
|
||||
/* ts A70207 API */
|
||||
/** @param flag Bitfield for control purposes:
|
||||
bit0= do not choose type but check the one that is already set
|
||||
bit1= do not issue error messages via burn_msgs queue
|
||||
*/
|
||||
enum burn_write_types burn_write_opts_auto_write_type(
|
||||
struct burn_write_opts *opts, struct burn_disc *disc,
|
||||
char reasons[1024], int flag)
|
||||
char reasons[BURN_REASONS_LEN], int flag)
|
||||
{
|
||||
struct burn_multi_caps *caps = NULL;
|
||||
struct burn_drive *d = opts->drive;
|
||||
struct burn_disc_mode_demands demands;
|
||||
int ret;
|
||||
enum burn_write_types wt;
|
||||
int ret, would_do_sao = 0;
|
||||
char *reason_pt;
|
||||
|
||||
reasons[0] = 0;
|
||||
ret = burn_disc_get_write_mode_demands(disc, &demands, 0);
|
||||
if (ret <= 0) {
|
||||
strcat(reasons, "cannot recognize job demands, ");
|
||||
|
||||
if (d->status != BURN_DISC_BLANK &&
|
||||
d->status != BURN_DISC_APPENDABLE){
|
||||
if (d->status == BURN_DISC_FULL)
|
||||
strcat(reasons, "MEDIA: closed or not recordable, ");
|
||||
else
|
||||
strcat(reasons,"MEDIA: no writeable media detected, ");
|
||||
if (!(flag & 3))
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002013a,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"No suitable media detected", 0, 0);
|
||||
return BURN_WRITE_NONE;
|
||||
}
|
||||
ret = burn_disc_get_write_mode_demands(disc, opts, &demands,
|
||||
!!opts->fill_up_media);
|
||||
if (ret <= 0) {
|
||||
strcat(reasons, "cannot recognize job demands, ");
|
||||
{wt = BURN_WRITE_NONE; goto ex;}
|
||||
}
|
||||
if (demands.exotic_track && !d->current_is_cd_profile) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020123,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"DVD Media are unsuitable for desired track type",
|
||||
0, 0);
|
||||
if (demands.audio)
|
||||
strcat(reasons, "audio track prohibited by non-CD, ");
|
||||
else
|
||||
strcat(reasons, "exotic track prohibited by non-CD, ");
|
||||
return BURN_WRITE_NONE;
|
||||
{wt = BURN_WRITE_NONE; goto ex;}
|
||||
}
|
||||
|
||||
if ((flag & 1) && opts->write_type != BURN_WRITE_SAO)
|
||||
goto try_tao;
|
||||
reason_pt = reasons + strlen(reasons);
|
||||
strcat(reasons, "SAO: ");
|
||||
if (d->status != BURN_DISC_BLANK) {
|
||||
strcat(reasons, "write type SAO works only on blank media, ");
|
||||
goto try_tao;
|
||||
}
|
||||
burn_disc_free_multi_caps(&caps);
|
||||
ret = burn_disc_get_multi_caps(d, BURN_WRITE_SAO, &caps, 0);
|
||||
if (ret < 0) {
|
||||
no_caps:;
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002012a,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Cannot inquire write mode capabilities",
|
||||
0, 0);
|
||||
strcat(reasons, "cannot inquire write mode capabilities, ");
|
||||
return BURN_WRITE_NONE;
|
||||
} if (ret > 0) {
|
||||
reason_pt = reasons + strlen(reasons);
|
||||
strcat(reasons, "SAO: ");
|
||||
if ((opts->multi || demands.multi_session) &&
|
||||
!caps->multi_session)
|
||||
strcat(reasons, "multi session capability lacking, ");
|
||||
if (demands.multi_track && !caps->multi_track)
|
||||
strcat(reasons, "multi track capability lacking, ");
|
||||
if (demands.unknown_track_size)
|
||||
strcat(reasons, "track size unpredictable, ");
|
||||
if (demands.mixed_mode)
|
||||
strcat(reasons, "tracks of different modes mixed, ");
|
||||
if (strcmp(reason_pt, "SAO: ") != 0)
|
||||
goto no_sao;
|
||||
burn_write_opts_set_write_type(opts,
|
||||
BURN_WRITE_SAO, BURN_BLOCK_SAO);
|
||||
return BURN_WRITE_SAO;
|
||||
} else
|
||||
strcat(reasons, "SAO: no SAO offered by drive and media, ");
|
||||
{wt = BURN_WRITE_NONE; goto ex;}
|
||||
} else if (ret == 0) {
|
||||
strcat(reasons, "no SAO offered by drive and media, ");
|
||||
goto no_sao;
|
||||
}
|
||||
if ((opts->multi || demands.multi_session) &&
|
||||
!caps->multi_session)
|
||||
strcat(reasons, "multi session capability lacking, ");
|
||||
if (demands.will_append)
|
||||
strcat(reasons, "appended session capability lacking, ");
|
||||
if (demands.multi_track && !caps->multi_track)
|
||||
strcat(reasons, "multi track capability lacking, ");
|
||||
if (demands.unknown_track_size == 1 &&
|
||||
(caps->might_do_sao == 1 || caps->might_do_sao == 3))
|
||||
strcat(reasons, "track size unpredictable, ");
|
||||
if (demands.mixed_mode)
|
||||
strcat(reasons, "tracks of different modes mixed, ");
|
||||
if (demands.exotic_track && !d->current_is_cd_profile)
|
||||
strcat(reasons, "non-data track on non-cd, ");
|
||||
else if (d->current_is_cd_profile)
|
||||
if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
|
||||
demands.block_types)
|
||||
strcat(reasons, "drive dislikes block type, ");
|
||||
if (d->current_is_cd_profile && opts->fill_up_media)
|
||||
strcat(reasons, "cd sao cannot do media fill up yet, ");
|
||||
if (strcmp(reason_pt, "SAO: ") != 0)
|
||||
goto no_sao;
|
||||
would_do_sao = 1;
|
||||
if (demands.unknown_track_size == 2 && (!(flag & 1)) &&
|
||||
(caps->might_do_sao == 1 || caps->might_do_sao == 3)) {
|
||||
strcat(reasons, "would have to use default track sizes, ");
|
||||
goto no_sao;
|
||||
} else if (caps->might_do_sao >= 3 && !(flag & 1))
|
||||
goto try_tao;
|
||||
do_sao:;
|
||||
if (!(flag & 1))
|
||||
burn_write_opts_set_write_type(
|
||||
opts, BURN_WRITE_SAO, BURN_BLOCK_SAO);
|
||||
{wt = BURN_WRITE_SAO; goto ex;}
|
||||
no_sao:;
|
||||
burn_disc_free_multi_caps(&caps);
|
||||
strcat(reasons, "\n");
|
||||
try_tao:;
|
||||
if ((flag & 1) && opts->write_type != BURN_WRITE_TAO)
|
||||
goto try_raw;
|
||||
reason_pt = reasons + strlen(reasons);
|
||||
strcat(reasons, "TAO: ");
|
||||
burn_disc_free_multi_caps(&caps);
|
||||
ret = burn_disc_get_multi_caps(d, BURN_WRITE_TAO, &caps, 0);
|
||||
if (ret < 0)
|
||||
goto no_caps;
|
||||
if (ret == 0) {
|
||||
strcat(reasons, "no TAO offered by drive and media, ");
|
||||
no_write_mode:;
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002012b,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive offers no suitable write mode with this job",
|
||||
0, 0);
|
||||
return BURN_WRITE_NONE;
|
||||
goto no_tao;
|
||||
}
|
||||
if ((opts->multi || demands.multi_session) && !caps->multi_session)
|
||||
strcat(reasons, "multi session capability lacking, ");
|
||||
if (demands.multi_track && !caps->multi_track)
|
||||
strcat(reasons, "multi track capability lacking, ");
|
||||
if (demands.exotic_track && !d->current_is_cd_profile)
|
||||
strcat(reasons, "non-data track on non-cd, ");
|
||||
if (d->current_is_cd_profile && !opts->force_is_set)
|
||||
if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
|
||||
demands.block_types)
|
||||
strcat(reasons, "drive dislikes block type, ");
|
||||
if (strcmp(reason_pt, "TAO: ") != 0)
|
||||
goto no_write_mode;
|
||||
goto no_tao;
|
||||
/* ( TAO data/audio block size will be handled automatically ) */
|
||||
burn_write_opts_set_write_type(opts,
|
||||
BURN_WRITE_TAO, BURN_BLOCK_MODE1);
|
||||
return BURN_WRITE_TAO;
|
||||
if (!(flag & 1))
|
||||
burn_write_opts_set_write_type(
|
||||
opts, BURN_WRITE_TAO, BURN_BLOCK_MODE1);
|
||||
{wt = BURN_WRITE_TAO; goto ex;}
|
||||
no_tao:;
|
||||
if (would_do_sao && !(flag & 1))
|
||||
goto do_sao;
|
||||
if (!d->current_is_cd_profile)
|
||||
goto no_write_mode;
|
||||
try_raw:;
|
||||
if ((flag & 1) && opts->write_type != BURN_WRITE_RAW)
|
||||
goto no_write_mode;
|
||||
|
||||
if (!(flag & 1)) /* For now: no automatic raw write modes */
|
||||
goto no_write_mode;
|
||||
|
||||
reason_pt = reasons + strlen(reasons);
|
||||
strcat(reasons, "RAW: ");
|
||||
if (!d->current_is_cd_profile)
|
||||
strcat(reasons, "write type RAW prohibited by non-cd, ");
|
||||
else if (d->status != BURN_DISC_BLANK)
|
||||
strcat(reasons, "write type RAW works only on blank media, ");
|
||||
else if ((d->block_types[BURN_WRITE_TAO] & demands.block_types) !=
|
||||
demands.block_types)
|
||||
strcat(reasons, "drive dislikes block type, ");
|
||||
if (strcmp(reason_pt, "RAW: ") != 0)
|
||||
goto no_write_mode;
|
||||
|
||||
/* For now: no setting of raw write modes */
|
||||
|
||||
{wt = BURN_WRITE_RAW; goto ex;}
|
||||
|
||||
no_write_mode:;
|
||||
wt = BURN_WRITE_NONE;
|
||||
ex:;
|
||||
burn_disc_free_multi_caps(&caps);
|
||||
if (wt == BURN_WRITE_NONE && !(flag & 3)) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002012b,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive offers no suitable write mode with this job",
|
||||
0, 0);
|
||||
}
|
||||
return wt;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70213 : new API function */
|
||||
void burn_write_opts_set_fillup(struct burn_write_opts *opts,int fill_up_media)
|
||||
{
|
||||
opts->fill_up_media = !!fill_up_media;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70303: API */
|
||||
void burn_write_opts_set_force(struct burn_write_opts *opts, int use_force)
|
||||
{
|
||||
opts->force_is_set = !!use_force;
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,6 +41,14 @@ struct burn_write_opts
|
||||
/* ts A61222 : Start address for media which allow a choice */
|
||||
off_t start_byte;
|
||||
|
||||
/* ts A70213 : Wether to fill up the available space on media */
|
||||
int fill_up_media;
|
||||
|
||||
/* ts A70303 : Wether to override conformance checks:
|
||||
- the check wether CD write+block type is supported by the drive
|
||||
*/
|
||||
int force_is_set;
|
||||
|
||||
/** A disc can have a media catalog number */
|
||||
int has_mediacatalog;
|
||||
unsigned char mediacatalog[13];
|
||||
|
@ -52,6 +52,10 @@ SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
|
||||
typedef int burn_drive_enumerator_t;
|
||||
|
||||
|
||||
/* Parameters for sibling list. See sibling_fds, sibling_fnames */
|
||||
#define BURN_OS_SG_MAX_SIBLINGS 5
|
||||
#define BURN_OS_SG_MAX_NAMELEN 16
|
||||
|
||||
/* The list of operating system dependent elements in struct burn_drive.
|
||||
Usually they are initialized in sg-*.c:enumerate_common().
|
||||
*/
|
||||
@ -60,5 +64,7 @@ int fd; \
|
||||
\
|
||||
/* ts A60926 : trying to lock against growisofs /dev/srN, /dev/scdN */ \
|
||||
int sibling_count; \
|
||||
int sibling_fds[LIBBURN_SG_MAX_SIBLINGS];
|
||||
int sibling_fds[BURN_OS_SG_MAX_SIBLINGS]; \
|
||||
/* ts A70409 : DDLP */ \
|
||||
char sibling_fnames[BURN_OS_SG_MAX_SIBLINGS][BURN_OS_SG_MAX_NAMELEN];
|
||||
|
||||
|
@ -3,9 +3,11 @@
|
||||
/* scsi block commands */
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "transport.h"
|
||||
#include "sbc.h"
|
||||
#include "spc.h"
|
||||
#include "options.h"
|
||||
|
||||
/* spc command set */
|
||||
@ -23,6 +25,7 @@ void sbc_load(struct burn_drive *d)
|
||||
c.dir = NO_TRANSFER;
|
||||
c.page = NULL;
|
||||
d->issue_command(d, &c);
|
||||
spc_wait_unit_attention(d, 60);
|
||||
}
|
||||
|
||||
void sbc_eject(struct burn_drive *d)
|
||||
|
@ -71,14 +71,19 @@ Hint: You should also look into sg-freebsd-port.c, which is a younger and
|
||||
#include <sys/poll.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <scsi/sg.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
||||
/* ts A61211 : to recognize CD devices on /dev/sr* */
|
||||
/* ts A61211 : to eventually recognize CD devices on /dev/sr* */
|
||||
#include <linux/cdrom.h>
|
||||
|
||||
|
||||
/* ts A61211 : preparing for exploration of recent Linux ATA adventures */
|
||||
/** Indication of the Linux kernel this software is running on */
|
||||
/* -1 = not evaluated , 0 = unrecognizable , 1 = 2.4 , 2 = 2.6 */
|
||||
static int sg_kernel_age = -1;
|
||||
|
||||
|
||||
/** PORTING : Device file families for bus scanning and drive access.
|
||||
Both device families must support the following ioctls:
|
||||
SG_IO,
|
||||
@ -104,22 +109,22 @@ static int linux_sg_enumerate_debug = 0;
|
||||
in the range of 0 to 31 . The resulting addresses must provide SCSI
|
||||
address parameters Host, Channel, Id, Lun and also Bus.
|
||||
E.g.: "/dev/sg%d"
|
||||
sr%d is supposed to map only CD-ROM style devices. Additionally a test
|
||||
with ioctl(CDROM_DRIVE_STATUS) is made to assert that it is such a drive,
|
||||
|
||||
This initial setting may be overridden in sg_select_device_family() by
|
||||
settings made via burn_preset_device_open().
|
||||
*/
|
||||
/* NEW INFO: If hard disks at /dev/sr allow ioctl(CDROM_DRIVE_STATUS), they
|
||||
are in danger.
|
||||
If you want it less dangerous:
|
||||
#undef CDROM_DRIVE_STATUS
|
||||
but then you might need linux_sg_accept_any_type = 1 which
|
||||
is _more dangerous_.
|
||||
*/
|
||||
/* !!! DO NOT SET TO sr%d UNLESS YOU PROTECTED ALL INDISPENSIBLE DEVICES
|
||||
by chmod -rw . A test wether non-CD devices are properly excluded would
|
||||
be well needed though. Heroic disks, scanners, etc. wanted !!! */
|
||||
static char linux_sg_device_family[80] = {"/dev/sg%d"};
|
||||
|
||||
/* Set this to 1 if you want the default linux_sg_device_family chosen
|
||||
depending on kernel release: sg for <2.6 , sr for >=2.6
|
||||
*/
|
||||
static int linux_sg_auto_family = 1;
|
||||
|
||||
|
||||
/* Set this to 1 in order to accept any TYPE_* (see scsi/scsi.h) */
|
||||
/* NEW INFO: Try with 0 first. There is hope via CDROM_DRIVE_STATUS. */
|
||||
/* But try with 0 first. There is hope via CDROM_DRIVE_STATUS. */
|
||||
/* !!! DO NOT SET TO 1 UNLESS YOU PROTECTED ALL INDISPENSIBLE DEVICES
|
||||
chmod -rw !!! */
|
||||
static int linux_sg_accept_any_type = 0;
|
||||
@ -168,12 +173,15 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
int channel_no, int target_no, int lun_no);
|
||||
|
||||
|
||||
/* >>> ts A61115 : this needs mending. A Linux aspect shows up in cdrskin. */
|
||||
/* ts A60813 : storage objects are in libburn/init.c
|
||||
wether to use O_EXCL
|
||||
wether to use O_EXCL with open(2) of devices
|
||||
wether to use fcntl(,F_SETLK,) after open(2) of devices
|
||||
what device family to use : 0=default, 1=sr, 2=scd, (3=st), 4=sg
|
||||
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_fcntl_f_setlk;
|
||||
extern int burn_sg_use_family;
|
||||
extern int burn_sg_open_o_nonblock;
|
||||
extern int burn_sg_open_abort_busy;
|
||||
|
||||
@ -188,6 +196,53 @@ int mmc_function_spy(char * text);
|
||||
/* (Public functions are listed below) */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
/* ts A70413 */
|
||||
/* This finds out wether the software is running on kernel >= 2.6
|
||||
*/
|
||||
static void sg_evaluate_kernel(void)
|
||||
{
|
||||
struct utsname buf;
|
||||
if (sg_kernel_age >= 0)
|
||||
return;
|
||||
|
||||
sg_kernel_age = 0;
|
||||
if (uname(&buf) == -1)
|
||||
return;
|
||||
sg_kernel_age = 1;
|
||||
if (strcmp(buf.release, "2.6") >= 0)
|
||||
sg_kernel_age = 2;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70314 */
|
||||
/* This installs the device file family if one was chosen explicitely
|
||||
by burn_preset_device_open()
|
||||
*/
|
||||
static void sg_select_device_family(void)
|
||||
{
|
||||
|
||||
/* >>> ??? do we need a mutex here ? */
|
||||
/* >>> (It might be concurrent but is supposed to have always
|
||||
the same effect. Any race condition should be harmless.) */
|
||||
|
||||
if (burn_sg_use_family == 1)
|
||||
strcpy(linux_sg_device_family, "/dev/sr%d");
|
||||
else if (burn_sg_use_family == 2)
|
||||
strcpy(linux_sg_device_family, "/dev/scd%d");
|
||||
else if (burn_sg_use_family == 3)
|
||||
strcpy(linux_sg_device_family, "/dev/st%d");
|
||||
else if (burn_sg_use_family == 4)
|
||||
strcpy(linux_sg_device_family, "/dev/sg%d");
|
||||
else if (linux_sg_auto_family) {
|
||||
sg_evaluate_kernel();
|
||||
if (sg_kernel_age >= 2)
|
||||
strcpy(linux_sg_device_family, "/dev/sr%d");
|
||||
else
|
||||
strcpy(linux_sg_device_family, "/dev/sg%d");
|
||||
linux_sg_auto_family = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int sgio_test(int fd)
|
||||
{
|
||||
@ -229,12 +284,86 @@ static int sg_handle_busy_device(char *fname, int os_errno)
|
||||
}
|
||||
|
||||
|
||||
/* ts A60925 : ticket 74 */
|
||||
static 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) {
|
||||
/* ts A70409 : DDLP-B */
|
||||
/* >>> release single lock on fname */
|
||||
return 1;
|
||||
}
|
||||
os_errno= errno;
|
||||
|
||||
sprintf(msg, "Encountered error when closing drive '%s'", fname);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70401 :
|
||||
fcntl() has the unappealing property to work only after open().
|
||||
So libburn will by default use open(O_EXCL) first and afterwards
|
||||
as second assertion will use fcntl(F_SETLK). One lock more should not harm.
|
||||
*/
|
||||
static int sg_fcntl_lock(int *fd, char *fd_name, int l_type, int verbous)
|
||||
{
|
||||
struct flock lockthing;
|
||||
char msg[81];
|
||||
int ret;
|
||||
|
||||
if (!burn_sg_fcntl_f_setlk)
|
||||
return 1;
|
||||
|
||||
memset(&lockthing, 0, sizeof(lockthing));
|
||||
lockthing.l_type = l_type;
|
||||
lockthing.l_whence = SEEK_SET;
|
||||
lockthing.l_start = 0;
|
||||
lockthing.l_len = 0;
|
||||
/*
|
||||
fprintf(stderr,"LIBBURN_EXPERIMENTAL: fcntl(%d, F_SETLK, %s)\n",
|
||||
*fd, l_type == F_WRLCK ? "F_WRLCK" : "F_RDLCK");
|
||||
*/
|
||||
|
||||
ret = fcntl(*fd, F_SETLK, &lockthing);
|
||||
if (ret == -1) {
|
||||
if (verbous) {
|
||||
sprintf(msg, "Device busy. Failed to fcntl-lock '%s'",
|
||||
fd_name);
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020008,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, errno, 0);
|
||||
}
|
||||
close(*fd);
|
||||
*fd = -1;
|
||||
|
||||
/* ts A70409 : DDLP-B */
|
||||
/* >>> release single lock on fd_name */
|
||||
|
||||
return(0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60926 */
|
||||
static int sg_open_drive_fd(char *fname, int scan_mode)
|
||||
{
|
||||
int open_mode = O_RDWR, fd;
|
||||
char msg[81];
|
||||
|
||||
/* ts A70409 : DDLP-B */
|
||||
/* >>> obtain single lock on fname */
|
||||
|
||||
/* ts A60813 - A60927
|
||||
O_EXCL with devices is a non-POSIX feature
|
||||
of Linux kernels. Possibly introduced 2002.
|
||||
@ -244,17 +373,22 @@ static int sg_open_drive_fd(char *fname, int scan_mode)
|
||||
/* 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. */
|
||||
default mode for both now. Disable on own risk.
|
||||
ts A70411
|
||||
Switched to O_NDELAY for LKML statement 2007/4/11/141 by Alan Cox:
|
||||
"open() has side effects. The CD layer allows you to open
|
||||
with O_NDELAY if you want to avoid them."
|
||||
*/
|
||||
if(burn_sg_open_o_nonblock)
|
||||
open_mode |= O_NONBLOCK;
|
||||
open_mode |= O_NDELAY;
|
||||
|
||||
/* <<< 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));
|
||||
"libburn: experimental: O_EXCL= %d , O_NDELAY= %d\n",
|
||||
!!(open_mode&O_EXCL),!!(open_mode&O_NDELAY));
|
||||
*/
|
||||
|
||||
fd = open(fname, open_mode);
|
||||
@ -273,50 +407,25 @@ static int sg_open_drive_fd(char *fname, int 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,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, errno, 0);
|
||||
return -1;
|
||||
}
|
||||
sg_fcntl_lock(&fd, fname, F_WRLCK, 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60925 : ticket 74 */
|
||||
static 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;
|
||||
}
|
||||
|
||||
|
||||
/* ts A60926 */
|
||||
static int sg_release_siblings(int sibling_fds[], int *sibling_count)
|
||||
static int sg_release_siblings(int sibling_fds[],
|
||||
char sibling_fnames[][BURN_OS_SG_MAX_NAMELEN],
|
||||
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);
|
||||
sg_close_drive_fd(sibling_fnames[i], -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,
|
||||
@ -334,7 +443,8 @@ static int sg_close_drive(struct burn_drive *d)
|
||||
|
||||
if (!burn_drive_is_open(d))
|
||||
return 0;
|
||||
sg_release_siblings(d->sibling_fds, &(d->sibling_count));
|
||||
sg_release_siblings(d->sibling_fds, d->sibling_fnames,
|
||||
&(d->sibling_count));
|
||||
ret = sg_close_drive_fd(d->devname, d->global_index, &(d->fd), 0);
|
||||
return ret;
|
||||
}
|
||||
@ -342,29 +452,45 @@ static int sg_close_drive(struct burn_drive *d)
|
||||
|
||||
/* ts A60926 */
|
||||
static 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 sibling_fds[],
|
||||
char sibling_fnames[][BURN_OS_SG_MAX_NAMELEN],
|
||||
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];
|
||||
struct stat stbuf;
|
||||
dev_t last_rdev = 0, path_rdev;
|
||||
|
||||
static char tldev[][81]= {"/dev/sr%d", "/dev/scd%d", "/dev/st%d",
|
||||
"/dev/sg%d", ""};
|
||||
static char tldev[][81]= {"/dev/sr%d", "/dev/scd%d", "/dev/sg%d", ""};
|
||||
/* ts A70609: removed "/dev/st%d" */
|
||||
|
||||
if(stat(path, &stbuf) == -1)
|
||||
return 0;
|
||||
path_rdev = stbuf.st_rdev;
|
||||
|
||||
sg_select_device_family();
|
||||
if (linux_sg_device_family[0] == 0)
|
||||
return 1;
|
||||
|
||||
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);
|
||||
sg_release_siblings(sibling_fds, sibling_fnames,
|
||||
sibling_count);
|
||||
|
||||
for (tld = 0; tldev[tld][0] != 0; tld++) {
|
||||
if (strcmp(tldev[tld], linux_sg_device_family)==0)
|
||||
continue;
|
||||
for (i = 0; i < 32; i++) {
|
||||
sprintf(fname, tldev[tld], i);
|
||||
if(stat(fname, &stbuf) == -1)
|
||||
continue;
|
||||
if (path_rdev == stbuf.st_rdev)
|
||||
continue;
|
||||
if (*sibling_count > 0 && last_rdev == stbuf.st_rdev)
|
||||
continue;
|
||||
ret = sg_obtain_scsi_adr(fname, &i_bus_no, &i_host_no,
|
||||
&i_channel_no, &i_target_no, &i_lun_no);
|
||||
if (ret <= 0)
|
||||
@ -378,7 +504,7 @@ static int sg_open_scsi_siblings(char *path, int driveno,
|
||||
if (fd < 0)
|
||||
goto failed;
|
||||
|
||||
if (*sibling_count>=LIBBURN_SG_MAX_SIBLINGS) {
|
||||
if (*sibling_count>=BURN_OS_SG_MAX_SIBLINGS) {
|
||||
sprintf(msg, "Too many scsi siblings of '%s'",
|
||||
path);
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
@ -388,18 +514,20 @@ static int sg_open_scsi_siblings(char *path, int driveno,
|
||||
goto failed;
|
||||
}
|
||||
sprintf(msg, "Opened O_EXCL scsi sibling '%s' of '%s'",
|
||||
fname, path);
|
||||
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;
|
||||
strcpy(sibling_fnames[*sibling_count], fname);
|
||||
(*sibling_count)++;
|
||||
last_rdev= stbuf.st_rdev;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
failed:;
|
||||
sg_release_siblings(sibling_fds, sibling_count);
|
||||
sg_release_siblings(sibling_fds, sibling_fnames, sibling_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -477,10 +605,13 @@ static void ata_enumerate(void)
|
||||
static void sg_enumerate(void)
|
||||
{
|
||||
struct sg_scsi_id sid;
|
||||
int i, fd, sibling_fds[LIBBURN_SG_MAX_SIBLINGS], sibling_count= 0, ret;
|
||||
int i, fd, sibling_fds[BURN_OS_SG_MAX_SIBLINGS], sibling_count= 0, ret;
|
||||
int sid_ret = 0;
|
||||
int bus_no= -1, host_no= -1, channel_no= -1, target_no= -1, lun_no= -1;
|
||||
char fname[10];
|
||||
char sibling_fnames[BURN_OS_SG_MAX_SIBLINGS][BURN_OS_SG_MAX_NAMELEN];
|
||||
|
||||
sg_select_device_family();
|
||||
|
||||
if (linux_sg_enumerate_debug)
|
||||
fprintf(stderr, "libburn_debug: linux_sg_device_family = %s\n",
|
||||
@ -520,6 +651,16 @@ static void sg_enumerate(void)
|
||||
"ioctl(SG_GET_SCSI_ID) failed, errno=%d '%s' , ",
|
||||
errno, strerror(errno));
|
||||
|
||||
if (sgio_test(fd) == -1) {
|
||||
if (linux_sg_enumerate_debug)
|
||||
fprintf(stderr,
|
||||
"FATAL: sgio_test() failed: errno=%d '%s'",
|
||||
errno, strerror(errno));
|
||||
|
||||
sg_close_drive_fd(fname, -1, &fd, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef CDROM_DRIVE_STATUS
|
||||
/* ts A61211 : not widening old acceptance range */
|
||||
if (strcmp(linux_sg_device_family,"/dev/sg%d") != 0) {
|
||||
@ -581,7 +722,8 @@ static void sg_enumerate(void)
|
||||
/* 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,
|
||||
fname, -1, sibling_fds, sibling_fnames,
|
||||
&sibling_count,
|
||||
sid.host_no, sid.channel,
|
||||
sid.scsi_id, sid.lun);
|
||||
if (ret<=0) {
|
||||
@ -591,7 +733,8 @@ static void sg_enumerate(void)
|
||||
continue;
|
||||
}
|
||||
/* the final occupation will be done in sg_grab() */
|
||||
sg_release_siblings(sibling_fds, &sibling_count);
|
||||
sg_release_siblings(sibling_fds, sibling_fnames,
|
||||
&sibling_count);
|
||||
}
|
||||
#ifdef SCSI_IOCTL_GET_BUS_NUMBER
|
||||
if(bus_no == -1)
|
||||
@ -645,7 +788,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
/* Adapter specific handles and data */
|
||||
out.fd = -1337;
|
||||
out.sibling_count = 0;
|
||||
for(i= 0; i<LIBBURN_SG_MAX_SIBLINGS; i++)
|
||||
for(i= 0; i<BURN_OS_SG_MAX_SIBLINGS; i++)
|
||||
out.sibling_fds[i] = -1337;
|
||||
|
||||
/* PORTING: ---------------- end of non portable part ------------ */
|
||||
@ -698,6 +841,7 @@ int sg_give_next_adr(burn_drive_enumerator_t *idx,
|
||||
if (initialize == -1)
|
||||
return 0;
|
||||
|
||||
sg_select_device_family();
|
||||
if (linux_sg_device_family[0] == 0)
|
||||
sg_limit = 0;
|
||||
if (linux_ata_device_family[0] == 0)
|
||||
@ -793,9 +937,12 @@ int sg_grab(struct burn_drive *d)
|
||||
open_mode |= O_EXCL;
|
||||
|
||||
/* ts A60813
|
||||
O_NONBLOCK was hardcoded here. So it should stay default mode. */
|
||||
O_NONBLOCK was hardcoded here. So it should stay default mode.
|
||||
ts A70411
|
||||
Switched to O_NDELAY for LKML statement 2007/4/11/141
|
||||
*/
|
||||
if(burn_sg_open_o_nonblock)
|
||||
open_mode |= O_NONBLOCK;
|
||||
open_mode |= O_NDELAY;
|
||||
|
||||
/* ts A60813 - A60822
|
||||
After enumeration the drive fd is probably still open.
|
||||
@ -808,12 +955,15 @@ int sg_grab(struct burn_drive *d)
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_grab ----------- opening");
|
||||
|
||||
/* ts A70409 : DDLP-B */
|
||||
/* >>> obtain single lock on d->devname */
|
||||
|
||||
/* 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->sibling_fnames,&(d->sibling_count),
|
||||
d->host, d->channel, d->id, d->lun);
|
||||
if(ret <= 0)
|
||||
goto drive_is_in_use;
|
||||
@ -821,6 +971,11 @@ int sg_grab(struct burn_drive *d)
|
||||
|
||||
fd = open(d->devname, open_mode);
|
||||
os_errno = errno;
|
||||
if (fd >= 0) {
|
||||
sg_fcntl_lock(&fd, d->devname, F_WRLCK, 1);
|
||||
if (fd < 0)
|
||||
goto drive_is_in_use;
|
||||
}
|
||||
} else
|
||||
fd= d->fd;
|
||||
|
||||
@ -1034,19 +1189,33 @@ ex:;
|
||||
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, l;
|
||||
int fd, ret, l, open_mode = O_RDONLY;
|
||||
struct my_scsi_idlun {
|
||||
int x;
|
||||
int host_unique_id;
|
||||
};
|
||||
struct my_scsi_idlun idlun;
|
||||
|
||||
|
||||
l = strlen(linux_ata_device_family) - 2;
|
||||
if (l > 0 && strncmp(path, linux_ata_device_family, l) == 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);
|
||||
/* ts A70409 : DDLP-B */
|
||||
/* >>> obtain single lock on path */
|
||||
|
||||
if(burn_sg_open_o_nonblock)
|
||||
open_mode |= O_NDELAY;
|
||||
if(burn_sg_open_o_excl) {
|
||||
/* O_EXCL | O_RDONLY does not work with /dev/sg* on
|
||||
SuSE 9.0 (kernel 2.4) and SuSE 9.3 (kernel 2.6) */
|
||||
/* so skip it for now */;
|
||||
}
|
||||
fd = open(path, open_mode);
|
||||
if(fd < 0)
|
||||
return 0;
|
||||
sg_fcntl_lock(&fd, path, F_RDLCK, 0);
|
||||
if(fd < 0)
|
||||
return 0;
|
||||
|
||||
|
141
libburn/spc.c
141
libburn/spc.c
@ -40,7 +40,7 @@ static unsigned char SPC_MODE_SELECT[] =
|
||||
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)
|
||||
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
@ -50,11 +50,41 @@ int spc_test_unit_ready(struct burn_drive *d)
|
||||
c.page = NULL;
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
if (c.error)
|
||||
if (c.error) {
|
||||
*key= c.sense[2];
|
||||
*asc= c.sense[12];
|
||||
*ascq= c.sense[13];
|
||||
return (c.sense[2] & 0xF) == 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spc_test_unit_ready(struct burn_drive *d)
|
||||
{
|
||||
int key,asc,ascq;
|
||||
|
||||
return spc_test_unit_ready_r(d, &key, &asc, &ascq);
|
||||
}
|
||||
|
||||
|
||||
/* ts A70315 */
|
||||
/** Wait until the drive state becomes clear in or until max_usec elapsed */
|
||||
int spc_wait_unit_attention(struct burn_drive *d, int max_sec)
|
||||
{
|
||||
int i, ret, key, asc, ascq;
|
||||
|
||||
for(i=0; i < max_sec; i++) {
|
||||
ret = spc_test_unit_ready_r(d, &key, &asc, &ascq);
|
||||
if(ret > 0 || key!=0x2 || asc!=0x4) /* ready or error */
|
||||
break;
|
||||
usleep(1000000);
|
||||
}
|
||||
if (i < max_sec)
|
||||
return (ret > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void spc_request_sense(struct burn_drive *d, struct buffer *buf)
|
||||
{
|
||||
struct command c;
|
||||
@ -141,6 +171,7 @@ void spc_sense_caps(struct burn_drive *d)
|
||||
/* ts A61225 : 1 = report about post-MMC-1 speed descriptors */
|
||||
static int speed_debug = 0;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SENSE);
|
||||
@ -150,6 +181,8 @@ void spc_sense_caps(struct burn_drive *d)
|
||||
c.page->sectors = 0;
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
if (c.error)
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
size = c.page->data[0] * 256 + c.page->data[1];
|
||||
m = d->mdata;
|
||||
@ -211,6 +244,18 @@ void spc_sense_caps(struct burn_drive *d)
|
||||
|
||||
num_write_speeds = page[30] * 256 + page[31];
|
||||
m->max_write_speed = m->min_write_speed = m->cur_write_speed;
|
||||
|
||||
if (32 + 4 * num_write_speeds > page_length + 2) {
|
||||
char msg[161];
|
||||
|
||||
sprintf(msg, "Malformed capabilities page 2Ah received (len=%d, #speeds=%d)", page_length, num_write_speeds);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002013c,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_write_speeds; i++) {
|
||||
speed = page[32 + 4*i + 2] * 256 + page[32 + 4*i + 3];
|
||||
|
||||
@ -318,7 +363,7 @@ void spc_sense_write_params(struct burn_drive *d)
|
||||
{
|
||||
struct buffer buf;
|
||||
struct scsi_mode_data *m;
|
||||
int size;
|
||||
int size, dummy;
|
||||
unsigned char *page;
|
||||
struct command c;
|
||||
|
||||
@ -343,26 +388,35 @@ void spc_sense_write_params(struct burn_drive *d)
|
||||
m->write_page_length = page[1];
|
||||
m->write_page_valid = 1;
|
||||
mmc_read_disc_info(d);
|
||||
|
||||
/* ts A70212 : try to setup d->media_capacity_remaining */
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
||||
d->current_profile == 0x12)
|
||||
d->read_format_capacities(d, -1);
|
||||
else if (d->status == BURN_DISC_BLANK ||
|
||||
(d->current_is_cd_profile && d->status == BURN_DISC_APPENDABLE)) {
|
||||
d->get_nwa(d, -1, &dummy, &dummy);
|
||||
}
|
||||
/* others are hopefully up to date from mmc_read_disc_info() */
|
||||
|
||||
/*
|
||||
fprintf(stderr, "LIBBURN_DEBUG: media_capacity_remaining = %.f\n",
|
||||
(double) d->media_capacity_remaining);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ts A61229 */
|
||||
#define Libburn_mmc_compose_mode_page_5 1
|
||||
|
||||
|
||||
/* 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.
|
||||
Thus the filling of the mode page is done by mmc_compose_mode_page_5().
|
||||
*/
|
||||
void spc_select_write_params(struct burn_drive *d,
|
||||
const struct burn_write_opts *o)
|
||||
{
|
||||
struct buffer buf;
|
||||
struct command c;
|
||||
#ifndef Libburn_mmc_compose_mode_page_5
|
||||
int bufe, sim;
|
||||
#endif
|
||||
|
||||
/* ts A61007 : All current callers are safe. */
|
||||
/* a ssert(o->drive == d); */
|
||||
@ -391,40 +445,10 @@ void spc_select_write_params(struct burn_drive *d,
|
||||
burn_print(12, "using write page length %d (valid %d)\n",
|
||||
d->mdata->write_page_length, d->mdata->write_page_valid);
|
||||
|
||||
#ifdef Libburn_mmc_compose_mode_page_5
|
||||
|
||||
/* ts A61229 */
|
||||
if (mmc_compose_mode_page_5(d, o, c.page->data + 8) <= 0)
|
||||
return;
|
||||
|
||||
#else
|
||||
|
||||
c.page->data[8] = 5;
|
||||
c.page->data[9] = d->mdata->write_page_length;
|
||||
|
||||
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! */
|
||||
|
||||
#endif /* ! Libburn_mmc_compose_mode_page_5 */
|
||||
|
||||
c.dir = TO_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
}
|
||||
@ -434,16 +458,9 @@ void spc_getcaps(struct burn_drive *d)
|
||||
spc_inquiry(d);
|
||||
spc_sense_caps(d);
|
||||
spc_sense_error_params(d);
|
||||
|
||||
/* <<< for debugging. >>> ??? to be fixely included here ?
|
||||
mmc_read_format_capacities(d, -1);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
@ -453,12 +470,24 @@ 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;
|
||||
int key, asc, ascq, useable_write_type = -1, useable_block_type = -1;
|
||||
int last_try = 0;
|
||||
struct command c;
|
||||
|
||||
while (try_write_type != 4) {
|
||||
/* ts A70213 : added pseudo try_write_type 4 to set a suitable mode */
|
||||
while (try_write_type != 5) {
|
||||
burn_print(9, "trying %d, %d\n", try_write_type,
|
||||
try_block_type);
|
||||
|
||||
/* ts A70213 */
|
||||
if (try_write_type == 4) {
|
||||
/* Pseudo write type NONE . Set a useable write mode */
|
||||
if (useable_write_type == -1)
|
||||
break;
|
||||
try_write_type = useable_write_type;
|
||||
try_block_type = useable_block_type;
|
||||
last_try= 1;
|
||||
}
|
||||
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SELECT);
|
||||
@ -483,6 +512,9 @@ void spc_probe_write_modes(struct burn_drive *d)
|
||||
d->issue_command(d, &c);
|
||||
d->silent_on_scsi_error = 0;
|
||||
|
||||
if (last_try)
|
||||
break;
|
||||
|
||||
key = c.sense[2];
|
||||
asc = c.sense[12];
|
||||
ascq = c.sense[13];
|
||||
@ -498,6 +530,15 @@ void spc_probe_write_modes(struct burn_drive *d)
|
||||
else
|
||||
d->block_types[try_write_type] |=
|
||||
1 << try_block_type;
|
||||
|
||||
/* ts A70213 */
|
||||
if ((useable_write_type < 0 && try_write_type > 0) ||
|
||||
(try_write_type == 1 && try_block_type == 8)) {
|
||||
/* Packet is not supported yet.
|
||||
Prefer TAO MODE_1. */
|
||||
useable_write_type = try_write_type;
|
||||
useable_block_type = try_block_type;
|
||||
}
|
||||
}
|
||||
switch (try_block_type) {
|
||||
case 0:
|
||||
|
@ -20,8 +20,16 @@ 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);
|
||||
|
||||
/* ts A70315 : test_unit_ready with result parameters */
|
||||
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq);
|
||||
|
||||
int spc_test_unit_ready(struct burn_drive *d);
|
||||
|
||||
/* ts A70315 */
|
||||
/** Wait until the drive state becomes clear in or until max_sec elapsed */
|
||||
int spc_wait_unit_attention(struct burn_drive *d, int max_sec);
|
||||
|
||||
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int spc_setup_drive(struct burn_drive *d);
|
||||
|
@ -113,6 +113,12 @@ struct burn_track *burn_track_create(void)
|
||||
t->mode = BURN_MODE1;
|
||||
t->isrc.has_isrc = 0;
|
||||
t->pad = 1;
|
||||
|
||||
/* ts A70213 */
|
||||
t->fill_up_media = 0;
|
||||
/* ts A70218 */
|
||||
t->default_size = 0;
|
||||
|
||||
t->entry = NULL;
|
||||
t->source = NULL;
|
||||
t->eos = 0;
|
||||
@ -342,6 +348,54 @@ int burn_track_set_sectors(struct burn_track *t, int sectors)
|
||||
if (size < 0)
|
||||
return 0;
|
||||
ret = t->source->set_size(t->source, size);
|
||||
t->open_ended = (t->source->get_size(t->source) <= 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70218 , API since A70328 */
|
||||
int burn_track_set_size(struct burn_track *t, off_t size)
|
||||
{
|
||||
if (t->source == NULL)
|
||||
return 0;
|
||||
if (t->source->set_size == NULL)
|
||||
return 0;
|
||||
t->open_ended = (size <= 0);
|
||||
return t->source->set_size(t->source, size);
|
||||
}
|
||||
|
||||
|
||||
/* ts A70213 */
|
||||
int burn_track_set_fillup(struct burn_track *t, int fill_up_media)
|
||||
{
|
||||
t->fill_up_media = fill_up_media;
|
||||
if (fill_up_media)
|
||||
t->open_ended = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70213 */
|
||||
/**
|
||||
@param flag bit0= force new size even if existing track size is larger
|
||||
*/
|
||||
int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag)
|
||||
{
|
||||
int max_sectors, ret = 2;
|
||||
char msg[160];
|
||||
|
||||
if (t->fill_up_media <= 0)
|
||||
return 2;
|
||||
max_sectors = max_size / 2048;
|
||||
if (burn_track_get_sectors(t) < max_sectors || (flag & 1)) {
|
||||
sprintf(msg, "Setting total track size to %ds (payload %ds)\n",
|
||||
max_sectors, (int) (t->source->get_size(t->source)/2048));
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msg, 0, 0);
|
||||
ret = burn_track_set_sectors(t, max_sectors);
|
||||
t->open_ended = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -352,6 +406,22 @@ int burn_track_is_open_ended(struct burn_track *t)
|
||||
return !!t->open_ended;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70218 : API */
|
||||
int burn_track_set_default_size(struct burn_track *t, off_t size)
|
||||
{
|
||||
t->default_size = size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70218 */
|
||||
off_t burn_track_get_default_size(struct burn_track *t)
|
||||
{
|
||||
return t->default_size;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61101 : API function */
|
||||
int burn_track_get_counters(struct burn_track *t,
|
||||
off_t *read_bytes, off_t *written_bytes)
|
||||
|
@ -27,6 +27,13 @@ struct burn_track
|
||||
int tailcount;
|
||||
/** 1 means Pad with zeros, 0 means start reading the next track */
|
||||
int pad;
|
||||
|
||||
/* ts A70213 : wether to expand this track to full available media */
|
||||
int fill_up_media;
|
||||
|
||||
/* ts A70218 : a track size to use if it is mandarory to have some */
|
||||
off_t default_size;
|
||||
|
||||
/** Data source */
|
||||
struct burn_source *source;
|
||||
/** End of Source flag */
|
||||
@ -88,8 +95,18 @@ int burn_track_get_shortage(struct burn_track *t);
|
||||
int burn_track_is_open_ended(struct burn_track *t);
|
||||
int burn_track_is_data_done(struct burn_track *t);
|
||||
|
||||
/* ts A70125 */
|
||||
/* ts A70125 : sets overall sectors of a track: offset+payload+padding */
|
||||
int burn_track_set_sectors(struct burn_track *t, int sectors);
|
||||
|
||||
/* ts A70218 : sets the payload size alone */
|
||||
int burn_track_set_size(struct burn_track *t, off_t size);
|
||||
|
||||
/* ts A70213 */
|
||||
int burn_track_set_fillup(struct burn_track *t, int fill_up_media);
|
||||
int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag);
|
||||
|
||||
/* ts A70218 */
|
||||
off_t burn_track_get_default_size(struct burn_track *t);
|
||||
|
||||
|
||||
#endif /* BURN__STRUCTURE_H */
|
||||
|
@ -117,8 +117,6 @@ struct burn_format_descr {
|
||||
};
|
||||
|
||||
|
||||
#define LIBBURN_SG_MAX_SIBLINGS 16
|
||||
|
||||
/** Gets initialized in enumerate_common() and burn_drive_register() */
|
||||
struct burn_drive
|
||||
{
|
||||
@ -129,6 +127,9 @@ struct burn_drive
|
||||
int lun;
|
||||
char *devname;
|
||||
|
||||
/* ts A70302: mmc5r03c.pdf 5.3.2 Physical Interface Standard */
|
||||
int phys_if_std; /* 1=SCSI, 2=ATAPI, 3,4,6=FireWire, 7=SATA, 8=USB */
|
||||
char phys_if_name[80]; /* MMC-5 5.3.2 table 91 , e.g. "SCSI Family" */
|
||||
|
||||
/* see os.h for name of particular os-*.h where this is defined */
|
||||
BURN_OS_TRANSPORT_DRIVE_ELEMENTS
|
||||
@ -206,6 +207,14 @@ struct burn_drive
|
||||
/* ts A70129 :
|
||||
from 51h READ DISC INFORMATION Last Track Number in Last Session */
|
||||
int last_track_no;
|
||||
/* ts A70212 : from various sources : free space on media (in bytes)
|
||||
With CD this might change after particular write
|
||||
parameters have been set and nwa has been inquired.
|
||||
(e.g. by d->send_write_parameters() ; d->get_nwa()).
|
||||
*/
|
||||
off_t media_capacity_remaining;
|
||||
/* ts A70215 : if > 0 : first lba on media that is too high for write*/
|
||||
int media_lba_limit;
|
||||
|
||||
|
||||
int toc_temp;
|
||||
|
527
libburn/write.c
527
libburn/write.c
@ -37,6 +37,7 @@
|
||||
#include "sg.h"
|
||||
#include "write.h"
|
||||
#include "options.h"
|
||||
#include "structure.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
@ -460,7 +461,7 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
||||
track length.
|
||||
*/
|
||||
track_length = burn_track_get_sectors(tar[i]);
|
||||
if (track_length < 300) {
|
||||
if (track_length < 300 && !burn_track_is_open_ended(tar[i])) {
|
||||
track_length = 300;
|
||||
if (!tar[i]->pad)
|
||||
tar[i]->pad = 1;
|
||||
@ -706,14 +707,21 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
|
||||
/* ts A61103 */
|
||||
ret = d->get_nwa(d, -1, &lba, &nwa);
|
||||
|
||||
/* ts A70213: CD-TAO: eventually expand size of track to max */
|
||||
burn_track_apply_fillup(t, d->media_capacity_remaining, 0);
|
||||
|
||||
/* <<< */
|
||||
sprintf(msg,
|
||||
"pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d\n",
|
||||
tnum+1, nwa, ret, d->nwa);
|
||||
"TAO pre-track %2.2d : get_nwa(%d)=%d, d=%d , demand=%.f , cap=%.f\n",
|
||||
tnum+1, nwa, ret, d->nwa, (double) burn_track_get_sectors(t) * 2048.0,
|
||||
(double) d->media_capacity_remaining);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msg,0,0);
|
||||
msg, 0, 0);
|
||||
if (nwa > d->nwa)
|
||||
d->nwa = nwa;
|
||||
|
||||
}
|
||||
|
||||
/* user data */
|
||||
@ -812,7 +820,9 @@ ex:;
|
||||
}
|
||||
|
||||
/* ts A61009 */
|
||||
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc)
|
||||
/* @param flag bit1 = do not libdax_msgs_submit() */
|
||||
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc,
|
||||
int flag)
|
||||
{
|
||||
int i, t;
|
||||
char msg[80];
|
||||
@ -826,9 +836,10 @@ int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc)
|
||||
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);
|
||||
if (!(flag & 2))
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x0002010a,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -838,6 +849,8 @@ int burn_disc_init_write_status(struct burn_write_opts *o,
|
||||
struct burn_disc *disc)
|
||||
{
|
||||
struct burn_drive *d = o->drive;
|
||||
struct burn_track *t = NULL;
|
||||
int sx, tx;
|
||||
|
||||
d->cancel = 0;
|
||||
|
||||
@ -862,12 +875,99 @@ int burn_disc_init_write_status(struct burn_write_opts *o,
|
||||
d->progress.buffered_bytes = 0;
|
||||
d->progress.buffer_min_fill = 0xffffffff;
|
||||
|
||||
/* Set eventual media fill up for last track only */
|
||||
for (sx = 0; sx < disc->sessions; sx++)
|
||||
for (tx = 0 ; tx < disc->session[sx]->tracks; tx++) {
|
||||
t = disc->session[sx]->track[tx];
|
||||
burn_track_set_fillup(t, 0);
|
||||
}
|
||||
if (o->fill_up_media && t != NULL)
|
||||
burn_track_set_fillup(t, 1);
|
||||
|
||||
d->busy = BURN_DRIVE_WRITING;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70219 : API */
|
||||
int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
|
||||
char reasons[BURN_REASONS_LEN], int silent)
|
||||
{
|
||||
enum burn_write_types wt;
|
||||
struct burn_drive *d = o->drive;
|
||||
char msg[160], *reason_pt;
|
||||
int no_media = 0;
|
||||
|
||||
reason_pt= reasons;
|
||||
reasons[0] = 0;
|
||||
|
||||
/* check write mode against write job */
|
||||
wt = burn_write_opts_auto_write_type(o, disc, reasons, 1);
|
||||
if (wt == BURN_WRITE_NONE) {
|
||||
if (strncmp(reasons, "MEDIA: ", 7)==0)
|
||||
no_media = 1;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
sprintf(reasons, "%s: ", d->current_profile_text);
|
||||
reason_pt= reasons + strlen(reasons);
|
||||
if (d->status == BURN_DISC_UNSUITABLE)
|
||||
goto unsuitable_profile;
|
||||
if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
|
||||
if (!burn_disc_write_is_ok(o, disc, (!!silent) << 1))
|
||||
strcat(reasons, "unsuitable track mode found, ");
|
||||
if (o->start_byte >= 0)
|
||||
strcat(reasons, "write start address not supported, ");
|
||||
} else if (d->current_profile == 0x1a || d->current_profile == 0x12) {
|
||||
/* DVD+RW , DVD-RAM */
|
||||
if (o->start_byte >= 0 && (o->start_byte % 2048))
|
||||
strcat(reasons,
|
||||
"write start address not properly aligned to 2048, ");
|
||||
} else if (d->current_profile == 0x13) {
|
||||
/* DVD-RW Restricted Overwrite */
|
||||
if (o->start_byte >= 0 && (o->start_byte % 32768))
|
||||
strcat(reasons,
|
||||
"write start address not properly aligned to 32k, ");
|
||||
} else if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
|
||||
d->current_profile == 0x15 ||
|
||||
d->current_profile == 0x1b || d->current_profile == 0x2b ) {
|
||||
/* DVD-R* Sequential , DVD+R[/DL] */
|
||||
if (o->start_byte >= 0)
|
||||
strcat(reasons, "write start address not supported, ");
|
||||
} else {
|
||||
unsuitable_profile:;
|
||||
sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s",
|
||||
d->current_profile, d->current_profile_text);
|
||||
if (!silent)
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002011e,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
strcat(reasons, "no suitable media profile detected, ");
|
||||
return 0;
|
||||
}
|
||||
ex:;
|
||||
if (reason_pt[0]) {
|
||||
if (no_media) {
|
||||
if (!silent)
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x0002013a,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"No suitable media detected", 0, 0);
|
||||
return -1;
|
||||
}
|
||||
if (!silent)
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020139,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Write job parameters are unsuitable", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70129 : learned much from dvd+rw-tools-7.0/growisofs_mmc.cpp */
|
||||
int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o,
|
||||
struct burn_session *s, int tnum)
|
||||
@ -886,6 +986,8 @@ int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, msg,0,0);
|
||||
if (nwa > d->nwa)
|
||||
d->nwa = nwa;
|
||||
/* ts A70214 : eventually adjust already expanded size of track */
|
||||
burn_track_apply_fillup(s->track[tnum], d->media_capacity_remaining,1);
|
||||
|
||||
if (o->write_type == BURN_WRITE_SAO) { /* DAO */
|
||||
/* Round track size up to 32 KiB and reserve track */
|
||||
@ -899,7 +1001,48 @@ int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o,
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020138,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70226 */
|
||||
int burn_disc_open_track_dvd_plus_r(struct burn_write_opts *o,
|
||||
struct burn_session *s, int tnum)
|
||||
{
|
||||
struct burn_drive *d = o->drive;
|
||||
char msg[160];
|
||||
int ret, lba, nwa;
|
||||
off_t size;
|
||||
|
||||
ret = d->get_nwa(d, -1, &lba, &nwa);
|
||||
sprintf(msg,
|
||||
"DVD+R pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d",
|
||||
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;
|
||||
/* ts A70214 : eventually adjust already expanded size of track */
|
||||
burn_track_apply_fillup(s->track[tnum], d->media_capacity_remaining,1);
|
||||
|
||||
if (o->write_type == BURN_WRITE_SAO &&
|
||||
! burn_track_is_open_ended(s->track[tnum])) {
|
||||
/* Round track size up to 32 KiB and reserve track */
|
||||
size = ((off_t) burn_track_get_sectors(s->track[tnum]))
|
||||
* (off_t) 2048;
|
||||
size = (size + (off_t) 0x7fff) & ~((off_t) 0x7fff);
|
||||
ret = d->reserve_track(d, size);
|
||||
if (ret <= 0) {
|
||||
sprintf(msg, "Cannot reserve track of %.f bytes",
|
||||
(double) size);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020138,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -932,9 +1075,60 @@ int burn_disc_close_track_dvd_minus_r(struct burn_write_opts *o,
|
||||
}
|
||||
|
||||
|
||||
/* ts A70229 */
|
||||
int burn_disc_finalize_dvd_plus_r(struct burn_write_opts *o)
|
||||
{
|
||||
struct burn_drive *d = o->drive;
|
||||
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
"Finalizing DVD+R ...", 0, 0);
|
||||
|
||||
/* CLOSE SESSION, 101b, Finalize with minimal radius */
|
||||
d->close_track_session(d, 2, 1); /* (2<<1)|1 = 5 */
|
||||
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
"... finalizing DVD+R done ", 0, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70226 */
|
||||
int burn_disc_close_track_dvd_plus_r(struct burn_write_opts *o,
|
||||
struct burn_session *s, int tnum, int is_last_track)
|
||||
{
|
||||
struct burn_drive *d = o->drive;
|
||||
char msg[80];
|
||||
|
||||
sprintf(msg,
|
||||
"Closing track %2.2d (absolute track and session number %d)",
|
||||
tnum + 1, d->last_track_no);
|
||||
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
|
||||
|
||||
d->busy = BURN_DRIVE_CLOSING_SESSION;
|
||||
d->close_track_session(d, 0, d->last_track_no); /* CLOSE TRACK, 001b */
|
||||
|
||||
/* Each session becomes a single logical track. So to distinguish them,
|
||||
it is mandatory to close the session together with each track. */
|
||||
|
||||
if (is_last_track && !o->multi)
|
||||
burn_disc_finalize_dvd_plus_r(o);
|
||||
else
|
||||
d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
|
||||
d->busy = BURN_DRIVE_WRITING;
|
||||
d->last_track_no++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61218 - A70129 */
|
||||
int burn_dvd_write_track(struct burn_write_opts *o,
|
||||
struct burn_session *s, int tnum)
|
||||
struct burn_session *s, int tnum, int is_last_track)
|
||||
{
|
||||
struct burn_track *t = s->track[tnum];
|
||||
struct burn_drive *d = o->drive;
|
||||
@ -942,16 +1136,41 @@ int burn_dvd_write_track(struct burn_write_opts *o,
|
||||
int sectors;
|
||||
int i, open_ended = 0, ret= 0, is_flushed = 0;
|
||||
|
||||
sectors = burn_track_get_sectors(t);
|
||||
open_ended = burn_track_is_open_ended(t);
|
||||
/* ts A70213 : eventually expand size of track to max */
|
||||
burn_track_apply_fillup(t, d->media_capacity_remaining, 0);
|
||||
|
||||
if (d->current_profile == 0x11 || d->current_profile == 0x14) {
|
||||
/* DVD-R, DVD-RW Sequential */
|
||||
if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
|
||||
d->current_profile == 0x15) {
|
||||
/* DVD-R, DVD-RW Sequential, DVD-R/DL Sequential */
|
||||
ret = burn_disc_open_track_dvd_minus_r(o, s, tnum);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
|
||||
/* DVD+R , DVD+R/DL */
|
||||
ret = burn_disc_open_track_dvd_plus_r(o, s, tnum);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
}
|
||||
|
||||
sectors = burn_track_get_sectors(t);
|
||||
open_ended = burn_track_is_open_ended(t);
|
||||
/* <<< */
|
||||
{
|
||||
char msg[160];
|
||||
|
||||
sprintf(msg,
|
||||
"DVD pre-track %2.2d : demand=%.f%s, cap=%.f\n",
|
||||
tnum+1, (double) sectors * 2048.0,
|
||||
(open_ended ? " (open ended)" : ""),
|
||||
(double) d->media_capacity_remaining);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msg, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/* >>> ts A70215 : what about offset padding ? */
|
||||
|
||||
burn_disc_init_track_status(o, s, tnum, sectors);
|
||||
for (i = 0; open_ended || i < sectors; i++) {
|
||||
|
||||
@ -973,6 +1192,8 @@ int burn_dvd_write_track(struct burn_write_opts *o,
|
||||
d->progress.sector++;
|
||||
}
|
||||
|
||||
/* >>> ts A70215 : what about tail padding ? */
|
||||
|
||||
/* Pad up buffer to next full o->obs (usually 32 kB) */
|
||||
if (o->obs_pad && out->bytes > 0 && out->bytes < o->obs) {
|
||||
memset(out->data + out->bytes, 0, o->obs - out->bytes);
|
||||
@ -985,10 +1206,17 @@ int burn_dvd_write_track(struct burn_write_opts *o,
|
||||
is_flushed = 1;
|
||||
|
||||
/* Eventually finalize track */
|
||||
if (d->current_profile == 0x11 || d->current_profile == 0x14) {
|
||||
/* DVD-R, DVD-RW Sequential */
|
||||
if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
|
||||
d->current_profile == 0x15) {
|
||||
/* DVD-R, DVD-RW Sequential, DVD-R/DL Sequential */
|
||||
ret = burn_disc_close_track_dvd_minus_r(o, s, tnum);
|
||||
if (ret != 2)
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
|
||||
/* DVD+R , DVD+R/DL */
|
||||
ret = burn_disc_close_track_dvd_plus_r(o, s, tnum,
|
||||
is_last_track);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
}
|
||||
ret = 1;
|
||||
@ -1038,7 +1266,7 @@ int burn_disc_close_session_dvd_minus_rw(struct burn_write_opts *o,
|
||||
}
|
||||
|
||||
|
||||
/* ts A70129 : for profile 0x11 DVD-R and 0x14 DVD-RW Sequential */
|
||||
/* ts A70129 : for profile 0x11 DVD-R, 0x14 DVD-RW Seq, 0x15 DVD-R/DL Seq */
|
||||
int burn_disc_close_session_dvd_minus_r(struct burn_write_opts *o,
|
||||
struct burn_session *s)
|
||||
{
|
||||
@ -1048,6 +1276,11 @@ int burn_disc_close_session_dvd_minus_r(struct burn_write_opts *o,
|
||||
if (o->write_type != BURN_WRITE_TAO)
|
||||
return 2;
|
||||
|
||||
#ifdef Libburn_dvd_r_dl_multi_no_close_sessioN
|
||||
if (d->current_profile == 0x15 && o->multi)
|
||||
return 2;
|
||||
#endif
|
||||
|
||||
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Closing session", 0, 0);
|
||||
@ -1061,7 +1294,7 @@ int burn_disc_close_session_dvd_minus_r(struct burn_write_opts *o,
|
||||
|
||||
/* ts A61218 */
|
||||
int burn_dvd_write_session(struct burn_write_opts *o,
|
||||
struct burn_session *s)
|
||||
struct burn_session *s, int is_last_session)
|
||||
{
|
||||
int i,ret;
|
||||
struct burn_drive *d = o->drive;
|
||||
@ -1069,12 +1302,14 @@ int burn_dvd_write_session(struct burn_write_opts *o,
|
||||
/* >>> open_session ? */
|
||||
|
||||
for (i = 0; i < s->tracks; i++) {
|
||||
ret = burn_dvd_write_track(o, s, i);
|
||||
ret = burn_dvd_write_track(o, s, i,
|
||||
is_last_session && i == (s->tracks - 1));
|
||||
if (ret <= 0)
|
||||
break;
|
||||
}
|
||||
if ((d->current_profile == 0x11 || d->current_profile == 0x14)) {
|
||||
/* DVD-R , DVD-RW Sequential */
|
||||
if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
|
||||
d->current_profile == 0x15) {
|
||||
/* DVD-R , DVD-RW Sequential, DVD-R/DL Sequential */
|
||||
ret = burn_disc_close_session_dvd_minus_r(o, s);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
@ -1095,6 +1330,8 @@ int burn_dvd_write_session(struct burn_write_opts *o,
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
}
|
||||
} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
|
||||
/* DVD+R , DVD+R/DL do each track as an own session */;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -1125,7 +1362,7 @@ int burn_disc_setup_dvd_plus_rw(struct burn_write_opts *o,
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020127,
|
||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
}
|
||||
|
||||
/* >>> perform OPC if needed */;
|
||||
@ -1152,47 +1389,37 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o,
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020127,
|
||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
|
||||
d->nwa *= 16; /* convert to 2048 block units */
|
||||
}
|
||||
|
||||
if (d->current_profile == 0x13) { /* DVD-RW restricted overwrite */
|
||||
|
||||
/* ??? mmc5r03c.pdf 7.5.2 :
|
||||
"For DVD-RW media ... If a medium is in Restricted overwrite
|
||||
mode, this mode page shall not be used."
|
||||
/* ??? mmc5r03c.pdf 7.5.2 :
|
||||
"For DVD-RW media ... If a medium is in Restricted overwrite
|
||||
mode, this mode page shall not be used."
|
||||
|
||||
But growisofs composes a page 5 and sends it.
|
||||
mmc5r03c.pdf 5.3.16 , table 127 specifies that mode page 5
|
||||
shall be supported with feature 0026h Restricted Overwrite.
|
||||
5.3.22 describes a feature 002Ch Rigid Restrictive Overwrite
|
||||
which seems to apply to DVD-RW and does not mention page 5.
|
||||
But growisofs composes a page 5 and sends it.
|
||||
mmc5r03c.pdf 5.3.16 , table 127 specifies that mode page 5
|
||||
shall be supported with feature 0026h Restricted Overwrite.
|
||||
5.3.22 describes a feature 002Ch Rigid Restrictive Overwrite
|
||||
which seems to apply to DVD-RW and does not mention page 5.
|
||||
|
||||
5.4.14 finally states that profile 0013h includes feature
|
||||
002Ch rather than 0026h.
|
||||
5.4.14 finally states that profile 0013h includes feature
|
||||
002Ch rather than 0026h.
|
||||
|
||||
d->send_write_parameters(d, o);
|
||||
*/
|
||||
*/
|
||||
|
||||
d->busy = BURN_DRIVE_FORMATTING;
|
||||
d->busy = BURN_DRIVE_FORMATTING;
|
||||
|
||||
/* "quick grow" to at least byte equivalent of d->nwa */
|
||||
ret = d->format_unit(d, (off_t) d->nwa * (off_t) 2048,
|
||||
(d->nwa > 0) << 3);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
d->busy = BURN_DRIVE_WRITING;
|
||||
|
||||
} else {
|
||||
sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s",
|
||||
d->current_profile, d->current_profile_text);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002011e,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
/* "quick grow" to at least byte equivalent of d->nwa */
|
||||
ret = d->format_unit(d, (off_t) d->nwa * (off_t) 2048,
|
||||
(d->nwa > 0) << 3);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
d->busy = BURN_DRIVE_WRITING;
|
||||
|
||||
/* >>> perform OPC if needed */;
|
||||
|
||||
@ -1215,15 +1442,37 @@ int burn_disc_setup_dvd_minus_r(struct burn_write_opts *o,
|
||||
}
|
||||
|
||||
|
||||
/* ts A70226 : for DVD+R , DVD+R/DL */
|
||||
int burn_disc_setup_dvd_plus_r(struct burn_write_opts *o,
|
||||
struct burn_disc *disc)
|
||||
{
|
||||
struct burn_drive *d = o->drive;
|
||||
|
||||
/* most setup is in burn_disc_setup_track_dvd_plus_r() */;
|
||||
|
||||
d->nwa = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61218 - A70129 */
|
||||
int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
struct burn_disc *disc)
|
||||
{
|
||||
int i, ret, sx, tx, mode, exotic_track = 0, dao_is_ok;
|
||||
int i, ret, o_end;
|
||||
off_t default_size = 0;
|
||||
struct burn_drive *d = o->drive;
|
||||
struct burn_track *t;
|
||||
char msg[160];
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
int exotic_track = 0, dao_is_ok, sx, tx, mode;
|
||||
#endif
|
||||
|
||||
d->needs_close_session = 0;
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
for (sx = 0; sx < disc->sessions; sx++)
|
||||
for (tx = 0 ; tx < disc->session[sx]->tracks; tx++) {
|
||||
mode = disc->session[sx]->track[tx]->mode;
|
||||
@ -1235,10 +1484,11 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020123,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
||||
d->current_profile == 0x12) {
|
||||
/* DVD+RW , DVD-RW Restricted Overwrite , DVD-RAM */
|
||||
@ -1250,21 +1500,28 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002011f,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x12) {
|
||||
/* DVD+RW , DVD-RAM */
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
if (o->start_byte >= 0 && (o->start_byte % 2048)) {
|
||||
sprintf(msg,
|
||||
"Write start address not properly aligned to 2048");
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020125,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
ret = 1;
|
||||
if (d->current_profile == 0x1a)
|
||||
ret = burn_disc_setup_dvd_plus_rw(o, disc);
|
||||
@ -1274,22 +1531,27 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020121,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
o->obs_pad = 0; /* no filling-up of track's last 32k buffer */
|
||||
|
||||
} else if (d->current_profile == 0x13) {
|
||||
/* DVD-RW Restricted Overwrite */
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
if (o->start_byte >= 0 && (o->start_byte % 32768)) {
|
||||
sprintf(msg,
|
||||
"Write start address not properly aligned to 32K");
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020125,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
ret = burn_disc_setup_dvd_minus_rw(o, disc);
|
||||
if (ret <= 0) {
|
||||
sprintf(msg,
|
||||
@ -1297,24 +1559,31 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020121,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
|
||||
/* _Rigid_ Restricted Overwrite demands this */
|
||||
o->obs_pad = 1; /* fill-up track's last 32k buffer */
|
||||
|
||||
} else if (d->current_profile == 0x11 || d->current_profile == 0x14) {
|
||||
/* DVD-R , DVD-RW Sequential */
|
||||
} else if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
|
||||
d->current_profile == 0x15) {
|
||||
/* DVD-R , DVD-RW Sequential , DVD-R/DL Sequential */
|
||||
t = disc->session[0]->track[0];
|
||||
o_end = ( burn_track_is_open_ended(t) && !o->fill_up_media );
|
||||
default_size = burn_track_get_default_size(t);
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
dao_is_ok =
|
||||
(disc->sessions == 1 &&
|
||||
disc->session[0]->tracks == 1 &&
|
||||
(! burn_track_is_open_ended(
|
||||
disc->session[0]->track[0])) &&
|
||||
(default_size > 0 || !o_end) &&
|
||||
(!o->multi) && d->status == BURN_DISC_BLANK
|
||||
);
|
||||
if (o->write_type == BURN_WRITE_TAO &&
|
||||
!d->current_has_feat21h) {
|
||||
|
||||
/* <<< ??? keep this automatic write type change ? */
|
||||
if (dao_is_ok) {
|
||||
o->write_type = BURN_WRITE_SAO;
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
@ -1322,6 +1591,8 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Defaulted TAO to DAO (lack of feature 21h)",
|
||||
0, 0);
|
||||
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
} else {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020135,
|
||||
@ -1330,29 +1601,49 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
|
||||
} else if (o->write_type == BURN_WRITE_SAO && !dao_is_ok) {
|
||||
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020136,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"DAO burning is restricted to a single fixed size track and no multi-session",
|
||||
0,0);
|
||||
0, 0);
|
||||
|
||||
/* <<< ??? keep this automatic advise ? */
|
||||
if (d->current_has_feat21h)
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020137,
|
||||
LIBDAX_MSGS_SEV_HINT,
|
||||
LIBDAX_MSGS_PRIO_HIGH,
|
||||
"TAO would be possible and could do the job",
|
||||
0,0);
|
||||
0, 0);
|
||||
|
||||
goto early_failure;
|
||||
|
||||
}
|
||||
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
if (o->start_byte >= 0) {
|
||||
sprintf(msg, "Write start address not supported");
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020124,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
if (o->write_type == BURN_WRITE_SAO && o_end) {
|
||||
sprintf(msg, "Activated track default size %.f",
|
||||
(double) default_size);
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x0002012e,
|
||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
burn_track_set_size(t, default_size);
|
||||
}
|
||||
ret = burn_disc_setup_dvd_minus_r(o, disc);
|
||||
if (ret <= 0) {
|
||||
sprintf(msg,
|
||||
@ -1360,20 +1651,56 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020121,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
/* ??? padding needed ??? cowardly doing it for now */
|
||||
o->obs_pad = 1; /* fill-up track's last 32k buffer */
|
||||
|
||||
} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
|
||||
/* DVD+R , DVD+R/DL */
|
||||
t = disc->session[0]->track[0];
|
||||
o_end = ( burn_track_is_open_ended(t) && !o->fill_up_media );
|
||||
default_size = burn_track_get_default_size(t);
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* >>> oldfashioned checks hopefully never re-enabled */
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
if (o->write_type == BURN_WRITE_SAO && o_end) {
|
||||
sprintf(msg, "Activated track default size %.f",
|
||||
(double) default_size);
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x0002012e,
|
||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
burn_track_set_size(t, default_size);
|
||||
}
|
||||
ret = burn_disc_setup_dvd_plus_r(o, disc);
|
||||
if (ret <= 0) {
|
||||
sprintf(msg,
|
||||
"Write preparation setup failed for DVD+R");
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020121,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
}
|
||||
/* ??? padding needed ??? cowardly doing it for now */
|
||||
o->obs_pad = 1; /* fill-up track's last 32k buffer */
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
} else {
|
||||
sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s",
|
||||
d->current_profile, d->current_profile_text);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002011e,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto early_failure;
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
}
|
||||
o->obs = 32*1024; /* buffer flush trigger for sector.c:get_sector() */
|
||||
|
||||
@ -1382,7 +1709,8 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
d->progress.session = i;
|
||||
d->progress.tracks = disc->session[i]->tracks;
|
||||
|
||||
ret = burn_dvd_write_session(o, disc->session[i]);
|
||||
ret = burn_dvd_write_session(o, disc->session[i],
|
||||
i == (disc->sessions - 1));
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
|
||||
@ -1391,9 +1719,6 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
d->progress.start_sector = 0;
|
||||
d->progress.sectors = 0;
|
||||
}
|
||||
|
||||
/* >>> eventual normal finalization measures */
|
||||
|
||||
ret = 1;
|
||||
ex:;
|
||||
|
||||
@ -1415,8 +1740,9 @@ 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;
|
||||
struct burn_track *lt, *t;
|
||||
int first = 1, i, ret, lba, nwa = 0;
|
||||
off_t default_size;
|
||||
char msg[80];
|
||||
|
||||
/* ts A60924 : libburn/message.c gets obsoleted
|
||||
@ -1439,14 +1765,56 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
if (o->start_byte >= 0) {
|
||||
sprintf(msg, "Write start address not supported");
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020124,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0,0);
|
||||
msg, 0, 0);
|
||||
goto fail_wo_sync;
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
/* ts A70218 */
|
||||
if (o->write_type == BURN_WRITE_SAO) {
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* <<< covered by burn_precheck_write() "appended session" */
|
||||
if (disc->sessions > 1) {
|
||||
sao_restriction_violated:;
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002012f,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"SAO is restricted to a single session with fixed track sizes",
|
||||
0, 0);
|
||||
goto fail_wo_sync;
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
for (i = 0 ; i < disc->session[0]->tracks; i++) {
|
||||
t = disc->session[0]->track[i];
|
||||
if (burn_track_is_open_ended(t)) {
|
||||
default_size = burn_track_get_default_size(t);
|
||||
|
||||
#ifndef Libburn_precheck_write_ruleS
|
||||
/* <<< covered by burn_precheck_write() */
|
||||
if (default_size <= 0)
|
||||
goto sao_restriction_violated;
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
sprintf(msg,
|
||||
"Activated track default size %.f",
|
||||
(double) default_size);
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x0002012e,
|
||||
LIBDAX_MSGS_SEV_NOTE,
|
||||
LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
|
||||
burn_track_set_size(t, default_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
burn_print(1, "sync write of %d CD sessions\n", disc->sessions);
|
||||
|
||||
@ -1464,11 +1832,16 @@ return crap. so we send the command, then ignore the result.
|
||||
d->send_write_parameters(d, o);
|
||||
|
||||
ret = d->get_nwa(d, -1, &lba, &nwa);
|
||||
sprintf(msg, "Inquired nwa: %d (ret=%d)", nwa, ret);
|
||||
sprintf(msg,
|
||||
"SAO|RAW: Inquired nwa: %d , ret= %d , cap=%.f\n",
|
||||
nwa, ret, (double) d->media_capacity_remaining);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msg,0,0);
|
||||
msg,0, 0);
|
||||
|
||||
/* >>> ts A70212 : CD-DAO/SAO : eventually expand size of last track to maximum */;
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < disc->sessions; i++) {
|
||||
@ -1512,7 +1885,7 @@ return crap. so we send the command, then ignore the result.
|
||||
libdax_msgs_submit(
|
||||
libdax_messenger, d->global_index, 0x000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
msg,0,0);
|
||||
msg, 0, 0);
|
||||
|
||||
} else {
|
||||
d->nwa = -150;
|
||||
|
@ -15,7 +15,8 @@ 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);
|
||||
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc,
|
||||
int flag);
|
||||
|
||||
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc);
|
||||
int burn_write_leadin(struct burn_write_opts *o,
|
||||
@ -32,4 +33,16 @@ 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);
|
||||
|
||||
|
||||
|
||||
/* mmc5r03c.pdf 6.3.3.3.3: DVD-R DL: Close Function 010b: Close Session
|
||||
"When the recording mode is Incremental Recording,
|
||||
the disc is single session."
|
||||
Enable this macro to get away from growisofs which uses Close Session
|
||||
but also states "// DVD-R DL Seq has no notion of multi-session".
|
||||
|
||||
#define Libburn_dvd_r_dl_multi_no_close_sessioN 1
|
||||
|
||||
*/
|
||||
|
||||
#endif /* BURN__WRITE_H */
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
libburner is a minimal demo application for the library libburn as provided
|
||||
on http://libburnia.pykix.org . It can list the available devices, can
|
||||
blank a CD-RW or DVD-RW, can format a DVD-RW, and can burn to CD-R, CD-RW,
|
||||
DVD+RW, DVD-RAM or DVD-RW. Not tested: DVD-R. Not supported yet: DVD+R [DL].
|
||||
blank a CD-RW or DVD-RW, can format a DVD-RW, can burn to CD-R, CD-RW, DVD-R,
|
||||
DVD+R, DVD+RW, DVD-RAM or DVD-RW. Not supported yet: double layer media.
|
||||
|
||||
It's main purpose, nevertheless, is to show you how to use libburn and also
|
||||
to serve the libburnia team as reference application. libburner.c does indeed
|
||||
@ -276,7 +276,7 @@ int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
|
||||
return 2;
|
||||
} else if (disc_state == BURN_DISC_FULL ||
|
||||
disc_state == BURN_DISC_APPENDABLE) {
|
||||
; /* this is what libburn is willing to blank */
|
||||
; /* this is what libburner is willing to blank */
|
||||
} else if (disc_state == BURN_DISC_EMPTY) {
|
||||
fprintf(stderr,"FATAL: No media detected in drive\n");
|
||||
return 0;
|
||||
@ -306,8 +306,9 @@ int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
|
||||
}
|
||||
|
||||
|
||||
/** Persistently changes DVD-RW profile 0014h "Sequential Recording"
|
||||
to profile 0013h "Restricted Overwrite" which is usable with libburner.
|
||||
/** Persistently changes DVD-RW profile 0014h "Sequential Recording" to
|
||||
profile 0013h "Restricted Overwrite" which needs no blanking for re-use
|
||||
but is not capable of multi-session.
|
||||
|
||||
Expect a behavior similar to blanking with unusual noises from the drive.
|
||||
*/
|
||||
@ -372,7 +373,7 @@ int libburner_payload(struct burn_drive *drive,
|
||||
time_t start_time;
|
||||
int last_sector = 0, padding = 0, trackno, unpredicted_size = 0, fd;
|
||||
off_t fixed_size;
|
||||
char *adr, reasons[1024];
|
||||
char *adr, reasons[BURN_REASONS_LEN];
|
||||
struct stat stbuf;
|
||||
|
||||
if (all_tracks_type != BURN_AUDIO) {
|
||||
@ -502,8 +503,6 @@ 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)
|
||||
{
|
||||
|
133
test/open-cd-excl.c
Normal file
133
test/open-cd-excl.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* open-cd-excl.c --- This program tries to open a block device
|
||||
* by various exclusive and non-exclusive gestures in order to explore
|
||||
* their impact on running CD/DVD recordings.
|
||||
*
|
||||
* Copyright 2007, by Theodore Ts'o.
|
||||
*
|
||||
* Detail modifications 2007, by Thomas Schmitt.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for O_LARGEFILE *//*ts A70417: or _LARGEFILE64_SOURCE */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
|
||||
const char *progname;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-feirw] device\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* ts A70417: added parameter do_rdwr */
|
||||
static void init_flock(struct flock *fl, int do_rdwr)
|
||||
{
|
||||
memset(fl, 0, sizeof(struct flock));
|
||||
if (do_rdwr)
|
||||
fl->l_type = F_WRLCK;
|
||||
else
|
||||
fl->l_type = F_RDLCK;
|
||||
fl->l_whence = SEEK_SET;
|
||||
fl->l_start = 0;
|
||||
fl->l_len = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct flock fl;
|
||||
char *device_name;
|
||||
int fd, c, f_opt = 0, do_rdwr = 0, end_immediately = 0;
|
||||
int flags = O_NONBLOCK|O_LARGEFILE;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
/* ts A70417: added -w , -r , -i */
|
||||
while ((c = getopt (argc, argv, "feirw")) != EOF) {
|
||||
switch (c) {
|
||||
case 'e':
|
||||
flags |= O_EXCL;
|
||||
break;
|
||||
case 'f':
|
||||
f_opt++;
|
||||
break;
|
||||
case 'i':
|
||||
end_immediately = 1;
|
||||
break;
|
||||
case 'r':
|
||||
do_rdwr = 0;
|
||||
break;
|
||||
case 'w':
|
||||
do_rdwr = 1;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc)
|
||||
usage();
|
||||
device_name = argv[optind++];
|
||||
|
||||
/* ts A70417 : made read-write adjustable independently of f_opt */
|
||||
if (do_rdwr) {
|
||||
flags |= O_RDWR;
|
||||
printf("Using O_RDWR\n");
|
||||
} else {
|
||||
flags |= O_RDONLY;
|
||||
printf("Using O_RDONLY\n");
|
||||
}
|
||||
|
||||
if (flags & O_EXCL)
|
||||
printf("Trying to open %s with O_EXCL ...\n", device_name);
|
||||
fd = open(device_name, flags, 0);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
printf("failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (flags & O_EXCL)
|
||||
printf("succeeded\n");
|
||||
|
||||
if (f_opt) {
|
||||
init_flock(&fl, do_rdwr);
|
||||
if (fcntl(fd, F_GETLK, &fl) < 0) {
|
||||
perror("fcntl: F_GETLK: ");
|
||||
exit(1);
|
||||
}
|
||||
printf("fcntl lock apparently %sLOCKED\n",
|
||||
(fl.l_type == F_UNLCK) ? "NOT " : "");
|
||||
|
||||
init_flock(&fl, do_rdwr);
|
||||
printf("Trying to grab fcntl lock...\n");
|
||||
if (fcntl(fd, F_SETLK, &fl) < 0) {
|
||||
perror("fcntl: F_SETLK: ");
|
||||
printf("failed\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("succeeded\n");
|
||||
}
|
||||
|
||||
/* ts A70417: added end_immediately */
|
||||
printf("Holding %s open.\n", device_name);
|
||||
usleep(100000);
|
||||
if (end_immediately)
|
||||
exit(0);
|
||||
printf("Press ^C to exit.\n");
|
||||
while (1) {
|
||||
sleep(300);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
@ -200,11 +200,11 @@ int telltoc_aquire_by_driveno(int *driveno, int silent_drive)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** This gesture is necessary to get my NEC DVD_RW ND-4570A out of a state
|
||||
of noisy overexcitement after it was inquired for Next Writeable Address.
|
||||
of noisy overexcitement after its tray was loaded and it then was inquired
|
||||
for Next Writeable Address.
|
||||
The noise then still lasts 20 seconds. Same with cdrecord -toc, btw.
|
||||
It opens a small gap for losing the drive to another libburn instance.
|
||||
This opens a small gap for losing the drive to another libburn instance.
|
||||
Not a problem in telltoc. This is done as very last drive operation.
|
||||
Eventually the other libburn instance will have the same sanitizing effect.
|
||||
*/
|
||||
@ -226,9 +226,11 @@ int telltoc_media(struct burn_drive *drive)
|
||||
{
|
||||
int ret, media_found = 0, profile_no = -1;
|
||||
double max_speed = 0.0, min_speed = 0.0, speed_conv;
|
||||
off_t available = 0;
|
||||
enum burn_disc_status s;
|
||||
char profile_name[80], speed_unit[40];
|
||||
struct burn_multi_caps *caps;
|
||||
struct burn_write_opts *o = NULL;
|
||||
|
||||
printf("Media current: ");
|
||||
ret = burn_disc_get_profile(drive, &profile_no, profile_name);
|
||||
@ -251,16 +253,16 @@ int telltoc_media(struct burn_drive *drive)
|
||||
|
||||
printf("Media status : ");
|
||||
s = burn_disc_get_status(drive);
|
||||
if (s==BURN_DISC_FULL) {
|
||||
if (s == BURN_DISC_FULL) {
|
||||
printf("is written , is closed\n");
|
||||
media_found = 1;
|
||||
} else if (s==BURN_DISC_APPENDABLE) {
|
||||
} else if (s == BURN_DISC_APPENDABLE) {
|
||||
printf("is written , is appendable\n");
|
||||
media_found = 1;
|
||||
} else if (s==BURN_DISC_BLANK) {
|
||||
} else if (s == BURN_DISC_BLANK) {
|
||||
printf("is blank\n");
|
||||
media_found = 1;
|
||||
} else if (s==BURN_DISC_EMPTY)
|
||||
} else if (s == BURN_DISC_EMPTY)
|
||||
printf("is not present\n");
|
||||
else
|
||||
printf("is not recognizable\n");
|
||||
@ -276,6 +278,7 @@ int telltoc_media(struct burn_drive *drive)
|
||||
|
||||
ret = burn_disc_get_multi_caps(drive, BURN_WRITE_NONE, &caps, 0);
|
||||
if (ret > 0) {
|
||||
/* Media appears writeable */
|
||||
printf("Write multi : ");
|
||||
printf("%s multi-session , ",
|
||||
caps->multi_session == 1 ? "allows" : "prohibits");
|
||||
@ -309,12 +312,32 @@ int telltoc_media(struct burn_drive *drive)
|
||||
caps->advised_write_mode == BURN_WRITE_RAW ?
|
||||
" (advised)" : "");
|
||||
printf("\n");
|
||||
o= burn_write_opts_new(drive);
|
||||
if (o != NULL) {
|
||||
burn_write_opts_set_perform_opc(o, 0);
|
||||
if(caps->advised_write_mode == BURN_WRITE_TAO)
|
||||
burn_write_opts_set_write_type(o,
|
||||
BURN_WRITE_TAO, BURN_BLOCK_MODE1);
|
||||
else if (caps->advised_write_mode == BURN_WRITE_SAO)
|
||||
burn_write_opts_set_write_type(o,
|
||||
BURN_WRITE_SAO, BURN_BLOCK_SAO);
|
||||
else {
|
||||
burn_write_opts_free(o);
|
||||
o = NULL;
|
||||
}
|
||||
}
|
||||
available = burn_disc_available_space(drive, o);
|
||||
printf("Write space : %.1f MiB (%.fs)\n",
|
||||
((double) available) / 1024.0 / 1024.0,
|
||||
((double) available) / 2048.0);
|
||||
burn_disc_free_multi_caps(&caps);
|
||||
if (o != NULL)
|
||||
burn_write_opts_free(o);
|
||||
}
|
||||
|
||||
ret= burn_drive_get_write_speed(drive);
|
||||
ret = burn_drive_get_write_speed(drive);
|
||||
max_speed = ((double ) ret) / speed_conv;
|
||||
ret= burn_drive_get_min_write_speed(drive);
|
||||
ret = burn_drive_get_min_write_speed(drive);
|
||||
min_speed = ((double ) ret) / speed_conv;
|
||||
if (!media_found)
|
||||
printf("Drive speed : max=%.1f , min=%.1f\n",
|
||||
@ -325,11 +348,11 @@ int telltoc_media(struct burn_drive *drive)
|
||||
|
||||
ret = 0;
|
||||
if (media_found)
|
||||
ret= burn_disc_read_atip(drive);
|
||||
ret = burn_disc_read_atip(drive);
|
||||
if(ret>0) {
|
||||
ret= burn_drive_get_min_write_speed(drive);
|
||||
ret = burn_drive_get_min_write_speed(drive);
|
||||
min_speed = ((double ) ret) / speed_conv;
|
||||
ret= burn_drive_get_write_speed(drive);
|
||||
ret = burn_drive_get_write_speed(drive);
|
||||
max_speed = ((double ) ret) / speed_conv;
|
||||
printf("Media speed : max=%.1f , min=%.1f\n",
|
||||
max_speed, min_speed);
|
||||
@ -503,7 +526,7 @@ int telltoc_msinfo(struct burn_drive *drive,
|
||||
/* man mkisofs , option -C :
|
||||
The second number is the starting sector number of the new session.
|
||||
*/
|
||||
/* Set some write opts to be sent to drive. LG GSA-4082B needs it. */
|
||||
/* Set some roughly suitable write opts to be sent to drive. */
|
||||
o= burn_write_opts_new(drive);
|
||||
if(o!=NULL) {
|
||||
burn_write_opts_set_perform_opc(o, 0);
|
||||
@ -524,7 +547,7 @@ int telltoc_msinfo(struct burn_drive *drive,
|
||||
printf("%d,%d\n",lba,nwa);
|
||||
ret = 1;
|
||||
ex:;
|
||||
if (o!=NULL)
|
||||
if (o != NULL)
|
||||
burn_write_opts_free(o);
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user