Compare commits
249 Commits
ZeroThreeE
...
ZeroFourFo
Author | SHA1 | Date | |
---|---|---|---|
4175023fcd | |||
80c16a3b48 | |||
e1cc10b42e | |||
0b23bfc764 | |||
f3bef987ed | |||
94069733e9 | |||
e75e5e04b8 | |||
86d5bdfef8 | |||
c1298d82a6 | |||
5c6366ecbd | |||
616454c737 | |||
ea6957ef68 | |||
f9398c08e6 | |||
b4617c679c | |||
42bb74881a | |||
61671b41d7 | |||
1e74d7a04e | |||
c48244abfc | |||
13492efe4b | |||
bccb39efd8 | |||
6fc60be93c | |||
d69b856b6a | |||
b5e2d60c68 | |||
ff1ad50119 | |||
4cb6706307 | |||
6e74c8bc2e | |||
fdbed06f84 | |||
67e4282b82 | |||
bd8d4bb49f | |||
623edf9d9d | |||
d4fe8c75be | |||
9ebd020847 | |||
a93d18231a | |||
ec8b75217f | |||
99767afe1f | |||
024076ad54 | |||
c39e7d8ce4 | |||
95609061f1 | |||
d498003515 | |||
b1630a3b33 | |||
eddf4e6b13 | |||
654e25d40a | |||
69e1d4a51f | |||
305917fe86 | |||
b3b42ff649 | |||
63d1f5dcbf | |||
77a9a1fc92 | |||
beb1c1d2d1 | |||
e449654c7b | |||
d66a40bc0e | |||
bed900f3f4 | |||
922fc6c90b | |||
adac21d6ee | |||
d9e056c3ac | |||
32a6bd1f82 | |||
9f7be91aba | |||
fec4fd864f | |||
e48014caea | |||
82c6e92da0 | |||
206910da4e | |||
0a27b188a3 | |||
6705389f14 | |||
5c8d6865b5 | |||
2d6d2679a0 | |||
5432612965 | |||
9b1a57d84a | |||
e5ea580e3b | |||
981a1bf5e1 | |||
49925ad2ba | |||
fc5f2a4745 | |||
903a12c90b | |||
0f50c21888 | |||
f3739013fa | |||
bc5bb95dba | |||
cb68f7e0b7 | |||
63939c4f25 | |||
1280fdf221 | |||
3199bc21aa | |||
2d131a1741 | |||
cd84357589 | |||
e98a90cecf | |||
2a669879a4 | |||
e6885f7fac | |||
191db530c5 | |||
c3d9155340 | |||
3119ed2af3 | |||
5eb47cd3ed | |||
6864b1d621 | |||
5ad09b55ee | |||
f4fe30ec6c | |||
a63d9b11c4 | |||
ee7fcf7522 | |||
ed53a67a2b | |||
bc1944b970 | |||
e065ff1db7 | |||
e5f42759a0 | |||
f3966e5fee | |||
e2479d6088 | |||
291ef125b0 | |||
771e659a43 | |||
f71c2079ff | |||
01ec5f031d | |||
ce7678b8f4 | |||
769ea039a1 | |||
fc6163732e | |||
1efbf27fe3 | |||
214de7d7df | |||
97403bb20e | |||
5d93e04b28 | |||
3dda4b92b9 | |||
ec763a5ec9 | |||
06ec817caa | |||
ff9715aa78 | |||
7ec2972988 | |||
24d6db4b64 | |||
011ba599cd | |||
78c16e7590 | |||
c78403d8cf | |||
5e995c9cd0 | |||
83fe9f3621 | |||
9e4996a3b5 | |||
0721cf89d1 | |||
78dd75b1ff | |||
606c863a55 | |||
282e228a6b | |||
d8990e820e | |||
af3c8aaa5d | |||
1e78652ac9 | |||
a6f41f8beb | |||
9930c22d4a | |||
e71c12caf3 | |||
5e9b8b6341 | |||
5230cb0c1d | |||
85f24401a8 | |||
190ad329fd | |||
c8e9249e9d | |||
e43ec2b295 | |||
a80f8359fe | |||
129db7ee49 | |||
2748f396ae | |||
698866015e | |||
2b0ce8ec9a | |||
8fd2539a5c | |||
1077788276 | |||
361a110274 | |||
f379a2c91a | |||
7654785d43 | |||
15b9f786c8 | |||
635530b05e | |||
ab15717ce0 | |||
eb88f800d7 | |||
1786e8008f | |||
064ef80df9 | |||
488e970665 | |||
02ede28b9e | |||
e137f8fd20 | |||
854a806292 | |||
090861567d | |||
4b4f141fcc | |||
c70a78c477 | |||
542afd7b3b | |||
75dd141055 | |||
ffed552183 | |||
ea09a516bd | |||
ccad19e055 | |||
bdf862b429 | |||
bdff3ac16c | |||
2d3d255231 | |||
8bf8287c58 | |||
40cb77d953 | |||
df382b3f06 | |||
c8c349469d | |||
1f7a6575bc | |||
386149d5bf | |||
c62e63a8d9 | |||
1935d222ed | |||
b812af96f7 | |||
5a8910cdd8 | |||
0bbc34d861 | |||
8e171c89a6 | |||
5283401fb0 | |||
0b13c31b07 | |||
e72b2fd732 | |||
edc50c89ee | |||
ec5bb6eba5 | |||
6f2b1c214e | |||
43a415a081 | |||
277e3cfe29 | |||
0c14e6ee4c | |||
6841cb68e5 | |||
970e2798ba | |||
31650eb988 | |||
797f403b0d | |||
65c0e34363 | |||
b5f1b465b0 | |||
6d3c86690f | |||
f5460ee843 | |||
47e0838a1e | |||
b8b3f85b2e | |||
070afd1a9b | |||
53634f23de | |||
dcf35bd556 | |||
bcb56b5e9e | |||
16a5bbacb4 | |||
5f66cf5d2f | |||
1adf86532e | |||
c6bc4a5e97 | |||
f37e109aa1 | |||
2904a1bee7 | |||
5066b0ac38 | |||
f567874c98 | |||
3127749f5c | |||
4d78a15cbd | |||
df9e6eac0b | |||
9b552e9db6 | |||
99fceeb9e4 | |||
88ad4a4ee1 | |||
ba0e977e42 | |||
d2c9236c25 | |||
c7256fdc35 | |||
a9ea78e9e7 | |||
0c3c4bceb6 | |||
7e86bcc417 | |||
22ea36ffd2 | |||
d21697b289 | |||
12b6a07e9f | |||
ed06b376f2 | |||
fd3a907d9f | |||
58e6577134 | |||
cf0dd395f0 | |||
6950ac8c42 | |||
7958d0ce19 | |||
1bd8012f10 | |||
621a1c24e4 | |||
3b310d3e19 | |||
4c92ab4dee | |||
97abb69301 | |||
b1eb7f1c65 | |||
c09a34ebe4 | |||
7f9fed74e1 | |||
731d17581b | |||
0b575e044e | |||
5363693b07 | |||
69f9f8e493 | |||
4a7923ce4e | |||
23637b020e | |||
605e66a005 | |||
5ff8e34d2c | |||
00df1c9b85 |
@ -3,3 +3,4 @@ Philippe Rouquier
|
||||
Gabriel Craciunescu
|
||||
George Danchev
|
||||
Jean-Francois Wauthy
|
||||
Lorenzo Taylor
|
||||
|
@ -1,13 +1,12 @@
|
||||
Derek Foreman <derek@signalmarketing.com> and Ben Jansens <xor@orodu.net>
|
||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
||||
Mario Danic <mario.danic@gmail.com>, Thomas Schmitt <scdbackup@gmx.net>
|
||||
Copyright (C) 2006-2007 Mario Danic, Thomas Schmitt
|
||||
Copyright (C) 2006-2008 Mario Danic, Thomas Schmitt
|
||||
|
||||
|
||||
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.
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
10
Makefile.am
10
Makefile.am
@ -101,10 +101,14 @@ test_structest_CPPFLAGS = -Ilibburn
|
||||
test_structest_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
test_structest_SOURCES = test/structest.c
|
||||
|
||||
## cdrskin construction site - ts A60816 - A70720
|
||||
## cdrskin construction site - ts A60816 - A80408
|
||||
cdrskin_cdrskin_CPPFLAGS = -Ilibburn
|
||||
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_3_8
|
||||
cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_4_4
|
||||
|
||||
# cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
# ts A80123, change proposed by Simon Huggins to cause dynamic libburn linking
|
||||
cdrskin_cdrskin_LDADD = libburn/libburn.la $(THREAD_LIBS)
|
||||
|
||||
cdrskin_cdrskin_SOURCES = cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cdrfifo.h cdrskin/cdrskin_timestamp.h
|
||||
##
|
||||
## Open questions: how to compute $timestamp and express -DX="$timestamp"
|
||||
|
120
README
120
README
@ -1,25 +1,25 @@
|
||||
------------------------------------------------------------------------------
|
||||
libburnia.pykix.org
|
||||
libburnia-project.org
|
||||
------------------------------------------------------------------------------
|
||||
This all is under GPL.
|
||||
(See GPL reference, our clarification and commitment at the end of this text)
|
||||
------------------------------------------------------------------------------
|
||||
libburnia.pykix.org
|
||||
libburnia-project.org
|
||||
By Mario Danic <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
|
||||
Copyright (C) 2006-2007 Mario Danic, Thomas Schmitt
|
||||
Copyright (C) 2006-2008 Mario Danic, Thomas Schmitt
|
||||
|
||||
Still containing parts of
|
||||
Libburn. By Derek Foreman <derek@signalmarketing.com> and
|
||||
Ben Jansens <xor@orodu.net>
|
||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
||||
These parts are to be replaced by own code of above libburnia.pykix.org
|
||||
copyright holders and then libburnia.pykix.org is to be their sole copyright.
|
||||
These parts are to be replaced by own code of above libburnia-project.org
|
||||
copyright holders and then libburnia-project.org is to be their sole copyright.
|
||||
This is done to achieve the right to issue the clarification and the
|
||||
commitment as written at the end of this text.
|
||||
The rights and merits of the Libburn-copyright holders Derek Foreman and
|
||||
Ben Jansens will be duely respected.
|
||||
|
||||
This libburnia.pykix.org toplevel README (C) 2006-2007 Thomas Schmitt
|
||||
This libburnia-project.org toplevel README (C) 2006-2008 Thomas Schmitt
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Build and Installation
|
||||
@ -27,33 +27,39 @@ This libburnia.pykix.org toplevel README (C) 2006-2007 Thomas Schmitt
|
||||
Our build system is based on autotools. For preparing the build of a SVN
|
||||
snapshot you will need autotools of at least version 1.7.
|
||||
Check out from SVN by
|
||||
svn co http://libburnia-svn.pykix.org/libburn/trunk libburn_pykix
|
||||
go into directory libburn_pykix and apply autotools by
|
||||
svn co http://svn.libburnia-project.org/libburn/trunk libburn
|
||||
go into directory libburn and apply autotools by
|
||||
./bootstrap
|
||||
|
||||
Alternatively you may unpack a release tarball for which you do not need
|
||||
autotools installed.
|
||||
|
||||
To build a libburnia.pykix.org subproject it should be sufficient to go
|
||||
into its toplevel directory (here: "libburn_pykix") and execute
|
||||
./configure
|
||||
To build a libburnia-project.org subproject it should be sufficient to go
|
||||
into its toplevel directory (here: "libburn") and execute
|
||||
./configure --prefix=/usr
|
||||
make
|
||||
|
||||
To make the libraries accessible for running resp. developing applications
|
||||
and to install the cdrecord compatibility binary cdrskin, do:
|
||||
make install
|
||||
|
||||
|
||||
The other half of the project, libisofs, is hosted in the libburnia SVN, too:
|
||||
svn co http://libburnia-svn.pykix.org/libisofs/trunk libisofs_pykix
|
||||
See README file there.
|
||||
An important part of the project, libisofs, is hosted in a bzr repository at
|
||||
launchpad.net :
|
||||
bzr branch lp:libisofs
|
||||
|
||||
Another part the project, libisoburn, is hosted in the libburnia SVN, too:
|
||||
svn co http://svn.libburnia-project.org/libisoburn/trunk libisoburn
|
||||
|
||||
See README files there.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Overview of libburnia.pykix.org
|
||||
Overview of libburnia-project.org
|
||||
|
||||
libburnia.pykix.org is an open-source software project for reading, mastering
|
||||
libburnia-project.org is an open-source software project for reading, mastering
|
||||
and writing optical discs.
|
||||
For now this means only CD media and all single layer DVD media except DVD+R.
|
||||
|
||||
@ -67,29 +73,39 @@ 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.
|
||||
The burn API is quite comprehensively documented and can be used to build a
|
||||
presentable application.
|
||||
We have a functional binary which emulates parts of cdrecord in order to
|
||||
prove that usability, and in order to allow you to explore libburnia's scope
|
||||
by help of existing cdrecord frontends.
|
||||
We have a well tested code base for burning data and audio CDs and many DVD
|
||||
types. The burn API is quite comprehensively documented and can be used to
|
||||
build a presentable application.
|
||||
We have a functional binary which emulates the core use cases of cdrecord in
|
||||
order to prove that usability, and in order to allow you to explore libburn's
|
||||
scope by help of existing cdrecord frontends.
|
||||
|
||||
ISO 9660 filesystems with Rock Ridge and Joliet extensions can be created
|
||||
and manipulated quite freely. This capability together with our burn capability
|
||||
makes possible a single binary application which covers all steps of image
|
||||
composition, updating and writing. Quite unique in the Linux world.
|
||||
|
||||
The project components (list subject to growth, hopefully):
|
||||
|
||||
- libburn is the library by which preformatted data get onto optical media.
|
||||
It uses either /dev/sgN (e.g. on kernel 2.4 with ide-scsi) or
|
||||
/dev/hdX (e.g. on kernel 2.6).
|
||||
/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
|
||||
the pure SCSI knowledge has been taken from dvd+rw-tools, though.
|
||||
|
||||
- libisofs is the library to pack up hard disk files and directories into a
|
||||
ISO 9660 disk image. This may then be brought to media via libburn.
|
||||
ISO 9660 disk image. This may then be brought to CD via libburn.
|
||||
libisofs is to be the foundation of our upcoming mkisofs emulation.
|
||||
|
||||
- libisoburn is an add-on to libburn and libisofs which coordinates both and
|
||||
also allows to grow ISO-9660 filesystem images on multi-session
|
||||
media as well as on overwriteable media via the same API.
|
||||
All media peculiarities are handled automatically.
|
||||
|
||||
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
|
||||
Cdrecord is a powerful GPL'ed burn program included in Joerg
|
||||
cdrecord is a powerful GPL'ed burn program included in Joerg
|
||||
Schilling's cdrtools. cdrskin strives to be a second source for
|
||||
the services traditionally provided by cdrecord. Additionally it
|
||||
provides libburn's DVD capabilities, where only -sao is compatible
|
||||
@ -97,14 +113,34 @@ The project components (list subject to growth, hopefully):
|
||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
||||
Many bytes have been copied from the message output of cdrecord
|
||||
runs, though.
|
||||
See cdrskin/README and man cdrskin/cdrskin.1 for more.
|
||||
See cdrskin/README for more.
|
||||
|
||||
- test is a collection of application gestures and examples given by the
|
||||
authors of the library features. The main API example for libburn
|
||||
is test/libburner.c .
|
||||
- xorriso is an application of all three libraries which creates, loads,
|
||||
manipulates and writes ISO 9660 filesystem images with
|
||||
Rock Ridge extensions. Manipulation is not only adding or
|
||||
overwriting of files but also deletion, renaming, and attribute
|
||||
changing.
|
||||
See xorriso/README for more.
|
||||
|
||||
- "test" is a collection of application gestures and examples given by the
|
||||
authors of the library features. The burn API example of libburn
|
||||
is named test/libburner.c . The API for media information inquiry is
|
||||
demonstrated in test/telltoc.c .
|
||||
Explore these examples if you look for inspiration.
|
||||
|
||||
We plan to be a responsive upstream. Bear with us. We are still practicing.
|
||||
We strive to be a responsive upstream.
|
||||
|
||||
Our libraries are committed to maintain older feature sets in newer versions.
|
||||
This applies to source code headers (API) as well as to linkable objects (ABI).
|
||||
The only exception from this rule is about non-release versions x.y.*[13579]
|
||||
which are allowed to introduce new features, change those new features in
|
||||
any way and even may revoke such new features before the next release of
|
||||
x.y.*[02468]. As soon as it is released, a feature is promised to persist.
|
||||
|
||||
SONAMES:
|
||||
libburn.so.4 (since 0.3.4, March 2007),
|
||||
libisofs.so.6 (since 0.6.2, February 2008),
|
||||
libisoburn.so.1 (since 0.1.0, February 2008).
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
@ -204,6 +240,30 @@ Project history as far as known to me:
|
||||
We look back on improved stability, a substantially extended list of media
|
||||
and write modes, and better protection against typical user mishaps.
|
||||
|
||||
- 24th October 2007 version 0.4.0 is the foundation of new library libisoburn
|
||||
and an upcomming integrated application for manipulating and writing
|
||||
ISO 9660 + Rock Ridge images. cdrskin-0.4.0 got capabilities like growisofs
|
||||
by these enhancements: growing of overwriteable media and disk files.
|
||||
Taking again a bow towards Andy Polyakov.
|
||||
|
||||
- 26th Januar 2008 version 0.4.2 rectifies the version numbering so that we
|
||||
reliably release libburn.so.4 as should have been done since libburn-0.3.2.
|
||||
cdrskin now is by default linked dynamically and does a runtime check
|
||||
to ensure not to be started with a libburn which is older than itself.
|
||||
|
||||
- 3rd Feb 2008 libisofs-0.2.x (.so.5) has been deprecated.
|
||||
|
||||
- 14th Feb 2008 libisofs-0.6.2 permanently replaces the old libisofs-0.2.x.
|
||||
It is the first release of new libisofs.so.6 which will guarantee future
|
||||
API/ABI compatibility for its whole feature set.
|
||||
|
||||
- 15th Feb 2008 libisoburn-0.1.0 (.so.1) coordinates libisofs and libburn for
|
||||
the purpose of ISO image reading and writing. It emulates multi-session on
|
||||
overwriteable media. Application xorriso makes use of all three libraries.
|
||||
|
||||
- 8th Apr 2008 libburn-0.4.4 has proven to be capable of burning to DVD+R/DL
|
||||
and read performance on disk file pseudo-drives has been improved.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
332
cdrskin/README
332
cdrskin/README
@ -1,84 +1,36 @@
|
||||
------------------------------------------------------------------------------
|
||||
libburnia.pykix.org scdbackup.sourceforge.net/cdrskin_eng.html
|
||||
libburnia-project.org scdbackup.sourceforge.net/cdrskin_eng.html
|
||||
------------------------------------------------------------------------------
|
||||
Installation instructions at about line 60. First the legal stuff:
|
||||
------------------------------------------------------------------------------
|
||||
This all is under GPL.
|
||||
(See GPL reference, our clarification and commitment at the end of this text)
|
||||
------------------------------------------------------------------------------
|
||||
Based on and sub project of:
|
||||
libburnia.pykix.org
|
||||
By Mario Danic <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
|
||||
Copyright (C) 2006-2007 Mario Danic, Thomas Schmitt
|
||||
|
||||
libburnia.pykix.org is inspired by and in other components still containing
|
||||
parts of
|
||||
Libburn. By Derek Foreman <derek@signalmarketing.com> and
|
||||
Ben Jansens <xor@orodu.net>
|
||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
||||
See toplevel README for an overview of the current copyright situation in
|
||||
libburnia.pykix.org.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
My thanks to the above authors (except myself, of course) for making the
|
||||
following possible.
|
||||
|
||||
cdrskin. By Thomas Schmitt <scdbackup@gmx.net>
|
||||
Integrated sub project of libburnia.pykix.org but also published via:
|
||||
Integrated sub project of libburnia-project.org but also published via:
|
||||
http://scdbackup.sourceforge.net/cdrskin_eng.html
|
||||
http://scdbackup.sourceforge.net/cdrskin-0.3.8.tar.gz
|
||||
Copyright (C) 2006-2007 Thomas Schmitt
|
||||
|
||||
http://scdbackup.sourceforge.net/cdrskin-0.4.4.pl00.tar.gz
|
||||
Copyright (C) 2006-2008 Thomas Schmitt, provided under GPL version 2.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
On top of libburn there is implemented cdrskin 0.3.8, a limited cdrecord
|
||||
compatibility wrapper which allows to use some libburn features from
|
||||
the command line.
|
||||
Interested users of cdrecord are invited to participate in the development
|
||||
of cdrskin. Contact: scdbackup@gmx.net or libburn-hackers@pykix.org .
|
||||
We will keep copyright narrow but will of course acknowledge valuable
|
||||
contributions in a due way.
|
||||
|
||||
cdrskin is a limited cdrecord compatibility wrapper which allows to use
|
||||
most of the libburn features from the command line.
|
||||
|
||||
Important :
|
||||
This software is provided as is. There is no warranty implied and no
|
||||
protection against possible damages. You use this on your own risk.
|
||||
Don't blame me or other authors of libburn if anything goes wrong.
|
||||
Currently it is only supported on Linux with kernels >= 2.4.
|
||||
|
||||
I used it on my own risk with :
|
||||
SuSE 7.2, kernel 2.4.4, ide-scsi emulation, LITE-ON LTR48125S CD burner, 2002
|
||||
SuSE 9.0, kernel 2.4.21, ide-scsi emulation, LG GSA-4082B CD/DVD burner, 2004
|
||||
NEC ND-4570A CD/DVD burner, 2006
|
||||
RIP-14.4, kernel 2.6.14, no ide-scsi, with all above burners
|
||||
|
||||
It fails to compile or run on SuSE 6.4 (kernel 2.2.14).
|
||||
It does not find the IDE CD burner on SuSE 7.2 without ide-scsi.
|
||||
Other people sucessfully tested cdrskin on several kernel 2.6 based x86 Linux
|
||||
systems, including 64 bit systems. (Further reports are welcome.)
|
||||
By using this software you agree to the disclaimer at the end of this text
|
||||
"This software is provided as is. There is no warranty implied and ..."
|
||||
|
||||
|
||||
Compilation, First Glimpse, Installation
|
||||
|
||||
Obtain cdrskin-0.3.8.tar.gz, take it to a directory of your choice and do:
|
||||
Obtain cdrskin-0.4.4.pl00.tar.gz, take it to a directory of your choice and do:
|
||||
|
||||
tar xzf cdrskin-0.3.8.tar.gz
|
||||
cd cdrskin-0.3.8
|
||||
tar xzf cdrskin-0.4.4.pl00.tar.gz
|
||||
cd cdrskin-0.4.4
|
||||
|
||||
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 directory execute:
|
||||
|
||||
Within that toplevel directory of either cdrskin-0.3.8 or libburn then execute:
|
||||
|
||||
./configure
|
||||
./configure --prefix=/usr
|
||||
make
|
||||
|
||||
(Note: there are next-level directories "libburn" and "cdrskin". Those
|
||||
would be the wrong ones. Meant is the highest directory of tarball resp.
|
||||
SVN download. Among others containing files "AUTHORS", "configure",
|
||||
"Makefile.am", as well as directories "libburn" and "cdrskin".)
|
||||
|
||||
This will already produce a cdrskin binary. But it might be necessary to
|
||||
This will already produce a cdrskin binary. But it will be necessary to
|
||||
install libburn in order to use this binary. Installation of libburn is
|
||||
beyond the scope of cdrskin. For this, see included libburn docs.
|
||||
|
||||
@ -92,11 +44,21 @@ Version identification and help texts available afterwards:
|
||||
cdrskin/cdrskin -help
|
||||
man cdrskin/cdrskin.1
|
||||
|
||||
|
||||
Install (eventually as superuser) cdrskin to a directory where it can be found:
|
||||
If cdrskin was already installed by a previous version, or by "make install"
|
||||
in the course of this installation, then find out where:
|
||||
The command for global installation of both, libburn and cdrskin is
|
||||
make install
|
||||
If the library libburn.so.4 is not found with a test run of cdrskin, then
|
||||
try whether command
|
||||
ldconfig
|
||||
makes it accessible. With the statically linked binary this should not matter.
|
||||
|
||||
You may as well do the few necessary actions manually. If cdrskin was
|
||||
already installed by a previous version, or by "make install" in the course
|
||||
of this installation, then find out where:
|
||||
which cdrskin
|
||||
Copy your standalone binary to exactly the address which you get as reply
|
||||
Copy your standalone binary to exactly the address which you get as reply.
|
||||
E.g.:
|
||||
|
||||
cp cdrskin/cdrskin /usr/bin/cdrskin
|
||||
|
||||
@ -113,6 +75,10 @@ To install the man page, you may do: echo $MANPATH and choose one of the
|
||||
listed directories to copy the man-page under its ./man1 directory. Like:
|
||||
cp cdrskin/cdrskin.1 /usr/share/man/man1/cdrskin.1
|
||||
|
||||
Note: The content of the cdrskin tarball is essentially the complete libburn
|
||||
of the same version number. You may thus perform above steps in a local
|
||||
SVN copy of libburn or in a unpacked libburn tarball as well.
|
||||
|
||||
|
||||
Usage
|
||||
|
||||
@ -137,9 +103,21 @@ So full and insecure enabling of both for everybody would look like
|
||||
|
||||
chmod a+rw /dev/sr0 /dev/sr1
|
||||
|
||||
This is equivalent to the traditional setup chmod a+x,u+s cdrecord.
|
||||
|
||||
I strongly discourage to run cdrskin with setuid root or via sudo !
|
||||
It is not checked for the necessary degree of hacker safety.
|
||||
|
||||
Consider to put all authorized users into group "floppy", to chgrp the
|
||||
device file to that group and to disallow w-access to others.
|
||||
|
||||
Helpful with Linux kernel 2.4 is a special SCSI feature:
|
||||
It is possible to address a scsi(-emulated) drive via associated device files
|
||||
which are not listed by option --devices but point to the same SCSI addresses
|
||||
as listed device files. This addressing via e.g. /dev/sr0 or /dev/scd1 is
|
||||
compatible with generic read programs like dd and with write program growisofs.
|
||||
For finding /dev/sg1 from /dev/sr0, the program needs rw-access to both files.
|
||||
|
||||
|
||||
Usage examples
|
||||
|
||||
@ -174,7 +152,7 @@ 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 multi-session to the same CD , DVD-R[W] or DVD+R
|
||||
Write multi-session to the same CD , DVD-R[W] or DVD+R[/DL]
|
||||
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
|
||||
@ -201,44 +179,32 @@ See below "Audio CD" for specifications.
|
||||
-audio -swab track0[1-5].cd /path/to/track6.wav
|
||||
|
||||
|
||||
Usage example with http://scdbackup.sourceforge.net
|
||||
|
||||
Address may be a cdrecord-style "scsibus,target,lun" as listed with
|
||||
cdrskin -scanbus (and hopefully as listed with cdrecord -scanbus) :
|
||||
|
||||
export SCDBACKUP_SCSI_ADR="0,1,0"
|
||||
|
||||
or a device file address as listed by --devices with an accessible drive :
|
||||
|
||||
export SCDBACKUP_SCSI_ADR="/dev/sr1"
|
||||
|
||||
Set usage of cdrskin with appropriate options rather than cdrecord :
|
||||
|
||||
export SCDBACKUP_CDRECORD="cdrskin -v -v"
|
||||
|
||||
Run a backup :
|
||||
|
||||
scdbackup_home
|
||||
|
||||
|
||||
Restrictions
|
||||
|
||||
Many cdrecord options are still unsupported.
|
||||
Several advanced CD related options of cdrecord are still unsupported.
|
||||
See output of command
|
||||
cdrskin --list_ignored_options
|
||||
If you have use cases for them, please report your wishes and expectations.
|
||||
|
||||
DVD support is restricted to single layer DVD for now. Double layer media
|
||||
are implemented but untested.
|
||||
|
||||
On the other hand, the capability of multi-session and of writing streams
|
||||
of unpredicted lenght surpass the current DVD capabilities of cdrecord.
|
||||
|
||||
|
||||
Inspiration and Standard
|
||||
|
||||
cdrskin combines the command line interface standard set by cdrecord with
|
||||
libburn, which is a control software for optical drives according to standard
|
||||
MMC-5. For particular CD legacy commands, standards MMC-3 and MMC-1 apply.
|
||||
|
||||
For the original meaning of cdrecord options see :
|
||||
man cdrecord
|
||||
(http://cdrecord.berlios.de/old/private/man/cdrecord-2.0.html)
|
||||
Do not bother Joerg Schilling with any cdrskin problems.
|
||||
(Be cursed if you install cdrskin as "cdrecord" without clearly forwarding
|
||||
this "don't bother Joerg" demand.)
|
||||
|
||||
cdrskin does not contain any bytes copied from cdrecord's sources. Many bytes
|
||||
have been copied from the message output of cdrecord runs, though. I am
|
||||
thankful to Joerg Schilling for every single one of them.
|
||||
@ -249,94 +215,6 @@ Many thanks to Andy Polyakov for his dvd+rw-tools
|
||||
which provide me with examples and pointers into MMC specs for DVD writing.
|
||||
|
||||
|
||||
Drive Addressing
|
||||
|
||||
Drives get addressed either via their cdrecord-style addresses as listed
|
||||
with option -scanbus (see below "Pseudo-SCSI Adresses") or via the paths
|
||||
of device files.
|
||||
Not only device files listed by --devices may be used but also device files
|
||||
which via their major,minor numbers point to the same device driver as
|
||||
a listed device file.
|
||||
|
||||
Helpful with Linux kernel 2.4 is a special SCSI feature:
|
||||
It is possible to address a scsi(-emulated) drive via associated device files
|
||||
which are not listed by option --devices but point to the same SCSI addresses
|
||||
as listed device files. This addressing via e.g. /dev/sr0 or /dev/scd1 is
|
||||
compatible with generic read programs like dd and with write program growisofs.
|
||||
|
||||
Pseudo-SCSI Adresses
|
||||
|
||||
cdrecord and cdrskin share the syntax of SCSI addresses but not necessarily
|
||||
the meaning of the components. A cdrecord-style address for cdrskin
|
||||
[prefix:]scsibus,target,lun
|
||||
can be interpreted in two different modes.
|
||||
|
||||
Standard mode tries to be compatible to original cdrecord. This should be true
|
||||
with (emulated) SCSI where the 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
|
||||
where target only may have the values 0 or 1.
|
||||
|
||||
In this mode, option -scanbus will list only SCSI devices unless option
|
||||
dev=ATA or dev=ATAPI are given, which will suppress SCSI devices and only
|
||||
show IDE drives (i.e. /dev/hdX without ide-scsi emulation).
|
||||
|
||||
|
||||
In mode --old_pseudo_scsi_adr there is a scsibus,target,lun representation
|
||||
which has nothing to do with SCSI and thus is not compatible to cdrecord.
|
||||
Each number triple corresponds either to a device file address or to a
|
||||
libburn drive number.
|
||||
Component "scsibus" indicates the translation method. Defined busses are:
|
||||
0 target is the libburn drivenumber as listed with --devices
|
||||
1 associated to device file /dev/sgN , target chooses N
|
||||
2 associated to device file /dev/hdX , target 0='a', 1='b' ..., 25='z'
|
||||
|
||||
So "1,1,0" is /dev/sg1 (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
|
||||
drive accessability.
|
||||
Further busses may emerge as libburn evolves. "prefix" and "lun" may get
|
||||
a meaning. To stay upward compatible, use addresses as printed by -scanbus.
|
||||
|
||||
User Defined Device Address Translation
|
||||
|
||||
Some programs or users have their own ideas about the address of their burner.
|
||||
K3b 0.10 for example derives cdrecord addresses by own examination of the
|
||||
devices and not by calling cdrecord -scanbus.
|
||||
Standard mode will hopefully be fully compatible with their ideas.
|
||||
|
||||
Old frontends which do not know dev=ATA or dev=ATAPI and which do ask their
|
||||
"cdrecord" via -scanbus may be well served with option --old_pseudo_scsi_adr .
|
||||
|
||||
To direct any remaining stubborn callers to the appropriate drives, cdrskin
|
||||
allows to define device address aliases. Like
|
||||
cdrskin dev_translation=+1,0,0+/dev/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/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 "-".)
|
||||
|
||||
In K3b 0.10 it is possible to employ alternative writer programs by setting
|
||||
their full path (e.g. /usr/bin/cdrskin) in menu
|
||||
Settings:Configure K3b...:Programs:Search Path
|
||||
and to make them default in menu
|
||||
Settings:Configure K3b...:Programs:Programs:
|
||||
A suitable setting for "cdrecord" in menu
|
||||
Settings:Configure K3b...:Programs:User Parameters
|
||||
would then probably be
|
||||
-v dev_translation=+1,0,0+/dev/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.
|
||||
|
||||
|
||||
Startup Files
|
||||
|
||||
If not --no_rc is the first argument then cdrskin attempts on startup to read
|
||||
@ -352,8 +230,6 @@ A first character '#' marks a comment, empty lines are ignored.
|
||||
Example content of a startup file:
|
||||
# This is the default device
|
||||
dev=0,1,0
|
||||
# To accomodate to eventual remnant cdrskin-0.2.2 addresses
|
||||
dev_translation=+1,0,0+0,1,0
|
||||
|
||||
# Some more options
|
||||
fifo_start_at=0
|
||||
@ -395,24 +271,19 @@ Speed is counted in DVD units (i.e. 1x = 1,385,000 bytes/second). Currently
|
||||
there is no difference between -sao and -tao. If ever, then -tao will be the
|
||||
mode which preserves the current behavior.
|
||||
|
||||
For these media, -msinfo alone would not be enough to perform appending of an
|
||||
ISO filesystem. The filesystem driver will need a hint to find the start of the
|
||||
most recent session. For example put an ISO filesystem at address 1 GB:
|
||||
mkisofs -C 0,524288 ... | \
|
||||
cdrskin dev=/dev/sr0 -v fs=32m -eject speed=4 write_start_address=524288s -
|
||||
The superuser may then do:
|
||||
mount -t iso9660 -o ro,sbsector=524288 /dev/sr0 /mnt
|
||||
Note: On my linux-2.4.21-215 mount works only with sbsector <= 337920 (660 MiB)
|
||||
To extend a filesystem already existing at address 0
|
||||
mkisofs -C 0,524288 -M /dev/sr0 ... | cdrskin dev=/dev/sr0 ...
|
||||
Record the number 524288 for usage as first number with -C at the next
|
||||
extension:
|
||||
mkisofs -C 524288,1000000 ... | cdrskin write_start_address=1000000s ...
|
||||
|
||||
Program growisofs can append to an ISO filesystem on DVD+RW by additionally
|
||||
manipulating the first session. cdrskin does not want to get involved so deep
|
||||
into the format of the burned data. Be advised to use growisofs for the
|
||||
task of maintaining extendable ISO-Filesystems on DVD+RW.
|
||||
manipulating the first session. Meanwhile cdrskin can do the same.
|
||||
Option --grow_overwriteable_iso allows -multi (although unneeded), enables
|
||||
-msinfo and -toc, and makes blank=fast an invalidator for ISO filesystems
|
||||
on overwriteable media.
|
||||
|
||||
Initial session (equivalent to growisofs -Z):
|
||||
mkisofs ... | cdrskin --grow_overwriteable_iso blank=fast ...
|
||||
|
||||
Add-on session (equivalent to growisofs -M):
|
||||
cparms=$(cdrskin dev=/dev/sr0 --grow_overwriteable_iso -msinfo)
|
||||
mkisofs -C "$cparms" -M /dev/sr0 ... | \
|
||||
cdrskin dev=/dev/sr0 --grow_overwriteable_iso ... -
|
||||
|
||||
|
||||
DVD-RW and DVD-R
|
||||
@ -428,7 +299,7 @@ of multi-session like CD-R[W]. (But not capable of -audio recording.)
|
||||
This means they need option -multi to stay appendable, need to be blanked
|
||||
to be writeable from start, return useable info with -toc and -msinfo,
|
||||
eventually perform appending automatically.
|
||||
Without "Incremental Streaming" offered by the drive, only write mode DAO is
|
||||
Without Incremental Streaming offered by the drive, only write mode DAO is
|
||||
available with sequential DVD-R[W]. It only works with blank media, allows only
|
||||
one single track, no -multi, and demands a fixely predicted track size.
|
||||
(growisofs uses it with DVD-R[W] if option -dvd-compat is given.)
|
||||
@ -437,7 +308,7 @@ Overwriteable DVD-RW behave much like DVD+RW. "Restricted" refers only to the
|
||||
granularity of random access and block size which have always to be aligned to
|
||||
full 32 kB. Sequential DVD-RW are converted into overwriteable DVD-RW by
|
||||
cdrskin dev=... -v blank=format_overwrite
|
||||
(Command dvd+rw-format -force can achieve "Restricted Overwrite", too.)
|
||||
(Command dvd+rw-format -force can achieve Restricted Overwrite, too.)
|
||||
|
||||
Formatting or first use of freshly formatted DVD-RW can produce unusual noises
|
||||
from the drive and last several minutes. Depending on mutual compatibility of
|
||||
@ -470,10 +341,28 @@ Incremental Streaming afterwards. So blank=fast will do full blanking.
|
||||
blank=deformat_sequential_quickest is faster but might yield DAO-only media.
|
||||
|
||||
|
||||
DVD+R
|
||||
DVD+R and DVD+R/DL
|
||||
|
||||
From the view of cdrskin they behave much like DVD-R. Each track gets wrapped
|
||||
into an own session, though.
|
||||
DVD+R/DL appear as extra large DVD+R. cdrskin does not allow to set the address
|
||||
of the layer break where ia reading drive might show some delay while switching
|
||||
between both media layers.
|
||||
|
||||
|
||||
Emulated Drives
|
||||
|
||||
cdrskin can use filesystem objects as emulated drives. Regular files or block
|
||||
devices appear similar to DVD-RAM. Other file types resemble blank DVD-R.
|
||||
Necessary precondition is option --allow_emulated_drives which is not accepted
|
||||
if cdrskin took another user identity because of the setuid bit of its access
|
||||
permissions.
|
||||
Addresses of emulated drives begin with prefix "stdio:". E.g.
|
||||
dev=stdio:/tmp/my_pseudo_drive
|
||||
|
||||
For safety reasons the superuser is only allowed to use /dev/null as emulated
|
||||
drive. See man page section FILES for a way to lift that ban.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
@ -494,12 +383,36 @@ It will not read startup files, will abort on option dev_translation= ,
|
||||
will not have a fifo buffer, and will not be able to put out help texts or
|
||||
debugging messages.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Project aspects and legal stuff
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Important Disclaimer :
|
||||
|
||||
This software is provided as is. There is no warranty implied and no
|
||||
protection against possible damages. You use this on your own risk.
|
||||
Don't blame me or other authors of libburn if anything goes wrong.
|
||||
|
||||
Actually, in case of severe trouble, nearly always the drive and the media
|
||||
are the cause. Any mistake of the burn program is supposed to be caught
|
||||
by the drive's firmware and to lead to mere misburns.
|
||||
The worst mishaps which hit the author implied the need to reboot the
|
||||
system because of drives gnawing endlessly on ill media. Permanent hardware
|
||||
damage did not occur in 1.5 years of development.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Interested users are invited to participate in the development of cdrskin.
|
||||
Contact: scdbackup@gmx.net or libburn-hackers@pykix.org .
|
||||
We will keep copyright narrow but will of course acknowledge valuable
|
||||
contributions in a due way.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ -510,6 +423,21 @@ debugging messages.
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Based on and sub project of:
|
||||
libburnia-project.org
|
||||
By Mario Danic <mario.danic@gmail.com> and Thomas Schmitt <scdbackup@gmx.net>
|
||||
Copyright (C) 2006-2008 Mario Danic, Thomas Schmitt
|
||||
|
||||
libburnia-project.org is inspired by and in other components still containing
|
||||
parts of
|
||||
Libburn. By Derek Foreman <derek@signalmarketing.com> and
|
||||
Ben Jansens <xor@orodu.net>
|
||||
Copyright (C) 2002-2006 Derek Foreman and Ben Jansens
|
||||
See toplevel README for an overview of the current copyright situation in
|
||||
libburnia-project.org.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
cdrskin is currently copyright Thomas Schmitt only.
|
||||
It adopts the following commitment by the toplevel copyright holders:
|
||||
|
@ -38,7 +38,7 @@ original="./libburn_svn_release.tgz"
|
||||
# My changes are in $changes , mainly in $changes/cdrskin
|
||||
changes="./libburn-release"
|
||||
|
||||
skin_release="0.3.8"
|
||||
skin_release="0.4.4"
|
||||
patch_level=".pl00"
|
||||
skin_rev="$skin_release""$patch_level"
|
||||
|
||||
@ -58,7 +58,8 @@ compile_result="cdrskin/cdrskin"
|
||||
man_to_html_cmd="./cdrskin/convert_man_to_html.sh"
|
||||
man_page_html="cdrskin/man_1_cdrskin.html"
|
||||
|
||||
bintarget_dynamic="cdrskin_${skin_rev}-x86-suse9_0"
|
||||
# bintarget_dynamic="cdrskin_${skin_rev}-x86-suse9_0"
|
||||
bintarget_dynamic="cdrskin_${skin_rev}-amd64-suse10_2"
|
||||
bintarget_static="$bintarget_dynamic"-static
|
||||
|
||||
if test -d "$changes"
|
||||
@ -154,6 +155,10 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove libcevap
|
||||
rm -rf "$target"/libcevap
|
||||
|
||||
|
||||
# Remove unwanted SVN stuff (TODO: avoid downloading it)
|
||||
for i in "$target"/.svn "$target"/*/.svn
|
||||
do
|
@ -24,9 +24,9 @@ set -x
|
||||
# The top level directory in the SVN snapshot is named
|
||||
intermediate="./libburn_pykix"
|
||||
|
||||
# libburn source used: http://libburnia.pykix.org
|
||||
# libburn source used: http://libburnia-project.org
|
||||
# Downloaded by:
|
||||
# $ svn co http://libburnia-svn.pykix.org/libburn/tags/... $intermediate
|
||||
# $ svn co http://libburnia-project.org/libburn/tags/... $intermediate
|
||||
# packed up in a tarball just to save it from inadverted changes by
|
||||
# $ tar czf libburn_svn.tgz $intermediate
|
||||
original="./libburn_svn.tgz"
|
||||
@ -38,7 +38,7 @@ original="./libburn_svn.tgz"
|
||||
# My changes are in $changes , mainly in $changes/cdrskin
|
||||
changes="./libburn-develop"
|
||||
|
||||
skin_release="0.3.9"
|
||||
skin_release="0.4.5"
|
||||
patch_level=""
|
||||
skin_rev="$skin_release""$patch_level"
|
||||
|
||||
@ -58,7 +58,7 @@ compile_result="cdrskin/cdrskin"
|
||||
man_to_html_cmd="./cdrskin/convert_man_to_html.sh"
|
||||
man_page_html="cdrskin/man_1_cdrskin.html"
|
||||
|
||||
bintarget_dynamic="cdrskin_${skin_rev}-x86-suse9_0"
|
||||
bintarget_dynamic="cdrskin_${skin_rev}-amd64-suse10_2"
|
||||
bintarget_static="$bintarget_dynamic"-static
|
||||
|
||||
if test -d "$changes"
|
||||
@ -143,6 +143,9 @@ rm "$cdrskin_target"/doener_*.gif "$cdrskin_target"/doener_*.png
|
||||
# Remove automatically generated HTML man page
|
||||
rm "$cdrskin_target"/man_1_cdrskin.html
|
||||
|
||||
# Remove libcevap
|
||||
rm -rf "$target"/libcevap
|
||||
|
||||
# Remove all add_ts_changes_to_libburn besides this one
|
||||
for i in "$cdrskin_target"/add_ts_changes_to_libburn*
|
||||
do
|
||||
@ -222,6 +225,8 @@ tar czf "$cdrskin_tarball" "$target"
|
||||
"$compile_cmd" $compile_static_opts -libburn_svn -O2 -do_strip
|
||||
cp "$compile_result" "../$bintarget_static"
|
||||
fi
|
||||
# "$compile_cmd" -libburn_svn -O2 -do_diet -do_strip
|
||||
# cp "$compile_result" "../$bintarget_dynamic"_diet
|
||||
"$man_to_html_cmd"
|
||||
mv "$man_page_html" ..
|
||||
)
|
||||
@ -234,7 +239,7 @@ rm -rf "$target"
|
||||
./"$bintarget_dynamic" -version
|
||||
./"$bintarget_static" -version
|
||||
ls -l "$cdrskin_tarball"
|
||||
ls -l "$bintarget_dynamic"
|
||||
ls -l "$bintarget_dynamic"*
|
||||
ls -l "$bintarget_static"
|
||||
ls -l $(basename "$man_page_html")
|
||||
|
@ -79,6 +79,7 @@ struct CdrfifO {
|
||||
|
||||
/* eventual ISO-9660 image size obtained from first 64k of input */
|
||||
double iso_fs_size;
|
||||
char *iso_fs_descr; /* eventually block 16 to 31 of input */
|
||||
|
||||
/* (sequential) fd chaining */
|
||||
/* fds: 0=source, 1=dest */
|
||||
@ -162,6 +163,7 @@ int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
|
||||
o->empty_counter= 0.0;
|
||||
o->full_counter= 0.0;
|
||||
o->iso_fs_size= -1.0;
|
||||
o->iso_fs_descr= NULL;
|
||||
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;
|
||||
@ -222,6 +224,8 @@ int Cdrfifo_destroy(struct CdrfifO **ff, int flag)
|
||||
|
||||
/* eventual closing of source fds is the job of the calling application */
|
||||
|
||||
if(o->iso_fs_descr!=NULL)
|
||||
free((char *) o->iso_fs_descr);
|
||||
if(o->buffer!=NULL)
|
||||
free((char *) o->buffer);
|
||||
free((char *) o);
|
||||
@ -400,6 +404,14 @@ int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes, int flag)
|
||||
}
|
||||
|
||||
|
||||
int Cdrfifo_adopt_iso_fs_descr(struct CdrfifO *o, char **pt, int flag)
|
||||
{
|
||||
*pt= o->iso_fs_descr;
|
||||
o->iso_fs_descr= NULL;
|
||||
return(*pt!=NULL);
|
||||
}
|
||||
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
@ -882,19 +894,24 @@ int Cdrfifo_fill(struct CdrfifO *o, int size, int flag)
|
||||
}
|
||||
|
||||
#ifndef Cdrfifo_standalonE
|
||||
{ int Scan_for_iso_size(unsigned char data[2048], double *size_in_bytes,
|
||||
if(fill>=32*2048) {
|
||||
int Scan_for_iso_size(unsigned char data[2048], double *size_in_bytes,
|
||||
int flag);
|
||||
int i;
|
||||
int bs= 16*2048;
|
||||
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;
|
||||
/* memorize blocks 16 to 31 */
|
||||
if(o->iso_fs_descr!=NULL)
|
||||
free((char *) o->iso_fs_descr);
|
||||
o->iso_fs_descr= TSOB_FELD(char,bs);
|
||||
if(o->iso_fs_descr==NULL)
|
||||
return(-1);
|
||||
memcpy(o->iso_fs_descr,o->buffer+bs,bs);
|
||||
|
||||
/* try to obtain ISO-9660 file system size from block 16 */
|
||||
ret= Scan_for_iso_size((unsigned char *) (o->buffer+bs), &size, 0);
|
||||
if(ret>0)
|
||||
o->iso_fs_size= size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -123,6 +123,16 @@ int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
|
||||
int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes,int flag);
|
||||
|
||||
|
||||
/** Take over the eventually memorized blocks 16 to 31 of input (2 kB each).
|
||||
The fifo forgets the blocks by this call. I.e. a second one will return 0.
|
||||
After this call it is the responsibility of the caller to dispose the
|
||||
retrieved memory via call free().
|
||||
@param pt Will be filled either with NULL or a pointer to 32 kB of data
|
||||
@return 0=nothing is buffered, 1=pt points to valid freeable data
|
||||
*/
|
||||
int Cdrfifo_adopt_iso_fs_descr(struct CdrfifO *o, char **pt, int flag);
|
||||
|
||||
|
||||
/** Check for pending data at the fifo's source file descriptor and wether the
|
||||
fifo is ready to take them. Simultaneously check the buffer for existing
|
||||
data and the destination fd for readiness to accept some. If so, a small
|
||||
|
@ -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 "July 19, 2007"
|
||||
.TH CDRSKIN 1 "September 26, 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[W], DVD-R[W], DVD+R[W], DVD-RAM
|
||||
via libburn.
|
||||
cdrskin \- burns preformatted data to CD-R[W], DVD-R[W], DVD+R[W], DVD+R/DL,
|
||||
DVD-RAM via libburn.
|
||||
.SH SYNOPSIS
|
||||
.B cdrskin
|
||||
.RI [ options | track_source_addresses ]
|
||||
@ -31,7 +31,7 @@ via libburn.
|
||||
\fBcdrskin\fP is a program that provides some of cdrecord's options
|
||||
in a compatible way for CD media. With DVD it has its own ways.
|
||||
You do not need to be superuser for its daily usage.
|
||||
.PP
|
||||
.SS
|
||||
.B Overview of features:
|
||||
.br
|
||||
Blanking of CD-RW and DVD-RW.
|
||||
@ -44,16 +44,20 @@ or in Session at Once mode for seamless tracks.
|
||||
.br
|
||||
Multi session on CD (follow-up sessions in TAO only)
|
||||
.br
|
||||
or on DVD-R[W] (in Incremental mode) or on DVD+R.
|
||||
or on DVD-R[W] (in Incremental mode) or on DVD+R[/DL].
|
||||
.br
|
||||
Single session on DVD-RW or DVD-R (Disk-at-once)
|
||||
Single session on DVD-RW or DVD-R (Disk-at-once).
|
||||
.br
|
||||
or on overwriteable DVD+RW, DVD-RW, DVD-RAM.
|
||||
Single session or emulated ISO-9660 multi-session
|
||||
.br
|
||||
on overwriteable DVD+RW, DVD-RW, DVD-RAM,
|
||||
.br
|
||||
or on data file or block device.
|
||||
.br
|
||||
Bus scan, burnfree, speed options, retrieving media info, padding, fifo.
|
||||
.br
|
||||
See section EXAMPLES at the end of this text.
|
||||
.PP
|
||||
.SS
|
||||
.B General information paragraphs:
|
||||
.br
|
||||
Track recording model
|
||||
@ -67,7 +71,9 @@ Sequentially Recordable DVD Media
|
||||
Overwriteable DVD Media
|
||||
.br
|
||||
Drive preparation and addressing
|
||||
.PP
|
||||
.br
|
||||
Emulated drives
|
||||
.SS
|
||||
.B Track recording model:
|
||||
.br
|
||||
The input-output entities which get processed are called tracks.
|
||||
@ -109,9 +115,22 @@ Another type of data track content are archive formats which originally
|
||||
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
|
||||
.SS
|
||||
.B Write mode selection:
|
||||
.br
|
||||
In general there are two approaches for writing media:
|
||||
.br
|
||||
A permissive mode depicted by option
|
||||
.B -tao
|
||||
which needs no predicted track size and allows to make use of
|
||||
eventual multi-session capabilities.
|
||||
.br
|
||||
A more restrictive mode
|
||||
.B -sao
|
||||
(alias -dao) which usually demands a predictable track size and is not
|
||||
necessarily capable of multi-session. It may have advantages for some
|
||||
readers resp. players of the recorded tracks.
|
||||
.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.
|
||||
@ -119,7 +138,7 @@ the capabilities of the drive and the state of the present media.
|
||||
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
|
||||
.SS
|
||||
.B Recordable CD Media:
|
||||
.br
|
||||
CD-R can be initially written only once and eventually extended until they
|
||||
@ -128,15 +147,11 @@ read-only. Closing is done automatically unless option
|
||||
.B -multi
|
||||
is given which keeps the media appendable.
|
||||
.br
|
||||
There are two write modes,
|
||||
.B -tao
|
||||
and
|
||||
.B -sao .
|
||||
.br
|
||||
-tao allows to use track source of unpredictable length (like stdin) and allows
|
||||
to write further sessions to appendable media. -sao produces audio sessions
|
||||
with seamless tracks but needs predicted track sizes and cannot append sessions
|
||||
to media.
|
||||
Write mode
|
||||
-tao allows to use track sources of unpredictable length (like stdin) and
|
||||
allows to write further sessions to appendable media.
|
||||
-sao produces audio sessions with seamless tracks but needs predicted track
|
||||
sizes and cannot append sessions to media.
|
||||
.br
|
||||
CD-RW media can be blanked to make them re-usable for another
|
||||
round of overwriting. Usually
|
||||
@ -145,10 +160,10 @@ is the appropriate option.
|
||||
Blanking damages the previous content but does not
|
||||
make it completely unreadable. It is no effective privacy precaution.
|
||||
Multiple cycles of blanking and overwriting with random numbers might be.
|
||||
.PP
|
||||
.SS
|
||||
.B Sequentially Recordable DVD Media:
|
||||
.br
|
||||
Currently DVD-RW, DVD-R and DVD+R can be used for the Sequential recording
|
||||
Currently DVD-RW, DVD-R and DVD+R[/DL] can be used for the Sequential recording
|
||||
model.
|
||||
.br
|
||||
DVD-RW must be in state "Sequential Recording".
|
||||
@ -183,22 +198,35 @@ unpredicted length and to keep media appendable by option
|
||||
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
|
||||
The write modes for DVD+R[/DL] resemble those with DVD-R except that with +R
|
||||
each track gets wrapped in an own session. There is no -dummy writing with
|
||||
DVD+R.
|
||||
DVD+R[/DL].
|
||||
.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
|
||||
.br
|
||||
.B Note:
|
||||
Option -multi might make DVD media unreadable in some DVD-ROM drives.
|
||||
Best reader compatibility is achieved without it
|
||||
(i.e. by single session media).
|
||||
.SS
|
||||
.B Overwriteable DVD Media:
|
||||
.br
|
||||
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.
|
||||
Options -audio and -multi are not allowed. Only one track is allowed.
|
||||
-toc does not return information about the media content.
|
||||
DVD+RW and DVD-RAM media need no special initial formatting. They offer a
|
||||
single continuous data area for blockwise random access.
|
||||
.br
|
||||
Option -audio is not allowed. Only one track is allowed.
|
||||
Option -multi cannot mark a recognizeable end of overwriteable media.
|
||||
Therefore -multi is banned unless ISO-9660 images shall be expandable by help
|
||||
of option
|
||||
.B --grow_overwriteable_iso .
|
||||
Without this option or without an ISO-9660 filesystem image present
|
||||
on media, -toc does not return information about the media content and
|
||||
media get treated as blank regardless wether they hold data or not.
|
||||
.br
|
||||
Currently there is no difference between -sao and -tao. If ever, then -tao
|
||||
will be the mode which preserves the current behavior.
|
||||
.br
|
||||
@ -211,7 +239,7 @@ can be done by option
|
||||
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
|
||||
.SS
|
||||
.B Drive preparation and addressing:
|
||||
.br
|
||||
The drives, either CD burners or DVD burners, are accessed via addresses which
|
||||
@ -226,8 +254,10 @@ who is able to get this list without further
|
||||
precautions.
|
||||
.br
|
||||
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.
|
||||
is less security sensitive than chmod u+s,a+x /usr/bin/cdrskin. The risk for
|
||||
the drive is somewhat higher but the overall system is much less at stake.
|
||||
Consider to restrict rw-access to a single group which bundles the users who
|
||||
are allowed to use the burner drive (like group "floppy").
|
||||
.br
|
||||
.PP
|
||||
If you only got one CD capable drive then you may leave out cdrskin option
|
||||
@ -245,6 +275,40 @@ 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/sg0).
|
||||
.br
|
||||
.SS
|
||||
.B Emulated drives:
|
||||
.br
|
||||
Option
|
||||
.B --allow_emulated_drives
|
||||
enables addressing of pseudo-drives
|
||||
which get emulated on top of filesystem objects. Regular data files and
|
||||
block devices result in pseudo-drives which behave much like DVD-RAM.
|
||||
If the given address does not exist yet but its directory exists, then
|
||||
it gets created as regular file.
|
||||
Other file types like character devices or pipes result in pseudo-drives
|
||||
which behave much like blank DVD-R.
|
||||
The target file address is given after prefix "stdio:".
|
||||
.br
|
||||
E.g.: dev=stdio:/tmp/my_pseudo_drive
|
||||
.br
|
||||
Addresses of the form "stdio:/dev/fd/<number>" are treated special. The
|
||||
number is read literally and used as open file descriptor. With
|
||||
dev="stdio:/dev/fd/1" the normal standard output of the program is
|
||||
redirected to stderr and the stream data of a burn run will appear on stdout.
|
||||
.br
|
||||
Not good for terminals ! Redirect it.
|
||||
.br
|
||||
Pseudo-drives allow -dummy. Their reply with --tell_media_space can be utopic.
|
||||
-dummy burn runs touch the file but do not modify its data content.
|
||||
.br
|
||||
Note: --allow_emulated_drives is restricted to stdio:/dev/null if cdrskin
|
||||
is run by the
|
||||
.B superuser
|
||||
or if it has changed user identity via the
|
||||
.B setuid
|
||||
bit of its access permissions. The ban for the superuser can be lifted by a
|
||||
skillfully created file. See section FILES below.
|
||||
.br
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-\-help
|
||||
@ -252,6 +316,11 @@ Show non-cdrecord compatible options.
|
||||
.TP
|
||||
.BI \-help
|
||||
Show cdrecord compatible options.
|
||||
.br
|
||||
Note that some of the help texts are quite wrong - for cdrecord as well as
|
||||
for cdrskin (e.g. -format, blank=, -load). They are, nevertheless, traditional
|
||||
indicators for the availability of the listed options. Some frontend programs
|
||||
make decisions after reading them.
|
||||
.TP
|
||||
.BI \-version
|
||||
Print cdrskin id line, compatibility lure line, libburn version, cdrskin
|
||||
@ -286,11 +355,11 @@ Print this list of blanking types.
|
||||
.TP
|
||||
all
|
||||
Blank an entire CD-RW or an unformatted DVD-RW.
|
||||
(See also --prodvd_cli_compatible)
|
||||
(See also --prodvd_cli_compatible, --grow_overwriteable_iso)
|
||||
.TP
|
||||
fast
|
||||
Minimally blank an entire CD-RW or blank an unformatted DVD-RW.
|
||||
(See also --prodvd_cli_compatible)
|
||||
(See also --prodvd_cli_compatible, --grow_overwriteable_iso)
|
||||
.TP
|
||||
format_overwrite
|
||||
Format a DVD-RW to "Restricted Overwrite". The user should bring some patience.
|
||||
@ -330,7 +399,7 @@ Incremental Streaming (-tao).
|
||||
.RE
|
||||
.TP
|
||||
.BI \-checkdrive
|
||||
Retrieve some info about the addressed drive.
|
||||
Retrieve some info about the addressed drive and then exit.
|
||||
Exits with non-zero value if the drive cannot be found and opened.
|
||||
.TP
|
||||
.BI \-dao
|
||||
@ -368,7 +437,7 @@ Try to perform the drive operations without actually affecting the inserted
|
||||
media. There is no warranty that this will work with a particular combination
|
||||
of drive, media, and write mode. Blanking is prevented reliably, though.
|
||||
To avoid inadverted real burning, -dummy refuses burn runs on anything but
|
||||
CD-R[W] and DVD-R[W].
|
||||
CD-R[W], DVD-R[W], or emulated stdio-drives.
|
||||
.TP
|
||||
.BI \-eject
|
||||
Eject the disc after work is done.
|
||||
@ -388,6 +457,9 @@ that drive and media will not simulate the write mode but will write for real.
|
||||
.B Caution:
|
||||
Use this only when in urgent need.
|
||||
.TP
|
||||
.BI \-format
|
||||
Same as blank=format_overwrite_full -force but restricted to DVD+RW.
|
||||
.TP
|
||||
.BI fs= size
|
||||
Set the fifo size to the given value. The value may have appended letters which
|
||||
multiply the preceding number:
|
||||
@ -407,6 +479,19 @@ option fifo_start_at=size.
|
||||
.BI gracetime= seconds
|
||||
Set the grace time before starting to write. (Default is 0)
|
||||
.TP
|
||||
.BI -immed
|
||||
Equivalent to:
|
||||
.br
|
||||
modesty_on_drive=1:min_percent=75:max_percent=95
|
||||
.br
|
||||
The name of this cdrecord option stems from the "Immed" bit which can make some
|
||||
long running drive commands asynchronous and thus eases the load on some
|
||||
wiring hardware types. Regardless of option -immed, cdrskin uses asynchronous
|
||||
commands where possible and appropriate.
|
||||
.TP
|
||||
.BI -inq
|
||||
Print the identification of the drive and then exit.
|
||||
.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.
|
||||
@ -423,6 +508,18 @@ 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 kiB. See option fs= .
|
||||
.TP
|
||||
.BI -load
|
||||
Load the media and exit. Exit value is 0 if any kind of media was found, non
|
||||
zero else. Note: Option -eject will unload the media even if -load is given.
|
||||
.TP
|
||||
.BI -lock
|
||||
Like option -load but leave the drive's eject button disabled if there is any
|
||||
media found and not option -eject is given.
|
||||
.br
|
||||
Use program "eject" or cdrskin -eject to get the tray out of the drive.
|
||||
Runs of programs like cdrecord, growisofs, wodim, cdrskin will not be hampered
|
||||
and normally enable the drive's eject button when they are done.
|
||||
.TP
|
||||
.BI minbuf= percentage
|
||||
Equivalent to:
|
||||
.br
|
||||
@ -446,6 +543,9 @@ 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
|
||||
the most recent session was not written with option -multi.
|
||||
.br
|
||||
To have a chance for working on overwriteable media, this option has to be
|
||||
accompanied by option --grow_overwriteable_iso.
|
||||
.TP
|
||||
.BI \-multi
|
||||
This option keeps the CD or unformatted DVD-R[W] appendable after the current
|
||||
@ -454,9 +554,8 @@ Without it the disc gets closed and may not be written any more - unless it
|
||||
is a -RW and gets blanked which causes loss of its content.
|
||||
.br
|
||||
The following sessions can only be written in -tao mode. -multi is prohibited
|
||||
with overwriteable DVD media and with DVD-R[W] DAO write mode.
|
||||
Option --prodvd_cli_compatible eventually makes -multi tolerable but cannot
|
||||
make it work.
|
||||
with DVD-R[W] DAO write mode. Option --prodvd_cli_compatible eventually makes
|
||||
-multi tolerable but cannot make it work.
|
||||
.br
|
||||
In order to have all filesystem content accessible, the eventual ISO-9660
|
||||
filesystem of a follow-up
|
||||
@ -466,6 +565,15 @@ which can be retrieved by cdrskin option -msinfo.
|
||||
.br
|
||||
To retrieve an archive file which was written as follow-up session,
|
||||
you may use option -toc to learn about the "lba" of the desired track number.
|
||||
This lba is the address of the 2048 byte block where the archive begins.
|
||||
.br
|
||||
With overwriteable DVD media, -multi cannot mark the end of the session.
|
||||
So when adding a new session this end has to be determined from the payload.
|
||||
Currently only ISO-9660 filesystems can be used that way. See option
|
||||
.B \--grow_overwriteable_iso
|
||||
for lifting the ban on -multi.
|
||||
.br
|
||||
Note: -multi might make DVD media unreadable in some DVD-ROM drives.
|
||||
.TP
|
||||
.BI \-nopad
|
||||
Do not add trailing zeros to the data stream. Nevertheless, since there seems
|
||||
@ -490,7 +598,7 @@ One should use it only if inavoidable.
|
||||
.TP
|
||||
.BI \-sao
|
||||
Write CD in Session At Once mode, a sequential DVD-R[W] in Disc-at-once
|
||||
(DAO) mode, or a DVD+R.
|
||||
(DAO) mode, or a DVD+R[/DL].
|
||||
.br
|
||||
With CD this mode is able to put several audio tracks on media without
|
||||
producing audible gaps between them.
|
||||
@ -498,8 +606,8 @@ 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.
|
||||
-sao is permissible with overwriteable DVD and with DVD+R[/DL] 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
|
||||
@ -527,7 +635,7 @@ It is not an error to set a speed higher than is suitable for drive
|
||||
and media. One should stay within a realistic speed range, though.
|
||||
Special speed settings are:
|
||||
.br
|
||||
0 = minimal speed , -1 = maximal speed (default).
|
||||
0 = minimal speed , -1 = maximal speed (default), text "any" = like -1.
|
||||
.TP
|
||||
.BI \-swab
|
||||
Announce that the raw audio data source of subsequent tracks is byte swapped
|
||||
@ -539,7 +647,7 @@ suffix ".wav".
|
||||
.TP
|
||||
.BI \-tao
|
||||
Write CD in Track At Once (TAO) mode, sequential DVD-R[W] in Incremental
|
||||
Streaming mode, or DVD+R without traditional -sao restrictions.
|
||||
Streaming mode, or DVD+R[/DL] 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
|
||||
@ -591,6 +699,23 @@ some extra lines to be put out with info retrieval options.
|
||||
Level 2 additionally reports about option settings derived from arguments or
|
||||
startup files. Level 3 is for debugging and useful mainly in conjunction with
|
||||
somebody who had a look into the program sourcecode.
|
||||
.TP
|
||||
.BI \-waiti
|
||||
Wait until input data is available at stdin or EOF occurs at stdin.
|
||||
Only then begin to access any drives.
|
||||
.br
|
||||
One should use this if cdrskin is working at the end of a pipe where the
|
||||
feeder process reads from the drive before it starts writing its output into
|
||||
cdrskin. Example:
|
||||
.br
|
||||
mkisofs ... -C 0,12800 -M /dev/sr0 | \\
|
||||
.br
|
||||
cdrskin dev=/dev/sr0 ... -waiti -
|
||||
.br
|
||||
This option works even if stdin is not among the track sources. If no process
|
||||
is piping in, then the Enter key of your terminal will act as trigger for
|
||||
cdrskin. Note that this input line will not be consumed by cdrskin if stdin
|
||||
is not among the track sources. It will end up as shell command, usually.
|
||||
.PP
|
||||
Alphabetical list of options which are genuine to cdrskin and intended for
|
||||
normal use:
|
||||
@ -601,6 +726,10 @@ drive for the loaded media. By default, such an adjustment is only made with
|
||||
pseudo-speeds 0 and -1 whereas speed settings > 0 are sent unchanged to the
|
||||
drive which will then choose an appropriate speed on its own.
|
||||
.TP
|
||||
.BI \--allow_emulated_drives
|
||||
Enable drive addresses of the form dev=stdio:<path>. See above, paragraph
|
||||
"Drive preparation and addressing".
|
||||
.TP
|
||||
.BI \--allow_setuid
|
||||
Disable the loud warning about insecure discrepance between login user and
|
||||
effective user which indicates application of chmod u+s to the program binary.
|
||||
@ -642,6 +771,59 @@ Number dev='Devicefile' rw-Permissions : 'Vendor' 'Model'
|
||||
Number and Devicefile can both be used with option dev=, but number is
|
||||
volatile (numbering changes if drives become busy).
|
||||
.TP
|
||||
.BI direct_write_amount= size
|
||||
Do not write a session with tracks but rather make an appropriate number of
|
||||
direct write operations with no preparations. Flushing the drive buffer will
|
||||
be the only finalization. It is advised to eject the media afterwards because
|
||||
the write operations circumvent the usual system i/o with its caches and
|
||||
buffers. By ejecting, those invalid memory copies get surely discarded.
|
||||
.br
|
||||
Only few media can be written this way: DVD-RAM, RVD+RW and overwriteable
|
||||
DVD-RW. Writing is restricted to the already formatted area of the media.
|
||||
.br
|
||||
Writing starts at byte 0 of the media or at the address given by option
|
||||
.B write_start_address= .
|
||||
Only the first track source is used as input for the write operations.
|
||||
The fifo (fs=) is disabled.
|
||||
.br
|
||||
Parameter
|
||||
.B size
|
||||
controls the amount of data to be written. Size 0 means that the track source
|
||||
shall be used up until EOF. In this case, the last write transaction gets
|
||||
padded up to the necessary size by zeros. Size -1 revokes direct writing
|
||||
and switches back to normal session oriented writing.
|
||||
.br
|
||||
Both, write_start_address and direct_write_amount size must be aligned to a
|
||||
media dependend transaction size. With DVD-RAM and DVD+RW this is 2k, with
|
||||
overwriteable DVD-RW it is 32k.
|
||||
.TP
|
||||
.BI fallback_program= command
|
||||
Set a command name to be executed if cdrskin encounters a known cdrecord
|
||||
option which it does not yet support. If a non-empty command is given with
|
||||
fallback_program=, and if no essential options are given which are specific
|
||||
to cdrskin, then cdrskin will delegate the job to said command.
|
||||
.br
|
||||
The natural commands to be given are cdrecord or wodim but one may well submit
|
||||
the address of an own program.
|
||||
.br
|
||||
The fallback programm will get all arguments of cdrskin which do not match
|
||||
the shell patterns --?* or *_*=* . This eventually suppresses path names of
|
||||
track sources which happen to match those patterns. The options from the
|
||||
startup files are not handed to the fallback program.
|
||||
.br
|
||||
Fallback program execution is disabled if cdrskin is run setuid and not
|
||||
option --allow_setuid is given. In general, the drive's device files and the
|
||||
involved programs should be set up so that each program runs under its advised
|
||||
conditions. (E.g. cdrskin as member of group floppy, cdrecord setuid root.)
|
||||
.br
|
||||
Two alias names for cdrskin are predefined with default fallback programs:
|
||||
.br
|
||||
.B unicord
|
||||
implies fallback_program=cdrecord
|
||||
.br
|
||||
.B codim
|
||||
implies fallback_program=wodim
|
||||
.TP
|
||||
.BI fifo_start_at= size
|
||||
Do not wait for full fifo but start burning as soon as the given number
|
||||
of bytes is read. This option may be helpful to bring the average throughput
|
||||
@ -652,6 +834,46 @@ the software protection against buffer underun is as weak as the size of
|
||||
fifo_start_at= . So it is best if the drive offers hardware protection which
|
||||
is enabled automatically if not driveropts=noburnfree is given.
|
||||
.TP
|
||||
.BI \--grow_overwriteable_iso
|
||||
Enable emulation of multi-session writing on overwriteable media which
|
||||
contain an ISO-9660 filesystem. This emulation is learned from growisofs -M
|
||||
but adapted to the usage model of
|
||||
.br
|
||||
.B cdrskin -msinfo
|
||||
.br
|
||||
.B mkisofs -C -M | cdrskin -waiti [-multi] -
|
||||
.br
|
||||
--grow_overwriteable_iso does not hamper the use of true multi-session media.
|
||||
I.e. it is possible to use the same cdrskin options with both kinds of media
|
||||
and to achieve similar results if ISO-9660 filesystem images are to be written.
|
||||
This option implies option -isosize and therefore demands that the track
|
||||
source is a ISO-9660 filesystem image.
|
||||
.br
|
||||
With overwriteable media and no option blank=fast|all present it expands an
|
||||
eventual ISO-9660 filesystem on media. It is assumed that this image's inner
|
||||
size description points to the end of the valuable data.
|
||||
Overwriteable media with a recognizeable ISO-9660 size will be regarded as
|
||||
appendable rather than as blank. I.e. options -msinfo and -toc will work.
|
||||
-toc will always show a single session with its size increasing with
|
||||
every added mkisofs image.
|
||||
.br
|
||||
If not overriden by option write_start_address=, the track with the new image
|
||||
will be placed behind the end of the old one. One may use option
|
||||
assert_write_lba= to make sure that media state and mkisofs job do match.
|
||||
.br
|
||||
--grow_overwriteable_iso causes option blank=fast|all to invalidate an
|
||||
eventual ISO-9660 image by altering the first few bytes of block 16 on
|
||||
overwriteable media.
|
||||
Option -multi is tolerated in order not to hamper true multi-session media.
|
||||
.br
|
||||
An equivalent of growisofs -Z for overwriteable media is:
|
||||
.br
|
||||
.B mkisofs | cdrskin --grow_overwriteable_iso blank=fast [-multi] -
|
||||
.br
|
||||
With multi-session DVD, blank=fast will act like dvd+rw-format -blank=full .
|
||||
.br
|
||||
growisofs -dvd-compat is roughly equivalent to cdrskin without option -multi.
|
||||
.TP
|
||||
.BI \--list_ignored_options
|
||||
List all ignored cdrecord options. The "-" options cannot be used as addresses
|
||||
of track sources. No track source address may begin with a text equal to an
|
||||
@ -729,7 +951,7 @@ tested. Currently this applies to :
|
||||
.br
|
||||
Profile 0015h , DVD-R/DL Sequential (will not allow -multi).
|
||||
.br
|
||||
Profile 002Bh , DVD+R/DL.
|
||||
Profile 0043h , BD-RE.
|
||||
.br
|
||||
If you really test such media, then please report the outcome on
|
||||
libburn-hackers@pykix.org
|
||||
@ -796,9 +1018,12 @@ 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".
|
||||
With multi-session media this option might increase readatibility on 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".
|
||||
.br
|
||||
You can expect the best possible read compatibility if you do not use -multi at
|
||||
all.
|
||||
.TP
|
||||
.BI grab_drive_and_wait= seconds
|
||||
Open the addressed drive, wait the given number of seconds, release the drive,
|
||||
@ -906,7 +1131,7 @@ cdrskin -v dev=0,1,0 fs=32m speed=8 \\
|
||||
.br
|
||||
-tao padsize=300k -
|
||||
.SS
|
||||
.B Write multi-session to the same CD, DVD-R[W] or DVD+R:
|
||||
.B Write multi-session to the same CD, DVD-R[W] or DVD+R[/DL]:
|
||||
.br
|
||||
cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 1.iso
|
||||
.br
|
||||
@ -937,6 +1162,9 @@ cdrskin -v dev=ATA:1,0,0 speed=48 -sao \\
|
||||
track1.wav track2.au -audio -swab track3.raw
|
||||
.br
|
||||
.SH FILES
|
||||
.SS
|
||||
Startup files:
|
||||
.br
|
||||
If not --no_rc is given as the first argument then cdrskin attempts on
|
||||
startup to read the arguments from the following files:
|
||||
.PP
|
||||
@ -954,23 +1182,32 @@ The files are read in the sequence given above, but none of them is
|
||||
required for cdrskin to function properly. Each readable line is treated
|
||||
as one single argument. No extra blanks.
|
||||
A first character '#' marks a comment, empty lines are ignored.
|
||||
.SS
|
||||
.B Example content of a startup file:
|
||||
.br
|
||||
Example content of a startup file:
|
||||
.br
|
||||
# This is the default device
|
||||
.br
|
||||
dev=0,1,0
|
||||
.br
|
||||
# To accomodate to remnant cdrskin-0.2.2 addresses
|
||||
.br
|
||||
dev_translation=+1,0,0+0,1,0
|
||||
.br
|
||||
# Some more options
|
||||
.br
|
||||
fifo_start_at=0
|
||||
.br
|
||||
fs=16m
|
||||
.br
|
||||
.SS
|
||||
Disabling superuser safety precautions:
|
||||
The superuser is normally banned from using any other emulated drive but
|
||||
/dev/null. This ban can be lifted by the existence of file
|
||||
.PP
|
||||
.B /root/cdrskin_permissions/allow_emulated_drives
|
||||
.PP
|
||||
where the directory must be owned by the superuser and must not offer
|
||||
w-permissions for group or others.
|
||||
.br
|
||||
Warning: Superusers must take care not to spoil their hard disk via its raw
|
||||
block device (like stdio:/dev/hda or stdio:/dev/sd0).
|
||||
|
||||
.SH SEE ALSO
|
||||
.TP
|
||||
Formatting data track sources for cdrskin:
|
||||
|
1494
cdrskin/cdrskin.c
1494
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, DVD, linux, recording, burning, CD-R, CD-RW, DVD-R, DVD-RW, DVD+RW, DVD+R, cdrecord, compatible, scdbackup">
|
||||
<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, DVD+R/DL, DVD-RAM, cdrecord, compatible, scdbackup">
|
||||
<META NAME="robots" CONTENT="follow">
|
||||
<TITLE>cdrskin homepage english</TITLE>
|
||||
</HEAD>
|
||||
@ -24,8 +24,8 @@
|
||||
|
||||
<P>
|
||||
<H2>Purpose:</H2>
|
||||
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
|
||||
Burns preformatted data to CD and DVD media:<BR>
|
||||
CD-R, DVD-R, DVD+R, DVD+R/DL, CD-RW, DVD-RW, DVD-RAM, DVD+RW
|
||||
</P>
|
||||
<P>
|
||||
|
||||
@ -34,7 +34,7 @@ CD-R, DVD-R, DVD+R, CD-RW, DVD-RW, DVD-RAM, DVD+RW
|
||||
<P>
|
||||
<H2>Hardware requirements:</H2>
|
||||
A CD/DVD recorder suitable for
|
||||
<A HREF="http://libburnia.pykix.org">libburnia.pykix.org</A> <BR>
|
||||
<A HREF="http://libburnia-project.org">http://libburnia-project.org</A> <BR>
|
||||
(SCSI , ATA , USB , or SATA writers compliant to standard MMC-3 for CD
|
||||
and to MMC-5 for DVD).
|
||||
<BR>
|
||||
@ -43,7 +43,7 @@ and to MMC-5 for DVD).
|
||||
<P>
|
||||
<H2>Software requirements :</H2>
|
||||
<DL>
|
||||
<DT>Linux kernel 2.4 or higher</DT>
|
||||
<DT>Linux with kernel 2.4 or higher (and libc, of course) :</DT>
|
||||
<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>
|
||||
@ -56,8 +56,9 @@ and to MMC-5 for DVD).
|
||||
GPL software included:<BR>
|
||||
</H2>
|
||||
<DL>
|
||||
<DT>libburn-0.3.8</DT>
|
||||
<DD>(by Derek Foreman, Ben Jansens, and team of libburnia.pykix.org)</DD>
|
||||
<DT>libburn-0.4.4</DT>
|
||||
<DD>(founded by Derek Foreman and Ben Jansens,
|
||||
furthered by team of libburnia-project.org)</DD>
|
||||
<DD>transfers data to CD and DVD</DD>
|
||||
</DL>
|
||||
</P>
|
||||
@ -124,7 +125,7 @@ as listed by option --devices.</DT>
|
||||
<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>
|
||||
<DT>Write several sessions to the same CD, DVD-R[W] or DVD+R[/DL]:</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>
|
||||
@ -165,8 +166,16 @@ man cdrecord</A></KBD></DD>
|
||||
this "don't bother Joerg" demand.)
|
||||
</DD>
|
||||
</DL>
|
||||
<DL>
|
||||
<DT>Learn to know a more versatile way to burn ISO 9660 formatted data</DT>
|
||||
<DD>
|
||||
Standalone ISO 9660 multi-session CD/DVD tool
|
||||
<A HREF="http://scdbackup.sourceforge.net/xorriso_eng.html">xorriso</A>.
|
||||
</DD>
|
||||
</DL>
|
||||
|
||||
Testers wanted who are willing to risk some double layer DVD media.
|
||||
Testers wanted who are willing to risk some double layer DVD-R media
|
||||
or to do experiments on BD-RE.
|
||||
|
||||
</P>
|
||||
|
||||
@ -175,29 +184,34 @@ Testers wanted who are willing to risk some double layer DVD media.
|
||||
<P>
|
||||
<DL>
|
||||
<DT>Download as source code (see README):</DT>
|
||||
<DD><A HREF="cdrskin-0.3.8.pl00.tar.gz">cdrskin-0.3.8.pl00.tar.gz</A>
|
||||
(615 KB).
|
||||
<DD><A HREF="cdrskin-0.4.4.pl00.tar.gz">cdrskin-0.4.4.pl00.tar.gz</A>
|
||||
(715 KB).
|
||||
</DD>
|
||||
<DD>
|
||||
The "stable" cdrskin tarballs are source code identical with "stable"
|
||||
libburn releases or with "stabilized" libburn SVN snapshots. They get
|
||||
produced via a different procedure, though.<BR>
|
||||
The cdrskin tarballs are source code identical with libburn releases
|
||||
of the same version number.
|
||||
They get produced via a different procedure, though.<BR>
|
||||
cdrskin is part of libburn - full libburn is provided with cdrskin releases.
|
||||
</DD>
|
||||
|
||||
<!-- This is not offered any more for 0.4.4 and 0.4.5
|
||||
<DD> </DD>
|
||||
<DT>Download as single x86 binaries (untar and move to /usr/bin/cdrskin):</DT>
|
||||
<DD><A HREF="cdrskin_0.3.8.pl00-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.3.8.pl00-x86-suse9_0.tar.gz</A>, (90 KB),
|
||||
<DD><A HREF="cdrskin_0.4.2.pl00-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.4.2.pl00-x86-suse9_0.tar.gz</A>, (110 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.8.pl00-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.3.8.pl00-x86-suse9_0-static.tar.gz</A>, (290 KB), -static compiled,
|
||||
<DD><A HREF="cdrskin_0.4.2.pl00-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.4.2.pl00-x86-suse9_0-static.tar.gz</A>, (310 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> an introduction</DD>
|
||||
@ -220,18 +234,14 @@ cdrskin_0.3.8.pl00-x86-suse9_0-static.tar.gz</A>, (290 KB), -static compiled,
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
Enhancements towards previous stable version cdrskin-0.3.4:
|
||||
Enhancements towards previous stable version cdrskin-0.4.2:
|
||||
<UL>
|
||||
<LI>Now able to cope with the peculiarities of Linux 2.4 USB</LI>
|
||||
<LI>Refusal to perform -dummy runs on media which cannot simulate burning</LI>
|
||||
<LI>Precautions against using the burner drive as track source</LI>
|
||||
<LI>New option modesty_on_drive= may help with hda -> hdb burns</LI>
|
||||
<LI>New option minbuf= , cdrecord compatible frontend of modesty_on_drive=</LI>
|
||||
<LI>New option --adjust_speed_to_drive</LI>
|
||||
<LI>Support for DVD+R/DL media is now official</LI>
|
||||
<LI>Experimental code for BD-RE with --allow_untested_media</LI>
|
||||
</UL>
|
||||
|
||||
<!--
|
||||
Bug fixes towards cdrskin-0.3.8.pl00:
|
||||
Bug fixes towards cdrskin-0.4.2.pl00:
|
||||
<UL>
|
||||
<LI>none yet</LI>
|
||||
</UL>
|
||||
@ -243,23 +253,25 @@ Enhancements towards previous stable version cdrskin-0.3.4:
|
||||
|
||||
<P>
|
||||
<DL>
|
||||
<DT><H3>Development snapshot, version 0.3.9 :</H3></DT>
|
||||
<DD>Enhancements towards stable version 0.3.8.pl00:
|
||||
<DT><H3>Development snapshot, version 0.4.5 :</H3></DT>
|
||||
<DD>Enhancements towards stable version 0.4.4.pl00:
|
||||
<UL>
|
||||
<!--
|
||||
-->
|
||||
<LI>none yet</LI>
|
||||
</UL>
|
||||
</DD>
|
||||
<DD> </DD>
|
||||
<DD><A HREF="README_cdrskin_devel">README 0.3.9</A>
|
||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.3.9 --help</A></DD>
|
||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.3.9 -help</A></DD>
|
||||
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.3.9)</A></DD>
|
||||
<DD><A HREF="README_cdrskin_devel">README 0.4.5</A>
|
||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.4.5 --help</A></DD>
|
||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.4.5 -help</A></DD>
|
||||
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.4.5)</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>
|
||||
<DD>Download: <KBD><B>svn co http://libburnia-svn.pykix.org/libburn/trunk libburn_pykix</B>
|
||||
<A HREF="http://libburnia-project.org"> libburnia-project.org</A></DT>
|
||||
<DD>Download: <KBD><B>svn co http://svn.libburnia-project.org/libburn/trunk libburn</B>
|
||||
</KBD></DD>
|
||||
<DD>Build: <KBD><B>cd libburn_pykix ; ./bootstrap ; ./configure ; make</B>
|
||||
<DD>Build: <KBD><B>cd libburn ; ./bootstrap ; ./configure --prefix /usr ; make ; cdrskin/compile_cdrskin.sh</B>
|
||||
</KBD></DD>
|
||||
<DD>Build of SVN versions needs <A HREF="http://sources.redhat.com/autobook/">
|
||||
autotools</A> of at least version 1.7 installed.
|
||||
@ -267,22 +279,29 @@ But after the run of <KBD>./bootstrap</KBD>, only
|
||||
vanilla tools like make and gcc are needed.</DD>
|
||||
</DD>
|
||||
<DD> </DD>
|
||||
<DT>The following downloads are intended for adventurous end users or
|
||||
<DT>The following download is intended for adventurous end users or
|
||||
admins with full system souvereignty.</DT>
|
||||
<DD>Source (./bootstrap is already applied, build tested, for more see
|
||||
<A HREF="README_cdrskin_devel">upcoming README</A> ):
|
||||
</DD>
|
||||
<DD>
|
||||
<A HREF="cdrskin-0.3.9.tar.gz">cdrskin-0.3.9.tar.gz</A>
|
||||
(615 KB).
|
||||
<A HREF="cdrskin-0.4.5.tar.gz">cdrskin-0.4.5.tar.gz</A>
|
||||
(715 KB).
|
||||
</DD>
|
||||
|
||||
<!-- This is not offered any more for 0.4.4 and 0.4.5
|
||||
|
||||
<DT>The following downloads are intended for adventurous end users or
|
||||
admins with full system souvereignty.</DT>
|
||||
<DD>Binary (untar and move to /usr/bin/cdrskin):</DD>
|
||||
<DD><A HREF="cdrskin_0.3.9-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.3.9-x86-suse9_0.tar.gz</A>, (90 KB).
|
||||
<DD><A HREF="cdrskin_0.4.3-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.4.3-x86-suse9_0.tar.gz</A>, (110 KB).
|
||||
</DD>
|
||||
<DD><A HREF="cdrskin_0.3.9-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.3.9-x86-suse9_0-static.tar.gz</A>, (290 KB)
|
||||
<DD><A HREF="cdrskin_0.4.3-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.4.3-x86-suse9_0-static.tar.gz</A>, (310 KB)
|
||||
</DD>
|
||||
-->
|
||||
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
@ -330,6 +349,8 @@ Example how to setup K3b to use cdrskin for burning data CD projects.
|
||||
is a GUI frontend which uses cdrecord for CD burning.)
|
||||
</P>
|
||||
|
||||
<!--
|
||||
|
||||
<HR>
|
||||
|
||||
<A NAME="scdbackup">
|
||||
@ -384,6 +405,8 @@ and try again.
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
-->
|
||||
|
||||
<HR>
|
||||
|
||||
<A NAME="cdrecord">
|
||||
@ -443,14 +466,25 @@ and by <A HREF="http://sourceforge.net">sourceforge.net</A><BR>
|
||||
<HR>
|
||||
<DL>
|
||||
<DT>Links to my other published software projects :
|
||||
<DD><A HREF="http://scdbackup.webframe.org/xorriso_eng.html">
|
||||
xorriso, a standalone ISO 9660 multi-session CD/DVD burn tool.
|
||||
No mkisofs needed.
|
||||
<DL>
|
||||
<DD>
|
||||
<A HREF="http://scdbackup.sourceforge.net/xorriso_eng.html">
|
||||
(a second source of above)</A>
|
||||
</DD>
|
||||
</DL>
|
||||
</DD>
|
||||
<DD><A HREF=http://scdbackup.webframe.org/main_eng.html>
|
||||
scdbackup, multi volume CD backup</A>
|
||||
<DL><DD><A HREF=http://scdbackup.sourceforge.net/main_eng.html>
|
||||
(a second source of above)</A></DL>
|
||||
<DD><A HREF=http://stic.webframe.org>Some Tools for Image Collectors</A>
|
||||
<DL><DD><A HREF=http://stic.sourceforge.net>(a second source of above)</A></DL>
|
||||
(a second source of above)</A></DD></DL></DD>
|
||||
<DD><A HREF=http://stic.sourceforge.net>Some Tools for Image Collectors</A>
|
||||
</DD>
|
||||
<DD><A HREF=http://scdbackup.webframe.org/pppoem>
|
||||
pppoem, a DSL throughput monitor (mainly for Linux kernel 2.4)</A>
|
||||
</DD>
|
||||
</DL>
|
||||
<BR><BR>
|
||||
Legal statement: This website does not serve any commercial purpose.<BR>
|
||||
|
@ -1 +1 @@
|
||||
#define Cdrskin_timestamP "2007.07.20.120001"
|
||||
#define Cdrskin_timestamP "2008.04.08.100001"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# compile_cdrskin.sh
|
||||
# Copyright 2005 - 2006 Thomas Schmitt, scdbackup@gmx.net, GPL
|
||||
# Copyright 2005 - 2008 Thomas Schmitt, scdbackup@gmx.net, GPL version 2
|
||||
# to be executed within ./libburn-* resp ./cdrskin-*
|
||||
|
||||
debug_opts=
|
||||
debug_opts="-O2"
|
||||
def_opts=
|
||||
largefile_opts="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1"
|
||||
libvers="-DCdrskin_libburn_0_3_8"
|
||||
libvers="-DCdrskin_libburn_0_4_4"
|
||||
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_8"
|
||||
elif test "$i" = "-libburn_0_4_4"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_0_3_8"
|
||||
libvers="-DCdrskin_libburn_0_4_4"
|
||||
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_9"
|
||||
libvers="-DCdrskin_libburn_0_4_5"
|
||||
libdax_audioxtr_o="libburn/libdax_audioxtr.o"
|
||||
libdax_msgs_o="libburn/libdax_msgs.o"
|
||||
cleanup_src_or_obj="libburn/cleanup.o"
|
||||
@ -68,10 +68,7 @@ do
|
||||
do_strip=1
|
||||
elif test "$i" = "-g"
|
||||
then
|
||||
debug_opts="$debug_opts -g"
|
||||
elif test "$i" = "-O2"
|
||||
then
|
||||
debug_opts="$debug_opts -O2"
|
||||
debug_opts="-g"
|
||||
elif test "$i" = "-help" -o "$i" = "--help" -o "$i" = "-h"
|
||||
then
|
||||
echo "cdrskin/compile_cdrskin.sh : to be executed within top level directory"
|
||||
@ -79,7 +76,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_8 set macro to match libburn-0.3.8."
|
||||
echo " -libburn_0_4_4 set macro to match libburn-0.4.4."
|
||||
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."
|
||||
@ -87,8 +84,7 @@ do
|
||||
echo " -oldfashioned use pre-0.2.2 libburn features only."
|
||||
echo " -do_diet produce capability reduced lean version."
|
||||
echo " -do_strip apply program strip to compiled programs."
|
||||
echo " -g compile with cc option -g."
|
||||
echo " -O2 compile with cc option -O2."
|
||||
echo " -g produce debuggable programm."
|
||||
echo " -static compile with cc option -static."
|
||||
exit 0
|
||||
elif test "$i" = "-static"
|
||||
@ -133,6 +129,7 @@ then
|
||||
\
|
||||
libburn/sg.o \
|
||||
libburn/write.o \
|
||||
libburn/read.o \
|
||||
$libdax_audioxtr_o \
|
||||
$libdax_msgs_o \
|
||||
\
|
||||
|
@ -16,7 +16,7 @@ manpage="cdrskin"
|
||||
raw_html=$(pwd)/"cdrskin/raw_man_1_cdrskin.html"
|
||||
htmlpage=$(pwd)/"cdrskin/man_1_cdrskin.html"
|
||||
|
||||
if test -r "$manpage"
|
||||
if test -r "$man_dir"/"$manpage".1
|
||||
then
|
||||
dummy=dummy
|
||||
else
|
||||
@ -45,17 +45,19 @@ then
|
||||
-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/^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/^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/^If you only got one CD capable drive/\ <BR>If you only got one CD capable drive/' \
|
||||
-e 's/<b>Emulated drives:<\/b>/\ <BR><b>Emulated drives:<\/b>/' \
|
||||
-e 's/^Alphabetical list of options/\ <BR>Alphabetical list of options/' \
|
||||
-e 's/and for all others\.<\/td><\/table>/and for all others.<\/td><\/table> <BR><HR><FONT SIZE=-1><CENTER>(HTML generated from '"$manpage"'.1 on '"$(date)"' by '$(basename "$0")' )<\/CENTER><\/FONT>/' \
|
||||
-e 's/<\/body>/<BR><HR><FONT SIZE=-1><CENTER>(HTML generated from '"$manpage"'.1 on '"$(date)"' by '$(basename "$0")' )<\/CENTER><\/FONT><\/body>/' \
|
||||
-e 's/See section FILES/See section <A HREF="#FILES">FILES<\/A>/' \
|
||||
-e 's/See section EXAMPLES/See section <A HREF="#EXAMPLES">EXAMPLES<\/A>/' \
|
||||
<"$2" >"$htmlpage"
|
||||
|
||||
|
@ -10,21 +10,20 @@ 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.
|
||||
Sequential DVD-R[W] and DVD+R are handled like CD-R[W] with TAO and
|
||||
Sequential DVD-R[W], DVD+R, DVD+R/DL 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
|
||||
runs, though. The most comprehensive technical overview of cdrskin
|
||||
can be found in [http://libburnia.pykix.org/browser/libburn/trunk/cdrskin/README?format=txt cdrskin/README].
|
||||
can be found in [http://libburnia-project.org/browser/libburn/trunk/cdrskin/README?format=txt cdrskin/README].
|
||||
|
||||
About libburn API for burning CD: http://libburnia-api.pykix.org
|
||||
About libburn API for burning CD and DVD: http://api.libburnia-project.org
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
For yet unsupported media types see the advice to use dvd+rw-tools at
|
||||
the end of this text.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
@ -80,12 +79,45 @@ controls drive accessability by rw-permissions of the drive rather than
|
||||
by x-permission of the burn binary. To be usable with cdrskin, the drive
|
||||
has to offer both, r- and w-permission.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
cdrskin does not only read from and write to optical drives which comply
|
||||
to the MMC standard but also does the same with regular files or block
|
||||
devices other than optical drives.
|
||||
|
||||
Because the power to alter a disk file might be a bad surprise for a
|
||||
traditional user of cdrecord, it is necessary to give option
|
||||
--allow_emulated_drives before an emulated drive may be addressed.
|
||||
Eventually one of the startup files would be a good place for it.
|
||||
See man page, section FILES.
|
||||
|
||||
The addresses of emulated drives begin with the prefix "stdio:".
|
||||
{{{
|
||||
dev=stdio:/tmp/pseudo_drive
|
||||
dev=stdio:/dev/usbstick
|
||||
}}}
|
||||
|
||||
Regular files and block devices behave much like DVD-RAM.
|
||||
|
||||
Other file types may be valid targets for write-only operations.
|
||||
This includes standard output, named pipes, character devices
|
||||
{{{
|
||||
dev=stdio:/dev/fd/1
|
||||
dev=stdio:/tmp/named_pipe
|
||||
dev=stdio:/dev/ptyxy
|
||||
}}}
|
||||
|
||||
These files behave much like blank DVD-R.
|
||||
|
||||
All files used as pseudo-drives have to offer rw-permission.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
The DVD capabilities of cdrskin differ from those of cdrecord-ProDVD. cdrskin
|
||||
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.
|
||||
offers TAO-like multi-session with DVD-R[W], DVD+R[/DL] 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
|
||||
@ -107,7 +139,8 @@ multi-session, if the drive is capable of "Incremental Streaming"
|
||||
(MMC feature 21h).
|
||||
|
||||
Used sequential DVD-RW media may be blanked by blank=fast or blank=all which
|
||||
normally both do full blanking.
|
||||
normally both do full blanking. Thus sequential DVD-RW behave much like large
|
||||
CD-RW with possibly more than 99 tracks.
|
||||
|
||||
blank=deformat_sequential does minimal blanking of DVD-RW which usually yields
|
||||
media incapable of "Incremental Streaming".
|
||||
@ -117,6 +150,13 @@ overwriteable DVD-RW which normally ignore those two options. It also makes
|
||||
option -multi tolerable with media and write modes which are not suitable for
|
||||
multi-session. (The default behavior of cdrskin deems me to be preferrable.)
|
||||
|
||||
Option --grow_overwriteable_iso gives cdrskin ISO pseudo-multi-session
|
||||
capabilities on DVD-RAM and DVD+RW similar to growisofs.
|
||||
Associated options blank=, -multi, -msinfo and -toc are available in this case.
|
||||
They either pretend a blank media (if there is no ISO 9660 image) or appendable
|
||||
media with a single session and track on it. blank= invalidates ISO images.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
assert_write_lba=<lba> allows to ensure that the start block address which
|
||||
@ -228,10 +268,10 @@ for an illustrated example with K3b 0.10 .
|
||||
|
||||
DVD advise:
|
||||
|
||||
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.
|
||||
For burning of DVD media other than DVD-RAM, DVD+RW, DVD+R, DVD+R/DL,
|
||||
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 more, including BD discs.
|
||||
|
||||
http://fy.chalmers.se/~appro/linux/DVD+RW/tools
|
||||
|
||||
@ -239,19 +279,27 @@ They are not compatible or related to cdrecord resp. cdrecord-ProDVD
|
||||
(now obsoleted by original source cdrtools cdrecord with identical
|
||||
capabilities besides the license key).
|
||||
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Advanced multi-session use cases:
|
||||
|
||||
A special feature of dvd+rw-tools is growing of ISO-9660 filesystems on
|
||||
overwriteable media. This is not the same as multi-session writing of cdrskin
|
||||
with CD media, but retrieves additional information from the existing ISO
|
||||
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.
|
||||
|
||||
So, inspired by growisofs, cdrskin can offer DVD multi-session not only with
|
||||
sequential DVD-R[W] and with DVD+R [DL], but also with DVD-RAM, DVD+RW and
|
||||
even regular disk files or block devices other than CD/DVD writers.
|
||||
This is enabled by option --grow_overwriteable_iso.
|
||||
|
||||
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.
|
||||
The libburnia project provides an integrated ISO-9660 multi-session tool
|
||||
named [wiki:Xorriso xorriso] which tries to go one step beyond
|
||||
growisofs. It uses [wiki:Libburn libburn] , [wiki:Libisofs libisofs]
|
||||
and [wiki:Libisoburn libisoburn].
|
||||
|
||||
See [http://scdbackup.sourceforge.net/man_1_xorriso.html man xorriso].
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
|
113
configure.ac
113
configure.ac
@ -1,4 +1,4 @@
|
||||
AC_INIT([libburn], [0.3.8], [http://libburnia.pykix.org])
|
||||
AC_INIT([libburn], [0.4.4], [http://libburnia-project.org])
|
||||
AC_PREREQ([2.50])
|
||||
dnl AC_CONFIG_HEADER([config.h])
|
||||
|
||||
@ -7,35 +7,104 @@ AC_CANONICAL_TARGET
|
||||
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
|
||||
dnl Making releases:
|
||||
dnl BURN_MICRO_VERSION += 1;
|
||||
dnl BURN_INTERFACE_AGE += 1;
|
||||
dnl BURN_BINARY_AGE += 1;
|
||||
dnl if any functions have been added, set BURN_INTERFACE_AGE to 0.
|
||||
dnl if backwards compatibility has been broken,
|
||||
dnl set BURN_BINARY_AGE and BURN_INTERFACE_AGE to 0.
|
||||
dnl Notes by ts A71207 - A80126 :
|
||||
dnl
|
||||
dnl if MAJOR or MINOR version changes, be sure to change AC_INIT above to match
|
||||
dnl Regrettably the meaning of the various version types was misunderstood
|
||||
dnl before version 0.4.1.
|
||||
dnl
|
||||
dnl In the past MAJOR.MINOR.MICRO versions led to the following SONAME numbers:
|
||||
dnl 0.2.2 = 2 , 0.2.3 = 3 , 0.2.6 = 6
|
||||
dnl 0.3.0 = 0 , 0.3.2 = 2 , 0.3.4 = 4 . 0.3.6 = 6 , 0.3.8 = 4
|
||||
dnl 0.4.0 = 0 (also released as SONAME 4)
|
||||
dnl
|
||||
dnl Meanwhile the following schemes are maintained in parallel:
|
||||
dnl
|
||||
dnl BURN_MAJOR_VERSION , BURN_MINOR_VERSION , BURN_MICRO_VERSION
|
||||
dnl are three small non-negative integers which describe the evolution
|
||||
dnl steps of the library.
|
||||
dnl Older applications are able to use younger libraries over
|
||||
dnl quite a long range of such steps. Some day, nevertheless,
|
||||
dnl compatibility might get terminated, after due notice.
|
||||
dnl
|
||||
dnl SONAME (libburn.so.4)
|
||||
dnl is a small positive integer which marks a family of compatible
|
||||
dnl evolution steps. Libraries with a particular SONAME allow a binary
|
||||
dnl with the same SONAME to start up. Any further compatibility check is to
|
||||
dnl be done by own runtime means. Especially *_version() calls in the API
|
||||
dnl which return BURN_MAJOR_VERSION, BURN_MINOR_VERSION, BURN_MICRO_VERSION.
|
||||
dnl See below.
|
||||
dnl
|
||||
dnl CURRENT, AGE, REVISION
|
||||
dnl are three integers used by libtool. CURRENT is positive, the others
|
||||
dnl non-negative. The use at runtime is not known yet. But libtool computes
|
||||
dnl at build time SONAME = CURRENT - AGE.
|
||||
dnl So this is a superspace of the SONAME version space. To avoid
|
||||
dnl ill SONAME, the value of CURRENT must be larger than AGE.
|
||||
dnl See also http://www.gnu.org/software/libtool/manual.html#Interfaces
|
||||
dnl
|
||||
dnl The name of the dynamic library will be libburn.so.$SONAME.$AGE.$REV .
|
||||
dnl In the terminology of this file:
|
||||
dnl CURRENT = LT_CURRENT
|
||||
dnl AGE = LT_AGE
|
||||
dnl REVISION= LT_REVISION
|
||||
dnl
|
||||
dnl Beginning with libburn-0.4.1 a rectified counting was introduced as
|
||||
dnl CURRENT=10, REVISION=1, AGE=6
|
||||
dnl This rectification declared that version to be binary compatible up
|
||||
dnl from libburn-0.3.4.
|
||||
dnl Real compatibility was given since libburn-0.3.2.
|
||||
dnl Beware of libburn-0.2.6 which had SONAME=6 and is not binary compatible.
|
||||
dnl Applications for libburn-0.2 to libburn-0.3.1 need recompilation but no
|
||||
dnl source code changes.
|
||||
dnl
|
||||
dnl Neatly versioned stable releases meanwhile:
|
||||
dnl 0.4.2 = libburn.so.4.7.0
|
||||
dnl 0.4.4 = libburn.so.4.9.0
|
||||
dnl
|
||||
dnl So LT_CURRENT, LT_REVISION and LT_AGE get set directly here.
|
||||
dnl SONAME of the emerging library is LT_CURRENT - LT_AGE.
|
||||
dnl The linker will do no finer checks. Especially no age range check for
|
||||
dnl the application binary. If SONAME matches, then the couple starts.
|
||||
dnl
|
||||
dnl Therefore at run time info is provided by libburn function burn_version().
|
||||
dnl It returns the major, minor and micro revision of the library.
|
||||
dnl Before using any API feature, a program should check for age.
|
||||
dnl
|
||||
dnl The variables BURN_*_VERSION are mere copies for informing libtool.
|
||||
dnl The true values which get issued and should be compared are macros
|
||||
dnl defined in libburn/libburn.h .
|
||||
dnl
|
||||
dnl Normally one can allow a program to run with a library which passed the
|
||||
dnl linker SONAME test and which is not older than the library it was
|
||||
dnl developed for. Library2 is younger than library1 if:
|
||||
dnl major2>major1 || (major2==major1 &&
|
||||
dnl (minor2>minor1 || (minor2==minor1 && micro2 > micro1)))
|
||||
dnl
|
||||
dnl If BURN_*_VERSION changes, be sure to change AC_INIT above to match.
|
||||
dnl
|
||||
dnl As said: Only copies. Original in libburn/libburn.h : burn_header_version_*
|
||||
BURN_MAJOR_VERSION=0
|
||||
BURN_MINOR_VERSION=3
|
||||
BURN_MICRO_VERSION=8
|
||||
BURN_INTERFACE_AGE=0
|
||||
BURN_BINARY_AGE=0
|
||||
BURN_MINOR_VERSION=4
|
||||
BURN_MICRO_VERSION=4
|
||||
BURN_VERSION=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
|
||||
|
||||
AC_SUBST(BURN_MAJOR_VERSION)
|
||||
AC_SUBST(BURN_MINOR_VERSION)
|
||||
AC_SUBST(BURN_MICRO_VERSION)
|
||||
AC_SUBST(BURN_INTERFACE_AGE)
|
||||
AC_SUBST(BURN_BINARY_AGE)
|
||||
AC_SUBST(BURN_VERSION)
|
||||
|
||||
dnl Libtool versioning
|
||||
LT_RELEASE=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION
|
||||
LT_CURRENT=4
|
||||
LT_REVISION=$BURN_INTERFACE_AGE
|
||||
LT_AGE=`expr $BURN_BINARY_AGE - $BURN_INTERFACE_AGE`
|
||||
LT_RELEASE=$BURN_MAJOR_VERSION.$BURN_MINOR_VERSION.$BURN_MICRO_VERSION
|
||||
dnl
|
||||
dnl ts A80127
|
||||
dnl This is the release version libburn-0.4.4 = libburn.so.4.9.0
|
||||
dnl ### This is the development version after libburn-0.4.4 = libburn.so.4.9.0
|
||||
dnl ### LT_CURRENT++, LT_AGE++ has not yet happened.
|
||||
dnl
|
||||
dnl SONAME = 13 - 9 = 4 . Library name = libburn.so.4.9.0
|
||||
LT_CURRENT=13
|
||||
LT_REVISION=0
|
||||
LT_AGE=9
|
||||
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
|
||||
|
||||
AC_SUBST(LT_RELEASE)
|
||||
@ -44,6 +113,12 @@ AC_SUBST(LT_REVISION)
|
||||
AC_SUBST(LT_AGE)
|
||||
AC_SUBST(LT_CURRENT_MINUS_AGE)
|
||||
|
||||
dnl ts A71207: This is done only not to break any old components
|
||||
BURN_INTERFACE_AGE=$LT_REVISION
|
||||
BURN_BINARY_AGE=`expr $LT_AGE + $BURN_INTERFACE_AGE`
|
||||
AC_SUBST(BURN_INTERFACE_AGE)
|
||||
AC_SUBST(BURN_BINARY_AGE)
|
||||
|
||||
AC_PREFIX_DEFAULT([/usr/local])
|
||||
test "$prefix" = "NONE" && prefix=$ac_default_prefix
|
||||
|
||||
|
45
doc/comments
45
doc/comments
@ -7,10 +7,10 @@
|
||||
|
||||
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+R, DVD-RW, DVD-R.
|
||||
For now this means CD-R, CD-RW, DVD-RAM, DVD+RW, DVD+R, DVD+R/DL, DVD-RW, DVD-R.
|
||||
|
||||
Not supported yet are dual layer media, HD-DVD, BD (blue ray). Testers for
|
||||
dual layer DVD+/-R are wanted, though.
|
||||
Not supported yet are DVD-R/DL, HD-DVD, BD (blue ray). Testers for
|
||||
BD and DVD-R/DL are wanted, though.
|
||||
|
||||
The project comprises of several more or less interdependent parts which
|
||||
together strive to be a usable foundation for application development.
|
||||
@ -22,13 +22,18 @@ 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 data and audio CDs and many DVD types.
|
||||
The burn API is quite comprehensively documented and can be used to build a
|
||||
presentable application.
|
||||
We have a well tested code base for burning data and audio CDs and many DVD
|
||||
types. The burn API is quite comprehensively documented and can be used to
|
||||
build a presentable application.
|
||||
We have a functional binary which emulates the core use cases of cdrecord in
|
||||
order to prove that usability, and in order to allow you to explore libburn's
|
||||
scope by help of existing cdrecord frontends.
|
||||
|
||||
ISO 9660 filesystems with Rock Ridge and Joliet extensions can be created
|
||||
and manipulated quite freely. This capability together with our burn capability
|
||||
makes possible a single binary application which covers all steps of image
|
||||
composition, updating and writing. Quite unique in the Linux world.
|
||||
|
||||
@subsection components The project components (list subject to growth, hopefully):
|
||||
|
||||
- libburn is the library by which preformatted data get onto optical media.
|
||||
@ -43,6 +48,11 @@ scope by help of existing cdrecord frontends.
|
||||
ISO 9660 disk image. This may then be brought to CD via libburn.
|
||||
libisofs is to be the foundation of our upcoming mkisofs emulation.
|
||||
|
||||
- libisoburn is an add-on to libburn and libisofs which coordinates both and
|
||||
also allows to grow ISO-9660 filesystem images on multi-session
|
||||
media as well as on overwriteable media via the same API.
|
||||
All media peculiarities are handled automatically.
|
||||
|
||||
- cdrskin is a limited cdrecord compatibility wrapper for libburn.
|
||||
cdrecord is a powerful GPL'ed burn program included in Joerg
|
||||
Schilling's cdrtools. cdrskin strives to be a second source for
|
||||
@ -54,13 +64,32 @@ scope by help of existing cdrecord frontends.
|
||||
runs, though.
|
||||
See cdrskin/README for more.
|
||||
|
||||
- xorriso is an application of all three libraries which creates, loads,
|
||||
manipulates and writes ISO 9660 filesystem images with
|
||||
Rock Ridge extensions. Manipulation is not only adding or
|
||||
overwriting of files but also deletion, renaming, and attribute
|
||||
changing.
|
||||
See xorriso/README for more
|
||||
|
||||
- "test" is a collection of application gestures and examples given by the
|
||||
authors of the library features. The burn API example of libburn
|
||||
is named test/libburner.c . The API for media information inquiry is
|
||||
demonstrated in test/telltoc.c .
|
||||
Explore these examples if you look for inspiration.
|
||||
|
||||
We plan to be a responsive upstream. Bear with us.
|
||||
We strive to be a responsive upstream.
|
||||
|
||||
Our libraries are committed to maintain older feature sets in newer versions.
|
||||
This applies to source code headers (API) as well as to linkable objects (ABI).
|
||||
The only exception from this rule is about non-release versions x.y.*[13579]
|
||||
which are allowed to introduce new features, change those new features in
|
||||
any way and even may revoke such new features before the next release of
|
||||
x.y.*[02468]. As soon as it is released, a feature is promised to persist.
|
||||
|
||||
SONAMES:
|
||||
libburn.so.4 (since 0.3.4, March 2007),
|
||||
libisofs.so.6 (since 0.6.2, February 2008),
|
||||
libisoburn.so.1 (since 0.1.0, February 2008).
|
||||
|
||||
|
||||
@section using Using the libraries
|
||||
@ -89,7 +118,7 @@ languages and development tools.
|
||||
@section libburner Libburner
|
||||
|
||||
libburner is a minimal demo application for the library libburn
|
||||
(see: libburn/libburn.h) as provided on http://libburn.pykix.org .
|
||||
(see: libburn/libburn.h) as provided on http://libburnia-project.org .
|
||||
It can list the available devices, can blank a CD-RW or DVD-RW and
|
||||
can burn to recordable CD and recordable single layer DVD.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
libburnia.pykix.org Optical Media Rotisserie Recipes as of February 2007
|
||||
libburnia-project.org Optical Media Rotisserie Recipes as of August 2007
|
||||
|
||||
Content:
|
||||
- TAO Multi-Session CD Cookbook (CD-R, CD-RW)
|
||||
@ -18,7 +18,7 @@ by reading libburn/* from http://icculus.org/burn
|
||||
and by experiments with drives NEC ND-4570A, LG GSA-4082B, LITE-ON LTR48125S
|
||||
which used in part code from http://icculus.org/burn.
|
||||
|
||||
For libburnia.pykix.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -215,7 +215,7 @@ backed by reading mmc5r03c.pdf from http://www.t10.org/ftp/t10/drafts/mmc5/
|
||||
and by experiments with drives NEC ND-4570A, LG GSA-4082B, LITE-ON LTR48125S
|
||||
which used in part code from http://icculus.org/burn.
|
||||
|
||||
For libburnia.pykix.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -405,7 +405,7 @@ Inspired by Andy Polyakov's http://fy.chalmers.se/~appro/linux/DVD+RW/tools ,
|
||||
backed by reading mmc5r03c.pdf from http://www.t10.org/ftp/t10/drafts/mmc5/
|
||||
and by experiments with drives NEC ND-4570A and LG GSA-4082B.
|
||||
|
||||
For libburnia.pykix.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -680,7 +680,7 @@ Inspired by Andy Polyakov's http://fy.chalmers.se/~appro/linux/DVD+RW/tools ,
|
||||
backed by reading mmc5r03c.pdf from http://www.t10.org/ftp/t10/drafts/mmc5/
|
||||
and by experiments with drives NEC ND-4570A and LG GSA-4082B.
|
||||
|
||||
For libburnia.pykix.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -990,15 +990,12 @@ 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>
|
||||
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -1088,8 +1085,19 @@ 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.
|
||||
Note: growisofs has code for that gesture but explicitly avoids to use it, if
|
||||
the media was appendable before writing began. Instead it recommends to fill
|
||||
up the media with zeros. This gesture nevertheless caused error replies from
|
||||
the drives in my own experiments.
|
||||
The reason given by Andy Polyakov is that some DVD-ROM drives get mislead by
|
||||
the lead-out information of (formerly) appendable media unless the media is
|
||||
fully written.
|
||||
(http://fy.chalmers.se/~appro/linux/DVD+RW/ , "Compatibility: caveat lector")
|
||||
|
||||
Own experiments showed no such problems with PC attached PATA DVD-ROM drives.
|
||||
For best DVD-ROM compatibility one should avoid appendable media at all
|
||||
by closing them already after the first session.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Hearsay about DVD+R/DL (Dual Layer) :
|
||||
|
1178
doc/doxygen.conf.in
1178
doc/doxygen.conf.in
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@ libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libburn
|
||||
Description: Disc reading/writing library
|
||||
Description: Library to read/write optical discs
|
||||
Version: @VERSION@
|
||||
Requires:
|
||||
Libs: -L${libdir} -lburn
|
||||
|
219
libburn/async.c
219
libburn/async.c
@ -1,5 +1,25 @@
|
||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||
|
||||
|
||||
/* ts A71019 */
|
||||
|
||||
/* Standard measure should be: Threads are created detached.
|
||||
According to the man pages they should then care for disposing themselves.
|
||||
|
||||
>>> ??? It is yet unclear why the threads vanish from the process list
|
||||
even if joinable and even if never joined.
|
||||
|
||||
To be activated after release of libburn-0.4.0
|
||||
*/
|
||||
#define Libburn_create_detached_threadS 1
|
||||
|
||||
/* Alternative : Threads are created joinable.
|
||||
Threads get detached in remove_worker() and thus should dispose themselves.
|
||||
|
||||
#define Libburn_detach_done_workeR 1
|
||||
*/
|
||||
|
||||
|
||||
#include "libburn.h"
|
||||
#include "transport.h"
|
||||
#include "drive.h"
|
||||
@ -7,9 +27,12 @@
|
||||
#include "options.h"
|
||||
#include "async.h"
|
||||
#include "init.h"
|
||||
#include "file.h"
|
||||
#include "back_hacks.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -53,6 +76,12 @@ struct write_opts
|
||||
struct burn_disc *disc;
|
||||
};
|
||||
|
||||
struct fifo_opts
|
||||
{
|
||||
struct burn_source *source;
|
||||
int flag;
|
||||
};
|
||||
|
||||
|
||||
struct w_list
|
||||
{
|
||||
@ -67,10 +96,12 @@ struct w_list
|
||||
struct erase_opts erase;
|
||||
struct format_opts format;
|
||||
struct write_opts write;
|
||||
struct fifo_opts fifo;
|
||||
} u;
|
||||
};
|
||||
|
||||
static struct w_list *workers;
|
||||
static struct w_list *workers = NULL;
|
||||
|
||||
|
||||
static struct w_list *find_worker(struct burn_drive *d)
|
||||
{
|
||||
@ -86,6 +117,11 @@ static void add_worker(struct burn_drive *d, WorkerFunc f, void *data)
|
||||
{
|
||||
struct w_list *a;
|
||||
struct w_list *tmp;
|
||||
pthread_attr_t *attr_pt = NULL;
|
||||
|
||||
#ifdef Libburn_create_detached_threadS
|
||||
pthread_attr_t attr;
|
||||
#endif
|
||||
|
||||
a = malloc(sizeof(struct w_list));
|
||||
a->drive = d;
|
||||
@ -96,26 +132,65 @@ static void add_worker(struct burn_drive *d, WorkerFunc f, void *data)
|
||||
tmp = workers;
|
||||
workers = a;
|
||||
|
||||
if (d)
|
||||
if (d != NULL)
|
||||
d->busy = BURN_DRIVE_SPAWNING;
|
||||
|
||||
if (pthread_create(&a->thread, NULL, f, a)) {
|
||||
#ifdef Libburn_create_detached_threadS
|
||||
/* ts A71019 :
|
||||
Trying to start the threads detached to get rid of the zombies
|
||||
which do neither react on pthread_join() nor on pthread_detach().
|
||||
*/
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
attr_pt= &attr;
|
||||
/*
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020158,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_LOW,
|
||||
"add_worker(): Creating detached thread.", 0, 0);
|
||||
*/
|
||||
#endif
|
||||
|
||||
if (pthread_create(&a->thread, attr_pt, f, a)) {
|
||||
free(a);
|
||||
workers = tmp;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void remove_worker(pthread_t th)
|
||||
{
|
||||
struct w_list *a, *l = NULL;
|
||||
|
||||
#ifdef Libburn_detach_done_workeR
|
||||
int ret;
|
||||
char msg[80];
|
||||
#endif
|
||||
|
||||
for (a = workers; a; l = a, a = a->next)
|
||||
if (a->thread == th) {
|
||||
if (l)
|
||||
l->next = a->next;
|
||||
else
|
||||
workers = a->next;
|
||||
|
||||
#ifdef Libburn_detach_done_workeR
|
||||
/* ts A71019 : burry dead puppy before forgetting it */
|
||||
/* Alternative : threads get detached and thus should
|
||||
dispose themselves.
|
||||
*/
|
||||
ret = pthread_detach(th);
|
||||
/*
|
||||
sprintf(msg,
|
||||
"remove_workers(): pid= %lu pthread_detach(%lu)= %d",
|
||||
(unsigned long) getpid(), (unsigned long) th, ret);
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020158,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_LOW,
|
||||
msg, 0, 0);
|
||||
*/
|
||||
|
||||
#endif /* Libburn_detach_done_workeR */
|
||||
|
||||
free(a);
|
||||
break;
|
||||
}
|
||||
@ -130,7 +205,12 @@ static void remove_worker(pthread_t th)
|
||||
|
||||
static void *scan_worker_func(struct w_list *w)
|
||||
{
|
||||
burn_drive_scan_sync(w->u.scan.drives, w->u.scan.n_drives);
|
||||
int ret;
|
||||
|
||||
ret = burn_drive_scan_sync(w->u.scan.drives, w->u.scan.n_drives, 1);
|
||||
if (ret <= 0)
|
||||
w->u.scan.done = -1;
|
||||
else
|
||||
w->u.scan.done = 1;
|
||||
return NULL;
|
||||
}
|
||||
@ -165,12 +245,13 @@ drive_is_active:;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!workers) {
|
||||
if (workers == NULL) {
|
||||
/* start it */
|
||||
|
||||
/* ts A61007 : test moved up from burn_drive_scan_sync()
|
||||
was burn_wait_all() */
|
||||
if (!burn_drives_are_clear())
|
||||
/* ts A70907 : now demanding freed drives, not only released */
|
||||
if (!burn_drives_are_clear(1))
|
||||
goto drive_is_active;
|
||||
*drives = NULL;
|
||||
*n_drives = 0;
|
||||
@ -211,9 +292,6 @@ void burn_disc_erase(struct burn_drive *drive, int fast)
|
||||
{
|
||||
struct erase_opts o;
|
||||
|
||||
/* A70103 : will be set to 0 by burn_disc_erase_sync() */
|
||||
drive->cancel = 1;
|
||||
|
||||
/* ts A61006 */
|
||||
/* a ssert(drive); */
|
||||
/* a ssert(!SCAN_GOING()); */
|
||||
@ -233,12 +311,17 @@ void burn_disc_erase(struct burn_drive *drive, int fast)
|
||||
0, 0);
|
||||
return;
|
||||
}
|
||||
/* A70103 : will be set to 0 by burn_disc_erase_sync() */
|
||||
drive->cancel = 1;
|
||||
|
||||
/* 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) */
|
||||
/* ts A70216 : allow blanking of CD-RW or DVD-RW in any regular state
|
||||
and of any kind of full media */
|
||||
/* ts A70909 : the willingness to burn any BURN_DISC_FULL media is
|
||||
inappropriate. One would rather need a -force option
|
||||
Note: keep this in sync with mmc_read_disc_info() */
|
||||
if ((drive->current_profile != 0x0a &&
|
||||
drive->current_profile != 0x13 &&
|
||||
drive->current_profile != 0x14 &&
|
||||
@ -247,6 +330,8 @@ void burn_disc_erase(struct burn_drive *drive, int fast)
|
||||
(drive->status != BURN_DISC_FULL &&
|
||||
drive->status != BURN_DISC_APPENDABLE &&
|
||||
drive->status != BURN_DISC_BLANK)
|
||||
||
|
||||
(drive->drive_role != 1)
|
||||
) {
|
||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
||||
0x00020130,
|
||||
@ -287,6 +372,14 @@ void burn_disc_format(struct burn_drive *drive, off_t size, int flag)
|
||||
0, 0);
|
||||
return;
|
||||
}
|
||||
if (drive->drive_role != 1) {
|
||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
||||
0x00020146,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is a virtual placeholder", 0, 0);
|
||||
drive->cancel = 1;
|
||||
return;
|
||||
}
|
||||
if (flag & 128) /* application prescribed format type */
|
||||
flag |= 16; /* enforce re-format */
|
||||
|
||||
@ -320,7 +413,13 @@ void burn_disc_format(struct burn_drive *drive, off_t size, int flag)
|
||||
|
||||
static void *write_disc_worker_func(struct w_list *w)
|
||||
{
|
||||
struct burn_drive *d = w->u.write.drive;
|
||||
|
||||
d->thread_pid = getpid();
|
||||
d->thread_pid_valid= 1;
|
||||
burn_disc_write_sync(w->u.write.opts, w->u.write.disc);
|
||||
d->thread_pid_valid= 0;
|
||||
d->thread_pid = 0;
|
||||
|
||||
/* the options are refcounted, free out ref count which we added below
|
||||
*/
|
||||
@ -334,17 +433,6 @@ 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;
|
||||
|
||||
/* ts A70203 : people have been warned in API specs */
|
||||
if (opts->write_type == BURN_WRITE_NONE)
|
||||
return;
|
||||
|
||||
/* ts A61006 */
|
||||
/* a ssert(!SCAN_GOING()); */
|
||||
@ -357,8 +445,24 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* For the next lines any return indicates failure */
|
||||
opts->drive->cancel = 1;
|
||||
|
||||
/* ts A70203 : people have been warned in API specs */
|
||||
if (opts->write_type == BURN_WRITE_NONE)
|
||||
return;
|
||||
|
||||
if (opts->drive->drive_role == 0) {
|
||||
libdax_msgs_submit(libdax_messenger, opts->drive->global_index,
|
||||
0x00020146,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is a virtual placeholder (null-drive)", 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ts A61007 : obsolete Assert in spc_select_write_params() */
|
||||
if (!opts->drive->mdata->valid) {
|
||||
if (opts->drive->drive_role == 1 && !opts->drive->mdata->valid) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
opts->drive->global_index, 0x00020113,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
@ -372,48 +476,13 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
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, 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)
|
||||
continue;
|
||||
mode = disc->session[i]->track[0]->mode;
|
||||
for (j = 1; j < disc->session[i]->tracks; j++)
|
||||
if (mode != disc->session[i]->track[j]->mode)
|
||||
mixed_mode = 1;
|
||||
}
|
||||
if (mixed_mode && opts->write_type == BURN_WRITE_SAO) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
opts->drive->global_index, 0x00020133,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"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 */
|
||||
|
||||
o.drive = opts->drive;
|
||||
@ -425,6 +494,40 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
add_worker(opts->drive, (WorkerFunc) write_disc_worker_func, &o);
|
||||
}
|
||||
|
||||
|
||||
static void *fifo_worker_func(struct w_list *w)
|
||||
{
|
||||
burn_fifo_source_shoveller(w->u.fifo.source, w->u.fifo.flag);
|
||||
remove_worker(pthread_self());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int burn_fifo_start(struct burn_source *source, int flag)
|
||||
{
|
||||
struct fifo_opts o;
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
|
||||
fs->is_started = -1;
|
||||
|
||||
/* create and set up ring buffer */;
|
||||
fs->buf = calloc(fs->chunksize, fs->chunks);
|
||||
if (fs->buf == NULL) {
|
||||
/* >>> could not start ring buffer */;
|
||||
return -1;
|
||||
}
|
||||
|
||||
o.source = source;
|
||||
o.flag = flag;
|
||||
add_worker(NULL, (WorkerFunc) fifo_worker_func, &o);
|
||||
fs->is_started = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef Libburn_has_burn_async_join_alL
|
||||
|
||||
/* ts A71019 : never used */
|
||||
void burn_async_join_all(void)
|
||||
{
|
||||
void *ret;
|
||||
@ -432,3 +535,7 @@ void burn_async_join_all(void)
|
||||
while (workers)
|
||||
pthread_join(workers->thread, &ret);
|
||||
}
|
||||
|
||||
#endif /* Libburn_has_burn_async_join_alL */
|
||||
|
||||
|
||||
|
@ -5,4 +5,10 @@
|
||||
|
||||
void burn_async_join_all(void);
|
||||
struct burn_write_opts;
|
||||
|
||||
/* ts A70930 */
|
||||
/* To be called when the first read() call comes to a fifo */
|
||||
int burn_fifo_start(struct burn_source *source, int flag);
|
||||
|
||||
|
||||
#endif /* BURN__ASYNC_H */
|
||||
|
734
libburn/drive.c
734
libburn/drive.c
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,8 @@ unsigned int burn_drive_count(void);
|
||||
|
||||
/* ts A61007 */
|
||||
/* void burn_wait_all(void); */
|
||||
int burn_drives_are_clear(void);
|
||||
/* @param flag bit0= demand freed drives (else released drives) */
|
||||
int burn_drives_are_clear(int flag);
|
||||
|
||||
int burn_sector_length_write(struct burn_drive *d);
|
||||
int burn_track_control(struct burn_drive *d, int);
|
||||
@ -52,8 +53,10 @@ void burn_write_empty_subcode(int fd);
|
||||
void burn_drive_free(struct burn_drive *d);
|
||||
void burn_drive_free_all(void);
|
||||
|
||||
/* @param flag bit0= reset global drive list */
|
||||
int burn_drive_scan_sync(struct burn_drive_info *drives[],
|
||||
unsigned int *n_drives);
|
||||
unsigned int *n_drives, int flag);
|
||||
|
||||
void burn_disc_erase_sync(struct burn_drive *d, int fast);
|
||||
int burn_drive_get_block_types(struct burn_drive *d,
|
||||
enum burn_write_types write_type);
|
||||
@ -111,4 +114,15 @@ int burn_disc_get_write_mode_demands(struct burn_disc *disc,
|
||||
struct burn_write_opts *opts,
|
||||
struct burn_disc_mode_demands *result, int flag);
|
||||
|
||||
|
||||
/* ts A70924 : convert a special stdio address into fd number.
|
||||
@return >0 is a valid fd , -1 indicates unsuitable address string.
|
||||
*/
|
||||
int burn_drive__fd_from_special_adr(char *adr);
|
||||
|
||||
|
||||
/* ts A70929 : Find the drive which is being worked on by pid */
|
||||
int burn_drive_find_by_thread_pid(struct burn_drive **d, pid_t pid);
|
||||
|
||||
|
||||
#endif /* __DRIVE */
|
||||
|
396
libburn/file.c
396
libburn/file.c
@ -2,12 +2,21 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include "source.h"
|
||||
#include "libburn.h"
|
||||
#include "file.h"
|
||||
#include "async.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
|
||||
/* main channel data can be padded on read, but 0 padding the subs will make
|
||||
an unreadable disc */
|
||||
@ -93,14 +102,14 @@ struct burn_source *burn_file_source_new(const char *path, const char *subpath)
|
||||
{
|
||||
struct burn_source_file *fs;
|
||||
struct burn_source *src;
|
||||
int fd1, fd2 = 0;
|
||||
int fd1 = -1, fd2 = -1;
|
||||
|
||||
if (!path)
|
||||
return NULL;
|
||||
fd1 = open(path, O_RDONLY);
|
||||
if (fd1 == -1)
|
||||
return NULL;
|
||||
if (subpath) {
|
||||
if (subpath != NULL) {
|
||||
fd2 = open(subpath, O_RDONLY);
|
||||
if (fd2 == -1) {
|
||||
close(fd1);
|
||||
@ -108,15 +117,30 @@ struct burn_source *burn_file_source_new(const char *path, const char *subpath)
|
||||
}
|
||||
}
|
||||
fs = malloc(sizeof(struct burn_source_file));
|
||||
fs->datafd = fd1;
|
||||
|
||||
if (subpath)
|
||||
/* ts A70825 */
|
||||
if (fs == NULL) {
|
||||
failure:;
|
||||
close(fd1);
|
||||
if (fd2 >= 0)
|
||||
close(fd2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fs->datafd = fd1;
|
||||
fs->subfd = fd2;
|
||||
|
||||
/* ts A70125 */
|
||||
fs->fixed_size = 0;
|
||||
|
||||
src = burn_source_new();
|
||||
|
||||
/* ts A70825 */
|
||||
if (src == NULL) {
|
||||
free((char *) fs);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
src->read = file_read;
|
||||
if (subpath)
|
||||
src->read_sub = file_read_sub;
|
||||
@ -139,14 +163,23 @@ struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size)
|
||||
if (datafd == -1)
|
||||
return NULL;
|
||||
fs = malloc(sizeof(struct burn_source_file));
|
||||
if (fs == NULL) /* ts A70825 */
|
||||
return NULL;
|
||||
fs->datafd = datafd;
|
||||
fs->subfd = subfd;
|
||||
fs->fixed_size = size;
|
||||
|
||||
src = burn_source_new();
|
||||
|
||||
/* ts A70825 */
|
||||
if (src == NULL) {
|
||||
free((char *) fs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
src->read = file_read;
|
||||
if(subfd != -1)
|
||||
src->read = file_read_sub;
|
||||
src->read_sub = file_read_sub;
|
||||
src->get_size = file_size;
|
||||
src->set_size = file_set_size;
|
||||
src->free_data = file_free;
|
||||
@ -154,3 +187,356 @@ struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size)
|
||||
return src;
|
||||
}
|
||||
|
||||
|
||||
/* ts A71003 */
|
||||
/* ------------------------------ fifo --------------------------- */
|
||||
|
||||
/* The fifo mechanism consists of a burn_source proxy which is here,
|
||||
a thread management team which is located in async.c,
|
||||
and a synchronous shoveller which is here.
|
||||
*/
|
||||
|
||||
static int fifo_sleep(int flag)
|
||||
{
|
||||
static struct timespec sleeptime = { 0, 50000000}; /* 50 ms */
|
||||
|
||||
return nanosleep(&sleeptime, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int fifo_read(struct burn_source *source,
|
||||
unsigned char *buffer,
|
||||
int size)
|
||||
{
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
int ret, todo, rpos, bufsize, diff;
|
||||
|
||||
if (fs->end_of_consumption) {
|
||||
/* ??? msg: reading has been ended already */;
|
||||
return 0;
|
||||
}
|
||||
if (fs->is_started == 0) {
|
||||
ret = burn_fifo_start(source, 0);
|
||||
if (ret <= 0) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020152,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Cannot start fifo thread", 0, 0);
|
||||
fs->end_of_consumption = 1;
|
||||
return -1;
|
||||
}
|
||||
fs->is_started = 1;
|
||||
}
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
/* Reading from the ring buffer */
|
||||
|
||||
/* This needs no mutex because each volatile variable has one thread
|
||||
which may write and the other which only reads and is aware of
|
||||
volatility.
|
||||
The feeder of the ringbuffer is in burn_fifo_source_shoveller().
|
||||
*/
|
||||
todo = size;
|
||||
bufsize = fs->chunksize * fs->chunks;
|
||||
while (todo > 0) {
|
||||
/* readpos is not volatile here , writepos is volatile */
|
||||
rpos = fs->buf_readpos;
|
||||
while (rpos == fs->buf_writepos) {
|
||||
if (fs->end_of_input)
|
||||
break;
|
||||
if (fs->input_error) {
|
||||
if (todo < size) /* deliver partial buffer */
|
||||
break;
|
||||
fs->end_of_consumption = 1;
|
||||
libdax_msgs_submit(libdax_messenger, -1,
|
||||
0x00020154,
|
||||
LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Forwarded input error ends output", 0, 0);
|
||||
return -1;
|
||||
}
|
||||
fifo_sleep(0);
|
||||
}
|
||||
diff = fs->buf_writepos - rpos; /* read volatile only once */
|
||||
if (diff == 0)
|
||||
break;
|
||||
if (diff > 0)
|
||||
/* diff bytes are available */;
|
||||
else
|
||||
/* at least (bufsize - rpos) bytes are available */
|
||||
diff = bufsize - rpos;
|
||||
if (diff > todo)
|
||||
diff = todo;
|
||||
memcpy(buffer, fs->buf+(size-todo)+rpos, diff);
|
||||
fs->buf_readpos += diff;
|
||||
if (fs->buf_readpos >= bufsize)
|
||||
fs->buf_readpos = 0;
|
||||
todo -= diff;
|
||||
}
|
||||
if (size - todo <= 0)
|
||||
fs->end_of_consumption = 1;
|
||||
else
|
||||
fs->out_counter += size - todo;
|
||||
|
||||
/*
|
||||
fprintf(stderr,
|
||||
"libburn_EXPERIMENTAL: read= %d , pos= %d , out_count= %.f\n",
|
||||
(size - todo), fs->buf_readpos, (double) fs->out_counter);
|
||||
*/
|
||||
|
||||
return (size - todo);
|
||||
}
|
||||
|
||||
|
||||
static off_t fifo_get_size(struct burn_source *source)
|
||||
{
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
|
||||
return fs->inp->get_size(fs->inp);
|
||||
}
|
||||
|
||||
|
||||
static int fifo_set_size(struct burn_source *source, off_t size)
|
||||
{
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
|
||||
return fs->inp->set_size(fs->inp, size);
|
||||
}
|
||||
|
||||
|
||||
static void fifo_free(struct burn_source *source)
|
||||
{
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
|
||||
if (fs->inp != NULL)
|
||||
burn_source_free(fs->inp);
|
||||
if (fs->buf != NULL)
|
||||
free(fs->buf);
|
||||
free((char *) fs);
|
||||
}
|
||||
|
||||
|
||||
int burn_fifo_source_shoveller(struct burn_source *source, int flag)
|
||||
{
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
int ret, bufsize, diff, wpos, rpos, trans_end, free_bytes;
|
||||
char *bufpt;
|
||||
|
||||
fs->thread_pid = getpid();
|
||||
fs->thread_pid_valid = 1;
|
||||
|
||||
bufsize = fs->chunksize * fs->chunks;
|
||||
while (!fs->end_of_consumption) {
|
||||
|
||||
/* wait for enough buffer space available */
|
||||
wpos = fs->buf_writepos;
|
||||
while (1) {
|
||||
rpos = fs->buf_readpos;
|
||||
diff = rpos - wpos;
|
||||
trans_end = 0;
|
||||
if (diff == 0)
|
||||
free_bytes = bufsize - 1;
|
||||
else if (diff > 0)
|
||||
free_bytes = diff - 1;
|
||||
else {
|
||||
free_bytes = (bufsize - wpos) + rpos - 1;
|
||||
if (bufsize - wpos < fs->chunksize)
|
||||
trans_end = 1;
|
||||
}
|
||||
if (free_bytes >= fs->chunksize)
|
||||
break;
|
||||
fifo_sleep(0);
|
||||
}
|
||||
|
||||
/* prepare the receiving memory */
|
||||
bufpt = fs->buf + wpos;
|
||||
if (trans_end) {
|
||||
bufpt = calloc(fs->chunksize, 1);
|
||||
if (bufpt == NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1,
|
||||
0x00000003,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Out of virtual memory", 0, 0);
|
||||
fs->input_error = ENOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Obtain next chunk */
|
||||
if (fs->inp->read != NULL)
|
||||
ret = fs->inp->read(fs->inp,
|
||||
(unsigned char *) bufpt, fs->chunksize);
|
||||
else
|
||||
ret = fs->inp->read_xt( fs->inp,
|
||||
(unsigned char *) bufpt, fs->chunksize);
|
||||
if (ret > 0)
|
||||
fs->in_counter += ret;
|
||||
else if (ret == 0)
|
||||
break; /* EOF */
|
||||
else {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020153,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Read error on fifo input", errno, 0);
|
||||
fs->input_error = errno;
|
||||
if(errno == 0)
|
||||
fs->input_error = EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/* activate read chunk */
|
||||
if (ret > fs->chunksize) /* beware of ill custom burn_source */
|
||||
ret = fs->chunksize;
|
||||
if (trans_end) {
|
||||
/* copy to end of buffer */
|
||||
memcpy(fs->buf + wpos, bufpt, bufsize - wpos);
|
||||
/* copy to start of buffer */
|
||||
memcpy(fs->buf, bufpt + (bufsize - wpos),
|
||||
fs->chunksize - (bufsize - wpos));
|
||||
free(bufpt);
|
||||
if (ret >= bufsize - wpos)
|
||||
fs->buf_writepos = ret - (bufsize - wpos);
|
||||
else
|
||||
fs->buf_writepos += ret;
|
||||
} else if (fs->buf_writepos + ret == bufsize)
|
||||
fs->buf_writepos = 0;
|
||||
else
|
||||
fs->buf_writepos += ret;
|
||||
|
||||
/*
|
||||
fprintf(stderr, "[%2.2d%%] ",
|
||||
(int) (100.0 - 100.0 * ((double) free_bytes) /
|
||||
(double) bufsize));
|
||||
fprintf(stderr,
|
||||
"libburn_EXPERIMENTAL: writepos= %d ,in_count = %.f\n",
|
||||
fs->buf_writepos, (double) fs->in_counter);
|
||||
*/
|
||||
}
|
||||
if (!fs->end_of_consumption)
|
||||
fs->end_of_input = 1;
|
||||
|
||||
/* wait for end of reading by consumer */;
|
||||
while (fs->buf_readpos != fs->buf_writepos && !fs->end_of_consumption)
|
||||
fifo_sleep(0);
|
||||
|
||||
/* destroy ring buffer */;
|
||||
if (!fs->end_of_consumption)
|
||||
fs->end_of_consumption = 2; /* Claim stop of consumption */
|
||||
|
||||
/* This is not prone to race conditions because either the consumer
|
||||
indicated hangup by fs->end_of_consumption = 1 or the consumer set
|
||||
fs->buf_readpos to a value indicating the buffer is empty.
|
||||
So in both cases the consumer is aware that reading is futile
|
||||
or even fatal.
|
||||
*/
|
||||
free(fs->buf); /* Give up fifo buffer. Next fifo might start soon. */
|
||||
fs->buf = NULL;
|
||||
|
||||
return (fs->input_error == 0);
|
||||
}
|
||||
|
||||
|
||||
int burn_fifo_cancel(struct burn_source *source)
|
||||
{
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
|
||||
burn_source_cancel(fs->inp);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
struct burn_source *burn_fifo_source_new(struct burn_source *inp,
|
||||
int chunksize, int chunks, int flag)
|
||||
{
|
||||
struct burn_source_fifo *fs;
|
||||
struct burn_source *src;
|
||||
|
||||
if (((double) chunksize) * ((double) chunks) > 1024.0*1024.0*1024.0) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020155,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Desired fifo buffer too large (> 1GB)", 0, 0);
|
||||
return NULL;
|
||||
}
|
||||
if (chunksize < 1 || chunks < 2) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020156,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Desired fifo buffer too small", 0, 0);
|
||||
return NULL;
|
||||
}
|
||||
fs = malloc(sizeof(struct burn_source_fifo));
|
||||
if (fs == NULL)
|
||||
return NULL;
|
||||
fs->is_started = 0;
|
||||
fs->thread_pid = 0;
|
||||
fs->thread_pid_valid = 0;
|
||||
fs->inp = NULL; /* set later */
|
||||
fs->chunksize = chunksize;
|
||||
fs->chunks = chunks;
|
||||
fs->buf = NULL;
|
||||
fs->buf_writepos = fs->buf_readpos = 0;
|
||||
fs->end_of_input = 0;
|
||||
fs->input_error = 0;
|
||||
fs->end_of_consumption = 0;
|
||||
fs->in_counter = fs->out_counter = 0;
|
||||
|
||||
src = burn_source_new();
|
||||
if (src == NULL) {
|
||||
free((char *) fs);
|
||||
return NULL;
|
||||
}
|
||||
src->read = NULL;
|
||||
src->read_sub = NULL;
|
||||
src->get_size = fifo_get_size;
|
||||
src->set_size = fifo_set_size;
|
||||
src->free_data = fifo_free;
|
||||
src->data = fs;
|
||||
src->version= 1;
|
||||
src->read_xt = fifo_read;
|
||||
src->cancel= burn_fifo_cancel;
|
||||
fs->inp = inp;
|
||||
inp->refcount++; /* make sure inp lives longer than src */
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
|
||||
/* ts A71003 : API */
|
||||
int burn_fifo_inquire_status(struct burn_source *source,
|
||||
int *size, int *free_bytes, char **status_text)
|
||||
{
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
int ret = 0, diff, wpos, rpos;
|
||||
static char *(states[8]) = {
|
||||
"standby", "active", "ending", "failing",
|
||||
"unused", "abandoned", "ended", "aborted"};
|
||||
|
||||
*status_text = NULL;
|
||||
*size = 0;
|
||||
|
||||
if (source->free_data != fifo_free) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020157,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"burn_source is not a fifo object", 0, 0);
|
||||
return -1;
|
||||
}
|
||||
*size = fs->chunksize * fs->chunks;
|
||||
rpos = fs->buf_readpos;
|
||||
wpos = fs->buf_writepos;
|
||||
diff = rpos - wpos;
|
||||
if (diff == 0)
|
||||
*free_bytes = *size - 1;
|
||||
else if (diff > 0)
|
||||
*free_bytes = diff - 1;
|
||||
else
|
||||
*free_bytes = (*size - wpos) + rpos - 1;
|
||||
ret = 0;
|
||||
if (fs->end_of_consumption > 0)
|
||||
ret |= 4;
|
||||
if (fs->input_error)
|
||||
ret |= 3;
|
||||
else if (fs->end_of_input)
|
||||
ret |= 2;
|
||||
else if(fs->buf != NULL)
|
||||
ret |= 1;
|
||||
*status_text = states[ret];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,58 @@
|
||||
|
||||
struct burn_source_file
|
||||
{
|
||||
char magic[4];
|
||||
|
||||
int datafd;
|
||||
int subfd;
|
||||
off_t fixed_size;
|
||||
};
|
||||
|
||||
|
||||
/* ts A70126 : burn_source_file obsoleted burn_source_fd */
|
||||
|
||||
|
||||
/* ts A70930 */
|
||||
struct burn_source_fifo {
|
||||
char magic[4];
|
||||
|
||||
/* The fifo stays inactive and unequipped with eventual resources
|
||||
until its read() method is called for the first time.
|
||||
Only then burn_fifo_start() gets called, allocates the complete
|
||||
resources, starts a thread with burn_fifo_source_shuffler()
|
||||
which shuffles data and finally destroys the resources.
|
||||
This late start is to stay modest in case of multiple tracks
|
||||
in one disc.
|
||||
*/
|
||||
int is_started;
|
||||
|
||||
int thread_pid;
|
||||
int thread_pid_valid;
|
||||
|
||||
/* the burn_source for which this fifo is acting as proxy */
|
||||
struct burn_source *inp;
|
||||
|
||||
/* <<< up to now it was only a pipe. This is on its way out. */
|
||||
int outlet[2];
|
||||
|
||||
/* The ring buffer mechanism */
|
||||
int chunksize;
|
||||
int chunks;
|
||||
char *buf;
|
||||
volatile int buf_writepos;
|
||||
volatile int buf_readpos;
|
||||
volatile int end_of_input;
|
||||
volatile int input_error;
|
||||
volatile int end_of_consumption;
|
||||
|
||||
off_t in_counter;
|
||||
off_t out_counter;
|
||||
};
|
||||
|
||||
|
||||
/** The worker behind the fifo thread.
|
||||
Gets started from burn_fifo_start() in async.c
|
||||
*/
|
||||
int burn_fifo_source_shoveller(struct burn_source *source, int flag);
|
||||
|
||||
|
||||
#endif /* LIBBURN__FILE_H */
|
||||
|
160
libburn/init.c
160
libburn/init.c
@ -8,12 +8,18 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ts A70928 : init.h is for others, not for init .c
|
||||
#include "init.h"
|
||||
*/
|
||||
|
||||
|
||||
#include "sg.h"
|
||||
#include "error.h"
|
||||
#include "libburn.h"
|
||||
#include "drive.h"
|
||||
#include "transport.h"
|
||||
|
||||
/* ts A60825 : The storage location for back_hacks.h variables. */
|
||||
#define BURN_BACK_HACKS_INIT 1
|
||||
@ -53,7 +59,6 @@ int burn_sg_open_o_nonblock = 1;
|
||||
to unconditional abort of the process */
|
||||
int burn_sg_open_abort_busy = 0;
|
||||
|
||||
|
||||
/* ts A61002 */
|
||||
|
||||
#include "cleanup.h"
|
||||
@ -61,6 +66,10 @@ int burn_sg_open_abort_busy = 0;
|
||||
/* Parameters for builtin abort handler */
|
||||
static char abort_message_prefix[81] = {"libburn : "};
|
||||
static pid_t abort_control_pid= 0;
|
||||
volatile int burn_global_abort_level= 0;
|
||||
int burn_global_abort_signum= 0;
|
||||
void *burn_global_signal_handle = NULL;
|
||||
burn_abort_handler_t burn_global_signal_handler = NULL;
|
||||
|
||||
|
||||
/* ts A70223 : wether implemented untested profiles are supported */
|
||||
@ -107,11 +116,12 @@ void burn_finish(void)
|
||||
|
||||
/* ts A61007 */
|
||||
/* burn_wait_all(); */
|
||||
if (!burn_drives_are_clear()) {
|
||||
if (!burn_drives_are_clear(0)) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020107,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is busy on attempt to shut down library", 0, 0);
|
||||
return;
|
||||
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"A drive is still busy on shutdown of library", 0, 0);
|
||||
usleep(1000001);
|
||||
burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
|
||||
}
|
||||
|
||||
/* ts A60904 : ticket 62, contribution by elmom : name addon "_all" */
|
||||
@ -200,6 +210,8 @@ int burn_msgs_obtain(char *minimum_severity,
|
||||
ret = libdax_msgs__text_to_sev(minimum_severity, &minimum_sevno, 0);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
if (libdax_messenger == NULL)
|
||||
return 0;
|
||||
ret = libdax_msgs_obtain(libdax_messenger, &item, minimum_sevno,
|
||||
LIBDAX_MSGS_PRIO_ZERO, 0);
|
||||
if (ret <= 0)
|
||||
@ -226,40 +238,124 @@ ex:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70922 : API */
|
||||
int burn_msgs_submit(int error_code, char msg_text[], int os_errno,
|
||||
char severity[], struct burn_drive *d)
|
||||
{
|
||||
int ret, sevno, global_index = -1;
|
||||
|
||||
ret = libdax_msgs__text_to_sev(severity, &sevno, 0);
|
||||
if (ret <= 0)
|
||||
sevno = LIBDAX_MSGS_SEV_ALL;
|
||||
if (error_code <= 0) {
|
||||
switch(sevno) {
|
||||
case LIBDAX_MSGS_SEV_ABORT: error_code = 0x00040000;
|
||||
break; case LIBDAX_MSGS_SEV_FATAL: error_code = 0x00040001;
|
||||
break; case LIBDAX_MSGS_SEV_SORRY: error_code = 0x00040002;
|
||||
break; case LIBDAX_MSGS_SEV_WARNING: error_code = 0x00040003;
|
||||
break; case LIBDAX_MSGS_SEV_HINT: error_code = 0x00040004;
|
||||
break; case LIBDAX_MSGS_SEV_NOTE: error_code = 0x00040005;
|
||||
break; case LIBDAX_MSGS_SEV_UPDATE: error_code = 0x00040006;
|
||||
break; case LIBDAX_MSGS_SEV_DEBUG: error_code = 0x00040007;
|
||||
break; default: error_code = 0x00040008;
|
||||
}
|
||||
}
|
||||
if (d != NULL)
|
||||
global_index = d->global_index;
|
||||
ret = libdax_msgs_submit(libdax_messenger, global_index, error_code,
|
||||
sevno, LIBDAX_MSGS_PRIO_HIGH, msg_text, os_errno, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A71016 API */
|
||||
int burn_text_to_sev(char *severity_name, int *sevno, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libdax_msgs__text_to_sev(severity_name, sevno, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A80202 API */
|
||||
int burn_sev_to_text(int severity_number, char **severity_name, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = libdax_msgs__sev_to_text(severity_number, severity_name, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int burn_builtin_abort_handler(void *handle, int signum, int flag)
|
||||
{
|
||||
|
||||
#define Libburn_new_thread_signal_handleR 1
|
||||
/*
|
||||
#define Libburn_signal_handler_verbouS 1
|
||||
*/
|
||||
int ret;
|
||||
struct burn_drive *d;
|
||||
|
||||
#ifdef Libburn_signal_handler_verbouS
|
||||
fprintf(stderr,
|
||||
"libburn_ABORT: pid = %d , abort_control_pid = %d , sig= %d\n",
|
||||
getpid(), abort_control_pid, signum);
|
||||
#endif
|
||||
|
||||
/* ts A70928:
|
||||
Must be quick. Allowed to coincide with other thread and to share
|
||||
the increment with that one. It must not decrease, though, and
|
||||
yield at least 1 if any thread calls this function.
|
||||
*/
|
||||
burn_global_abort_level++;
|
||||
burn_global_abort_signum= signum;
|
||||
|
||||
if(getpid() != abort_control_pid) {
|
||||
|
||||
#ifdef Not_yeT
|
||||
pthread_t thread_id;
|
||||
#ifdef Libburn_new_thread_signal_handleR
|
||||
|
||||
/* >>> need better handling of self-induced SIGs
|
||||
like SIGSEGV or SIGFPE.
|
||||
Like bonking the control thread if it did not show up
|
||||
after a short while.
|
||||
*/
|
||||
ret = burn_drive_find_by_thread_pid(&d, getpid());
|
||||
if (ret > 0 && d->busy == BURN_DRIVE_WRITING) {
|
||||
/* This is an active writer thread */
|
||||
|
||||
/* >>> if this is a non-fatal signal : return -2 */
|
||||
#ifdef Libburn_signal_handler_verbouS
|
||||
fprintf(stderr, "libburn_ABORT: pid %d found drive busy with writing, (level= %d)\n", (int) getpid(), burn_global_abort_level);
|
||||
#endif
|
||||
|
||||
thread_id = pthread_self();
|
||||
/* >>> find thread_id in worker list of async.c */
|
||||
/* >>> if owning a drive : mark idle and canceled
|
||||
(can't do anything more) */
|
||||
d->sync_cache(d);
|
||||
|
||||
usleep(1000000); /* calm down */
|
||||
/* >>> perform a more qualified end of burn process */;
|
||||
|
||||
/* forward signal to control thread */
|
||||
if (abort_control_pid>1)
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
|
||||
if (burn_global_abort_level > 0) {
|
||||
/* control process did not show up yet */
|
||||
#ifdef Libburn_signal_handler_verbouS
|
||||
fprintf(stderr, "libburn_ABORT: pid %d sending signum %d to pid %d\n", (int) getpid(), (int) signum, (int) abort_control_pid);
|
||||
#endif
|
||||
kill(abort_control_pid, signum);
|
||||
}
|
||||
|
||||
/* >>> ??? end thread */;
|
||||
#ifdef Libburn_signal_handler_verbouS
|
||||
fprintf(stderr, "libburn_ABORT: pid %d signum %d returning -2\n", (int) getpid(), (int) signum);
|
||||
#endif
|
||||
|
||||
return -2;
|
||||
} else {
|
||||
usleep(1000000); /* calm down */
|
||||
return -2;
|
||||
}
|
||||
|
||||
#else
|
||||
usleep(1000000); /* calm down */
|
||||
return -2;
|
||||
#endif /* ! Not_yeT */
|
||||
#endif /* ! Libburn_new_thread_signal_handleR */
|
||||
|
||||
}
|
||||
burn_global_abort_level = -1;
|
||||
Cleanup_set_handlers(NULL, NULL, 2);
|
||||
fprintf(stderr,"%sABORT : Trying to shut down drive and library\n",
|
||||
abort_message_prefix);
|
||||
@ -267,10 +363,13 @@ int burn_builtin_abort_handler(void *handle, int signum, int flag)
|
||||
"%sABORT : Wait the normal burning time before any kill -9\n",
|
||||
abort_message_prefix);
|
||||
close(0); /* somehow stdin as input blocks abort until EOF */
|
||||
|
||||
burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
|
||||
|
||||
fprintf(stderr,
|
||||
"\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
|
||||
abort_message_prefix);
|
||||
burn_global_abort_level = -2;
|
||||
return(1);
|
||||
}
|
||||
|
||||
@ -289,8 +388,10 @@ void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
|
||||
strncpy(abort_message_prefix, (char *) handle,
|
||||
sizeof(abort_message_prefix)-1);
|
||||
abort_message_prefix[sizeof(abort_message_prefix)-1] = 0;
|
||||
abort_control_pid= getpid();
|
||||
abort_control_pid = getpid();
|
||||
Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler, mode|4);
|
||||
burn_global_signal_handle = handle;
|
||||
burn_global_signal_handler = handler;
|
||||
}
|
||||
|
||||
|
||||
@ -300,3 +401,16 @@ void burn_allow_untested_profiles(int yes)
|
||||
burn_support_untested_profiles = !!yes;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70915 : API */
|
||||
int burn_set_messenger(void *messenger)
|
||||
{
|
||||
struct libdax_msgs *pt;
|
||||
|
||||
if (libdax_msgs_refer(&pt, messenger, 0) <= 0)
|
||||
return 0;
|
||||
libdax_msgs_destroy(&libdax_messenger, 0);
|
||||
libdax_messenger = (struct libdax_msgs *) pt;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -5,4 +5,17 @@
|
||||
|
||||
extern int burn_running;
|
||||
|
||||
/** Indicator for burn_drive_get_status() wether a signal hit parts of the
|
||||
thread team.
|
||||
0= all works well ,
|
||||
1 to 5 = waiting for eventual signal on control thread
|
||||
> 5 = do abort now
|
||||
-1 = control thread has been informed
|
||||
*/
|
||||
extern volatile int burn_global_abort_level;
|
||||
extern int burn_global_abort_signum;
|
||||
extern void *burn_global_signal_handle;
|
||||
extern burn_abort_handler_t burn_global_signal_handler;
|
||||
|
||||
|
||||
#endif /* BURN__INIT_H */
|
||||
|
@ -251,7 +251,15 @@ enum burn_drive_status
|
||||
|
||||
/* ts A61223 */
|
||||
/** The drive is formatting media */
|
||||
BURN_DRIVE_FORMATTING
|
||||
BURN_DRIVE_FORMATTING,
|
||||
|
||||
/* ts A70822 */
|
||||
/** The drive is busy in synchronous read (if you see this then it
|
||||
has been interrupted) */
|
||||
BURN_DRIVE_READING_SYNC,
|
||||
/** The drive is busy in synchronous write (if you see this then it
|
||||
has been interrupted) */
|
||||
BURN_DRIVE_WRITING_SYNC
|
||||
|
||||
};
|
||||
|
||||
@ -291,7 +299,7 @@ struct burn_toc_entry
|
||||
/** Track start time frames for normal tracks */
|
||||
unsigned char pframe;
|
||||
|
||||
/* Indicates wether extension data are valid and eventually override
|
||||
/* Indicates whether extension data are valid and eventually override
|
||||
older elements in this structure:
|
||||
bit0= DVD extension is valid
|
||||
*/
|
||||
@ -310,39 +318,158 @@ struct burn_toc_entry
|
||||
};
|
||||
|
||||
|
||||
/** Data source for tracks */
|
||||
/** Data source interface for tracks.
|
||||
This allows to use arbitrary program code as provider of track input data.
|
||||
|
||||
Objects compliant to this interface are either provided by the application
|
||||
or by API calls of libburn: burn_fd_source_new() , burn_file_source_new(),
|
||||
and burn_fifo_source_new().
|
||||
|
||||
The API calls allow to use any file object as data source. Consider to feed
|
||||
an eventual custom data stream asynchronously into a pipe(2) and to let
|
||||
libburn handle the rest.
|
||||
In this case the following rule applies:
|
||||
Call burn_source_free() exactly once for every source obtained from
|
||||
libburn API. You MUST NOT otherwise use or manipulate its components.
|
||||
|
||||
In general, burn_source objects can be freed as soon as they are attached
|
||||
to track objects. The track objects will keep them alive and dispose them
|
||||
when they are no longer needed. With a fifo burn_source it makes sense to
|
||||
keep the own reference for inquiring its state while burning is in
|
||||
progress.
|
||||
|
||||
---
|
||||
|
||||
The following description of burn_source applies only to application
|
||||
implemented burn_source objects. You need not to know it for API provided
|
||||
ones.
|
||||
|
||||
If you really implement an own passive data producer by this interface,
|
||||
then beware: it can do anything and it can spoil everything.
|
||||
|
||||
In this case the functions (*read), (*get_size), (*set_size), (*free_data)
|
||||
MUST be implemented by the application and attached to the object at
|
||||
creation time.
|
||||
Function (*read_sub) is allowed to be NULL or it MUST be implemented and
|
||||
attached.
|
||||
|
||||
burn_source.refcount MUST be handled properly: If not exactly as many
|
||||
references are freed as have been obtained, then either memory leaks or
|
||||
corrupted memory are the consequence.
|
||||
All objects which are referred to by *data must be kept existent until
|
||||
(*free_data) is called via burn_source_free() by the last referer.
|
||||
*/
|
||||
struct burn_source {
|
||||
/** Reference count for the data source. Should be 1 when a new source
|
||||
is created. Increment it to take a reference for yourself. Use
|
||||
burn_source_free to destroy your reference to it. */
|
||||
|
||||
/** Reference count for the data source. MUST be 1 when a new source
|
||||
is created and thus the first reference is handed out. Increment
|
||||
it to take more references for yourself. Use burn_source_free()
|
||||
to destroy your references to it. */
|
||||
int refcount;
|
||||
|
||||
/** Read data from the source */
|
||||
int (*read)(struct burn_source *,
|
||||
unsigned char *buffer,
|
||||
int size);
|
||||
|
||||
/** Read subchannel data from the source (NULL if lib generated) */
|
||||
int (*read_sub)(struct burn_source *,
|
||||
unsigned char *buffer,
|
||||
int size);
|
||||
/** Read data from the source. Semantics like with read(2), but MUST
|
||||
either deliver the full buffer as defined by size or MUST deliver
|
||||
EOF (return 0) or failure (return -1) at this call or at the
|
||||
next following call. I.e. the only incomplete buffer may be the
|
||||
last one from that source.
|
||||
libburn will read a single sector by each call to (*read).
|
||||
The size of a sector depends on BURN_MODE_*. The known range is
|
||||
2048 to 2352.
|
||||
|
||||
/** Get the size of the source's data */
|
||||
IMPORTANT:
|
||||
If this function pointer is NULL, then the struct burn_source is of
|
||||
version >= 1 and the job of .(*read)() is done by .(*read_xt)().
|
||||
See below, member .version.
|
||||
*/
|
||||
int (*read)(struct burn_source *, unsigned char *buffer, int size);
|
||||
|
||||
|
||||
/** Read subchannel data from the source (NULL if lib generated)
|
||||
WARNING: This is an obscure feature with CD raw write modes.
|
||||
Unless you checked the libburn code for correctness in that aspect
|
||||
you should not rely on raw writing with own subchannels.
|
||||
ADVICE: Set this pointer to NULL.
|
||||
*/
|
||||
int (*read_sub)(struct burn_source *, unsigned char *buffer, int size);
|
||||
|
||||
|
||||
/** Get the size of the source's data. Return 0 means unpredictable
|
||||
size. If application provided (*get_size) allows return 0, then
|
||||
the application MUST provide a fully functional (*set_size).
|
||||
*/
|
||||
off_t (*get_size)(struct burn_source *);
|
||||
|
||||
/** Set the size of the source's data */
|
||||
|
||||
/* ts A70125 : BROKE BINARY BACKWARD COMPATIBILITY AT libburn-0.3.1. */
|
||||
/** Program the reply of (*get_size) to a fixed value. It is advised
|
||||
to implement this by a attribute off_t fixed_size; in *data .
|
||||
The read() function does not have to take into respect this fake
|
||||
setting. It is rather a note of libburn to itself. Eventually
|
||||
necessary truncation or padding is done in libburn. Truncation
|
||||
is usually considered a misburn. Padding is considered ok.
|
||||
|
||||
libburn is supposed to work even if (*get_size) ignores the
|
||||
setting by (*set_size). But your application will not be able to
|
||||
enforce fixed track sizes by burn_track_set_size() and possibly
|
||||
even padding might be left out.
|
||||
*/
|
||||
int (*set_size)(struct burn_source *source, off_t size);
|
||||
|
||||
/** Clean up the source specific data */
|
||||
|
||||
/** Clean up the source specific data. This function will be called
|
||||
once by burn_source_free() when the last referer disposes the
|
||||
source.
|
||||
*/
|
||||
void (*free_data)(struct burn_source *);
|
||||
|
||||
|
||||
/** Next source, for when a source runs dry and padding is disabled
|
||||
THIS IS AUTOMATICALLY HANDLED, DO NOT TOUCH
|
||||
WARNING: This is an obscure feature. Set to NULL at creation and
|
||||
from then on leave untouched and uninterpreted.
|
||||
*/
|
||||
struct burn_source *next;
|
||||
|
||||
/** Source specific data */
|
||||
|
||||
/** Source specific data. Here the various source classes express their
|
||||
specific properties and the instance objects store their individual
|
||||
management data.
|
||||
E.g. data could point to a struct like this:
|
||||
struct app_burn_source
|
||||
{
|
||||
struct my_app *app_handle;
|
||||
... other individual source parameters ...
|
||||
off_t fixed_size;
|
||||
};
|
||||
|
||||
Function (*free_data) has to be prepared to clean up and free
|
||||
the struct.
|
||||
*/
|
||||
void *data;
|
||||
|
||||
|
||||
/* ts A71222 : Supposed to be binary backwards compatible extension. */
|
||||
|
||||
/** Valid only if above member .(*read)() is NULL. This indicates a
|
||||
version of struct burn_source younger than 0.
|
||||
From then on, member .version tells which further members exist
|
||||
in the memory layout of struct burn_source. libburn will only touch
|
||||
those announced extensions.
|
||||
|
||||
Versions:
|
||||
0 has .(*read)() != NULL, not even .version is present.
|
||||
1 has .version, .(*read_xt)(), .(*cancel)()
|
||||
*/
|
||||
int version;
|
||||
|
||||
/** This substitutes for (*read)() in versions above 0. */
|
||||
int (*read_xt)(struct burn_source *, unsigned char *buffer, int size);
|
||||
|
||||
/** Informs the burn_source that the consumer of data prematurely
|
||||
ended reading. This call may or may not be issued by libburn
|
||||
before (*free_data)() is called.
|
||||
*/
|
||||
int (*cancel)(struct burn_source *source);
|
||||
};
|
||||
|
||||
|
||||
@ -355,12 +482,12 @@ struct burn_drive_info
|
||||
char product[17];
|
||||
/** Revision of the drive */
|
||||
char revision[5];
|
||||
/** Location of the drive in the filesystem. */
|
||||
|
||||
/** Invalid: Was: "Location of the drive in the filesystem." */
|
||||
/** This string has no meaning any more. Once it stored the persistent
|
||||
drive address. Now always use function burn_drive_d_get_adr() to
|
||||
inquire a persistent address. ^^^^^^ ALWAYS ^^^^^^^^ */
|
||||
char location[17];
|
||||
/** This is currently the string which is used as persistent
|
||||
drive address. But be warned: there is NO GUARANTEE that this
|
||||
will stay so. Always use function burn_drive_get_adr() to
|
||||
inquire a persistent address. ^^^^^^ ALWAYS ^^^^^^ */
|
||||
|
||||
/** Can the drive read DVD-RAM discs */
|
||||
unsigned int read_dvdram:1;
|
||||
@ -515,7 +642,7 @@ struct burn_speed_descriptor {
|
||||
This must be called before using any other functions in the library. It
|
||||
may be called more than once with no effect.
|
||||
It is possible to 'restart' the library by shutting it down and
|
||||
re-initializing it. This is necessary if you follow the older and
|
||||
re-initializing it. Once this was necessary if you follow the older and
|
||||
more general way of accessing a drive via burn_drive_scan() and
|
||||
burn_drive_grab(). See burn_drive_scan_and_grab() with its strong
|
||||
urges and its explanations.
|
||||
@ -602,7 +729,8 @@ 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".
|
||||
Currently it contains: 0x15 "DVD-R/DL sequential recording",
|
||||
0x43 "BD-RE"
|
||||
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
|
||||
@ -613,31 +741,81 @@ 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
|
||||
the following API calls to form a non-obtrusive way to use libburn:
|
||||
/** 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 the following API calls to form a
|
||||
non-obtrusive way to use libburn:
|
||||
burn_drive_add_whitelist() , burn_drive_scan() , burn_drive_grab()
|
||||
You are *strongly urged* to use this call whenever you know the drive
|
||||
address in advance.
|
||||
|
||||
If not, then you have to use directly above calls. In that case, you are
|
||||
*strongly urged* to drop any unintended drive which will be exclusively
|
||||
occupied and not closed by burn_drive_scan().
|
||||
This can be done by shutting down the library including a call to
|
||||
burn_finish(). You may later start a new libburn session and should then
|
||||
use the function described here with an address obtained after
|
||||
burn_drive_scan() via burn_drive_get_adr(&(drive_infos[driveno]), adr) .
|
||||
burn_drive_scan() via burn_drive_d_get_adr(drive_infos[driveno].drive,adr).
|
||||
Another way is to drop the unwanted drives by burn_drive_info_forget().
|
||||
|
||||
Operating on multiple drives:
|
||||
|
||||
Different than with burn_drive_scan() it is allowed to call
|
||||
burn_drive_scan_and_grab() without giving up any other scanned drives. So
|
||||
this call can be used to get a collection of more than one aquired drives.
|
||||
The attempt to aquire the same drive twice will fail, though.
|
||||
|
||||
Pseudo-drives:
|
||||
|
||||
burn_drive_scan_and_grab() is able to aquire virtual drives which will
|
||||
accept options much like a MMC burner drive. Many of those options will not
|
||||
cause any effect, though. The address of a pseudo-drive begins with
|
||||
prefix "stdio:" followed by a path.
|
||||
Examples: "stdio:/tmp/pseudo_drive" , "stdio:/dev/null" , "stdio:-"
|
||||
|
||||
If the path is empty, the result is a null-drive = drive role 0.
|
||||
It pretends to have loaded no media and supports no reading or writing.
|
||||
|
||||
If the path leads to an existing regular file, or to a not yet existing
|
||||
file, or to an existing block device, then the result is a random access
|
||||
stdio-drive capable of reading and writing = drive role 2.
|
||||
|
||||
If the path leads to an existing file of any type other than directory,
|
||||
then the result is a sequential write-only stdio-drive = drive role 3.
|
||||
|
||||
The special address form "stdio:/dev/fd/<number>" is interpreted literally
|
||||
as reference to open file descriptor <number>. This address form coincides
|
||||
with real files on some systems, but it is in fact hardcoded in libburn.
|
||||
Special address "stdio:-" means stdout = "stdio:/dev/fd/1".
|
||||
The role of such a drive is determined by the file type obtained via
|
||||
fstat(<number>).
|
||||
|
||||
Roles 2 and 3 perform all their eventual data transfer activities on a file
|
||||
via standard i/o functions open(2), lseek(2), read(2), write(2), close(2).
|
||||
The media profile is reported as 0xffff. Write space information from those
|
||||
media is not necessarily realistic.
|
||||
|
||||
The capabilities of role 2 resemble DVD-RAM but it can simulate writing.
|
||||
If the path does not exist in the filesystem yet, it is attempted to create
|
||||
it as a regular file as soon as write operations are started.
|
||||
|
||||
The capabilities of role 3 resemble a blank DVD-R.
|
||||
|
||||
One may distinguish pseudo-drives from MMC drives by call
|
||||
burn_drive_get_drive_role().
|
||||
|
||||
@param drive_infos On success returns a one element array with the drive
|
||||
(cdrom/burner). Thus use with driveno 0 only. On failure
|
||||
the array has no valid elements at all.
|
||||
The returned array should be freed via burn_drive_info_free()
|
||||
when it is no longer needed, and before calling a scan
|
||||
function again.
|
||||
when it is no longer needed.
|
||||
This is a result from call burn_drive_scan(). See there.
|
||||
Use with driveno 0 only.
|
||||
@param adr The persistent address of the desired drive. Either obtained
|
||||
by burn_drive_get_adr() or guessed skillfully by application
|
||||
resp. its user.
|
||||
@param adr The persistent address of the desired drive. Either once
|
||||
obtained by burn_drive_d_get_adr() or composed skillfully by
|
||||
application resp. its user. E.g. "/dev/sr0".
|
||||
Consider to preprocess it by burn_drive_convert_fs_adr().
|
||||
@param load Nonzero to make the drive attempt to load a disc (close its
|
||||
tray door, etc).
|
||||
@return 1 = success , 0 = drive not found , -1 = other error
|
||||
@ -660,9 +838,14 @@ void burn_drive_clear_whitelist(void);
|
||||
|
||||
|
||||
/** Scan for drives. This function MUST be called until it returns nonzero.
|
||||
No drives may be in use when this is called.
|
||||
All drive pointers are invalidated by using this function. Do NOT store
|
||||
drive pointers across calls to this function or death AND pain will ensue.
|
||||
In case of re-scanning:
|
||||
All pointers to struct burn_drive and all struct burn_drive_info arrays
|
||||
are invalidated by using this function. Do NOT store drive pointers across
|
||||
calls to this function !
|
||||
To avoid invalid pointers one MUST free all burn_drive_info arrays
|
||||
by burn_drive_info_free() before calling burn_drive_scan() a second time.
|
||||
If there are drives left, then burn_drive_scan() will refuse to work.
|
||||
|
||||
After this call all drives depicted by the returned array are subject
|
||||
to eventual (O_EXCL) locking. See burn_preset_device_open(). This state
|
||||
ends either with burn_drive_info_forget() or with burn_drive_release().
|
||||
@ -709,15 +892,25 @@ void burn_drive_info_free(struct burn_drive_info drive_infos[]);
|
||||
#define BURN_DRIVE_ADR_LEN 1024
|
||||
|
||||
/** Inquire the persistent address of the given drive.
|
||||
@param drive_info The drive to inquire. Usually some &(drive_infos[driveno])
|
||||
@param drive The drive to inquire.
|
||||
@param adr An application provided array of at least BURN_DRIVE_ADR_LEN
|
||||
characters size. The persistent address gets copied to it.
|
||||
@return >0 success , <=0 error (due to libburn internal problem)
|
||||
*/
|
||||
int burn_drive_d_get_adr(struct burn_drive *drive, char adr[]);
|
||||
|
||||
/** Inquire the persistent address of a drive via a given drive_info object.
|
||||
(Note: This is a legacy call.)
|
||||
@param drive_info The drive to inquire.Usually some &(drive_infos[driveno])
|
||||
@param adr An application provided array of at least BURN_DRIVE_ADR_LEN
|
||||
characters size. The persistent address gets copied to it.
|
||||
@return >0 success , <=0 error (due to libburn internal problem)
|
||||
*/
|
||||
int burn_drive_get_adr(struct burn_drive_info *drive_info, char adr[]);
|
||||
|
||||
|
||||
/* ts A60922 ticket 33 */
|
||||
/** Evaluate wether the given address would be a possible persistent drive
|
||||
/** Evaluate whether the given address would be a possible persistent drive
|
||||
address of libburn.
|
||||
@return 1 means yes, 0 means no
|
||||
*/
|
||||
@ -756,7 +949,7 @@ int burn_drive_convert_scsi_adr(int bus_no, int host_no, int channel_no,
|
||||
/* ts A60923 - A61005 */
|
||||
/** Try to obtain bus,host,channel,target,lun from path. If there is an SCSI
|
||||
address at all, then this call should succeed with a persistent
|
||||
drive address obtained via burn_drive_get_adr(). It is also supposed to
|
||||
drive address obtained via burn_drive_d_get_adr(). It is also supposed to
|
||||
succeed with any device file of a (possibly emulated) SCSI device.
|
||||
@return 1 = success , 0 = failure , -1 = severe error
|
||||
*/
|
||||
@ -776,13 +969,25 @@ 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).
|
||||
Linux: The drive is unlocked afterwards. (O_EXCL , F_SETLK).
|
||||
Linux: The drive device file is not reserved afterwards. (O_EXCL, F_SETLK).
|
||||
@param drive The drive to release.
|
||||
@param eject Nonzero to make the drive eject the disc in it.
|
||||
*/
|
||||
void burn_drive_release(struct burn_drive *drive, int eject);
|
||||
|
||||
|
||||
/* ts A70918 */
|
||||
/** Like burn_drive_release() but keeping the drive tray closed and its
|
||||
eject button disabled. This physically locked drive state will last until
|
||||
the drive is grabbed again and released via burn_drive_release().
|
||||
Programs like eject, cdrecord, growisofs will break that ban too.
|
||||
@param drive The drive to release and leave locked.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 means success, <=0 means failure
|
||||
*/
|
||||
int burn_drive_leave_locked(struct burn_drive *d, int flag);
|
||||
|
||||
|
||||
/** Returns what kind of disc a drive is holding. This function may need to be
|
||||
called more than once to get a proper status from it. See burn_disc_status
|
||||
for details.
|
||||
@ -884,19 +1089,25 @@ off_t burn_disc_available_space(struct burn_drive *d,
|
||||
/* 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",
|
||||
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".
|
||||
libburn currently writes only to profiles
|
||||
0x09 "CD-R", 0x0a "CD-RW",
|
||||
0x11 "DVD-R sequential recording", 0x12 "DVD-RAM",
|
||||
0x13 "DVD-RW restricted overwrite", 0x14 "DVD-RW sequential recording",
|
||||
0x1a "DVD+RW", 0x1b "DVD+R"
|
||||
0x2b "DVD+R/DL"
|
||||
If enabled by burn_allow_untested_profiles() it also writes to profiles
|
||||
0x15 "DVD-R/DL sequential recording", 0x43 "BD-RE".
|
||||
Writeable stdio-drives return this profile:
|
||||
0xffff "stdio file"
|
||||
@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)
|
||||
@param name Profile Name (see above list, unknown profiles have empty name)
|
||||
@return 1 profile is valid, 0 no profile info available
|
||||
*/
|
||||
int burn_disc_get_profile(struct burn_drive *d, int *pno, char name[80]);
|
||||
|
||||
/** Tells whether a disc can be erased or not
|
||||
@param d The drive to inquire.
|
||||
@return Non-zero means erasable
|
||||
*/
|
||||
int burn_disc_erasable(struct burn_drive *d);
|
||||
@ -916,6 +1127,15 @@ enum burn_drive_status burn_drive_get_status(struct burn_drive *drive,
|
||||
*/
|
||||
struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive);
|
||||
|
||||
|
||||
/* ts A70901 */
|
||||
/** Inquires the drive associated with a burn_write_opts object.
|
||||
@param opts object to inquire
|
||||
@return pointer to drive
|
||||
*/
|
||||
struct burn_drive *burn_write_opts_get_drive(struct burn_write_opts *opts);
|
||||
|
||||
|
||||
/** Frees a write_opts struct created with burn_write_opts_new
|
||||
@param opts write_opts to free
|
||||
*/
|
||||
@ -1036,7 +1256,7 @@ void burn_disc_read(struct burn_drive *drive, const struct burn_read_opts *o);
|
||||
|
||||
|
||||
/* ts A70219 */
|
||||
/** Examines a completed setup for burn_disc_write() wether it is permissible
|
||||
/** Examines a completed setup for burn_disc_write() whether 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.
|
||||
@ -1048,9 +1268,6 @@ void burn_disc_read(struct burn_drive *drive, const struct burn_read_opts *o);
|
||||
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
|
||||
@ -1058,6 +1275,9 @@ int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
|
||||
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().
|
||||
Note: This function is not suitable for overwriting data in the middle of
|
||||
a valid data area because it is allowed to append trailing data.
|
||||
For exact random access overwriting use burn_random_access_write().
|
||||
@param o The options for the writing operation.
|
||||
@param disc The struct burn_disc * that described the disc to be created
|
||||
*/
|
||||
@ -1072,7 +1292,7 @@ void burn_drive_cancel(struct burn_drive *drive);
|
||||
|
||||
|
||||
/* ts A61223 */
|
||||
/** Inquire wether the most recent write run was successful. Reasons for
|
||||
/** Inquire whether the most recent write run was successful. Reasons for
|
||||
non-success may be: rejection of burn parameters, abort during fatal errors
|
||||
during write, a call to burn_drive_cancel() by the application thread.
|
||||
@param d The drive to inquire.
|
||||
@ -1113,7 +1333,9 @@ int burn_msf_to_lba(int m, int s, int f);
|
||||
*/
|
||||
void burn_lba_to_msf(int lba, int *m, int *s, int *f);
|
||||
|
||||
/** Create a new disc */
|
||||
/** Create a new disc
|
||||
@return Pointer to a burn_disc object or NULL on failure.
|
||||
*/
|
||||
struct burn_disc *burn_disc_create(void);
|
||||
|
||||
/** Delete disc and decrease the reference count on all its sessions
|
||||
@ -1121,7 +1343,9 @@ struct burn_disc *burn_disc_create(void);
|
||||
*/
|
||||
void burn_disc_free(struct burn_disc *d);
|
||||
|
||||
/** Create a new session */
|
||||
/** Create a new session
|
||||
@return Pointer to a burn_session object or NULL on failure.
|
||||
*/
|
||||
struct burn_session *burn_session_create(void);
|
||||
|
||||
/** Free a session (and decrease reference count on all tracks inside)
|
||||
@ -1185,7 +1409,7 @@ void burn_track_define_data(struct burn_track *t, int offset, int tail,
|
||||
|
||||
|
||||
/* ts A61024 */
|
||||
/** Define wether a track shall swap bytes of its input stream.
|
||||
/** Define whether a track shall swap bytes of its input stream.
|
||||
@param t The track to change
|
||||
@param swap_source_bytes 0=do not swap, 1=swap byte pairs
|
||||
@return 1=success , 0=unacceptable value
|
||||
@ -1250,7 +1474,12 @@ int burn_track_set_default_size(struct burn_track *t, off_t size);
|
||||
*/
|
||||
void burn_source_free(struct burn_source *s);
|
||||
|
||||
/** Creates a data source for an image file (and maybe subcode file) */
|
||||
/** Creates a data source for an image file (and maybe subcode file)
|
||||
@param path The file address for the main channel payload.
|
||||
@param subpath Eventual address for subchannel data. Only used in exotic
|
||||
raw write modes. Submit NULL for normal tasks.
|
||||
@return Pointer to a burn_source object, NULL indicates failure
|
||||
*/
|
||||
struct burn_source *burn_file_source_new(const char *path,
|
||||
const char *subpath);
|
||||
|
||||
@ -1258,17 +1487,74 @@ struct burn_source *burn_file_source_new(const char *path,
|
||||
readable filedescriptor, an eventually open readable subcodes file
|
||||
descriptor and eventually a fixed size in bytes.
|
||||
@param datafd The source of data.
|
||||
@param subfd The eventual source for subcodes. Not used if -1.
|
||||
@param subfd The eventual source of subchannel data. Only used in exotic
|
||||
raw write modes. Submit -1 for normal tasks.
|
||||
@param size The eventual fixed size of eventually both fds.
|
||||
If this value is 0, the size will be determined from datafd.
|
||||
@return Pointer to a burn_source object, NULL indicates failure
|
||||
*/
|
||||
struct burn_source *burn_fd_source_new(int datafd, int subfd, off_t size);
|
||||
|
||||
|
||||
/* ts A70930 */
|
||||
/** Creates a fifo which acts as proxy for an already existing data source.
|
||||
The fifo provides a ring buffer which shall smoothen the data stream
|
||||
between burn_source and writer thread. Each fifo serves only for one
|
||||
data source and gets attached to one track as its only data source
|
||||
by burn_track_set_source().
|
||||
A fifo starts its life in "standby" mode with no buffer space allocated.
|
||||
As soon as its track requires bytes, the fifo establishes a worker thread
|
||||
and allocates its buffer. After input has ended and all buffer content is
|
||||
consumed, the buffer space gets freed and the worker thread ends.
|
||||
This happens asynchronously. So expect two buffers and worker threads to
|
||||
exist for a short time between tracks. Be modest in your size demands if
|
||||
multiple tracks are to be expected.
|
||||
@param inp The burn_source for which the fifo shall act as proxy.
|
||||
It can be disposed by burn_source_free() immediately
|
||||
after this call.
|
||||
@param chunksize The size in bytes of a chunk. Use 2048 for sources
|
||||
suitable for BURN_BLOCK_MODE1 and 2352 for sources
|
||||
which deliver for BURN_BLOCK_AUDIO.
|
||||
Some variations of burn_source might work only with
|
||||
a particular chunksize. E.g. libisofs demands 2048.
|
||||
@param chunks The number of chunks to be allocated in ring buffer.
|
||||
This value must be >= 2.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0).
|
||||
@return A pointer to the newly created burn_source.
|
||||
Later both burn_sources, inp and the returned fifo, have
|
||||
to be disposed by calling burn_source_free() for each.
|
||||
inp can be freed immediately, the returned fifo may be
|
||||
kept as handle for burn_fifo_inquire_status().
|
||||
*/
|
||||
struct burn_source *burn_fifo_source_new(struct burn_source *inp,
|
||||
int chunksize, int chunks, int flag);
|
||||
|
||||
/* ts A71003 */
|
||||
/** Inquires state and fill parameters of a fifo burn_source which was created
|
||||
by burn_fifo_source_new() . Do not use with other burn_source variants.
|
||||
@param fifo The fifo object to inquire
|
||||
@param size The total size of the fifo
|
||||
@param free_bytes The current free capacity of the fifo
|
||||
@param status_text Returns a pointer to a constant text, see below
|
||||
@return <0 reply invalid, >=0 fifo status code:
|
||||
bit0+1=input status, bit2=consumption status, i.e:
|
||||
0="standby" : data processing not started yet
|
||||
1="active" : input and consumption are active
|
||||
2="ending" : input has ended without error
|
||||
3="failing" : input had error and ended,
|
||||
4="unused" : ( consumption has ended before processing start )
|
||||
5="abandoned" : consumption has ended prematurely
|
||||
6="ended" : consumption has ended without input error
|
||||
7="aborted" : consumption has ended after input error
|
||||
*/
|
||||
int burn_fifo_inquire_status(struct burn_source *fifo, int *size,
|
||||
int *free_bytes, char **status_text);
|
||||
|
||||
|
||||
/* ts A70328 */
|
||||
/** Sets a fixed track size after the data source object has already been
|
||||
created.
|
||||
@param t The track to poperate on
|
||||
@param t The track to operate on
|
||||
@param size the number of bytes to use as track size
|
||||
@return <=0 indicates failure , >0 success
|
||||
*/
|
||||
@ -1303,7 +1589,7 @@ void burn_drive_set_speed(struct burn_drive *d, int read, int write);
|
||||
be full. To check and wait for enough free buffer space before writing
|
||||
will move the task of waiting from the operating system's device driver
|
||||
to libburn. While writing is going on and waiting is enabled, any write
|
||||
operation will be checked wether it will fill the drive buffer up to
|
||||
operation will be checked whether it will fill the drive buffer up to
|
||||
more than max_percent. If so, then waiting will happen until the buffer
|
||||
fill is predicted with at most min_percent.
|
||||
Thus: if min_percent < max_percent then transfer rate will oscillate.
|
||||
@ -1386,9 +1672,19 @@ void burn_write_opts_set_toc_entries(struct burn_write_opts *opts,
|
||||
*/
|
||||
void burn_write_opts_set_format(struct burn_write_opts *opts, int format);
|
||||
|
||||
/** Sets the simulate value for the write_opts struct
|
||||
/** Sets the simulate value for the write_opts struct .
|
||||
This corresponds to the Test Write bit in MMC mode page 05h. Several media
|
||||
types do not support this. See struct burn_multi_caps.might_simulate for
|
||||
actual availability of this feature.
|
||||
If the media is suitable, the drive will perform burn_write_disc() as a
|
||||
simulation instead of effective write operations. This means that the
|
||||
media content and burn_disc_get_status() stay unchanged.
|
||||
Note: With stdio-drives, the target file gets eventually created, opened,
|
||||
lseeked, and closed, but not written. So there are effects on it.
|
||||
Warning: Call burn_random_access_write() will never do simulation because
|
||||
it does not get any burn_write_opts.
|
||||
@param opts The write opts to change
|
||||
@param sim If non-zero, the drive will perform a simulation instead of a burn
|
||||
@param sim Non-zero enables simulation, 0 enables real writing
|
||||
@return Returns 1 on success and 0 on failure.
|
||||
*/
|
||||
int burn_write_opts_set_simulate(struct burn_write_opts *opts, int sim);
|
||||
@ -1417,6 +1713,7 @@ void burn_write_opts_set_mediacatalog(struct burn_write_opts *opts, unsigned cha
|
||||
/* ts A61106 */
|
||||
/** Sets the multi flag which eventually marks the emerging session as not
|
||||
being the last one and thus creating a BURN_DISC_APPENDABLE media.
|
||||
@param opts The option object to be manipulated
|
||||
@param multi 1=media will be appendable, 0=media will be closed (default)
|
||||
*/
|
||||
void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi);
|
||||
@ -1424,11 +1721,14 @@ void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi);
|
||||
|
||||
/* ts A61222 */
|
||||
/** Sets a start address for writing to media and write modes which allow to
|
||||
choose this address at all (DVD+RW, DVD-RAM, formatted DVD-RW only for
|
||||
choose this address at all (for now: DVD+RW, DVD-RAM, formatted DVD-RW).
|
||||
now). The address is given in bytes. If it is not -1 then a write run
|
||||
will fail if choice of start address is not supported or if the block
|
||||
alignment of the address is not suitable for media and write mode.
|
||||
(Alignment to 32 kB blocks is advised with DVD media.)
|
||||
Alignment to 32 kB blocks is supposed to be safe with DVD media.
|
||||
Call burn_disc_get_multi_caps() can obtain the necessary media info. See
|
||||
resulting struct burn_multi_caps elements .start_adr , .start_alignment ,
|
||||
.start_range_low , .start_range_high .
|
||||
@param opts The write opts to change
|
||||
@param value The address in bytes (-1 = start at default address)
|
||||
*/
|
||||
@ -1439,7 +1739,7 @@ void burn_write_opts_set_start_byte(struct burn_write_opts *opts, off_t value);
|
||||
/** 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
|
||||
Controls whether 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
|
||||
@ -1450,8 +1750,8 @@ void burn_write_opts_set_fillup(struct burn_write_opts *opts,
|
||||
|
||||
/* ts A70303 */
|
||||
/** Eventually makes libburn ignore the failure of some conformance checks:
|
||||
- the check wether CD write+block type is supported by the drive
|
||||
- the check wether the media profile supports simulated burning
|
||||
- the check whether CD write+block type is supported by the drive
|
||||
- the check whether the media profile supports simulated burning
|
||||
@param opts The write opts to change
|
||||
@param use_force 1=ignore above checks, 0=refuse work on failed check
|
||||
*/
|
||||
@ -1558,7 +1858,7 @@ int burn_drive_get_speedlist(struct burn_drive *d,
|
||||
/** Look up the fastest speed descriptor which is not faster than the given
|
||||
speed_goal. If it is 0, then the fastest one is chosen among the
|
||||
descriptors with the highest end_lba. If it is -1 then the slowest speed
|
||||
descriptor is chosen regardless of end_lba. Parameter flag decides wether
|
||||
descriptor is chosen regardless of end_lba. Parameter flag decides whether
|
||||
the speed goal means write speed or read speed.
|
||||
@param d Drive to query
|
||||
@param speed_goal Upper limit for speed,
|
||||
@ -1737,7 +2037,9 @@ int burn_track_get_mode(struct burn_track *track);
|
||||
*/
|
||||
int burn_session_get_hidefirst(struct burn_session *session);
|
||||
|
||||
/** Returns the library's version in its parts
|
||||
/** Returns the library's version in its parts.
|
||||
This is the runtime counterpart of the three build time macros
|
||||
burn_header_version_* below.
|
||||
@param major The major version number
|
||||
@param minor The minor version number
|
||||
@param micro The micro version number
|
||||
@ -1745,10 +2047,80 @@ int burn_session_get_hidefirst(struct burn_session *session);
|
||||
void burn_version(int *major, int *minor, int *micro);
|
||||
|
||||
|
||||
/* ts A80129 */
|
||||
/** These three release version numbers tell the revision of this header file
|
||||
and of the API it describes. They are memorized by applications at build
|
||||
time.
|
||||
Immediately after burn_initialize() an application should do this check:
|
||||
burn_version(&major, &minor, µ);
|
||||
if(major > burn_header_version_major
|
||||
|| (major == burn_header_version_major
|
||||
&& (minor > burn_header_version_minor
|
||||
|| (minor == burn_header_version_minor
|
||||
&& micro >= burn_header_version_micro)))) {
|
||||
... Young enough. Go on with program run ....
|
||||
} else {
|
||||
... Too old. Do not use this libburn version ...
|
||||
}
|
||||
|
||||
*/
|
||||
#define burn_header_version_major 0
|
||||
#define burn_header_version_minor 4
|
||||
#define burn_header_version_micro 4
|
||||
/** Note:
|
||||
Above version numbers are also recorded in configure.ac because libtool
|
||||
wants them as parameters at build time.
|
||||
For the library compatibility check BURN_*_VERSION in configure.ac
|
||||
are not decisive. Only the three numbers above do matter.
|
||||
*/
|
||||
/** Usage discussion:
|
||||
|
||||
Some developers of the libburnia project have differing
|
||||
opinions how to ensure the compatibility of libaries
|
||||
and applications.
|
||||
|
||||
It is about whether to use at compile time and at runtime
|
||||
the version numbers isoburn_header_version_* provided here.
|
||||
Thomas Schmitt advises to use them.
|
||||
Vreixo Formoso advises to use other means.
|
||||
|
||||
At compile time:
|
||||
|
||||
Vreixo Formoso advises to leave proper version matching
|
||||
to properly programmed checks in the the application's
|
||||
build system, which will eventually refuse compilation.
|
||||
|
||||
Thomas Schmitt advises to use the macros defined here
|
||||
for comparison with the application's requirements of
|
||||
library revisions and to eventually break compilation.
|
||||
|
||||
Both advises are combinable. I.e. be master of your
|
||||
build system and have #if checks in the source code
|
||||
of your application, nevertheless.
|
||||
|
||||
At runtime (via *_is_compatible()):
|
||||
|
||||
Vreixo Formoso advises to compare the application's
|
||||
requirements of library revisions with the runtime
|
||||
library. This is to allow runtime libraries which are
|
||||
young enough for the application but too old for
|
||||
the lib*.h files seen at compile time.
|
||||
|
||||
Thomas Schmitt advises to compare the header
|
||||
revisions defined here with the runtime library.
|
||||
This is to enforce a strictly monotonous chain
|
||||
of revisions from app to header to library,
|
||||
at the cost of excluding some older libraries.
|
||||
|
||||
These two advises are mutually exclusive.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* ts A60924 : ticket 74 */
|
||||
/** Control queueing and stderr printing of messages from libburn.
|
||||
Severity may be one of "NEVER", "FATAL", "SORRY", "WARNING", "HINT",
|
||||
"NOTE", "UPDATE", "DEBUG", "ALL".
|
||||
Severity may be one of "NEVER", "ABORT", "FATAL", "FAILURE", "SORRY",
|
||||
"WARNING", "HINT", "NOTE", "UPDATE", "DEBUG", "ALL".
|
||||
@param queue_severity Gives the minimum limit for messages to be queued.
|
||||
Default: "NEVER". If you queue messages then you
|
||||
must consume them by burn_msgs_obtain().
|
||||
@ -1767,8 +2139,9 @@ int burn_msgs_set_severities(char *queue_severity,
|
||||
/** Obtain the oldest pending libburn message from the queue which has at
|
||||
least the given minimum_severity. This message and any older message of
|
||||
lower severity will get discarded from the queue and is then lost forever.
|
||||
@param minimum_severity may be one of "NEVER", "FATAL", "SORRY",
|
||||
"WARNING", "HINT", "NOTE", "UPDATE", "DEBUG", "ALL".
|
||||
@param minimum_severity may be one of "NEVER", "ABORT", "FATAL",
|
||||
"FAILURE", "SORRY", "WARNING", "HINT", "NOTE", "UPDATE",
|
||||
"DEBUG", "ALL".
|
||||
To call with minimum_severity "NEVER" will discard the
|
||||
whole queue.
|
||||
@param error_code Will become a unique error code as liste in
|
||||
@ -1784,8 +2157,60 @@ int burn_msgs_obtain(char *minimum_severity,
|
||||
char severity[]);
|
||||
|
||||
|
||||
/* ts A70922 */
|
||||
/** Submit a message to the libburn queueing system. It will be queued or
|
||||
printed as if it was generated by libburn itself.
|
||||
@param error_code The unique error code of your message.
|
||||
Submit 0 if you do not have reserved error codes within
|
||||
the libburnia project.
|
||||
@param msg_text Not more than BURN_MSGS_MESSAGE_LEN characters of
|
||||
message text.
|
||||
@param os_errno Eventual errno related to the message. Submit 0 if
|
||||
the message is not related to a operating system error.
|
||||
@param severity One of "ABORT", "FATAL", "FAILURE", "SORRY", "WARNING",
|
||||
"HINT", "NOTE", "UPDATE", "DEBUG". Defaults to "FATAL".
|
||||
@param d An eventual drive to which the message shall be related.
|
||||
Submit NULL if the message is not specific to a
|
||||
particular drive object.
|
||||
@return 1 if message was delivered, <=0 if failure
|
||||
*/
|
||||
int burn_msgs_submit(int error_code, char msg_text[], int os_errno,
|
||||
char severity[], struct burn_drive *d);
|
||||
|
||||
|
||||
/* ts A71016 */
|
||||
/** Convert a severity name into a severity number, which gives the severity
|
||||
rank of the name.
|
||||
@param severity_name A name as with burn_msgs_submit(), e.g. "SORRY".
|
||||
@param severity_number The rank number: the higher, the more severe.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return >0 success, <=0 failure
|
||||
*/
|
||||
int burn_text_to_sev(char *severity_name, int *severity_number, int flag);
|
||||
|
||||
|
||||
/* ts A80202 : @since 0.4.4 */
|
||||
/** Convert a severity number into a severity name
|
||||
@param severity_number The rank number: the higher, the more severe.
|
||||
@param severity_name A name as with burn_msgs_submit(), e.g. "SORRY".
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
*/
|
||||
int burn_sev_to_text(int severity_number, char **severity_name, int flag);
|
||||
|
||||
|
||||
|
||||
/* ts A70915 */
|
||||
/** Replace the messenger object handle of libburn by a compatible handle
|
||||
obtained from a related library.
|
||||
See also: libisofs, API function iso_get_messenger().
|
||||
@param messenger The foreign but compatible message handle.
|
||||
@return 1 : success, <=0 : failure
|
||||
*/
|
||||
int burn_set_messenger(void *messenger);
|
||||
|
||||
|
||||
/* ts A61002 */
|
||||
/* The prototype of a handler function suitable for burn_set_abort_handling().
|
||||
/** The prototype of a handler function suitable for burn_set_abort_handling().
|
||||
Such a function has to return -2 if it does not want the process to
|
||||
exit with value 1.
|
||||
*/
|
||||
@ -1807,6 +2232,102 @@ typedef int (*burn_abort_handler_t)(void *handle, int signum, int flag);
|
||||
void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
|
||||
int mode);
|
||||
|
||||
|
||||
/* ts A70811 */
|
||||
/** Write data in random access mode.
|
||||
The drive must be grabbed successfully before calling this function which
|
||||
circumvents usual libburn session processing and rather writes data without
|
||||
preparations or finalizing. This will work only with overwriteable media
|
||||
which are also suitable for burn_write_opts_set_start_byte(). The same
|
||||
address alignment restrictions as with this function apply. I.e. for DVD
|
||||
it is best to align to 32 KiB blocks (= 16 LBA units). The amount of data
|
||||
to be written is subject to the same media dependent alignment rules.
|
||||
Again, 32 KiB is most safe.
|
||||
Call burn_disc_get_multi_caps() can obtain the necessary media info. See
|
||||
resulting struct burn_multi_caps elements .start_adr , .start_alignment ,
|
||||
.start_range_low , .start_range_high .
|
||||
Other than burn_disc_write() this is a synchronous call which returns
|
||||
only after the write transaction has ended (sucessfully or not). So it is
|
||||
wise not to transfer giant amounts of data in a single call.
|
||||
Important: Data have to fit into the already formatted area of the media.
|
||||
@param d The drive to which to write
|
||||
@param byte_address The start address of the write in byte
|
||||
(1 LBA unit = 2048 bytes) (do respect media alignment)
|
||||
@param data The bytes to be written
|
||||
@param data_count The number of those bytes (do respect media alignment)
|
||||
data_count == 0 is permitted (e.g. to flush the
|
||||
drive buffer without further data transfer).
|
||||
@param flag Bitfield for control purposes:
|
||||
bit0 = flush the drive buffer after eventual writing
|
||||
@return 1=sucessful , <=0 : number of transfered bytes * -1
|
||||
*/
|
||||
int burn_random_access_write(struct burn_drive *d, off_t byte_address,
|
||||
char *data, off_t data_count, int flag);
|
||||
|
||||
|
||||
/* ts A70812 */
|
||||
/** Read data in random access mode.
|
||||
The drive must be grabbed successfully before calling this function.
|
||||
With all currently supported drives and media the byte_address has to
|
||||
be aligned to 2048 bytes. Only data tracks with 2048 bytes per sector
|
||||
can be read this way. I.e. not CD-audio, not CD-video-stream ...
|
||||
This is a synchronous call which returns only after the full read job
|
||||
has ended (sucessfully or not). So it is wise not to read giant amounts
|
||||
of data in a single call.
|
||||
@param d The drive to which to write
|
||||
@param byte_address The start address of the read in byte (aligned to 2048)
|
||||
@param data A memory buffer capable of taking data_size bytes
|
||||
@param data_size The amount of data to be read. This does not have to
|
||||
be aligned to any block size.
|
||||
@param data_count The amount of data actually read (interesting on error)
|
||||
@param flag Bitfield for control purposes:
|
||||
bit0= - reserved -
|
||||
bit1= do not submit error message if read error
|
||||
@return 1=sucessful , <=0 an error occured
|
||||
*/
|
||||
int burn_read_data(struct burn_drive *d, off_t byte_address,
|
||||
char data[], off_t data_size, off_t *data_count, int flag);
|
||||
|
||||
|
||||
/* A70904 */
|
||||
/** Inquire whether the drive object is a real MMC drive or a pseudo-drive
|
||||
created by a stdio: address.
|
||||
@param d The drive to inquire
|
||||
@return 0= null-drive
|
||||
1= real MMC drive
|
||||
2= stdio-drive, random access, read-write
|
||||
3= stdio-drive, sequential, write-only
|
||||
*/
|
||||
int burn_drive_get_drive_role(struct burn_drive *d);
|
||||
|
||||
|
||||
/* ts A70923 */
|
||||
/** Find out whether a given address string would lead to the given drive
|
||||
object. This should be done in advance for track source addresses
|
||||
with parameter drive_role set to 2.
|
||||
Although a real MMC drive should hardly exist as two drive objects at
|
||||
the same time, this can easily happen with stdio-drives. So if more than
|
||||
one drive is used by the application, then this gesture is advised:
|
||||
burn_drive_d_get_adr(d2, adr2);
|
||||
if (burn_drive_equals_adr(d1, adr2, burn_drive_get_drive_role(d2)))
|
||||
... Both drive objects point to the same storage facility ...
|
||||
|
||||
@param d1 Existing drive object
|
||||
@param adr2 Address string to be tested. Prefix "stdio:" overrides
|
||||
parameter drive_role2 by either 0 or 2 as appropriate.
|
||||
The string must be shorter than BURN_DRIVE_ADR_LEN.
|
||||
@param drive_role2 Role as burn_drive_get_drive_role() would attribute
|
||||
to adr2 if it was a drive. Use value 2 for checking track
|
||||
sources resp. pseudo-drive addresses without "stdio:".
|
||||
Use 1 for checking drive addresses including those with
|
||||
prefix "stdio:".
|
||||
@return 1= adr2 leads to d1 , 0= adr2 seems not to lead to d1,
|
||||
-1 = adr2 is bad
|
||||
*/
|
||||
int burn_drive_equals_adr(struct burn_drive *d1, char *adr2, int drive_role2);
|
||||
|
||||
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
BURN_END_DECLS
|
||||
|
@ -34,7 +34,7 @@ int libdax_audioxtr_new(struct libdax_audioxtr **xtr, char *path, int flag)
|
||||
if(o==NULL)
|
||||
return(-1);
|
||||
strncpy(o->path,path,LIBDAX_AUDIOXTR_STRLEN-1);
|
||||
o->path[LIBDAX_AUDIOXTR_STRLEN]= 0;
|
||||
o->path[LIBDAX_AUDIOXTR_STRLEN-1]= 0;
|
||||
o->fd= -1;
|
||||
strcpy(o->fmt,"unidentified");
|
||||
o->fmt_info[0]= 0;
|
||||
|
@ -1,7 +1,8 @@
|
||||
|
||||
/* libdax_msgs
|
||||
Message handling facility of libdax.
|
||||
Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net>, provided under GPL
|
||||
Copyright (C) 2006 - 2008 Thomas Schmitt <scdbackup@gmx.net>,
|
||||
provided under GPL version 2
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -39,7 +40,7 @@ static int libdax_msgs_item_new(struct libdax_msgs_item **item,
|
||||
if(ret==0)
|
||||
o->timestamp= tv.tv_sec+0.000001*tv.tv_usec;
|
||||
o->process_id= getpid();
|
||||
o->driveno= -1;
|
||||
o->origin= -1;
|
||||
o->severity= LIBDAX_MSGS_SEV_ALL;
|
||||
o->priority= LIBDAX_MSGS_PRIO_ZERO;
|
||||
o->error_code= 0;
|
||||
@ -108,12 +109,12 @@ int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
|
||||
|
||||
|
||||
int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
|
||||
double *timestamp, pid_t *process_id, int *driveno,
|
||||
double *timestamp, pid_t *process_id, int *origin,
|
||||
int flag)
|
||||
{
|
||||
*timestamp= item->timestamp;
|
||||
*process_id= item->process_id;
|
||||
*driveno= item->driveno;
|
||||
*origin= item->origin;
|
||||
return(1);
|
||||
}
|
||||
|
||||
@ -137,6 +138,7 @@ int libdax_msgs_new(struct libdax_msgs **m, int flag)
|
||||
(*m)= o= (struct libdax_msgs *) malloc(sizeof(struct libdax_msgs));
|
||||
if(o==NULL)
|
||||
return(-1);
|
||||
o->refcount= 1;
|
||||
o->oldest= NULL;
|
||||
o->youngest= NULL;
|
||||
o->count= 0;
|
||||
@ -152,43 +154,6 @@ int libdax_msgs_new(struct libdax_msgs **m, int flag)
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_destroy(struct libdax_msgs **m, int flag)
|
||||
{
|
||||
struct libdax_msgs *o;
|
||||
struct libdax_msgs_item *item, *next_item;
|
||||
|
||||
o= *m;
|
||||
if(o==NULL)
|
||||
return(0);
|
||||
|
||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
||||
if(pthread_mutex_destroy(&(o->lock_mutex))!=0) {
|
||||
pthread_mutex_unlock(&(o->lock_mutex));
|
||||
pthread_mutex_destroy(&(o->lock_mutex));
|
||||
}
|
||||
#endif
|
||||
|
||||
for(item= o->oldest; item!=NULL; item= next_item) {
|
||||
next_item= item->next;
|
||||
libdax_msgs_item_destroy(&item,0);
|
||||
}
|
||||
free((char *) o);
|
||||
*m= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
|
||||
int print_severity, char *print_id, int flag)
|
||||
{
|
||||
m->queue_severity= queue_severity;
|
||||
m->print_severity= print_severity;
|
||||
strncpy(m->print_id,print_id,80);
|
||||
m->print_id[80]= 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int libdax_msgs_lock(struct libdax_msgs *m, int flag)
|
||||
{
|
||||
|
||||
@ -219,6 +184,65 @@ static int libdax_msgs_unlock(struct libdax_msgs *m, int flag)
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_destroy(struct libdax_msgs **m, int flag)
|
||||
{
|
||||
struct libdax_msgs *o;
|
||||
struct libdax_msgs_item *item, *next_item;
|
||||
|
||||
o= *m;
|
||||
if(o==NULL)
|
||||
return(0);
|
||||
if(o->refcount > 1) {
|
||||
if(libdax_msgs_lock(*m,0)<=0)
|
||||
return(-1);
|
||||
o->refcount--;
|
||||
libdax_msgs_unlock(*m,0);
|
||||
*m= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
#ifndef LIBDAX_MSGS_SINGLE_THREADED
|
||||
if(pthread_mutex_destroy(&(o->lock_mutex))!=0) {
|
||||
pthread_mutex_unlock(&(o->lock_mutex));
|
||||
pthread_mutex_destroy(&(o->lock_mutex));
|
||||
}
|
||||
#endif
|
||||
|
||||
for(item= o->oldest; item!=NULL; item= next_item) {
|
||||
next_item= item->next;
|
||||
libdax_msgs_item_destroy(&item,0);
|
||||
}
|
||||
free((char *) o);
|
||||
*m= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_refer(struct libdax_msgs **pt, struct libdax_msgs *m, int flag)
|
||||
{
|
||||
if(libdax_msgs_lock(m,0)<=0)
|
||||
return(0);
|
||||
m->refcount++;
|
||||
*pt= m;
|
||||
libdax_msgs_unlock(m,0);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_set_severities(struct libdax_msgs *m, int queue_severity,
|
||||
int print_severity, char *print_id, int flag)
|
||||
{
|
||||
if(libdax_msgs_lock(m,0)<=0)
|
||||
return(0);
|
||||
m->queue_severity= queue_severity;
|
||||
m->print_severity= print_severity;
|
||||
strncpy(m->print_id,print_id,80);
|
||||
m->print_id[80]= 0;
|
||||
libdax_msgs_unlock(m,0);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs__text_to_sev(char *severity_name, int *severity,
|
||||
int flag)
|
||||
{
|
||||
@ -228,6 +252,10 @@ int libdax_msgs__text_to_sev(char *severity_name, int *severity,
|
||||
*severity= LIBDAX_MSGS_SEV_ABORT;
|
||||
else if(strncmp(severity_name,"FATAL",5)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_FATAL;
|
||||
else if(strncmp(severity_name,"FAILURE",7)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_FAILURE;
|
||||
else if(strncmp(severity_name,"MISHAP",6)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_MISHAP;
|
||||
else if(strncmp(severity_name,"SORRY",5)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_SORRY;
|
||||
else if(strncmp(severity_name,"WARNING",7)==0)
|
||||
@ -240,10 +268,12 @@ int libdax_msgs__text_to_sev(char *severity_name, int *severity,
|
||||
*severity= LIBDAX_MSGS_SEV_UPDATE;
|
||||
else if(strncmp(severity_name,"DEBUG",5)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_DEBUG;
|
||||
else if(strncmp(severity_name,"ERRFILE",7)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_ERRFILE;
|
||||
else if(strncmp(severity_name,"ALL",3)==0)
|
||||
*severity= LIBDAX_MSGS_SEV_ALL;
|
||||
else {
|
||||
*severity= LIBDAX_MSGS_SEV_NEVER;
|
||||
*severity= LIBDAX_MSGS_SEV_ALL;
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
@ -254,8 +284,7 @@ int libdax_msgs__sev_to_text(int severity, char **severity_name,
|
||||
int flag)
|
||||
{
|
||||
if(flag&1) {
|
||||
*severity_name=
|
||||
"NEVER\nABORT\nFATAL\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nALL";
|
||||
*severity_name= "NEVER\nABORT\nFATAL\nFAILURE\nMISHAP\nSORRY\nWARNING\nHINT\nNOTE\nUPDATE\nDEBUG\nERRFILE\nALL";
|
||||
return(1);
|
||||
}
|
||||
*severity_name= "";
|
||||
@ -265,6 +294,10 @@ int libdax_msgs__sev_to_text(int severity, char **severity_name,
|
||||
*severity_name= "ABORT";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_FATAL)
|
||||
*severity_name= "FATAL";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_FAILURE)
|
||||
*severity_name= "FAILURE";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_MISHAP)
|
||||
*severity_name= "MISHAP";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_SORRY)
|
||||
*severity_name= "SORRY";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_WARNING)
|
||||
@ -277,6 +310,8 @@ int libdax_msgs__sev_to_text(int severity, char **severity_name,
|
||||
*severity_name= "UPDATE";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_DEBUG)
|
||||
*severity_name= "DEBUG";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_ERRFILE)
|
||||
*severity_name= "ERRFILE";
|
||||
else if(severity>=LIBDAX_MSGS_SEV_ALL)
|
||||
*severity_name= "ALL";
|
||||
else {
|
||||
@ -287,7 +322,7 @@ int libdax_msgs__sev_to_text(int severity, char **severity_name,
|
||||
}
|
||||
|
||||
|
||||
int libdax_msgs_submit(struct libdax_msgs *m, int driveno, int error_code,
|
||||
int libdax_msgs_submit(struct libdax_msgs *m, int origin, int error_code,
|
||||
int severity, int priority, char *msg_text,
|
||||
int os_errno, int flag)
|
||||
{
|
||||
@ -325,7 +360,7 @@ int libdax_msgs_submit(struct libdax_msgs *m, int driveno, int error_code,
|
||||
ret= libdax_msgs_item_new(&item,m->youngest,0);
|
||||
if(ret<=0)
|
||||
goto failed;
|
||||
item->driveno= driveno;
|
||||
item->origin= origin;
|
||||
item->error_code= error_code;
|
||||
item->severity= severity;
|
||||
item->priority= priority;
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
/* libdax_msgs
|
||||
Message handling facility of libdax.
|
||||
Copyright (C) 2006-2007 Thomas Schmitt <scdbackup@gmx.net>,
|
||||
provided under GPL
|
||||
Copyright (C) 2006-2008 Thomas Schmitt <scdbackup@gmx.net>,
|
||||
provided under GPL version 2
|
||||
*/
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ struct libdax_msgs_item {
|
||||
|
||||
double timestamp;
|
||||
pid_t process_id;
|
||||
int driveno;
|
||||
int origin;
|
||||
|
||||
int severity;
|
||||
int priority;
|
||||
@ -43,6 +43,8 @@ struct libdax_msgs_item {
|
||||
|
||||
struct libdax_msgs {
|
||||
|
||||
int refcount;
|
||||
|
||||
struct libdax_msgs_item *oldest;
|
||||
struct libdax_msgs_item *youngest;
|
||||
int count;
|
||||
@ -68,6 +70,31 @@ struct libdax_msgs {
|
||||
#ifndef LIBDAX_MSGS_H_INTERNAL
|
||||
|
||||
|
||||
/* Architectural aspects */
|
||||
/*
|
||||
libdax_msgs is designed to serve in libraries which want to offer their
|
||||
applications a way to control the output of library messages. It shall be
|
||||
incorporated by an owner, i.e. a software entity which encloses the code
|
||||
of the .c file.
|
||||
|
||||
Owner of libdax_msgs is libburn. A fully compatible variant named libiso_msgs
|
||||
is owned by libisofs and can get generated by a script of the libburn
|
||||
project: libburn/libdax_msgs_to_xyz_msgs.sh .
|
||||
|
||||
Reason: One cannot link two owners of the same variant together because
|
||||
both would offer the same functions to the linker. For that situation one
|
||||
has to create a compatible variant as it is done for libisofs.
|
||||
|
||||
Compatible variants may get plugged together by call combinations like
|
||||
burn_set_messenger(iso_get_messenger());
|
||||
A new variant would demand a _set_messenger() function if it has to work
|
||||
with libisofs. If only libburn is planned as link partner then a simple
|
||||
_get_messenger() does suffice.
|
||||
Take care to shutdown libburn before its provider of the *_msgs object
|
||||
gets shut down.
|
||||
|
||||
*/
|
||||
|
||||
/* Public Opaque Handles */
|
||||
|
||||
/** A pointer to this is a opaque handle to a message handling facility */
|
||||
@ -86,13 +113,26 @@ struct libdax_msgs_item;
|
||||
|
||||
/* It is well advisable to let applications select severities via strings and
|
||||
forwarded functions libdax_msgs__text_to_sev(), libdax_msgs__sev_to_text().
|
||||
These macros are for use by libdax/libburn only.
|
||||
These macros are for use by the owner of libdax_msgs.
|
||||
*/
|
||||
|
||||
/** Use this to get messages of any severity. Do not use for submitting.
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_ALL 0x00000000
|
||||
|
||||
|
||||
/** Messages of this severity shall transport plain disk file paths
|
||||
whenever an event of severity SORRY or above is related with an
|
||||
individual disk file.
|
||||
No message text shall be added to the file path. The ERRFILE message
|
||||
shall be issued before the human readable message which carries the
|
||||
true event severity. That message should contain the file path so it
|
||||
can be found by strstr(message, path)!=NULL.
|
||||
The error code shall be the same as with the human readable message.
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_ERRFILE 0x08000000
|
||||
|
||||
|
||||
/** Debugging messages not to be visible to normal users by default
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_DEBUG 0x10000000
|
||||
@ -113,15 +153,70 @@ struct libdax_msgs_item;
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_WARNING 0x50000000
|
||||
|
||||
/** Non-fatal error messages indicating that parts of the action failed
|
||||
but processing will/should go on
|
||||
|
||||
/** Non-fatal error messages indicating that parts of an action failed but
|
||||
processing may go on if one accepts deviations from the desired result.
|
||||
|
||||
SORRY may also be the severity for incidents which are severe enough
|
||||
for FAILURE but happen within already started irrevocable actions,
|
||||
like ISO image generation. A precondition for such a severity ease is
|
||||
that the action can be continued after the incident.
|
||||
See below MISHAP for what xorriso would need instead of this kind of SORRY
|
||||
and generates for itself in case of libisofs image generation.
|
||||
|
||||
E.g.: A pattern yields no result.
|
||||
A speed setting cannot be made.
|
||||
A libisofs input file is inaccessible during image generation.
|
||||
|
||||
After SORRY a function should try to go on if that makes any sense
|
||||
and if no threshold prescribes abort on SORRY. The function should
|
||||
nevertheless indicate some failure in its return value.
|
||||
It should - but it does not have to.
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_SORRY 0x60000000
|
||||
|
||||
/** An error message which puts the whole operation of libdax in question
|
||||
|
||||
/** A FAILURE (see below) which can be tolerated during long lasting
|
||||
operations just because they cannot simply be stopped or revoked.
|
||||
|
||||
xorriso converts libisofs SORRY messages issued during image generation
|
||||
into MISHAP messages in order to allow its evaluators to distinguish
|
||||
image generation problems from minor image composition problems.
|
||||
E.g.:
|
||||
A libisofs input file is inaccessible during image generation.
|
||||
|
||||
After a MISHAP a function should behave like after SORRY.
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_MISHAP 0x64000000
|
||||
|
||||
|
||||
/** Non-fatal error indicating that an important part of an action failed and
|
||||
that only a new setup of preconditions will give hope for sufficient
|
||||
success.
|
||||
|
||||
E.g.: No media is inserted in the output drive.
|
||||
No write mode can be found for inserted media.
|
||||
A libisofs input file is inaccessible during grafting.
|
||||
|
||||
After FAILURE a function should end with a return value indicating failure.
|
||||
It is at the discretion of the function whether it ends immediately in any
|
||||
case or whether it tries to go on if the eventual threshold allows.
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_FAILURE 0x68000000
|
||||
|
||||
|
||||
/** An error message which puts the whole operation of the program in question
|
||||
|
||||
E.g.: Not enough memory for essential temporary objects.
|
||||
Irregular errors from resources.
|
||||
Programming errors (soft assert).
|
||||
|
||||
After FATAL a function should end very soon with a return value
|
||||
indicating severe failure.
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_FATAL 0x70000000
|
||||
|
||||
|
||||
/** A message from an abort handler which will finally finish libburn
|
||||
*/
|
||||
#define LIBDAX_MSGS_SEV_ABORT 0x71000000
|
||||
@ -134,7 +229,7 @@ struct libdax_msgs_item;
|
||||
|
||||
/* Registered Priorities */
|
||||
|
||||
/* Priorities are to be used by libburn/libdax only. */
|
||||
/* Priorities are to be selected by the programmers and not by the user. */
|
||||
|
||||
#define LIBDAX_MSGS_PRIO_ZERO 0x00000000
|
||||
#define LIBDAX_MSGS_PRIO_LOW 0x10000000
|
||||
@ -146,12 +241,23 @@ struct libdax_msgs_item;
|
||||
#define LIBDAX_MSGS_PRIO_NEVER 0x7fffffff
|
||||
|
||||
|
||||
/* Origin numbers of libburn drives may range from 0 to 1048575 */
|
||||
#define LIBDAX_MSGS_ORIGIN_DRIVE_BASE 0
|
||||
#define LIBDAX_MSGS_ORIGIN_DRIVE_TOP 0xfffff
|
||||
|
||||
/* Origin numbers of libisofs images may range from 1048575 to 2097152 */
|
||||
#define LIBDAX_MSGS_ORIGIN_IMAGE_BASE 0x100000
|
||||
#define LIBDAX_MSGS_ORIGIN_IMAGE_TOP 0x1fffff
|
||||
|
||||
|
||||
|
||||
/* Public Functions */
|
||||
|
||||
/* Calls initiated from inside libdax/libburn */
|
||||
/* Calls initiated from inside the direct owner (e.g. from libburn) */
|
||||
|
||||
|
||||
/** Create new empty message handling facility with queue.
|
||||
/** Create new empty message handling facility with queue and issue a first
|
||||
official reference to it.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return >0 success, <=0 failure
|
||||
*/
|
||||
@ -160,18 +266,37 @@ int libdax_msgs_new(struct libdax_msgs **m, int flag);
|
||||
|
||||
/** Destroy a message handling facility and all its eventual messages.
|
||||
The submitted pointer gets set to NULL.
|
||||
Actually only the last destroy call of all offical references to the object
|
||||
will really dispose it. All others just decrement the reference counter.
|
||||
Call this function only with official reference pointers obtained by
|
||||
libdax_msgs_new() or libdax_msgs_refer(), and only once per such pointer.
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 for success, 0 for pointer to NULL
|
||||
@return 1 for success, 0 for pointer to NULL, -1 for fatal error
|
||||
*/
|
||||
int libdax_msgs_destroy(struct libdax_msgs **m, int flag);
|
||||
|
||||
|
||||
/** Create an official reference to an existing libdax_msgs object. The
|
||||
references keep the object alive at least until it is released by
|
||||
a matching number of destroy calls. So each reference MUST be revoked
|
||||
by exactly one call to libdax_msgs_destroy().
|
||||
@param pt The pointer to be set and registered
|
||||
@param m A pointer to the existing object
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 for success, 0 for failure
|
||||
*/
|
||||
int libdax_msgs_refer(struct libdax_msgs **pt, struct libdax_msgs *o, int flag);
|
||||
|
||||
|
||||
/** Submit a message to a message handling facility.
|
||||
@param driveno libdax drive number. Use -1 if no number is known.
|
||||
@param origin program specific identification number of the originator of
|
||||
a message. E.g. drive number. Programs should have an own
|
||||
range of origin numbers. See above LIBDAX_MSGS_ORIGIN_*_BASE
|
||||
Use -1 if no number is known.
|
||||
@param error_code Unique error code. Use only registered codes. See below.
|
||||
The same unique error_code may be issued at different
|
||||
occasions but those should be equivalent out of the view
|
||||
of a libdax application. (E.g. "cannot open ATA drive"
|
||||
of a libdax_msgs application. (E.g. "cannot open ATA drive"
|
||||
versus "cannot open SCSI drive" would be equivalent.)
|
||||
@param severity The LIBDAX_MSGS_SEV_* of the event.
|
||||
@param priority The LIBDAX_MSGS_PRIO_* number of the event.
|
||||
@ -180,12 +305,13 @@ int libdax_msgs_destroy(struct libdax_msgs **m, int flag);
|
||||
@param flag Bitfield for control purposes (unused yet, submit 0)
|
||||
@return 1 on success, 0 on rejection, <0 for severe errors
|
||||
*/
|
||||
int libdax_msgs_submit(struct libdax_msgs *m, int driveno, int error_code,
|
||||
int libdax_msgs_submit(struct libdax_msgs *m, int origin, int error_code,
|
||||
int severity, int priority, char *msg_text,
|
||||
int os_errno, int flag);
|
||||
|
||||
|
||||
/* Calls from applications (to be forwarded by libdax/libburn) */
|
||||
|
||||
/* Calls from applications (to be forwarded by direct owner) */
|
||||
|
||||
|
||||
/** Convert a registered severity number into a severity name
|
||||
@ -256,7 +382,7 @@ int libdax_msgs_item_get_msg(struct libdax_msgs_item *item,
|
||||
@return 1 on success, 0 on invalid item, <0 for servere errors
|
||||
*/
|
||||
int libdax_msgs_item_get_origin(struct libdax_msgs_item *item,
|
||||
double *timestamp, pid_t *process_id, int *driveno,
|
||||
double *timestamp, pid_t *process_id, int *origin,
|
||||
int flag);
|
||||
|
||||
|
||||
@ -276,7 +402,7 @@ int libdax_msgs_item_get_rank(struct libdax_msgs_item *item,
|
||||
|
||||
|
||||
Format: error_code (LIBDAX_MSGS_SEV_*,LIBDAX_MSGS_PRIO_*) = explanation
|
||||
If no severity or priority are fixely associates, use "(,)".
|
||||
If no severity or priority are fixely associated, use "(,)".
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Range "libdax_msgs" : 0x00000000 to 0x0000ffff
|
||||
@ -284,6 +410,7 @@ Range "libdax_msgs" : 0x00000000 to 0x0000ffff
|
||||
0x00000000 (ALL,ZERO) = Initial setting in new libdax_msgs_item
|
||||
0x00000001 (DEBUG,ZERO) = Test error message
|
||||
0x00000002 (DEBUG,ZERO) = Debugging message
|
||||
0x00000003 (FATAL,HIGH) = Out of virtual memory
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
@ -304,6 +431,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
0x00020006 (FATAL,HIGH) = Too many scsi siblings
|
||||
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
|
||||
0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock
|
||||
0x00020009 (SORRY,HIGH) = Neither stdio-path nor its directory exist
|
||||
|
||||
General library operations:
|
||||
|
||||
@ -313,7 +441,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
0x00020104 (SORRY,HIGH) = NULL pointer caught
|
||||
0x00020105 (SORRY,HIGH) = Drive is already released
|
||||
0x00020106 (SORRY,HIGH) = Drive is busy on attempt to close
|
||||
0x00020107 (SORRY,HIGH) = Drive is busy on attempt to shut down library
|
||||
0x00020107 (WARNING,HIGH) = A drive is still busy on shutdown of library
|
||||
0x00020108 (SORRY,HIGH) = Drive is not grabbed on disc status inquiry
|
||||
0x00020108 (FATAL,HIGH) = Could not allocate new drive object
|
||||
0x00020109 (FATAL,HIGH) = Library not running
|
||||
@ -371,7 +499,31 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
0x0002013d (DEBUG,LOW) = Waiting for free buffer space takes long time
|
||||
0x0002013e (SORRY,HIGH) = Timeout with waiting for free buffer. Now disabled
|
||||
0x0002013f (DEBUG,LOW) = Reporting total time spent with waiting for buffer
|
||||
|
||||
0x00020140 (FATAL,HIGH) = Drive is busy on attempt to write random access
|
||||
0x00020141 (SORRY,HIGH) = Write data count not properly aligned
|
||||
0x00020142 (FATAL,HIGH) = Drive is not grabbed on random access write
|
||||
0x00020143 (SORRY,HIGH) = Read start address not properly aligned
|
||||
0x00020144 (SORRY,HIGH) = SCSI error on read
|
||||
0x00020145 (FATAL,HIGH) = Drive is busy on attempt to read data
|
||||
0x00020146 (FATAL,HIGH) = Drive is a virtual placeholder
|
||||
0x00020147 (SORRY,HIGH) = Cannot address start byte
|
||||
0x00020148 (SORRY,HIGH) = Cannot write desired amount of data
|
||||
0x00020149 (SORRY,HIGH) = Unsuitable filetype for pseudo-drive
|
||||
0x0002014a (SORRY,HIGH) = Cannot read desired amount of data
|
||||
0x0002014b (SORRY,HIGH) = Drive is already registered resp. scanned
|
||||
0x0002014c (FATAL,HIGH) = Emulated drive caught in SCSI function
|
||||
0x0002014d (SORRY,HIGH) = Asynchromous SCSI error
|
||||
0x0002014f (SORRY,HIGH) = Timeout with asynchromous SCSI command
|
||||
0x00020150 (DEBUG,LOW) = Reporting asynchronous waiting time
|
||||
0x00020151 (FATAL,HIGH) = Read attempt on write-only drive
|
||||
0x00020152 (FATAL,HIGH) = Cannot start fifo thread
|
||||
0x00020153 (SORRY,HIGH) = Read error on fifo input
|
||||
0x00020154 (NOTE,HIGH) = Forwarded input error ends output
|
||||
0x00020155 (SORRY,HIGH) = Desired fifo buffer too large
|
||||
0x00020156 (SORRY,HIGH) = Desired fifo buffer too small
|
||||
0x00020157 (FATAL,HIGH) = burn_source is not a fifo object
|
||||
0x00020158 (DEBUG,LOW) = Reporting thread disposal precautions
|
||||
0x00020159 (DEBUG,HIGH) = TOC Format 0 returns inconsistent data
|
||||
|
||||
libdax_audioxtr:
|
||||
0x00020200 (SORRY,HIGH) = Cannot open audio source file
|
||||
@ -379,6 +531,117 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Range "vreixo" : 0x00030000 to 0x0003ffff
|
||||
|
||||
0x0003ffff (FAILURE,HIGH) = Operation canceled
|
||||
0x0003fffe (FATAL,HIGH) = Unknown or unexpected fatal error
|
||||
0x0003fffd (FAILURE,HIGH) = Unknown or unexpected error
|
||||
0x0003fffc (FATAL,HIGH) = Internal programming error
|
||||
0x0003fffb (FAILURE,HIGH) = NULL pointer where NULL not allowed
|
||||
0x0003fffa (FATAL,HIGH) = Memory allocation error
|
||||
0x0003fff9 (FATAL,HIGH) = Interrupted by a signal
|
||||
0x0003fff8 (FAILURE,HIGH) = Invalid parameter value
|
||||
0x0003fff7 (FATAL,HIGH) = Cannot create a needed thread
|
||||
0x0003fff6 (FAILURE,HIGH) = Write error
|
||||
0x0003fff5 (FAILURE,HIGH) = Buffer read error
|
||||
0x0003ffc0 (FAILURE,HIGH) = Trying to add a node already added to another dir
|
||||
0x0003ffbf (FAILURE,HIGH) = Node with same name already exist
|
||||
0x0003ffbe (FAILURE,HIGH) = Trying to remove a node that was not added to dir
|
||||
0x0003ffbd (FAILURE,HIGH) = A requested node does not exist
|
||||
0x0003ffbc (FAILURE,HIGH) = Image already bootable
|
||||
0x0003ffbb (FAILURE,HIGH) = Trying to use an invalid file as boot image
|
||||
0x0003ff80 (FAILURE,HIGH) = Error on file operation
|
||||
0x0003ff7f (FAILURE,HIGH) = Trying to open an already openned file
|
||||
0x0003ff7e (FAILURE,HIGH) = Access to file is not allowed
|
||||
0x0003ff7d (FAILURE,HIGH) = Incorrect path to file
|
||||
0x0003ff7c (FAILURE,HIGH) = The file does not exist in the filesystem
|
||||
0x0003ff7b (FAILURE,HIGH) = Trying to read or close a file not openned
|
||||
0x0003ff7a (FAILURE,HIGH) = Directory used where no dir is expected
|
||||
0x0003ff79 (FAILURE,HIGH) = File read error
|
||||
0x0003ff78 (FAILURE,HIGH) = Not dir used where a dir is expected
|
||||
0x0003ff77 (FAILURE,HIGH) = Not symlink used where a symlink is expected
|
||||
0x0003ff76 (FAILURE,HIGH) = Cannot seek to specified location
|
||||
0x0003ff75 (HINT,MEDIUM) = File not supported in ECMA-119 tree and ignored
|
||||
0x0003ff74 (HINT,MEDIUM) = File bigger than supported by used standard
|
||||
0x0003ff73 (MISHAP,HIGH) = File read error during image creation
|
||||
0x0003ff72 (HINT,MEDIUM) = Cannot convert filename to requested charset
|
||||
0x0003ff71 (SORRY,HIGH) = File cannot be added to the tree
|
||||
0x0003ff70 (HINT,MEDIUM) = File path breaks specification constraints
|
||||
0x0003ff00 (FAILURE,HIGH) = Charset conversion error
|
||||
0x0003feff (FAILURE,HIGH) = Too much files to mangle
|
||||
0x0003fec0 (FAILURE,HIGH) = Wrong or damaged Primary Volume Descriptor
|
||||
0x0003febf (SORRY,HIGH) = Wrong or damaged RR entry
|
||||
0x0003febe (SORRY,HIGH) = Unsupported RR feature
|
||||
0x0003febd (FAILURE,HIGH) = Wrong or damaged ECMA-119
|
||||
0x0003febc (FAILURE,HIGH) = Unsupported ECMA-119 feature
|
||||
0x0003febb (SORRY,HIGH) = Wrong or damaged El-Torito catalog
|
||||
0x0003feba (SORRY,HIGH) = Unsupported El-Torito feature
|
||||
0x0003feb9 (SORRY,HIGH) = Cannot patch isolinux boot image
|
||||
0x0003feb8 (SORRY,HIGH) = Unsupported SUSP feature
|
||||
0x0003feb7 (WARNING,HIGH) = Error on a RR entry that can be ignored
|
||||
0x0003feb6 (HINT,MEDIUM) = Error on a RR entry that can be ignored
|
||||
0x0003feb5 (WARNING,HIGH) = Multiple ER SUSP entries found
|
||||
0x0003feb4 (HINT,MEDIUM) = Unsupported volume descriptor found
|
||||
0x0003feb3 (WARNING,HIGH) = El-Torito related warning
|
||||
0x0003feb2 (MISHAP,HIGH) = Image write cancelled
|
||||
0x0003feb1 (WARNING,HIGH) = El-Torito image is hidden
|
||||
|
||||
Outdated codes which may not be re-used for other purposes than
|
||||
re-instating them, if ever:
|
||||
|
||||
X 0x00031001 (SORRY,HIGH) = Cannot read file (ignored)
|
||||
X 0x00031002 (FATAL,HIGH) = Cannot read file (operation canceled)
|
||||
X 0x00031000 (FATAL,HIGH) = Unsupported ISO-9660 image
|
||||
X 0x00031001 (HINT,MEDIUM) = Unsupported Vol Desc that will be ignored
|
||||
X 0x00031002 (FATAL,HIGH) = Damaged ISO-9660 image
|
||||
X 0x00031003 (SORRY,HIGH) = Cannot read previous image file
|
||||
X 0x00030101 (HINT,MEDIUM) = Unsupported SUSP entry that will be ignored
|
||||
X 0x00030102 (SORRY,HIGH) = Wrong/damaged SUSP entry
|
||||
X 0x00030103 (WARNING,MEDIUM)= Multiple SUSP ER entries where found
|
||||
X 0x00030111 (SORRY,HIGH) = Unsupported RR feature
|
||||
X 0x00030112 (SORRY,HIGH) = Error in a Rock Ridge entry
|
||||
X 0x00030201 (HINT,MEDIUM) = Unsupported Boot Vol Desc that will be ignored
|
||||
X 0x00030202 (SORRY,HIGH) = Wrong El-Torito catalog
|
||||
X 0x00030203 (HINT,MEDIUM) = Unsupported El-Torito feature
|
||||
X 0x00030204 (SORRY,HIGH) = Invalid file to be an El-Torito image
|
||||
X 0x00030205 (WARNING,MEDIUM)= Cannot properly patch isolinux image
|
||||
X 0x00030206 (WARNING,MEDIUM)= Copying El-Torito from a previous image without
|
||||
X enought info about it
|
||||
X 0x00030301 (NOTE,MEDIUM) = Unsupported file type for Joliet tree
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Range "application" : 0x00040000 to 0x0004ffff
|
||||
|
||||
0x00040000 (ABORT,HIGH) : Application supplied message
|
||||
0x00040001 (FATAL,HIGH) : Application supplied message
|
||||
0x00040002 (SORRY,HIGH) : Application supplied message
|
||||
0x00040003 (WARNING,HIGH) : Application supplied message
|
||||
0x00040004 (HINT,HIGH) : Application supplied message
|
||||
0x00040005 (NOTE,HIGH) : Application supplied message
|
||||
0x00040006 (UPDATE,HIGH) : Application supplied message
|
||||
0x00040007 (DEBUG,HIGH) : Application supplied message
|
||||
0x00040008 (*,HIGH) : Application supplied message
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Range "libisofs-xorriso" : 0x00050000 to 0x0005ffff
|
||||
|
||||
This is an alternative representation of libisofs.so.6 error codes in xorriso.
|
||||
If values returned by iso_error_get_code() do not fit into 0x30000 to 0x3ffff
|
||||
then they get truncated to 16 bit and mapped into this range.
|
||||
(This should never need to happen, of course.)
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
Range "libisoburn" : 0x00060000 to 0x00006ffff
|
||||
|
||||
0x00060000 (*,*) : Message which shall be attributed to libisoburn
|
||||
|
||||
>>> the messages of libisoburn need to be registered individually
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
#endif /* LIDBAX_MSGS_________________ */
|
||||
|
37
libburn/libdax_msgs_to_xyz_msgs.sh
Executable file
37
libburn/libdax_msgs_to_xyz_msgs.sh
Executable file
@ -0,0 +1,37 @@
|
||||
#!/bin/sh
|
||||
|
||||
# libdax_msgs_to_iso_msgs.sh
|
||||
# generates ${xyz}_msgs.[ch] from libdax_msgs.[ch]
|
||||
# To be executed within ./libburn-* resp ./cdrskin-*
|
||||
|
||||
# The module name for the generated sourcecode in several
|
||||
# uppercase-lowercase forms
|
||||
xyz="libiso"
|
||||
Xyz="Libiso"
|
||||
XYZ="LIBISO"
|
||||
|
||||
# The project name for which the generated code shall serve
|
||||
project="libisofs"
|
||||
|
||||
|
||||
for i in libburn/libdax_msgs.[ch]
|
||||
do
|
||||
target_adr=$(echo "$i" | sed -e "s/libdax_/${xyz}_/")
|
||||
|
||||
echo "$target_adr"
|
||||
|
||||
sed \
|
||||
-e "s/^\/\* libdax_msgs/\/* ${xyz}_msgs (generated from XYZ_msgs : $(date))/" \
|
||||
-e "s/Message handling facility of libdax/Message handling facility of ${project}/" \
|
||||
-e "s/libdax_/${xyz}_/g" \
|
||||
-e "s/libdax:/${xyz}:/g" \
|
||||
-e "s/Libdax_/${Xyz}_/g" \
|
||||
-e "s/LIBDAX_/${XYZ}_/g" \
|
||||
-e "s/generated from XYZ_msgs/generated from libdax_msgs/" \
|
||||
-e "s/${xyz}_msgs is designed to serve in libraries/libdax_msgs is designed to serve in libraries/" \
|
||||
-e "s/Owner of ${xyz}_msgs is libburn/Owner of libdax_msgs is libburn/" \
|
||||
\
|
||||
<"$i" >"$target_adr"
|
||||
|
||||
done
|
||||
|
414
libburn/mmc.c
414
libburn/mmc.c
@ -91,6 +91,8 @@ extern struct libdax_msgs *libdax_messenger;
|
||||
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.
|
||||
ts A80228 : Made DVD+R/DL support official after nightmorph reported success
|
||||
in http://libburnia-project.org/ticket/13
|
||||
*/
|
||||
|
||||
/* ts A70519 : With MMC commands of data direction FROM_DRIVE:
|
||||
@ -116,6 +118,7 @@ extern struct libdax_msgs *libdax_messenger;
|
||||
static unsigned char MMC_GET_MSINFO[] =
|
||||
{ 0x43, 0, 1, 0, 0, 0, 0, 16, 0, 0 };
|
||||
static unsigned char MMC_GET_TOC[] = { 0x43, 2, 2, 0, 0, 0, 0, 16, 0, 0 };
|
||||
static unsigned char MMC_GET_TOC_FMT0[] = { 0x43, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
|
||||
static unsigned char MMC_GET_ATIP[] = { 0x43, 2, 4, 0, 0, 0, 0, 16, 0, 0 };
|
||||
static unsigned char MMC_GET_DISC_INFO[] =
|
||||
{ 0x51, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
|
||||
@ -165,15 +168,32 @@ static unsigned char MMC_READ_FORMAT_CAPACITIES[] =
|
||||
static unsigned char MMC_RESERVE_TRACK[] =
|
||||
{ 0x53, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
/* ts A70812 : Read data sectors (for types with 2048 bytes/sector only) */
|
||||
static unsigned char MMC_READ_10[] =
|
||||
{ 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
|
||||
static int mmc_function_spy_do_tell = 0;
|
||||
|
||||
int mmc_function_spy(char * text)
|
||||
int mmc_function_spy(struct burn_drive *d, char * text)
|
||||
{
|
||||
|
||||
if (mmc_function_spy_do_tell)
|
||||
fprintf(stderr,"libburn: experimental: mmc_function_spy: %s\n",
|
||||
text);
|
||||
if (d == NULL)
|
||||
return 1;
|
||||
if (d->drive_role != 1) {
|
||||
char msg[4096];
|
||||
|
||||
sprintf(msg, "Emulated drive caught in SCSI adapter \"%s\"",
|
||||
text);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002014c,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
d->cancel = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -208,7 +228,8 @@ void mmc_send_cue_sheet(struct burn_drive *d, struct cue_sheet *s)
|
||||
struct command c;
|
||||
|
||||
|
||||
mmc_function_spy("mmc_send_cue_sheet");
|
||||
if (mmc_function_spy(d, "mmc_send_cue_sheet") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, MMC_SEND_CUE_SHEET, sizeof(MMC_SEND_CUE_SHEET));
|
||||
/*
|
||||
@ -238,7 +259,9 @@ int mmc_reserve_track(struct burn_drive *d, off_t size)
|
||||
int lba;
|
||||
char msg[80];
|
||||
|
||||
mmc_function_spy("mmc_reserve_track");
|
||||
if (mmc_function_spy(d, "mmc_reserve_track") <= 0)
|
||||
return 0;
|
||||
|
||||
scsi_init_command(&c, MMC_RESERVE_TRACK, sizeof(MMC_RESERVE_TRACK));
|
||||
/*
|
||||
c.oplen = sizeof(MMC_RESERVE_TRACK);
|
||||
@ -270,7 +293,8 @@ int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf,
|
||||
{
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_read_track_info");
|
||||
if (mmc_function_spy(d, "mmc_read_track_info") <= 0)
|
||||
return 0;
|
||||
|
||||
scsi_init_command(&c, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO));
|
||||
/*
|
||||
@ -284,8 +308,9 @@ int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf,
|
||||
c.opcode[1] = 1;
|
||||
if(trackno<=0) {
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
||||
d->current_profile == 0x12 )
|
||||
/* DVD+RW , DVD-RW restricted overwrite , DVD-RAM */
|
||||
d->current_profile == 0x12 || d->current_profile == 0x43)
|
||||
/* DVD+RW , DVD-RW restricted overwrite , DVD-RAM
|
||||
BD-RE */
|
||||
trackno = 1;
|
||||
else if (d->current_profile == 0x10 ||
|
||||
d->current_profile == 0x11 ||
|
||||
@ -316,7 +341,8 @@ int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
|
||||
int ret, num, alloc_len = 20;
|
||||
unsigned char *data;
|
||||
|
||||
mmc_function_spy("mmc_get_nwa");
|
||||
if (mmc_function_spy(d, "mmc_get_nwa") <= 0)
|
||||
return -1;
|
||||
|
||||
ret = mmc_read_track_info(d, trackno, &buf, alloc_len);
|
||||
if (ret <= 0)
|
||||
@ -326,7 +352,7 @@ int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
|
||||
*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) {
|
||||
d->current_profile == 0x12 || d->current_profile == 0x43) {
|
||||
/* overwriteable */
|
||||
*lba = *nwa = num = 0;
|
||||
} else if (!(data[7]&1)) {
|
||||
@ -354,9 +380,10 @@ int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
|
||||
/* void mmc_close_disc(struct burn_drive *d, struct burn_write_opts *o) */
|
||||
void mmc_close_disc(struct burn_write_opts *o)
|
||||
{
|
||||
struct burn_drive *d;
|
||||
struct burn_drive *d = o->drive;
|
||||
|
||||
mmc_function_spy("mmc_close_disc");
|
||||
if (mmc_function_spy(d, "mmc_close_disc") <= 0)
|
||||
return;
|
||||
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
@ -364,7 +391,6 @@ void mmc_close_disc(struct burn_write_opts *o)
|
||||
|
||||
/* ts A61009 : made impossible by removing redundant parameter d */
|
||||
/* a ssert(o->drive == d); */
|
||||
d = o->drive;
|
||||
|
||||
o->multi = 0;
|
||||
spc_select_write_params(d, o);
|
||||
@ -375,9 +401,10 @@ void mmc_close_disc(struct burn_write_opts *o)
|
||||
/* void mmc_close_session(struct burn_drive *d, struct burn_write_opts *o) */
|
||||
void mmc_close_session(struct burn_write_opts *o)
|
||||
{
|
||||
struct burn_drive *d;
|
||||
struct burn_drive *d = o->drive;
|
||||
|
||||
mmc_function_spy("mmc_close_session");
|
||||
if (mmc_function_spy(d, "mmc_close_session") <= 0)
|
||||
return;
|
||||
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
@ -385,7 +412,6 @@ void mmc_close_session(struct burn_write_opts *o)
|
||||
|
||||
/* ts A61009 : made impossible by removing redundant parameter d */
|
||||
/* a ssert(o->drive == d); */
|
||||
d = o->drive;
|
||||
|
||||
o->multi = 3;
|
||||
spc_select_write_params(d, o);
|
||||
@ -401,7 +427,8 @@ void mmc_close(struct burn_drive *d, int session, int track)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_close");
|
||||
if (mmc_function_spy(d, "mmc_close") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, MMC_CLOSE, sizeof(MMC_CLOSE));
|
||||
/*
|
||||
@ -410,6 +437,8 @@ void mmc_close(struct burn_drive *d, int session, int track)
|
||||
*/
|
||||
c.retry = 1;
|
||||
|
||||
c.opcode[1] |= 1; /* ts A70918 : Immed */
|
||||
|
||||
/* (ts A61030 : shifted !!session rather than or-ing plain session ) */
|
||||
c.opcode[2] = ((session & 3) << 1) | !!track;
|
||||
c.opcode[4] = track >> 8;
|
||||
@ -417,6 +446,14 @@ void mmc_close(struct burn_drive *d, int session, int track)
|
||||
c.page = NULL;
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
|
||||
/* ts A70918 : Immed : wait for drive to complete command */
|
||||
if (c.error) {
|
||||
d->cancel = 1;
|
||||
return;
|
||||
}
|
||||
if (spc_wait_unit_attention(d, 3600, "CLOSE TRACK SESSION", 0) <= 0)
|
||||
d->cancel = 1;
|
||||
}
|
||||
|
||||
void mmc_get_event(struct burn_drive *d)
|
||||
@ -425,7 +462,8 @@ void mmc_get_event(struct burn_drive *d)
|
||||
struct command c;
|
||||
int alloc_len= 8;
|
||||
|
||||
mmc_function_spy("mmc_get_event");
|
||||
if (mmc_function_spy(d, "mmc_get_event") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, MMC_GET_EVENT, sizeof(MMC_GET_EVENT));
|
||||
/*
|
||||
@ -495,7 +533,7 @@ static int mmc_wait_for_buffer_free(struct burn_drive *d, struct buffer *buf)
|
||||
/* There is need to inquire the buffer fill */
|
||||
d->pessimistic_writes++;
|
||||
min_fac = ((double) d->wfb_min_percent) / 100.0;
|
||||
gettimeofday(&t0,&dummy_tz);
|
||||
gettimeofday(&t0, &dummy_tz);
|
||||
#ifdef Libburn_mmc_wfb_debuG
|
||||
sleeplist[0]= 0;
|
||||
sprintf(sleeplist,"(%d%s %d)",
|
||||
@ -590,7 +628,9 @@ void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf)
|
||||
struct command c;
|
||||
int len;
|
||||
|
||||
mmc_function_spy("mmc_write_12");
|
||||
if (mmc_function_spy(d, "mmc_write_12") <= 0)
|
||||
return;
|
||||
|
||||
len = buf->sectors;
|
||||
|
||||
/* ts A61009 */
|
||||
@ -630,11 +670,10 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
|
||||
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
|
||||
#endif /* Libburn_log_in_and_out_streaM */
|
||||
|
||||
mmc_function_spy("mmc_write");
|
||||
pthread_mutex_lock(&d->access_lock);
|
||||
cancelled = d->cancel;
|
||||
pthread_mutex_unlock(&d->access_lock);
|
||||
if (mmc_function_spy(d, "mmc_write") <= 0)
|
||||
return BE_CANCELLED;
|
||||
|
||||
cancelled = d->cancel;
|
||||
if (cancelled)
|
||||
return BE_CANCELLED;
|
||||
|
||||
@ -709,9 +748,7 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
}
|
||||
pthread_mutex_lock(&d->access_lock);
|
||||
d->cancel = 1;
|
||||
pthread_mutex_unlock(&d->access_lock);
|
||||
return BE_CANCELLED;
|
||||
}
|
||||
|
||||
@ -764,6 +801,153 @@ int mmc_fake_toc_entry(struct burn_toc_entry *entry, int session_number,
|
||||
}
|
||||
|
||||
|
||||
/* ts A71128 : for DVD-ROM drives which offer no reliable track information */
|
||||
static int mmc_read_toc_fmt0_al(struct burn_drive *d, int *alloc_len)
|
||||
{
|
||||
struct burn_track *track;
|
||||
struct burn_session *session;
|
||||
struct burn_toc_entry *entry;
|
||||
struct buffer buf;
|
||||
struct command c;
|
||||
int dlen, i, old_alloc_len, session_number, prev_session = -1;
|
||||
int lba, size;
|
||||
unsigned char *tdata, size_data[4], start_data[4];
|
||||
|
||||
if (*alloc_len < 4)
|
||||
return 0;
|
||||
|
||||
scsi_init_command(&c, MMC_GET_TOC_FMT0, sizeof(MMC_GET_TOC_FMT0));
|
||||
c.dxfer_len = *alloc_len;
|
||||
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
|
||||
c.opcode[8] = c.dxfer_len & 0xff;
|
||||
c.retry = 1;
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
c.page->sectors = 0;
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
|
||||
if (c.error) {
|
||||
err_ex:;
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002010d,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Could not inquire TOC", 0,0);
|
||||
d->status = BURN_DISC_UNSUITABLE;
|
||||
d->toc_entries = 0;
|
||||
/* Prefering memory leaks over fandangos */
|
||||
d->toc_entry = calloc(1, sizeof(struct burn_toc_entry));
|
||||
return 0;
|
||||
}
|
||||
dlen = c.page->data[0] * 256 + c.page->data[1];
|
||||
old_alloc_len = *alloc_len;
|
||||
*alloc_len = dlen + 2;
|
||||
if (old_alloc_len < 12)
|
||||
return 1;
|
||||
if (dlen + 2 > old_alloc_len)
|
||||
dlen = old_alloc_len - 2;
|
||||
d->complete_sessions = 1 + c.page->data[3] - c.page->data[2];
|
||||
d->last_track_no = d->complete_sessions;
|
||||
if (dlen - 2 < (d->last_track_no + 1) * 8) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020159,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"TOC Format 0 returns inconsistent data", 0,0);
|
||||
goto err_ex;
|
||||
}
|
||||
|
||||
d->toc_entries = d->last_track_no + d->complete_sessions;
|
||||
if (d->toc_entries < 1)
|
||||
return 0;
|
||||
d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
|
||||
if(d->toc_entry == NULL)
|
||||
return 0;
|
||||
|
||||
d->disc = burn_disc_create();
|
||||
if (d->disc == NULL)
|
||||
return 0;
|
||||
for (i = 0; i < d->complete_sessions; i++) {
|
||||
session = burn_session_create();
|
||||
if (session == NULL)
|
||||
return 0;
|
||||
burn_disc_add_session(d->disc, session, BURN_POS_END);
|
||||
burn_session_free(session);
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < d->last_track_no; i++) {
|
||||
tdata = c.page->data + 4 + i * 8;
|
||||
session_number = i + 1;
|
||||
if (session_number != prev_session && prev_session > 0) {
|
||||
/* leadout entry previous session */
|
||||
entry = &(d->toc_entry[(i - 1) + prev_session]);
|
||||
lba = mmc_four_char_to_int(start_data) +
|
||||
mmc_four_char_to_int(size_data);
|
||||
mmc_int_to_four_char(start_data, lba);
|
||||
mmc_int_to_four_char(size_data, 0);
|
||||
mmc_fake_toc_entry(entry, prev_session, 0xA2,
|
||||
size_data, start_data);
|
||||
entry->min= entry->sec= entry->frame= 0;
|
||||
d->disc->session[prev_session - 1]->leadout_entry =
|
||||
entry;
|
||||
}
|
||||
|
||||
/* ??? >>> d->media_capacity_remaining , d->media_lba_limit
|
||||
as of mmc_fake_toc()
|
||||
*/
|
||||
|
||||
entry = &(d->toc_entry[i + session_number - 1]);
|
||||
track = burn_track_create();
|
||||
if (track == NULL)
|
||||
return -1;
|
||||
burn_session_add_track(
|
||||
d->disc->session[session_number - 1],
|
||||
track, BURN_POS_END);
|
||||
track->entry = entry;
|
||||
burn_track_free(track);
|
||||
|
||||
memcpy(start_data, tdata + 4, 4);
|
||||
/* size_data are estimated from next track start */
|
||||
memcpy(size_data, tdata + 8 + 4, 4);
|
||||
size = mmc_four_char_to_int(size_data) -
|
||||
mmc_four_char_to_int(start_data);
|
||||
mmc_int_to_four_char(size_data, size);
|
||||
mmc_fake_toc_entry(entry, session_number, i + 1,
|
||||
size_data, start_data);
|
||||
if (prev_session != session_number)
|
||||
d->disc->session[session_number - 1]->firsttrack = i+1;
|
||||
d->disc->session[session_number - 1]->lasttrack = i+1;
|
||||
prev_session = session_number;
|
||||
}
|
||||
if (prev_session > 0 && prev_session <= d->disc->sessions) {
|
||||
/* leadout entry of last session of closed disc */
|
||||
tdata = c.page->data + 4 + d->last_track_no * 8;
|
||||
entry = &(d->toc_entry[(d->last_track_no - 1) + prev_session]);
|
||||
memcpy(start_data, tdata + 4, 4);
|
||||
mmc_int_to_four_char(size_data, 0);
|
||||
mmc_fake_toc_entry(entry, prev_session, 0xA2,
|
||||
size_data, start_data);
|
||||
entry->min= entry->sec= entry->frame= 0;
|
||||
d->disc->session[prev_session - 1]->leadout_entry = entry;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A71128 : for DVD-ROM drives which offer no reliable track information */
|
||||
static int mmc_read_toc_fmt0(struct burn_drive *d)
|
||||
{
|
||||
int alloc_len = 4, ret;
|
||||
|
||||
if (mmc_function_spy(d, "mmc_read_toc_fmt0") <= 0)
|
||||
return -1;
|
||||
ret = mmc_read_toc_fmt0_al(d, &alloc_len);
|
||||
if (alloc_len >= 12)
|
||||
ret = mmc_read_toc_fmt0_al(d, &alloc_len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70131 : compose a disc TOC structure from d->complete_sessions
|
||||
and 52h READ TRACK INFORMATION */
|
||||
int mmc_fake_toc(struct burn_drive *d)
|
||||
@ -776,6 +960,9 @@ int mmc_fake_toc(struct burn_drive *d)
|
||||
unsigned char *tdata, size_data[4], start_data[4];
|
||||
char msg[160];
|
||||
|
||||
if (mmc_function_spy(d, "mmc_fake_toc") <= 0)
|
||||
return -1;
|
||||
|
||||
if (d->last_track_no <= 0 || d->complete_sessions <= 0 ||
|
||||
d->status == BURN_DISC_BLANK)
|
||||
return 2;
|
||||
@ -789,6 +976,12 @@ int mmc_fake_toc(struct burn_drive *d)
|
||||
msg, 0,0);
|
||||
return 0;
|
||||
}
|
||||
/* ts A71128 : My DVD-ROM drive issues no reliable track info.
|
||||
One has to try 43h READ TOC/PMA/ATIP Form 0. */
|
||||
if (d->current_profile == 0x10 && d->last_track_no <= 1) {
|
||||
ret = mmc_read_toc_fmt0(d);
|
||||
return ret;
|
||||
}
|
||||
d->disc = burn_disc_create();
|
||||
if (d->disc == NULL)
|
||||
return -1;
|
||||
@ -799,12 +992,15 @@ int mmc_fake_toc(struct burn_drive *d)
|
||||
memset(d->toc_entry, 0,d->toc_entries * sizeof(struct burn_toc_entry));
|
||||
for (i = 0; i < d->complete_sessions; i++) {
|
||||
session = burn_session_create();
|
||||
if (session == NULL)
|
||||
return -1;
|
||||
burn_disc_add_session(d->disc, session, BURN_POS_END);
|
||||
burn_session_free(session);
|
||||
}
|
||||
memset(size_data, 0, 4);
|
||||
memset(start_data, 0, 4);
|
||||
|
||||
|
||||
/* Entry Layout :
|
||||
session 1 track 1 entry 0
|
||||
...
|
||||
@ -901,21 +1097,21 @@ static int mmc_read_toc_al(struct burn_drive *d, int *alloc_len)
|
||||
int i, bpl= 12, old_alloc_len;
|
||||
unsigned char *tdata;
|
||||
|
||||
mmc_function_spy("mmc_read_toc");
|
||||
|
||||
if (*alloc_len < 4)
|
||||
return 0;
|
||||
|
||||
if (!(d->current_profile == -1 || d->current_is_cd_profile)) {
|
||||
/* ts A70131 : MMC_GET_TOC uses Response Format 2
|
||||
For DVD this fails with 5,24,00 */
|
||||
/* One could try Response Format 0: mmc5r03.pdf 6.26.3.2
|
||||
which does not yield the same result wit the same disc
|
||||
/* mmc_read_toc_fmt0() uses
|
||||
Response Format 0: mmc5r03.pdf 6.26.3.2
|
||||
which does not yield the same result with the same disc
|
||||
on different drives.
|
||||
*/
|
||||
/* ts A70201 :
|
||||
This uses the session count from 51h READ DISC INFORMATION
|
||||
and the track records from 52h READ TRACK INFORMATION
|
||||
and the track records from 52h READ TRACK INFORMATION.
|
||||
mmc_read_toc_fmt0() is used as fallback for dull DVD-ROM.
|
||||
*/
|
||||
mmc_fake_toc(d);
|
||||
|
||||
@ -955,9 +1151,7 @@ static int mmc_read_toc_al(struct burn_drive *d, int *alloc_len)
|
||||
d->status = BURN_DISC_UNSUITABLE;
|
||||
d->toc_entries = 0;
|
||||
/* Prefering memory leaks over fandangos */
|
||||
d->toc_entry = malloc(sizeof(struct burn_toc_entry));
|
||||
memset(&(d->toc_entry[0]), 0, sizeof(struct burn_toc_entry));
|
||||
|
||||
d->toc_entry = calloc(1, sizeof(struct burn_toc_entry));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -977,17 +1171,21 @@ static int mmc_read_toc_al(struct burn_drive *d, int *alloc_len)
|
||||
ts A61007 : if re-enabled then not via Assert.
|
||||
a ssert(((dlen - 2) % 11) == 0);
|
||||
*/
|
||||
d->toc_entry = malloc(d->toc_entries * sizeof(struct burn_toc_entry));
|
||||
for (i = 0; i < d->toc_entries; i++)
|
||||
memset(&(d->toc_entry[i]), 0, sizeof(struct burn_toc_entry));
|
||||
d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
|
||||
if(d->toc_entry == NULL) /* ts A70825 */
|
||||
return 0;
|
||||
tdata = c.page->data + 4;
|
||||
|
||||
burn_print(12, "TOC:\n");
|
||||
|
||||
d->disc = burn_disc_create();
|
||||
if (d->disc == NULL) /* ts A70825 */
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < c.page->data[3]; i++) {
|
||||
session = burn_session_create();
|
||||
if (session == NULL) /* ts A70825 */
|
||||
return 0;
|
||||
burn_disc_add_session(d->disc, session, BURN_POS_END);
|
||||
burn_session_free(session);
|
||||
}
|
||||
@ -1067,6 +1265,9 @@ void mmc_read_toc(struct burn_drive *d)
|
||||
{
|
||||
int alloc_len = 4, ret;
|
||||
|
||||
if (mmc_function_spy(d, "mmc_read_toc") <= 0)
|
||||
return;
|
||||
|
||||
ret = mmc_read_toc_al(d, &alloc_len);
|
||||
/*
|
||||
fprintf(stderr,
|
||||
@ -1094,7 +1295,8 @@ int mmc_read_multi_session_c1(struct burn_drive *d, int *trackno, int *start)
|
||||
struct burn_track **tracks;
|
||||
struct burn_toc_entry toc_entry;
|
||||
|
||||
mmc_function_spy("mmc_read_multi_session_c1");
|
||||
if (mmc_function_spy(d, "mmc_read_multi_session_c1") <= 0)
|
||||
return 0;
|
||||
|
||||
/* First try to evaluate the eventually loaded TOC before issueing
|
||||
a MMC command. This search obtains the first track of the last
|
||||
@ -1181,9 +1383,9 @@ static int mmc_read_disc_info_al(struct burn_drive *d, int *alloc_len)
|
||||
|
||||
mmc_get_configuration(d);
|
||||
|
||||
/* ts A70910 : found this as condition for mmc_function_spy() which went up
|
||||
if (*alloc_len < 2)
|
||||
|
||||
mmc_function_spy("mmc_read_disc_info");
|
||||
*/
|
||||
|
||||
scsi_init_command(&c, MMC_GET_DISC_INFO, sizeof(MMC_GET_DISC_INFO));
|
||||
/*
|
||||
@ -1211,7 +1413,7 @@ static int mmc_read_disc_info_al(struct burn_drive *d, int *alloc_len)
|
||||
*alloc_len = len + 2;
|
||||
if (old_alloc_len < 34)
|
||||
return 1;
|
||||
if (*alloc_len < 24) /* data[23] is the last byte used her */
|
||||
if (*alloc_len < 24) /* data[23] is the last byte used here */
|
||||
return 0;
|
||||
if (len + 2 > old_alloc_len)
|
||||
len = old_alloc_len - 2;
|
||||
@ -1223,6 +1425,7 @@ static int mmc_read_disc_info_al(struct burn_drive *d, int *alloc_len)
|
||||
disc_status = 2; /* always full and finalized */
|
||||
d->erasable = 0; /* never erasable */
|
||||
}
|
||||
|
||||
switch (disc_status) {
|
||||
case 0:
|
||||
d->toc_entries = 0;
|
||||
@ -1246,6 +1449,15 @@ static int mmc_read_disc_info_al(struct burn_drive *d, int *alloc_len)
|
||||
break;
|
||||
}
|
||||
|
||||
/* ts A80207 : DVD +/- R DL can normally be read but not be written */
|
||||
if((d->current_profile == 0x2b || d->current_profile == 0x15) &&
|
||||
!d->current_is_supported_profile) {
|
||||
if(d->status == BURN_DISC_APPENDABLE)
|
||||
d->status = BURN_DISC_FULL;
|
||||
d->erasable = 0; /* never erasable */
|
||||
d->current_is_supported_profile = 1;
|
||||
}
|
||||
|
||||
if ((d->current_profile != 0 || d->status != BURN_DISC_UNREADY)
|
||||
&& ! d->current_is_supported_profile) {
|
||||
if (!d->silent_on_scsi_error) {
|
||||
@ -1281,7 +1493,7 @@ static int mmc_read_disc_info_al(struct burn_drive *d, int *alloc_len)
|
||||
ts A70112 : same for DVD-RAM
|
||||
*/
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
||||
d->current_profile == 0x12)
|
||||
d->current_profile == 0x12 || d->current_profile == 0x43)
|
||||
d->status = BURN_DISC_BLANK;
|
||||
|
||||
if (d->status == BURN_DISC_BLANK) {
|
||||
@ -1300,6 +1512,9 @@ static int mmc_read_disc_info_al(struct burn_drive *d, int *alloc_len)
|
||||
appendable. I.e number of complete tracks + 1. */
|
||||
d->last_track_no = (data[11] << 8) | data[6];
|
||||
}
|
||||
if (d->current_profile != 0x0a && d->current_profile != 0x13 &&
|
||||
d->current_profile != 0x14 && d->status != BURN_DISC_FULL)
|
||||
d->erasable = 0; /* stay in sync with burn_disc_erase() */
|
||||
|
||||
if (do_read_toc)
|
||||
mmc_read_toc(d);
|
||||
@ -1311,6 +1526,9 @@ void mmc_read_disc_info(struct burn_drive *d)
|
||||
{
|
||||
int alloc_len = 34, ret;
|
||||
|
||||
if (mmc_function_spy(d, "mmc_read_disc_info") <= 0)
|
||||
return;
|
||||
|
||||
ret = mmc_read_disc_info_al(d, &alloc_len);
|
||||
/*
|
||||
fprintf(stderr,"LIBBURN_DEBUG: 51h alloc_len = %d , ret = %d\n",
|
||||
@ -1339,7 +1557,8 @@ void mmc_read_atip(struct burn_drive *d)
|
||||
4234, 5646, 7056, 8468, -12, -13, -14, -15};
|
||||
/* 24, 32, 40, 48, -, -, -, - */
|
||||
|
||||
mmc_function_spy("mmc_read_atip");
|
||||
if (mmc_function_spy(d, "mmc_read_atip") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, MMC_GET_ATIP, sizeof(MMC_GET_ATIP));
|
||||
/*
|
||||
@ -1495,7 +1714,8 @@ void mmc_read_sectors(struct burn_drive *d,
|
||||
int errorblock, req;
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_read_sectors");
|
||||
if (mmc_function_spy(d, "mmc_read_sectors") <= 0)
|
||||
return;
|
||||
|
||||
/* ts A61009 : to be ensured by callers */
|
||||
/* a ssert(len >= 0); */
|
||||
@ -1564,7 +1784,8 @@ void mmc_erase(struct burn_drive *d, int fast)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_erase");
|
||||
if (mmc_function_spy(d, "mmc_erase") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, MMC_BLANK, sizeof(MMC_BLANK));
|
||||
/*
|
||||
@ -1584,7 +1805,9 @@ void mmc_read_lead_in(struct burn_drive *d, struct buffer *buf)
|
||||
int len;
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_read_lead_in");
|
||||
if (mmc_function_spy(d, "mmc_read_lead_in") <= 0)
|
||||
return;
|
||||
|
||||
len = buf->sectors;
|
||||
scsi_init_command(&c, MMC_READ_CD, sizeof(MMC_READ_CD));
|
||||
/*
|
||||
@ -1610,7 +1833,8 @@ void mmc_perform_opc(struct burn_drive *d)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_perform_opc");
|
||||
if (mmc_function_spy(d, "mmc_perform_opc") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, MMC_SEND_OPC, sizeof(MMC_SEND_OPC));
|
||||
/*
|
||||
@ -1640,7 +1864,8 @@ int mmc_set_streaming(struct burn_drive *d,
|
||||
char msg[160];
|
||||
unsigned char *pd;
|
||||
|
||||
mmc_function_spy("mmc_set_streaming");
|
||||
if (mmc_function_spy(d, "mmc_set_streaming") <= 0)
|
||||
return 0;
|
||||
|
||||
scsi_init_command(&c, MMC_SET_STREAMING, sizeof(MMC_SET_STREAMING));
|
||||
/*
|
||||
@ -1722,7 +1947,8 @@ void mmc_set_speed(struct burn_drive *d, int r, int w)
|
||||
int ret, end_lba = 0;
|
||||
struct burn_speed_descriptor *best_sd = NULL;
|
||||
|
||||
mmc_function_spy("mmc_set_speed");
|
||||
if (mmc_function_spy(d, "mmc_set_speed") <= 0)
|
||||
return;
|
||||
|
||||
if (r <= 0 || w <= 0) {
|
||||
/* ts A70712 : now searching for best speed descriptor */
|
||||
@ -1842,8 +2068,6 @@ static int mmc_get_configuration_al(struct burn_drive *d, int *alloc_len)
|
||||
d->current_feat21h_link_size = -1;
|
||||
d->current_feat2fh_byte4 = -1;
|
||||
|
||||
mmc_function_spy("mmc_get_configuration");
|
||||
|
||||
scsi_init_command(&c, MMC_GET_CONFIGURATION,
|
||||
sizeof(MMC_GET_CONFIGURATION));
|
||||
/*
|
||||
@ -1883,7 +2107,8 @@ static int mmc_get_configuration_al(struct burn_drive *d, int *alloc_len)
|
||||
d->current_is_supported_profile = 1;
|
||||
#endif
|
||||
#ifdef Libburn_support_dvd_raM
|
||||
if (cp == 0x12)
|
||||
if (cp == 0x12 || (cp == 0x43 && burn_support_untested_profiles))
|
||||
/* DVD-RAM , BD-RE */
|
||||
d->current_is_supported_profile = 1;
|
||||
#endif
|
||||
#ifdef Libburn_support_dvd_r_seQ
|
||||
@ -1893,8 +2118,7 @@ static int mmc_get_configuration_al(struct burn_drive *d, int *alloc_len)
|
||||
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 */
|
||||
if (cp == 0x1b || cp == 0x2b) /* DVD+R , DVD+R/DL */
|
||||
d->current_is_supported_profile = 1;
|
||||
#endif
|
||||
|
||||
@ -2030,6 +2254,9 @@ void mmc_get_configuration(struct burn_drive *d)
|
||||
{
|
||||
int alloc_len = 8, ret;
|
||||
|
||||
if (mmc_function_spy(d, "mmc_get_configuration") <= 0)
|
||||
return;
|
||||
|
||||
/* first command execution to learn Allocation Length */
|
||||
ret = mmc_get_configuration_al(d, &alloc_len);
|
||||
/*
|
||||
@ -2057,8 +2284,6 @@ static int mmc_read_format_capacities_al(struct burn_drive *d,
|
||||
char msg[160];
|
||||
*/
|
||||
|
||||
mmc_function_spy("mmc_read_format_capacities");
|
||||
|
||||
if (*alloc_len < 4)
|
||||
return 0;
|
||||
|
||||
@ -2195,6 +2420,9 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
|
||||
{
|
||||
int alloc_len = 4, ret;
|
||||
|
||||
if (mmc_function_spy(d, "mmc_read_format_capacities") <= 0)
|
||||
return 0;
|
||||
|
||||
ret = mmc_read_format_capacities_al(d, &alloc_len, top_wanted);
|
||||
/*
|
||||
fprintf(stderr,"LIBBURN_DEBUG: 23h alloc_len = %d , ret = %d\n",
|
||||
@ -2211,7 +2439,8 @@ void mmc_sync_cache(struct burn_drive *d)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
mmc_function_spy("mmc_sync_cache");
|
||||
if (mmc_function_spy(d, "mmc_sync_cache") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, MMC_SYNC_CACHE, sizeof(MMC_SYNC_CACHE));
|
||||
/*
|
||||
@ -2219,6 +2448,9 @@ void mmc_sync_cache(struct burn_drive *d)
|
||||
c.oplen = sizeof(MMC_SYNC_CACHE);
|
||||
*/
|
||||
c.retry = 1;
|
||||
|
||||
c.opcode[1] |= 2; /* ts A70918 : Immed */
|
||||
|
||||
c.page = NULL;
|
||||
c.dir = NO_TRANSFER;
|
||||
|
||||
@ -2240,6 +2472,16 @@ void mmc_sync_cache(struct burn_drive *d)
|
||||
}
|
||||
|
||||
d->issue_command(d, &c);
|
||||
|
||||
/* ts A70918 */
|
||||
if (c.error) {
|
||||
d->cancel = 1;
|
||||
return;
|
||||
}
|
||||
if (spc_wait_unit_attention(d, 3600, "SYNCHRONIZE CACHE", 0) <= 0)
|
||||
d->cancel = 1;
|
||||
else
|
||||
d->needs_sync_cache = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2253,7 +2495,8 @@ int mmc_read_buffer_capacity(struct burn_drive *d)
|
||||
unsigned char *data;
|
||||
int alloc_len = 12;
|
||||
|
||||
mmc_function_spy("mmc_read_buffer_capacity");
|
||||
if (mmc_function_spy(d, "mmc_read_buffer_capacity") <= 0)
|
||||
return 0;
|
||||
|
||||
scsi_init_command(&c, MMC_READ_BUFFER_CAPACITY,
|
||||
sizeof(MMC_READ_BUFFER_CAPACITY));
|
||||
@ -2319,7 +2562,8 @@ int mmc_format_unit(struct burn_drive *d, off_t size, int flag)
|
||||
char msg[160],descr[80];
|
||||
int full_format_type = 0x00; /* Full Format (or 0x10 for DVD-RW ?) */
|
||||
|
||||
mmc_function_spy("mmc_format_unit");
|
||||
if (mmc_function_spy(d, "mmc_format_unit") <= 0)
|
||||
return 0;
|
||||
|
||||
scsi_init_command(&c, MMC_FORMAT_UNIT, sizeof(MMC_FORMAT_UNIT));
|
||||
/*
|
||||
@ -2552,8 +2796,6 @@ static int mmc_get_write_performance_al(struct burn_drive *d,
|
||||
/* A61225 : 1 = report about speed descriptors */
|
||||
static int speed_debug = 0;
|
||||
|
||||
mmc_function_spy("mmc_get_write_performance");
|
||||
|
||||
if (d->current_profile <= 0)
|
||||
mmc_get_configuration(d);
|
||||
|
||||
@ -2671,6 +2913,9 @@ int mmc_get_write_performance(struct burn_drive *d)
|
||||
{
|
||||
int alloc_len = 8, max_descr = 0, ret;
|
||||
|
||||
if (mmc_function_spy(d, "mmc_get_write_performance") <= 0)
|
||||
return 0;
|
||||
|
||||
/* first command execution to learn number of descriptors and
|
||||
dxfer_len */
|
||||
ret = mmc_get_write_performance_al(d, &alloc_len, &max_descr);
|
||||
@ -2762,8 +3007,9 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
|
||||
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 */;
|
||||
d->current_profile == 0x2b || d->current_profile == 0x12 ||
|
||||
d->current_profile == 0x43) {
|
||||
/* not with DVD+R[W][/DL] or DVD-RAM or BD-RE */;
|
||||
return 0;
|
||||
} else {
|
||||
/* Traditional setup for CD */
|
||||
@ -2793,6 +3039,48 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
|
||||
}
|
||||
|
||||
|
||||
/* A70812 ts */
|
||||
int mmc_read_10(struct burn_drive *d, int start,int amount, struct buffer *buf)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "mmc_read_10") <= 0)
|
||||
return -1;
|
||||
;
|
||||
if (amount > BUFFER_SIZE / 2048)
|
||||
return -1;
|
||||
|
||||
scsi_init_command(&c, MMC_READ_10, sizeof(MMC_READ_10));
|
||||
c.dxfer_len = amount * 2048;
|
||||
c.retry = 1;
|
||||
mmc_int_to_four_char(c.opcode + 2, start);
|
||||
c.opcode[7] = (amount >> 8) & 0xFF;
|
||||
c.opcode[8] = amount & 0xFF;
|
||||
c.page = buf;
|
||||
c.page->bytes = 0;
|
||||
c.page->sectors = 0;
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
if (c.error) {
|
||||
char msg[160];
|
||||
sprintf(msg,
|
||||
"SCSI error on read_10(%d,%d): key=%X asc=%2.2Xh ascq=%2.2Xh",
|
||||
start, amount,
|
||||
c.sense[2],c.sense[12],c.sense[13]);
|
||||
if(!d->silent_on_scsi_error)
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020144,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return BE_CANCELLED;
|
||||
}
|
||||
|
||||
buf->sectors = amount;
|
||||
buf->bytes = amount * 2048;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61021 : the mmc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int mmc_setup_drive(struct burn_drive *d)
|
||||
@ -2815,6 +3103,7 @@ int mmc_setup_drive(struct burn_drive *d)
|
||||
d->read_buffer_capacity = mmc_read_buffer_capacity;
|
||||
d->format_unit = mmc_format_unit;
|
||||
d->read_format_capacities = mmc_read_format_capacities;
|
||||
d->read_10 = mmc_read_10;
|
||||
|
||||
|
||||
/* ts A70302 */
|
||||
@ -2835,6 +3124,7 @@ int mmc_setup_drive(struct burn_drive *d)
|
||||
d->current_feat21h_link_size = -1;
|
||||
d->current_feat2fh_byte4 = -1;
|
||||
d->needs_close_session = 0;
|
||||
d->needs_sync_cache = 0;
|
||||
d->bg_format_status = -1;
|
||||
d->num_format_descr = 0;
|
||||
d->complete_sessions = 0;
|
||||
|
@ -68,6 +68,11 @@ int mmc_compose_mode_page_5(struct burn_drive *d,
|
||||
const struct burn_write_opts *o,
|
||||
unsigned char *pd);
|
||||
|
||||
/* ts A70812 : return 0 = ok , return BE_CANCELLED = error occured */
|
||||
int mmc_read_10(struct burn_drive *d, int start, int amount,
|
||||
struct buffer *buf);
|
||||
|
||||
|
||||
|
||||
/* mmc5r03c.pdf 4.3.4.4.1 d) "The maximum number of RZones is 2 302." */
|
||||
#define BURN_MMC_FAKE_TOC_MAX_SIZE 2302
|
||||
|
@ -142,6 +142,8 @@ int burn_write_opts_set_simulate(struct burn_write_opts *opts, int sim)
|
||||
int burn_write_opts_set_underrun_proof(struct burn_write_opts *opts,
|
||||
int underrun_proof)
|
||||
{
|
||||
if (!opts->drive->mdata->valid)
|
||||
return 0;
|
||||
if (opts->drive->mdata->underrun_proof) {
|
||||
opts->underrun_proof = underrun_proof;
|
||||
return 1;
|
||||
@ -378,6 +380,13 @@ void burn_write_opts_set_force(struct burn_write_opts *opts, int use_force)
|
||||
}
|
||||
|
||||
|
||||
/* ts A70901: API */
|
||||
struct burn_drive *burn_write_opts_get_drive(struct burn_write_opts *opts)
|
||||
{
|
||||
return opts->drive;
|
||||
}
|
||||
|
||||
|
||||
void burn_read_opts_set_raw(struct burn_read_opts *opts, int raw)
|
||||
{
|
||||
opts->raw = raw;
|
||||
|
209
libburn/read.c
209
libburn/read.c
@ -12,6 +12,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sector.h"
|
||||
#include "libburn.h"
|
||||
#include "drive.h"
|
||||
@ -31,6 +34,12 @@
|
||||
#include "read.h"
|
||||
#include "options.h"
|
||||
|
||||
/* ts A70812 */
|
||||
#include "error.h"
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
|
||||
void burn_disc_read(struct burn_drive *d, const struct burn_read_opts *o)
|
||||
{
|
||||
#if 0
|
||||
@ -280,3 +289,203 @@ static void flipq(unsigned char *sub)
|
||||
*(sub + 12 + 11) = ~*(sub + 12 + 11);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/* ts A70904 */
|
||||
/** @param flag bit0=be silent on data shortage */
|
||||
int burn_stdio_read(int fd, char *buf, int bufsize, struct burn_drive *d,
|
||||
int flag)
|
||||
{
|
||||
int todo, count = 0;
|
||||
|
||||
for(todo = bufsize; todo > 0; ) {
|
||||
count = read(fd, buf + (bufsize - todo), todo);
|
||||
if(count <= 0)
|
||||
break;
|
||||
todo -= count;
|
||||
}
|
||||
if(todo > 0 && !(flag & 1)) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002014a,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Cannot read desired amount of data", errno, 0);
|
||||
}
|
||||
if (count < 0)
|
||||
return -1;
|
||||
return (bufsize - todo);
|
||||
}
|
||||
|
||||
|
||||
/* ts A70812 : API function */
|
||||
int burn_read_data(struct burn_drive *d, off_t byte_address,
|
||||
char data[], off_t data_size, off_t *data_count, int flag)
|
||||
{
|
||||
int alignment = 2048, start, upto, chunksize = 1, err, cpy_size, i;
|
||||
int sose_mem = 0, fd = -1, ret;
|
||||
char msg[81], *wpt;
|
||||
struct buffer buf;
|
||||
|
||||
/*
|
||||
#define Libburn_read_data_adr_logginG 1
|
||||
*/
|
||||
#ifdef Libburn_read_data_adr_logginG
|
||||
static FILE *log_fp= NULL;
|
||||
|
||||
if(log_fp == NULL)
|
||||
log_fp = fopen("/tmp/burn_read_data_log", "a");
|
||||
if(log_fp!=NULL)
|
||||
fprintf(log_fp, "%d\n", (int) (byte_address / 2048));
|
||||
#endif /* Libburn_read_data_logginG */
|
||||
|
||||
|
||||
*data_count = 0;
|
||||
sose_mem = d->silent_on_scsi_error;
|
||||
|
||||
if (d->released) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020142,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is not grabbed on random access read", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
if (d->drive_role == 0) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020146,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is a virtual placeholder (null-drive)", 0, 0);
|
||||
return 0;
|
||||
} else if (d->drive_role == 3) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020151,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Read attempt on write-only drive", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
if ((byte_address % alignment) != 0) {
|
||||
sprintf(msg,
|
||||
"Read start address not properly aligned (%d bytes)",
|
||||
alignment);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020143,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->busy != BURN_DRIVE_IDLE) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020145,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is busy on attempt to read data", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (d->drive_role != 1) {
|
||||
|
||||
/* <<< We need _LARGEFILE64_SOURCE defined by the build system.
|
||||
*/
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
fd = d->stdio_fd;
|
||||
if (fd < 0)
|
||||
d->stdio_fd = fd =
|
||||
open(d->devname, O_RDONLY | O_LARGEFILE);
|
||||
if (fd == -1) {
|
||||
if (errno != ENOENT || !(flag & 2))
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index,
|
||||
0x00020005,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Failed to open device (a pseudo-drive) for reading",
|
||||
errno, 0);
|
||||
ret = 0; goto ex;
|
||||
}
|
||||
if (lseek(fd, byte_address, SEEK_SET) == -1) {
|
||||
if (!(flag & 2))
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index,
|
||||
0x00020147,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Cannot address start byte", errno, 0);
|
||||
ret = 0; goto ex;
|
||||
}
|
||||
}
|
||||
|
||||
d->busy = BURN_DRIVE_READING_SYNC;
|
||||
d->buffer = &buf;
|
||||
|
||||
start = byte_address / 2048;
|
||||
upto = start + data_size / 2048;
|
||||
if (data_size % 2048)
|
||||
upto++;
|
||||
wpt = data;
|
||||
for (; start < upto; start += chunksize) {
|
||||
chunksize = upto - start;
|
||||
if (chunksize > 16) {
|
||||
chunksize = 16;
|
||||
cpy_size = 16 * 2048;
|
||||
} else
|
||||
cpy_size = data_size - *data_count;
|
||||
if (flag & 2)
|
||||
d->silent_on_scsi_error = 1;
|
||||
if (d->drive_role == 1) {
|
||||
err = d->read_10(d, start, chunksize, d->buffer);
|
||||
} else {
|
||||
ret = burn_stdio_read(fd, (char *) d->buffer->data,
|
||||
cpy_size, d, !!(flag & 2));
|
||||
err = 0;
|
||||
if (ret <= 0)
|
||||
err = BE_CANCELLED;
|
||||
}
|
||||
if (flag & 2)
|
||||
d->silent_on_scsi_error = sose_mem;
|
||||
if (err == BE_CANCELLED) {
|
||||
/* Try to read a smaller part of the chunk */
|
||||
for (i = 0; i < chunksize - 1; i++) {
|
||||
if (flag & 2)
|
||||
d->silent_on_scsi_error = 1;
|
||||
if (d->drive_role == 1) {
|
||||
err = d->read_10(d, start + i, 1,
|
||||
d->buffer);
|
||||
} else {
|
||||
ret = burn_stdio_read(fd,
|
||||
(char *) d->buffer->data,
|
||||
2048, d, 1);
|
||||
if (ret <= 0)
|
||||
err = BE_CANCELLED;
|
||||
}
|
||||
if (flag & 2)
|
||||
d->silent_on_scsi_error = sose_mem;
|
||||
if (err == BE_CANCELLED)
|
||||
break;
|
||||
memcpy(wpt, d->buffer->data, 2048);
|
||||
wpt += 2048;
|
||||
*data_count += 2048;
|
||||
}
|
||||
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index,
|
||||
0x00020000,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"burn_read_data() returns 0",
|
||||
0, 0);
|
||||
|
||||
ret = 0; goto ex;
|
||||
}
|
||||
memcpy(wpt, d->buffer->data, cpy_size);
|
||||
wpt += cpy_size;
|
||||
*data_count += cpy_size;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
ex:;
|
||||
/* <<< let it open until drive is given up or writing shall happen
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
*/
|
||||
d->buffer = NULL;
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
return ret;
|
||||
}
|
||||
|
@ -10,6 +10,13 @@
|
||||
#include "spc.h"
|
||||
#include "options.h"
|
||||
|
||||
|
||||
/* ts A70910
|
||||
debug: for tracing calls which might use open drive fds
|
||||
or for catching SCSI usage of emulated drives. */
|
||||
int mmc_function_spy(struct burn_drive *d, char * text);
|
||||
|
||||
|
||||
/* spc command set */
|
||||
static unsigned char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
|
||||
static unsigned char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
|
||||
@ -19,6 +26,9 @@ void sbc_load(struct burn_drive *d)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "load") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, SBC_LOAD, sizeof(SBC_LOAD));
|
||||
/*
|
||||
memcpy(c.opcode, SBC_LOAD, sizeof(SBC_LOAD));
|
||||
@ -26,24 +36,43 @@ void sbc_load(struct burn_drive *d)
|
||||
c.page = NULL;
|
||||
*/
|
||||
c.retry = 1;
|
||||
|
||||
/* ts A70921 : Had to revoke Immed because of LG GSA-4082B */
|
||||
/* c.opcode[1] |= 1; / * ts A70918 : Immed */
|
||||
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
spc_wait_unit_attention(d, 60);
|
||||
if (c.error)
|
||||
return;
|
||||
/* ts A70923 : Needed regardless of Immed bit. Was once 1 minute, now
|
||||
5 minutes for loading. If this does not suffice then other commands
|
||||
shall fail righteously. */
|
||||
spc_wait_unit_attention(d, 300, "waiting after START UNIT (+ LOAD)",0);
|
||||
}
|
||||
|
||||
void sbc_eject(struct burn_drive *d)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "eject") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, SBC_UNLOAD, sizeof(SBC_UNLOAD));
|
||||
/*
|
||||
memcpy(c.opcode, SBC_UNLOAD, sizeof(SBC_UNLOAD));
|
||||
c.oplen = sizeof(SBC_UNLOAD);
|
||||
c.page = NULL;
|
||||
*/
|
||||
|
||||
c.opcode[1] |= 1; /* ts A70918 : Immed */
|
||||
|
||||
c.page = NULL;
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
if (c.error)
|
||||
return;
|
||||
/* ts A70918 : Wait long. A late eject could surprise or hurt user. */
|
||||
spc_wait_unit_attention(d, 1800, "STOP UNIT (+ EJECT)", 0);
|
||||
}
|
||||
|
||||
/* ts A61118 : is it necessary to tell the drive to get ready for use ? */
|
||||
@ -51,6 +80,9 @@ int sbc_start_unit(struct burn_drive *d)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "start_unit") <= 0)
|
||||
return 0;
|
||||
|
||||
scsi_init_command(&c, SBC_START_UNIT, sizeof(SBC_START_UNIT));
|
||||
/*
|
||||
memcpy(c.opcode, SBC_START_UNIT, sizeof(SBC_START_UNIT));
|
||||
@ -58,9 +90,15 @@ int sbc_start_unit(struct burn_drive *d)
|
||||
c.page = NULL;
|
||||
*/
|
||||
c.retry = 1;
|
||||
|
||||
c.opcode[1] |= 1; /* ts A70918 : Immed */
|
||||
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
return (c.error==0);
|
||||
if (c.error)
|
||||
return 0;
|
||||
/* ts A70918 : now asynchronous */
|
||||
return spc_wait_unit_attention(d, 1800, "START UNIT", 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,7 +123,12 @@ static void get_bytes(struct burn_track *track, int count, unsigned char *data)
|
||||
/* Next we use source data */
|
||||
curr = valid;
|
||||
if (!track->eos) {
|
||||
valid = track->source->read(track->source, data + curr, count - curr);
|
||||
if (track->source->read != NULL)
|
||||
valid = track->source->read(track->source,
|
||||
data + curr, count - curr);
|
||||
else
|
||||
valid = track->source->read_xt(track->source,
|
||||
data + curr, count - curr);
|
||||
} else valid = 0;
|
||||
|
||||
if (valid <= 0) { /* ts A61031 : extended from (valid == -1) */
|
||||
|
@ -48,6 +48,8 @@ sg_issue_command() sends a SCSI command to the drive, receives reply,
|
||||
|
||||
sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
|
||||
|
||||
burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
|
||||
|
||||
|
||||
Porting hints are marked by the text "PORTING:".
|
||||
Send feedback to libburn-hackers@pykix.org .
|
||||
@ -74,6 +76,10 @@ Send feedback to libburn-hackers@pykix.org .
|
||||
#include <err.h> /* XXX */
|
||||
|
||||
|
||||
/* ts A70909 : >>> untestet yet wether this compiles */
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
|
||||
/** PORTING : ------ libburn portable headers and definitions ----- */
|
||||
|
||||
#include "transport.h"
|
||||
@ -557,3 +563,69 @@ int sg_is_enumerable_adr(char* adr)
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* ts A70909 */
|
||||
/** Estimate the potential payload capacity of a file address.
|
||||
@param path The address of the file to be examined. If it does not
|
||||
exist yet, then the directory will be inquired.
|
||||
@param bytes This value gets modified if an estimation is possible
|
||||
@return -2 = cannot perform necessary operations on file object
|
||||
-1 = neither path nor dirname of path exist
|
||||
0 = could not estimate size capacity of file object
|
||||
1 = estimation has been made, bytes was set
|
||||
*/
|
||||
int burn_os_stdio_capacity(char *path, off_t *bytes)
|
||||
{
|
||||
struct stat stbuf;
|
||||
struct statvfs vfsbuf;
|
||||
char testpath[4096], *cpt;
|
||||
long blocks;
|
||||
int open_mode = O_RDWR, fd, ret;
|
||||
off_t add_size = 0;
|
||||
|
||||
testpath[0] = 0;
|
||||
blocks = *bytes / 512;
|
||||
if (stat(path, &stbuf) == -1) {
|
||||
strcpy(testpath, path);
|
||||
cpt = strrchr(testpath, '/');
|
||||
if(cpt == NULL)
|
||||
strcpy(testpath, ".");
|
||||
else if(cpt == testpath)
|
||||
testpath[1] = 0;
|
||||
else
|
||||
*cpt = 0;
|
||||
if (stat(testpath, &stbuf) == -1)
|
||||
return -1;
|
||||
|
||||
#ifdef Libburn_if_this_was_linuX
|
||||
|
||||
} else if(S_ISBLK(stbuf.st_mode)) {
|
||||
if(burn_sg_open_o_excl)
|
||||
open_mode |= O_EXCL;
|
||||
fd = open(path, open_mode);
|
||||
if (fd == -1)
|
||||
return -2;
|
||||
ret = ioctl(fd, BLKGETSIZE, &blocks);
|
||||
close(fd);
|
||||
if (ret == -1)
|
||||
return -2;
|
||||
*bytes = ((off_t) blocks) * (off_t) 512;
|
||||
|
||||
#endif /* Libburn_if_this_was_linuX */
|
||||
|
||||
|
||||
} else if(S_ISREG(stbuf.st_mode)) {
|
||||
add_size = stbuf.st_blocks * (off_t) 512;
|
||||
strcpy(testpath, path);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (testpath[0]) {
|
||||
if (statvfs(testpath, &vfsbuf) == -1)
|
||||
return -2;
|
||||
*bytes = add_size + ((off_t) vfsbuf.f_bsize) *
|
||||
(off_t) vfsbuf.f_bavail;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,10 @@
|
||||
#include <err.h> /* XXX */
|
||||
|
||||
|
||||
/* ts A70909 : >>> untestet yet wether this compiles */
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
|
||||
#include "transport.h"
|
||||
#include "drive.h"
|
||||
#include "sg.h"
|
||||
@ -46,8 +50,9 @@ int burn_drive_is_banned(char *device_address);
|
||||
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
int mmc_function_spy(char * text);
|
||||
debug: for tracing calls which might use open drive fds
|
||||
or for catching SCSI usage of emulated drives. */
|
||||
int mmc_function_spy(struct burn_drive *d, char * text);
|
||||
|
||||
|
||||
/* ts A61021 : Moved most code from scsi_enumerate_drives under
|
||||
@ -386,7 +391,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("enumerate_common : -------- doing grab");
|
||||
mmc_function_spy(NULL, "enumerate_common : -------- doing grab");
|
||||
|
||||
/* try to get the drive info */
|
||||
if (t->grab(t)) {
|
||||
@ -400,7 +405,7 @@ static void enumerate_common(char *fname, int bus_no, int host_no,
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("enumerate_common : ----- would release ");
|
||||
mmc_function_spy(NULL, "enumerate_common : ----- would release ");
|
||||
|
||||
}
|
||||
|
||||
@ -448,7 +453,8 @@ int sg_grab(struct burn_drive *d)
|
||||
int count;
|
||||
struct cam_device *cam;
|
||||
|
||||
mmc_function_spy("sg_grab");
|
||||
if (mmc_function_spy(d, "sg_grab") <= 0)
|
||||
return 0;
|
||||
|
||||
if (burn_drive_is_open(d)) {
|
||||
d->released = 0;
|
||||
@ -483,14 +489,15 @@ int sg_grab(struct burn_drive *d)
|
||||
|
||||
int sg_release(struct burn_drive *d)
|
||||
{
|
||||
mmc_function_spy("sg_release");
|
||||
if (mmc_function_spy(d, "sg_release") <= 0)
|
||||
return 0;
|
||||
|
||||
if (d->cam == NULL) {
|
||||
burn_print(1, "release an ungrabbed drive. die\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mmc_function_spy("sg_release ----------- closing.");
|
||||
mmc_function_spy(NULL, "sg_release ----------- closing.");
|
||||
|
||||
sg_close_drive(d);
|
||||
d->released = 1;
|
||||
@ -506,7 +513,7 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
|
||||
char buf[161];
|
||||
snprintf(buf, sizeof (buf), "sg_issue_command d->cam=%p d->released=%d",
|
||||
(void*)d->cam, d->released);
|
||||
mmc_function_spy(buf);
|
||||
mmc_function_spy(NULL, buf);
|
||||
|
||||
if (d->cam == NULL) {
|
||||
c->error = 0;
|
||||
@ -598,3 +605,69 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70909 */
|
||||
/** Estimate the potential payload capacity of a file address.
|
||||
@param path The address of the file to be examined. If it does not
|
||||
exist yet, then the directory will be inquired.
|
||||
@param bytes This value gets modified if an estimation is possible
|
||||
@return -2 = cannot perform necessary operations on file object
|
||||
-1 = neither path nor dirname of path exist
|
||||
0 = could not estimate size capacity of file object
|
||||
1 = estimation has been made, bytes was set
|
||||
*/
|
||||
int burn_os_stdio_capacity(char *path, off_t *bytes)
|
||||
{
|
||||
struct stat stbuf;
|
||||
struct statvfs vfsbuf;
|
||||
char testpath[4096], *cpt;
|
||||
long blocks;
|
||||
int open_mode = O_RDWR, fd, ret;
|
||||
off_t add_size = 0;
|
||||
|
||||
testpath[0] = 0;
|
||||
blocks = *bytes / 512;
|
||||
if (stat(path, &stbuf) == -1) {
|
||||
strcpy(testpath, path);
|
||||
cpt = strrchr(testpath, '/');
|
||||
if(cpt == NULL)
|
||||
strcpy(testpath, ".");
|
||||
else if(cpt == testpath)
|
||||
testpath[1] = 0;
|
||||
else
|
||||
*cpt = 0;
|
||||
if (stat(testpath, &stbuf) == -1)
|
||||
return -1;
|
||||
|
||||
#ifdef Libburn_if_this_was_linuX
|
||||
|
||||
} else if(S_ISBLK(stbuf.st_mode)) {
|
||||
if(burn_sg_open_o_excl)
|
||||
open_mode |= O_EXCL;
|
||||
fd = open(path, open_mode);
|
||||
if (fd == -1)
|
||||
return -2;
|
||||
ret = ioctl(fd, BLKGETSIZE, &blocks);
|
||||
close(fd);
|
||||
if (ret == -1)
|
||||
return -2;
|
||||
*bytes = ((off_t) blocks) * (off_t) 512;
|
||||
|
||||
#endif /* Libburn_if_this_was_linuX */
|
||||
|
||||
|
||||
} else if(S_ISREG(stbuf.st_mode)) {
|
||||
add_size = stbuf.st_blocks * (off_t) 512;
|
||||
strcpy(testpath, path);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (testpath[0]) {
|
||||
if (statvfs(testpath, &vfsbuf) == -1)
|
||||
return -2;
|
||||
*bytes = add_size + ((off_t) vfsbuf.f_bsize) *
|
||||
(off_t) vfsbuf.f_bavail;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,8 @@ sg_issue_command() sends a SCSI command to the drive, receives reply,
|
||||
|
||||
sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
|
||||
|
||||
burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
|
||||
|
||||
|
||||
Porting hints are marked by the text "PORTING:".
|
||||
Send feedback to libburn-hackers@pykix.org .
|
||||
@ -73,6 +75,11 @@ Hint: You should also look into sg-freebsd-port.c, which is a younger and
|
||||
#include <stdlib.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
/* for ioctl(BLKGETSIZE) */
|
||||
#include <linux/fs.h>
|
||||
|
||||
|
||||
#include <scsi/sg.h>
|
||||
/* Values within sg_io_hdr_t indicating success after ioctl(SG_IO) : */
|
||||
@ -83,6 +90,7 @@ Hint: You should also look into sg-freebsd-port.c, which is a younger and
|
||||
|
||||
|
||||
/* ts A61211 : to eventually recognize CD devices on /dev/sr* */
|
||||
#include <limits.h>
|
||||
#include <linux/cdrom.h>
|
||||
|
||||
|
||||
@ -194,8 +202,9 @@ extern int burn_sg_open_abort_busy;
|
||||
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
int mmc_function_spy(char * text);
|
||||
debug: for tracing calls which might use open drive fds
|
||||
or for catching SCSI usage of emulated drives. */
|
||||
int mmc_function_spy(struct burn_drive *d, char * text);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
@ -299,6 +308,28 @@ static int sg_close_drive_fd(char *fname, int driveno, int *fd, int sorry)
|
||||
|
||||
if(*fd < 0)
|
||||
return(0);
|
||||
|
||||
#ifdef CDROM_MEDIA_CHANGED_disabled_because_not_helpful
|
||||
#ifdef CDSL_CURRENT
|
||||
/* ts A80217 : wondering whether the os knows about our activities */
|
||||
ret = ioctl(*fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT);
|
||||
sprintf(msg, "ioctl(CDROM_MEDIA_CHANGED) == %d", ret);
|
||||
libdax_msgs_submit(libdax_messenger, driveno, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
|
||||
|
||||
#ifdef BLKFLSBUF_disabled_because_not_helpful
|
||||
ret = ioctl(*fd, BLKFLSBUF, 0);
|
||||
sprintf(msg, "ioctl(BLKFLSBUF) == %d", ret);
|
||||
os_errno = 0;
|
||||
if(ret == -1)
|
||||
os_errno = errno;
|
||||
libdax_msgs_submit(libdax_messenger, driveno, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg, os_errno,0);
|
||||
#endif /* BLKFLSBUF */
|
||||
|
||||
#endif /* CDSL_CURRENT */
|
||||
#endif /* CDROM_MEDIA_CHANGED */
|
||||
|
||||
ret = close(*fd);
|
||||
*fd = -1337;
|
||||
if(ret != -1) {
|
||||
@ -932,7 +963,8 @@ int sg_grab(struct burn_drive *d)
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_grab");
|
||||
if (mmc_function_spy(d, "sg_grab") <= 0)
|
||||
return 0;
|
||||
|
||||
|
||||
/* ts A60813 - A60927
|
||||
@ -960,7 +992,7 @@ int sg_grab(struct burn_drive *d)
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_grab ----------- opening");
|
||||
mmc_function_spy(NULL, "sg_grab ----------- opening");
|
||||
|
||||
/* ts A70409 : DDLP-B */
|
||||
/* >>> obtain single lock on d->devname */
|
||||
@ -1018,7 +1050,8 @@ int sg_release(struct burn_drive *d)
|
||||
{
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_release");
|
||||
if (mmc_function_spy(d, "sg_release") <= 0)
|
||||
return 0;
|
||||
|
||||
if (d->fd < 1) {
|
||||
burn_print(1, "release an ungrabbed drive. die\n");
|
||||
@ -1027,7 +1060,7 @@ int sg_release(struct burn_drive *d)
|
||||
|
||||
/* ts A60821
|
||||
<<< debug: for tracing calls which might use open drive fds */
|
||||
mmc_function_spy("sg_release ----------- closing");
|
||||
mmc_function_spy(NULL, "sg_release ----------- closing");
|
||||
|
||||
sg_close_drive(d);
|
||||
return 0;
|
||||
@ -1124,7 +1157,7 @@ int sg_issue_command(struct burn_drive *d, struct command *c)
|
||||
char buf[161];
|
||||
sprintf(buf,"sg_issue_command d->fd= %d d->released= %d\n",
|
||||
d->fd,d->released);
|
||||
mmc_function_spy(buf);
|
||||
mmc_function_spy(NULL, buf);
|
||||
|
||||
#ifdef Libburn_log_sg_commandS
|
||||
/* ts A61030 */
|
||||
@ -1352,3 +1385,60 @@ int sg_is_enumerable_adr(char *adr)
|
||||
}
|
||||
|
||||
|
||||
/* ts A70909 */
|
||||
/** Estimate the potential payload capacity of a file address.
|
||||
@param path The address of the file to be examined. If it does not
|
||||
exist yet, then the directory will be inquired.
|
||||
@param bytes The pointed value gets modified, but only if an estimation is
|
||||
possible.
|
||||
@return -2 = cannot perform necessary operations on file object
|
||||
-1 = neither path nor dirname of path exist
|
||||
0 = could not estimate size capacity of file object
|
||||
1 = estimation has been made, bytes was set
|
||||
*/
|
||||
int burn_os_stdio_capacity(char *path, off_t *bytes)
|
||||
{
|
||||
struct stat stbuf;
|
||||
struct statvfs vfsbuf;
|
||||
char testpath[4096], *cpt;
|
||||
long blocks;
|
||||
int open_mode = O_RDONLY, fd, ret;
|
||||
off_t add_size = 0;
|
||||
|
||||
testpath[0] = 0;
|
||||
blocks = *bytes / 512;
|
||||
if (stat(path, &stbuf) == -1) {
|
||||
strcpy(testpath, path);
|
||||
cpt = strrchr(testpath, '/');
|
||||
if(cpt == NULL)
|
||||
strcpy(testpath, ".");
|
||||
else if(cpt == testpath)
|
||||
testpath[1] = 0;
|
||||
else
|
||||
*cpt = 0;
|
||||
if (stat(testpath, &stbuf) == -1)
|
||||
return -1;
|
||||
} else if(S_ISBLK(stbuf.st_mode)) {
|
||||
fd = open(path, open_mode);
|
||||
if (fd == -1)
|
||||
return -2;
|
||||
ret = ioctl(fd, BLKGETSIZE, &blocks);
|
||||
close(fd);
|
||||
if (ret == -1)
|
||||
return -2;
|
||||
*bytes = ((off_t) blocks) * (off_t) 512;
|
||||
} else if(S_ISREG(stbuf.st_mode)) {
|
||||
add_size = stbuf.st_blocks * (off_t) 512;
|
||||
strcpy(testpath, path);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (testpath[0]) {
|
||||
if (statvfs(testpath, &vfsbuf) == -1)
|
||||
return -2;
|
||||
*bytes = add_size + ((off_t) vfsbuf.f_bsize) *
|
||||
(off_t) vfsbuf.f_bavail;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -31,4 +31,6 @@ int scsi_enumerate_drives(void);
|
||||
|
||||
int sg_drive_is_open(struct burn_drive * d);
|
||||
|
||||
int burn_os_stdio_capacity(char *path, off_t *bytes);
|
||||
|
||||
#endif /* __SG */
|
||||
|
@ -18,8 +18,6 @@ void burn_source_free(struct burn_source *src)
|
||||
enum burn_source_status burn_track_set_source(struct burn_track *t,
|
||||
struct burn_source *s)
|
||||
{
|
||||
if (!s->read)
|
||||
return BURN_SOURCE_FAILED;
|
||||
s->refcount++;
|
||||
t->source = s;
|
||||
|
||||
@ -34,6 +32,24 @@ struct burn_source *burn_source_new(void)
|
||||
struct burn_source *out;
|
||||
|
||||
out = calloc(1, sizeof(struct burn_source));
|
||||
|
||||
/* ts A70825 */
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
memset((char *) out, 0, sizeof(struct burn_source));
|
||||
|
||||
out->refcount = 1;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/* ts A71223 */
|
||||
int burn_source_cancel(struct burn_source *src)
|
||||
{
|
||||
if(src->read == NULL)
|
||||
if(src->version > 0)
|
||||
if(src->cancel != NULL)
|
||||
src->cancel(src);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -5,4 +5,6 @@
|
||||
|
||||
struct burn_source *burn_source_new(void);
|
||||
|
||||
int burn_source_cancel(struct burn_source *src);
|
||||
|
||||
#endif /*__SOURCE*/
|
||||
|
128
libburn/spc.c
128
libburn/spc.c
@ -27,6 +27,11 @@
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
/* ts A70910
|
||||
debug: for tracing calls which might use open drive fds
|
||||
or for catching SCSI usage of emulated drives. */
|
||||
int mmc_function_spy(struct burn_drive *d, char * text);
|
||||
|
||||
|
||||
/* spc command set */
|
||||
/* ts A70519 : allocation length byte 3+4 was 0,255 */
|
||||
@ -63,6 +68,9 @@ int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "test_unit_ready") <= 0)
|
||||
return 0;
|
||||
|
||||
scsi_init_command(&c, SPC_TEST_UNIT_READY,sizeof(SPC_TEST_UNIT_READY));
|
||||
/*
|
||||
c.oplen = sizeof(SPC_TEST_UNIT_READY);
|
||||
@ -90,19 +98,73 @@ int spc_test_unit_ready(struct burn_drive *d)
|
||||
|
||||
|
||||
/* ts A70315 */
|
||||
/** @param flag bit0=do not wait 0.1 seconds before first test unit ready */
|
||||
/** Wait until the drive state becomes clear or until max_usec elapsed */
|
||||
int spc_wait_unit_attention(struct burn_drive *d, int max_sec)
|
||||
int spc_wait_unit_attention(struct burn_drive *d, int max_sec, char *cmd_text,
|
||||
int flag)
|
||||
{
|
||||
int i, ret, key, asc, ascq;
|
||||
int i, ret = 1, key = 0, asc = 0, ascq = 0;
|
||||
char msg[160];
|
||||
|
||||
for(i=0; i < max_sec; i++) {
|
||||
if (!(flag & 1))
|
||||
usleep(100000);
|
||||
for(i = !(flag & 1); i < max_sec * 10; i++) {
|
||||
ret = spc_test_unit_ready_r(d, &key, &asc, &ascq);
|
||||
if(ret > 0 || key!=0x2 || asc!=0x4) /* ready or error */
|
||||
|
||||
/* <<<
|
||||
fprintf(stderr,
|
||||
"libburn_EXPERIMENTAL: i= %d ret= %d key= %X asc= %2.2X ascq= %2.2X\n",
|
||||
i, ret, (unsigned) key, (unsigned) asc, (unsigned) ascq);
|
||||
*/
|
||||
|
||||
if(ret > 0) /* ready */
|
||||
break;
|
||||
if(key!=0x2 || asc!=0x4) {
|
||||
if (key == 0x2 && asc == 0x3A) {
|
||||
ret = 1; /* medium not present = ok */
|
||||
/* <<<
|
||||
ts A70912 :
|
||||
My LG GSA-4082B on asynchronous load:
|
||||
first it reports no media 2,3A,00,
|
||||
then it reports not ready 2,04,00,
|
||||
further media inquiry retrieves wrong data
|
||||
|
||||
if(i<=100)
|
||||
goto slumber;
|
||||
*/
|
||||
break;
|
||||
usleep(1000000);
|
||||
}
|
||||
if (i < max_sec)
|
||||
if (key == 0x6 && asc == 0x28 && ascq == 0x00)
|
||||
/* media change notice = try again */
|
||||
goto slumber;
|
||||
|
||||
sprintf(msg,
|
||||
"Asynchromous SCSI error on %s: key=%X asc=%2.2Xh ascq=%2.2Xh",
|
||||
cmd_text, (unsigned) key, (unsigned) asc,
|
||||
(unsigned) ascq);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002014d,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
d->cancel = 1;
|
||||
break;
|
||||
}
|
||||
slumber:;
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
sprintf(msg, "Async %s %s after %d.%d seconds",
|
||||
cmd_text, (ret > 0 ? "succeeded" : "failed"), i / 10, i % 10);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00020150,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_LOW, msg, 0, 0);
|
||||
|
||||
if (i < max_sec * 10)
|
||||
return (ret > 0);
|
||||
|
||||
sprintf(msg, "Timeout (%d s) with asynchronous SCSI command %s\n",
|
||||
max_sec, cmd_text);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002014f,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -111,6 +173,9 @@ void spc_request_sense(struct burn_drive *d, struct buffer *buf)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "request_sense") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
|
||||
c.retry = 0;
|
||||
/*
|
||||
@ -130,6 +195,9 @@ int spc_get_erase_progress(struct burn_drive *d)
|
||||
{
|
||||
struct buffer b;
|
||||
|
||||
if (mmc_function_spy(d, "get_erase_progress") <= 0)
|
||||
return 0;
|
||||
|
||||
spc_request_sense(d, &b);
|
||||
return (b.data[16] << 8) | b.data[17];
|
||||
}
|
||||
@ -140,6 +208,9 @@ void spc_inquiry(struct burn_drive *d)
|
||||
struct burn_scsi_inquiry_data *id;
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "inquiry") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, SPC_INQUIRY, sizeof(SPC_INQUIRY));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_INQUIRY, sizeof(SPC_INQUIRY));
|
||||
@ -171,6 +242,9 @@ void spc_prevent(struct burn_drive *d)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "prevent") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, SPC_PREVENT, sizeof(SPC_PREVENT));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_PREVENT, sizeof(SPC_PREVENT));
|
||||
@ -186,6 +260,9 @@ void spc_allow(struct burn_drive *d)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "allow") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, SPC_ALLOW, sizeof(SPC_ALLOW));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_ALLOW, sizeof(SPC_ALLOW));
|
||||
@ -368,6 +445,9 @@ void spc_sense_caps(struct burn_drive *d)
|
||||
{
|
||||
int alloc_len, start_len = 22, ret;
|
||||
|
||||
if (mmc_function_spy(d, "sense_caps") <= 0)
|
||||
return;
|
||||
|
||||
/* first command execution to learn Allocation Length */
|
||||
alloc_len = start_len;
|
||||
ret = spc_sense_caps_al(d, &alloc_len, 1);
|
||||
@ -389,6 +469,9 @@ void spc_sense_error_params(struct burn_drive *d)
|
||||
unsigned char *page;
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "sense_error_params") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
||||
@ -419,6 +502,9 @@ void spc_select_error_params(struct burn_drive *d,
|
||||
struct buffer buf;
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "select_error_params") <= 0)
|
||||
return;
|
||||
|
||||
scsi_init_command(&c, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
||||
@ -457,6 +543,9 @@ void spc_sense_write_params(struct burn_drive *d)
|
||||
unsigned char *page;
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "sense_write_params") <= 0)
|
||||
return;
|
||||
|
||||
/* ts A61007 : Done in soft at only caller burn_drive_grab() */
|
||||
/* a ssert(d->mdata->cdr_write || d->mdata->cdrw_write ||
|
||||
d->mdata->dvdr_write || d->mdata->dvdram_write); */
|
||||
@ -477,17 +566,21 @@ void spc_sense_write_params(struct burn_drive *d)
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
|
||||
size = c.page->data[0] * 256 + c.page->data[1];
|
||||
/* ts A71128 : do not interpret reply if error */
|
||||
m = d->mdata;
|
||||
if(!c.error) {
|
||||
size = c.page->data[0] * 256 + c.page->data[1];
|
||||
page = c.page->data + 8;
|
||||
burn_print(1, "write page length 0x%x\n", page[1]);
|
||||
m->write_page_length = page[1];
|
||||
m->write_page_valid = 1;
|
||||
} else
|
||||
m->write_page_valid = 0;
|
||||
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->current_profile == 0x12 || d->current_profile == 0x43)
|
||||
d->read_format_capacities(d, -1);
|
||||
else if (d->status == BURN_DISC_BLANK ||
|
||||
(d->current_is_cd_profile && d->status == BURN_DISC_APPENDABLE)) {
|
||||
@ -514,6 +607,9 @@ void spc_select_write_params(struct burn_drive *d,
|
||||
struct buffer buf;
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "select_write_params") <= 0)
|
||||
return;
|
||||
|
||||
/* ts A61007 : All current callers are safe. */
|
||||
/* a ssert(o->drive == d); */
|
||||
|
||||
@ -554,6 +650,9 @@ void spc_select_write_params(struct burn_drive *d,
|
||||
|
||||
void spc_getcaps(struct burn_drive *d)
|
||||
{
|
||||
if (mmc_function_spy(d, "getcaps") <= 0)
|
||||
return;
|
||||
|
||||
spc_inquiry(d);
|
||||
spc_sense_caps(d);
|
||||
spc_sense_error_params(d);
|
||||
@ -573,6 +672,9 @@ void spc_probe_write_modes(struct burn_drive *d)
|
||||
int last_try = 0;
|
||||
struct command c;
|
||||
|
||||
if (mmc_function_spy(d, "spc_probe_write_modes") <= 0)
|
||||
return;
|
||||
|
||||
/* 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,
|
||||
@ -739,11 +841,8 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
||||
d->silent_on_scsi_error = 0;
|
||||
|
||||
|
||||
d->idata = malloc(sizeof(struct burn_scsi_inquiry_data));
|
||||
d->idata->valid = 0;
|
||||
d->mdata = malloc(sizeof(struct scsi_mode_data));
|
||||
d->mdata->valid = 0;
|
||||
d->mdata->speed_descriptors = NULL;
|
||||
d->idata = calloc(1, sizeof(struct burn_scsi_inquiry_data));
|
||||
d->mdata = calloc(1, sizeof(struct scsi_mode_data));
|
||||
|
||||
/* ts A61007 : obsolete Assert in drive_getcaps() */
|
||||
if(d->idata == NULL || d->mdata == NULL) {
|
||||
@ -752,6 +851,9 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
|
||||
"Could not allocate new drive object", 0, 0);
|
||||
return -1;
|
||||
}
|
||||
d->idata->valid = 0;
|
||||
d->mdata->valid = 0;
|
||||
d->mdata->speed_descriptors = NULL;
|
||||
if(!(flag & 1)) {
|
||||
ret = spc_setup_drive(d);
|
||||
if (ret<=0)
|
||||
|
@ -28,7 +28,8 @@ 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);
|
||||
int spc_wait_unit_attention(struct burn_drive *d, int max_sec, char *cmd_text,
|
||||
int flag);
|
||||
|
||||
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
|
@ -40,6 +40,8 @@ struct burn_disc *burn_disc_create(void)
|
||||
{
|
||||
struct burn_disc *d;
|
||||
d = calloc(1, sizeof(struct burn_disc));
|
||||
if (d == NULL) /* ts A70825 */
|
||||
return NULL;
|
||||
d->refcnt = 1;
|
||||
d->sessions = 0;
|
||||
d->session = NULL;
|
||||
@ -64,6 +66,8 @@ struct burn_session *burn_session_create(void)
|
||||
{
|
||||
struct burn_session *s;
|
||||
s = calloc(1, sizeof(struct burn_session));
|
||||
if (s == NULL) /* ts A70825 */
|
||||
return NULL;
|
||||
s->refcnt = 1;
|
||||
s->tracks = 0;
|
||||
s->track = NULL;
|
||||
@ -104,6 +108,8 @@ struct burn_track *burn_track_create(void)
|
||||
{
|
||||
struct burn_track *t;
|
||||
t = calloc(1, sizeof(struct burn_track));
|
||||
if (t == NULL) /* ts A70825 */
|
||||
return NULL;
|
||||
t->refcnt = 1;
|
||||
t->indices = 0;
|
||||
t->offset = 0;
|
||||
|
@ -114,13 +114,21 @@ struct burn_format_descr {
|
||||
off_t size;
|
||||
|
||||
/* the Type Dependent Parameter (usually the write alignment size) */
|
||||
unsigned tdp;
|
||||
unsigned int tdp;
|
||||
};
|
||||
|
||||
|
||||
/** Gets initialized in enumerate_common() and burn_drive_register() */
|
||||
struct burn_drive
|
||||
{
|
||||
/* ts A70902:
|
||||
0=null-emulation
|
||||
1=MMC drive ,
|
||||
2=stdio random read-write
|
||||
3=stdio sequential write-only
|
||||
*/
|
||||
int drive_role;
|
||||
|
||||
int bus_no;
|
||||
int host;
|
||||
int id;
|
||||
@ -172,9 +180,12 @@ struct burn_drive
|
||||
*/
|
||||
int current_feat2fh_byte4;
|
||||
|
||||
/* ts A70114 : wether a DVD-RW media holds an incomplete session
|
||||
/* ts A70114 : whether a DVD-RW media holds an incomplete session
|
||||
(which could need closing after write) */
|
||||
int needs_close_session;
|
||||
/* ts A71003 : whether a random write operation was done and no
|
||||
synchronize chache has happened yet */
|
||||
int needs_sync_cache;
|
||||
|
||||
/* ts A61218 from 51h READ DISC INFORMATION */
|
||||
int bg_format_status; /* 0=needs format start, 1=needs format restart*/
|
||||
@ -182,7 +193,7 @@ struct burn_drive
|
||||
/* ts A70108 from 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24 */
|
||||
int format_descr_type; /* 1=unformatted, 2=formatted, 3=unclear */
|
||||
off_t format_curr_max_size; /* meaning depends on format_descr_type */
|
||||
unsigned format_curr_blsas; /* meaning depends on format_descr_type */
|
||||
unsigned int format_curr_blsas; /* dito */
|
||||
int best_format_type;
|
||||
off_t best_format_size;
|
||||
|
||||
@ -196,6 +207,8 @@ struct burn_drive
|
||||
/* ts A61106 */
|
||||
int silent_on_scsi_error;
|
||||
|
||||
int stdio_fd;
|
||||
|
||||
int nwa; /* next writeable address */
|
||||
int alba; /* absolute lba */
|
||||
int rlba; /* relative lba in section */
|
||||
@ -229,18 +242,24 @@ struct burn_drive
|
||||
int pbf_altered;
|
||||
int wait_for_buffer_free;
|
||||
int nominal_write_speed;
|
||||
unsigned wfb_min_usec;
|
||||
unsigned wfb_max_usec;
|
||||
unsigned wfb_timeout_sec;
|
||||
unsigned wfb_min_percent;
|
||||
unsigned wfb_max_percent;
|
||||
unsigned pessimistic_writes;
|
||||
unsigned waited_writes;
|
||||
unsigned waited_tries;
|
||||
unsigned waited_usec;
|
||||
unsigned int wfb_min_usec;
|
||||
unsigned int wfb_max_usec;
|
||||
unsigned int wfb_timeout_sec;
|
||||
unsigned int wfb_min_percent;
|
||||
unsigned int wfb_max_percent;
|
||||
unsigned int pessimistic_writes;
|
||||
unsigned int waited_writes;
|
||||
unsigned int waited_tries;
|
||||
unsigned int waited_usec;
|
||||
|
||||
volatile int cancel;
|
||||
volatile enum burn_drive_status busy;
|
||||
|
||||
/* ts A70929 */
|
||||
pid_t thread_pid;
|
||||
int thread_pid_valid;
|
||||
|
||||
|
||||
/* transport functions */
|
||||
int (*grab) (struct burn_drive *);
|
||||
int (*release) (struct burn_drive *);
|
||||
@ -320,6 +339,11 @@ struct burn_drive
|
||||
/* mmc5r03c.pdf 6.24 : get list of available formats */
|
||||
int (*read_format_capacities) (struct burn_drive *d, int top_wanted);
|
||||
|
||||
/* ts A70812 */
|
||||
/* mmc5r03c.pdf 6.15 : read data sectors (start and amount in LBA) */
|
||||
int (*read_10) (struct burn_drive *d, int start, int amount,
|
||||
struct buffer *buf);
|
||||
|
||||
};
|
||||
|
||||
/* end of generic 'drive' data structures */
|
||||
|
@ -47,7 +47,14 @@ char *burn_strndup(char *s, int n)
|
||||
|
||||
void burn_version(int *major, int *minor, int *micro)
|
||||
{
|
||||
/* ts A80408 : switched from configure.ac versioning to libburn.h versioning */
|
||||
#ifdef burn_header_version_major
|
||||
*major = burn_header_version_major;
|
||||
*minor = burn_header_version_minor;
|
||||
*micro = burn_header_version_micro;
|
||||
#else
|
||||
*major = BURN_MAJOR_VERSION;
|
||||
*minor = BURN_MINOR_VERSION;
|
||||
*micro = BURN_MICRO_VERSION;
|
||||
#endif
|
||||
}
|
||||
|
739
libburn/write.c
739
libburn/write.c
@ -18,11 +18,16 @@
|
||||
#define Libburn_sao_can_appenD 1
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "sector.h"
|
||||
#include "libburn.h"
|
||||
@ -38,6 +43,7 @@
|
||||
#include "write.h"
|
||||
#include "options.h"
|
||||
#include "structure.h"
|
||||
#include "source.h"
|
||||
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
@ -112,7 +118,9 @@ void type_to_form(int mode, unsigned char *ctladr, int *form)
|
||||
*form |= 0x40;
|
||||
}
|
||||
|
||||
int burn_write_flush(struct burn_write_opts *o, struct burn_track *track)
|
||||
|
||||
/* ts A71002 : outsourced from burn_write_flush() : no sync cache here */
|
||||
int burn_write_flush_buffer(struct burn_write_opts *o,struct burn_track *track)
|
||||
{
|
||||
struct burn_drive *d = o->drive;
|
||||
|
||||
@ -133,13 +141,25 @@ int burn_write_flush(struct burn_write_opts *o, struct burn_track *track)
|
||||
d->buffer->bytes = 0;
|
||||
d->buffer->sectors = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int burn_write_flush(struct burn_write_opts *o, struct burn_track *track)
|
||||
{
|
||||
int ret;
|
||||
struct burn_drive *d = o->drive;
|
||||
|
||||
ret = burn_write_flush_buffer(o, track);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
d->sync_cache(d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61030 */
|
||||
int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
/* ts A71002 : outsourced from burn_write_close_track() */
|
||||
int burn_write_track_minsize(struct burn_write_opts *o, struct burn_session *s,
|
||||
int tnum)
|
||||
{
|
||||
char msg[81];
|
||||
@ -147,11 +167,6 @@ int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
struct burn_track *t;
|
||||
int todo, step, cancelled, seclen;
|
||||
|
||||
/* ts A61106 */
|
||||
#ifdef Libburn_experimental_no_close_tracK
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
d = o->drive;
|
||||
t = s->track[tnum];
|
||||
|
||||
@ -185,8 +200,26 @@ int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
}
|
||||
d->cancel = cancelled;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A61030 */
|
||||
int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
int tnum)
|
||||
{
|
||||
char msg[81];
|
||||
struct burn_drive *d;
|
||||
struct burn_track *t;
|
||||
|
||||
/* ts A61106 */
|
||||
#ifdef Libburn_experimental_no_close_tracK
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
d = o->drive;
|
||||
t = s->track[tnum];
|
||||
|
||||
/* ts A61102 */
|
||||
d->busy = BURN_DRIVE_CLOSING_TRACK;
|
||||
|
||||
sprintf(msg, "Closing track %2.2d", tnum+1);
|
||||
@ -201,13 +234,13 @@ int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
*/
|
||||
d->close_track_session(o->drive, 0, 0xff);
|
||||
|
||||
/* ts A61102 */
|
||||
d->busy = BURN_DRIVE_WRITING;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ts A61030 */
|
||||
int burn_write_close_session(struct burn_write_opts *o, struct burn_session *s)
|
||||
{
|
||||
@ -804,14 +837,18 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
/* ts A61103 */
|
||||
ret = 1;
|
||||
ex:;
|
||||
if (d->cancel)
|
||||
burn_source_cancel(t->source);
|
||||
if (o->write_type == BURN_WRITE_TAO) {
|
||||
|
||||
/* ts A61103 */
|
||||
/* >>> if cancelled: ensure that at least 600 kB get written */
|
||||
|
||||
if (!burn_write_flush(o, t))
|
||||
/* ts A71002 */
|
||||
if (!burn_write_flush_buffer(o, t))
|
||||
ret = 0;
|
||||
|
||||
/* Ensure that at least 600 kB get written */
|
||||
burn_write_track_minsize(o, s, tnum);
|
||||
d->sync_cache(d);
|
||||
|
||||
/* ts A61030 */
|
||||
if (burn_write_close_track(o, s, tnum) <= 0)
|
||||
ret = 0;
|
||||
@ -910,6 +947,13 @@ int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
|
||||
reason_pt= reasons;
|
||||
reasons[0] = 0;
|
||||
|
||||
if (d->drive_role == 0) {
|
||||
sprintf(reasons,
|
||||
"DRIVE: is a virtual placeholder (null-drive)");
|
||||
no_media = 1;
|
||||
goto ex;
|
||||
}
|
||||
|
||||
/* check write mode against write job */
|
||||
wt = burn_write_opts_auto_write_type(o, disc, reasons, 1);
|
||||
if (wt == BURN_WRITE_NONE) {
|
||||
@ -922,25 +966,29 @@ int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
|
||||
reason_pt= reasons + strlen(reasons);
|
||||
if (d->status == BURN_DISC_UNSUITABLE)
|
||||
goto unsuitable_profile;
|
||||
if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
|
||||
if (d->drive_role == 2 ||
|
||||
d->current_profile == 0x1a || d->current_profile == 0x12 ||
|
||||
d->current_profile == 0x43) {
|
||||
/* DVD+RW , DVD-RAM , BD-RE, emulated drive on stdio file */
|
||||
if (o->start_byte >= 0 && (o->start_byte % 2048))
|
||||
strcat(reasons,
|
||||
"write start address not properly aligned to 2048, ");
|
||||
} else if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
|
||||
/* CD-R , CD-RW */
|
||||
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 ||
|
||||
} else if (d->drive_role == 3 ||
|
||||
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] */
|
||||
/* DVD-R* Sequential , DVD+R[/DL] , sequential stdio "drive" */
|
||||
if (o->start_byte >= 0)
|
||||
strcat(reasons, "write start address not supported, ");
|
||||
} else {
|
||||
@ -1177,7 +1225,7 @@ int burn_dvd_write_track(struct burn_write_opts *o,
|
||||
}
|
||||
|
||||
|
||||
/* >>> ts A70215 : what about offset padding ? */
|
||||
/* (offset padding is done within sector_data()) */
|
||||
|
||||
burn_disc_init_track_status(o, s, tnum, sectors);
|
||||
for (i = 0; open_ended || i < sectors; i++) {
|
||||
@ -1200,7 +1248,7 @@ int burn_dvd_write_track(struct burn_write_opts *o,
|
||||
d->progress.sector++;
|
||||
}
|
||||
|
||||
/* >>> ts A70215 : what about tail padding ? */
|
||||
/* (tail padding is done in sector_data()) */
|
||||
|
||||
/* Pad up buffer to next full o->obs (usually 32 kB) */
|
||||
if (o->obs_pad && out->bytes > 0 && out->bytes < o->obs) {
|
||||
@ -1229,6 +1277,8 @@ int burn_dvd_write_track(struct burn_write_opts *o,
|
||||
}
|
||||
ret = 1;
|
||||
ex:;
|
||||
if (d->cancel)
|
||||
burn_source_cancel(t->source);
|
||||
if (!is_flushed)
|
||||
d->sync_cache(d); /* burn_write_flush() was not called */
|
||||
return ret;
|
||||
@ -1321,8 +1371,8 @@ int burn_dvd_write_session(struct burn_write_opts *o,
|
||||
ret = burn_disc_close_session_dvd_minus_r(o, s);
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
} else if (d->current_profile == 0x12) {
|
||||
/* DVD-RAM */
|
||||
} else if (d->current_profile == 0x12 || d->current_profile == 0x43) {
|
||||
/* DVD-RAM , BD-RE */
|
||||
/* ??? any finalization needed ? */;
|
||||
} else if (d->current_profile == 0x13) {
|
||||
/* DVD-RW restricted overwrite */
|
||||
@ -1431,8 +1481,6 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o,
|
||||
|
||||
/* >>> perform OPC if needed */;
|
||||
|
||||
/* >>> */;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1473,63 +1521,11 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
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;
|
||||
if (disc->session[sx]->track[tx]->mode != BURN_MODE1)
|
||||
exotic_track = 1;
|
||||
}
|
||||
if (exotic_track) {
|
||||
sprintf(msg,"DVD Media are unsuitable for desired track type");
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020123,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
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 */
|
||||
if (disc->sessions!=1 || disc->session[0]->tracks>1
|
||||
|| o->multi ) {
|
||||
sprintf(msg,
|
||||
"Burning is restricted to a single track and no multi-session on %s",
|
||||
d->current_profile_text);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002011f,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
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);
|
||||
goto early_failure;
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
if (d->current_profile == 0x1a || d->current_profile == 0x12 ||
|
||||
d->current_profile == 0x43) {
|
||||
/* DVD+RW , DVD-RAM , BD-RE */
|
||||
ret = 1;
|
||||
if (d->current_profile == 0x1a)
|
||||
ret = burn_disc_setup_dvd_plus_rw(o, disc);
|
||||
@ -1546,20 +1542,6 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
|
||||
} 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);
|
||||
goto early_failure;
|
||||
}
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
ret = burn_disc_setup_dvd_minus_rw(o, disc);
|
||||
if (ret <= 0) {
|
||||
sprintf(msg,
|
||||
@ -1580,69 +1562,6 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
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 &&
|
||||
(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,
|
||||
d->global_index, 0x00020134,
|
||||
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,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Cannot perform TAO (lack of feature 21h), job unsuitable for DAO",
|
||||
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);
|
||||
|
||||
/* <<< ??? 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);
|
||||
|
||||
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);
|
||||
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);
|
||||
@ -1670,11 +1589,6 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
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);
|
||||
@ -1696,19 +1610,6 @@ int burn_dvd_write_sync(struct burn_write_opts *o,
|
||||
}
|
||||
/* ??? 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);
|
||||
goto early_failure;
|
||||
#endif /* ! Libburn_precheck_write_ruleS */
|
||||
|
||||
}
|
||||
o->obs = 32*1024; /* buffer flush trigger for sector.c:get_sector() */
|
||||
|
||||
@ -1743,6 +1644,323 @@ early_failure:;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70904 */
|
||||
int burn_stdio_open_write(struct burn_drive *d, off_t start_byte,
|
||||
int sector_size, int flag)
|
||||
{
|
||||
|
||||
/* <<< We need _LARGEFILE64_SOURCE defined by the build system.
|
||||
*/
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
int fd = -1;
|
||||
int mode = O_RDWR | O_CREAT | O_LARGEFILE;
|
||||
char msg[160];
|
||||
|
||||
if (d->devname[0] == 0) /* null drives should not come here */
|
||||
return -1;
|
||||
fd = burn_drive__fd_from_special_adr(d->devname);
|
||||
if (fd >= 0)
|
||||
fd = dup(fd); /* check validity and make closeable */
|
||||
else
|
||||
fd = open(d->devname, mode, S_IRUSR | S_IWUSR);
|
||||
if (fd == -1) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020005,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Failed to open device (a pseudo-drive)", errno, 0);
|
||||
d->cancel = 1;
|
||||
return -1;
|
||||
}
|
||||
if (start_byte < 0)
|
||||
start_byte = 0;
|
||||
if (d->drive_role == 2)
|
||||
if (lseek(fd, start_byte, SEEK_SET)==-1) {
|
||||
sprintf(msg, "Cannot address start byte %.f",
|
||||
(double) start_byte);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020147,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, errno, 0);
|
||||
close(fd);
|
||||
d->cancel = 1;
|
||||
fd = -1;
|
||||
}
|
||||
d->nwa = start_byte / sector_size;
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70904 */
|
||||
int burn_stdio_read_source(struct burn_source *source, char *buf, int bufsize,
|
||||
struct burn_write_opts *o, int flag)
|
||||
{
|
||||
int count= 0, todo;
|
||||
|
||||
for(todo = bufsize; todo > 0; todo -= count) {
|
||||
if(source->read!=NULL)
|
||||
count = source->read(source,
|
||||
(unsigned char *) (buf + (bufsize - todo)), todo);
|
||||
else
|
||||
count = source->read_xt(source,
|
||||
(unsigned char *) (buf + (bufsize - todo)), todo);
|
||||
if (count <= 0)
|
||||
break;
|
||||
}
|
||||
return (bufsize - todo);
|
||||
}
|
||||
|
||||
|
||||
/* ts A70904 */
|
||||
int burn_stdio_write(int fd, char *buf, int count, struct burn_drive *d,
|
||||
int flag)
|
||||
{
|
||||
if (write(fd, buf, count) != count) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020148,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Cannot write desired amount of data", errno, 0);
|
||||
d->cancel = 1;
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70910 : to be used as burn_drive.write(), emulating mmc_write() */
|
||||
int burn_stdio_mmc_write(struct burn_drive *d, int start, struct buffer *buf)
|
||||
{
|
||||
int ret;
|
||||
off_t start_byte;
|
||||
|
||||
if (d->cancel)
|
||||
return BE_CANCELLED;
|
||||
if (d->stdio_fd < 0) {
|
||||
|
||||
/* >>> program error */;
|
||||
|
||||
d->cancel = 1;
|
||||
return BE_CANCELLED;
|
||||
}
|
||||
if (start != d->nwa) {
|
||||
char msg[80];
|
||||
|
||||
start_byte = ((off_t) start) *
|
||||
(off_t) (buf->bytes / buf->sectors);
|
||||
if (lseek(d->stdio_fd, start_byte, SEEK_SET)==-1) {
|
||||
sprintf(msg, "Cannot address start byte %.f",
|
||||
(double) start_byte);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020147,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, errno, 0);
|
||||
d->cancel = 1;
|
||||
return BE_CANCELLED;
|
||||
}
|
||||
d->nwa = start;
|
||||
}
|
||||
ret = burn_stdio_write(d->stdio_fd,(char *)buf->data, buf->bytes, d,0);
|
||||
if (ret <= 0)
|
||||
return BE_CANCELLED;
|
||||
d->nwa += buf->sectors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70910 : to be used as burn_drive.write(),
|
||||
emulating mmc_write() with simulated writing. */
|
||||
int burn_stdio_mmc_dummy_write(struct burn_drive *d, int start,
|
||||
struct buffer *buf)
|
||||
{
|
||||
if (d->cancel)
|
||||
return BE_CANCELLED;
|
||||
d->nwa = start + buf->sectors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70911 */
|
||||
/* Flush stdio system buffer to physical device.
|
||||
@param flag bit0= do not report debug message (intermediate sync)
|
||||
*/
|
||||
int burn_stdio_sync_cache(int fd, struct burn_drive *d, int flag)
|
||||
{
|
||||
if (fd < 0) {
|
||||
|
||||
/* >>> program error */;
|
||||
|
||||
d->cancel = 1;
|
||||
return 0;
|
||||
}
|
||||
d->needs_sync_cache = 0;
|
||||
if (!(flag & 1))
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
||||
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
||||
"syncing cache (stdio fsync)", 0, 0);
|
||||
if (fsync(fd) != 0) {
|
||||
if (errno == EINVAL) /* E.g. /dev/null cannot fsync */
|
||||
return 1;
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020148,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Cannot write desired amount of data", errno, 0);
|
||||
d->cancel = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70911 : to be used as burn_drive.sync_cache(),
|
||||
emulating mmc_sync_cache() */
|
||||
void burn_stdio_mmc_sync_cache(struct burn_drive *d)
|
||||
{
|
||||
burn_stdio_sync_cache(d->stdio_fd, d, 0);
|
||||
}
|
||||
|
||||
|
||||
/* ts A70912 */
|
||||
/* Enforces eventual nominal write speed.
|
||||
@param flag bit0= initialize *prev_time */
|
||||
int burn_stdio_slowdown(struct burn_drive *d, struct timeval *prev_time,
|
||||
int amount, int flag)
|
||||
{
|
||||
struct timeval tnow;
|
||||
struct timezone dummy_tz;
|
||||
double to_wait;
|
||||
|
||||
if (flag & 1) {
|
||||
gettimeofday(prev_time, &dummy_tz);
|
||||
return 1;
|
||||
}
|
||||
if(d->nominal_write_speed <= 0)
|
||||
return 2;
|
||||
gettimeofday(&tnow, &dummy_tz);
|
||||
to_wait = ( ((double) amount) / (double) d->nominal_write_speed ) -
|
||||
(double) ( tnow.tv_sec - prev_time->tv_sec ) -
|
||||
(double) ( tnow.tv_usec - prev_time->tv_usec ) / 1.0e6
|
||||
- 0.001; /* best would be 1 / kernel granularity HZ */
|
||||
if (to_wait >= 0.0001) {
|
||||
usleep((int) (to_wait * 1000000.0));
|
||||
}
|
||||
gettimeofday(prev_time, &dummy_tz);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70904 */
|
||||
int burn_stdio_write_track(struct burn_write_opts *o, struct burn_session *s,
|
||||
int tnum, int flag)
|
||||
{
|
||||
int open_ended, bufsize, ret, sectors, fd;
|
||||
struct burn_track *t = s->track[tnum];
|
||||
struct burn_drive *d = o->drive;
|
||||
char buf[16*2048];
|
||||
int i, prev_sync_sector = 0;
|
||||
struct buffer *out = d->buffer;
|
||||
struct timeval prev_time;
|
||||
|
||||
bufsize = sizeof(buf);
|
||||
fd = d->stdio_fd;
|
||||
|
||||
sectors = burn_track_get_sectors(t);
|
||||
burn_disc_init_track_status(o, s, tnum, sectors);
|
||||
open_ended = burn_track_is_open_ended(t);
|
||||
|
||||
/* attach stdio emulators for mmc_*() functions */
|
||||
if (o->simulate)
|
||||
d->write = burn_stdio_mmc_dummy_write;
|
||||
else
|
||||
d->write = burn_stdio_mmc_write;
|
||||
d->sync_cache = burn_stdio_mmc_sync_cache;
|
||||
|
||||
burn_stdio_slowdown(d, &prev_time, 0, 1); /* initialize */
|
||||
for (i = 0; open_ended || i < sectors; i++) {
|
||||
/* transact a (CD sized) sector */
|
||||
if (!sector_data(o, t, 0))
|
||||
{ret= 0; goto ex;}
|
||||
if (open_ended) {
|
||||
d->progress.sectors = sectors = d->progress.sector;
|
||||
if (burn_track_is_data_done(t))
|
||||
break;
|
||||
}
|
||||
d->progress.sector++;
|
||||
/* Flush to disk after each full MB */
|
||||
if (d->progress.sector - prev_sync_sector >= 512) {
|
||||
prev_sync_sector = d->progress.sector;
|
||||
if (!o->simulate)
|
||||
burn_stdio_sync_cache(d->stdio_fd, d, 1);
|
||||
burn_stdio_slowdown(d, &prev_time, 512 * 2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
out->sectors += (o->obs - out->bytes) / 2048;
|
||||
out->bytes = o->obs;
|
||||
}
|
||||
ret = burn_write_flush(o, t);
|
||||
ret= 1;
|
||||
ex:;
|
||||
if (d->cancel)
|
||||
burn_source_cancel(t->source);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ts A70904 */
|
||||
int burn_stdio_write_sync(struct burn_write_opts *o,
|
||||
struct burn_disc *disc)
|
||||
{
|
||||
int ret;
|
||||
struct burn_drive *d = o->drive;
|
||||
|
||||
d->needs_close_session = 0;
|
||||
o->obs_pad = 0; /* no filling-up of track's last 32k buffer */
|
||||
o->obs = 32*1024; /* buffer size */
|
||||
|
||||
if (disc->sessions != 1)
|
||||
{ret= 0 ; goto ex;}
|
||||
if (disc->session[0]->tracks != 1)
|
||||
{ret= 0 ; goto ex;}
|
||||
|
||||
/* update progress */
|
||||
d->progress.session = 0;
|
||||
d->progress.tracks = 1;
|
||||
|
||||
/* >>> adjust sector size (2048) to eventual audio or even raw */
|
||||
/* open target file */
|
||||
if (d->stdio_fd >= 0)
|
||||
close(d->stdio_fd);
|
||||
d->stdio_fd = burn_stdio_open_write(d, o->start_byte, 2048, 0);
|
||||
if (d->stdio_fd == -1)
|
||||
{ret = 0; goto ex;}
|
||||
|
||||
ret = burn_stdio_write_track(o, disc->session[0], 0, 0);
|
||||
if (ret <= 0)
|
||||
goto ex;
|
||||
|
||||
/* XXX: currently signs an end of session */
|
||||
d->progress.sector = 0;
|
||||
d->progress.start_sector = 0;
|
||||
d->progress.sectors = 0;
|
||||
ret = 1;
|
||||
ex:;
|
||||
if (d->stdio_fd >= 0)
|
||||
close(d->stdio_fd);
|
||||
d->stdio_fd = -1;
|
||||
|
||||
/* update media state records */
|
||||
burn_drive_mark_unready(d);
|
||||
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
|
||||
{
|
||||
struct cue_sheet *sheet;
|
||||
@ -1765,6 +1983,13 @@ void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
|
||||
d->rlba = -150;
|
||||
d->toc_temp = 9;
|
||||
|
||||
/* ts A70904 */
|
||||
if (d->drive_role != 1) {
|
||||
ret = burn_stdio_write_sync(o, disc);
|
||||
if (ret <= 0)
|
||||
goto fail_wo_sync;
|
||||
return;
|
||||
}
|
||||
/* ts A61218 */
|
||||
if (! d->current_is_cd_profile) {
|
||||
ret = burn_dvd_write_sync(o, disc);
|
||||
@ -1773,45 +1998,12 @@ 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);
|
||||
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);
|
||||
@ -1969,3 +2161,126 @@ fail_wo_sync:;
|
||||
d->cancel = 1;
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
}
|
||||
|
||||
/* ts A70811 : API function */
|
||||
int burn_random_access_write(struct burn_drive *d, off_t byte_address,
|
||||
char *data, off_t data_count, int flag)
|
||||
{
|
||||
int alignment = 0, start, upto, chunksize, err, fd = -1, ret;
|
||||
char msg[81], *rpt;
|
||||
struct buffer buf;
|
||||
|
||||
if (d->released) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020142,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is not grabbed on random access write", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
if(d->drive_role == 0) {
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020146,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is a virtual placeholder (null-drive)", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(d->drive_role == 2)
|
||||
alignment = 2 * 1024;
|
||||
if (d->current_profile == 0x12) /* DVD-RAM */
|
||||
alignment = 2 * 1024;
|
||||
if (d->current_profile == 0x13) /* DVD-RW restricted overwrite */
|
||||
alignment = 32 * 1024;
|
||||
if (d->current_profile == 0x1a) /* DVD+RW */
|
||||
alignment = 2 * 1024;
|
||||
if (d->current_profile == 0x43) /* BD-RE */
|
||||
alignment = 2 * 1024;
|
||||
if (alignment == 0) {
|
||||
sprintf(msg, "Write start address not supported");
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020125,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Write start address not supported", 0, 0);
|
||||
return 0;
|
||||
}
|
||||
if ((byte_address % alignment) != 0) {
|
||||
sprintf(msg,
|
||||
"Write start address not properly aligned (%d bytes)",
|
||||
alignment);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020126,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
if ((data_count % alignment) != 0) {
|
||||
sprintf(msg,
|
||||
"Write data count not properly aligned (%ld bytes)",
|
||||
(long) alignment);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x00020141,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
if (d->busy != BURN_DRIVE_IDLE) {
|
||||
libdax_msgs_submit(libdax_messenger,
|
||||
d->global_index, 0x00020140,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Drive is busy on attempt to write random access",0,0);
|
||||
return 0;
|
||||
}
|
||||
if(d->drive_role != 1) {
|
||||
fd = burn_stdio_open_write(d, byte_address, 2048, 0);
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
}
|
||||
d->busy = BURN_DRIVE_WRITING_SYNC;
|
||||
d->buffer = &buf;
|
||||
|
||||
start = byte_address / 2048;
|
||||
upto = start + data_count / 2048;
|
||||
rpt = data;
|
||||
for (; start < upto; start += 16) {
|
||||
chunksize = upto - start;
|
||||
if (chunksize > 16)
|
||||
chunksize = 16;
|
||||
d->buffer->bytes = chunksize * 2048;
|
||||
memcpy(d->buffer->data, rpt, d->buffer->bytes);
|
||||
rpt += d->buffer->bytes;
|
||||
d->buffer->sectors = chunksize;
|
||||
d->nwa = start;
|
||||
if(d->drive_role == 1) {
|
||||
err = d->write(d, d->nwa, d->buffer);
|
||||
} else {
|
||||
ret = burn_stdio_write(fd, (char *) d->buffer->data,
|
||||
d->buffer->bytes, d, 0);
|
||||
err = 0;
|
||||
if (ret <= 0)
|
||||
err = BE_CANCELLED;
|
||||
}
|
||||
if (err == BE_CANCELLED) {
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
return (-(start * 2048 - byte_address));
|
||||
}
|
||||
}
|
||||
|
||||
if(d->drive_role == 1)
|
||||
d->needs_sync_cache = 1;
|
||||
if(flag & 1) {
|
||||
if(d->drive_role == 1)
|
||||
d->sync_cache(d);
|
||||
else
|
||||
burn_stdio_sync_cache(fd, d, 0);
|
||||
d->needs_sync_cache = 0;
|
||||
}
|
||||
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
d->buffer = NULL;
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
1503
libcevap/cgen.c
Normal file
1503
libcevap/cgen.c
Normal file
File diff suppressed because it is too large
Load Diff
35
libcevap/cgen.h
Normal file
35
libcevap/cgen.h
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
#ifndef Cgen_includeD
|
||||
#define Cgen_includeD Yes
|
||||
|
||||
|
||||
|
||||
struct CgeN {
|
||||
|
||||
char *classname;
|
||||
char *structname;
|
||||
char *functname;
|
||||
|
||||
int is_managed_list;
|
||||
int is_bossless_list;
|
||||
int gen_for_stic; /* 0=no smem,srgex,sfile , 1=all three, 2=smem only */
|
||||
int make_ansi;
|
||||
int make_lowercase;
|
||||
char global_include_file[4096];
|
||||
FILE *global_include_fp;
|
||||
|
||||
struct CtyP *elements;
|
||||
struct CtyP *last_element;
|
||||
|
||||
int may_overwrite;
|
||||
FILE *fp;
|
||||
char filename[4096];
|
||||
FILE *ptt_fp;
|
||||
char ptt_filename[4096];
|
||||
|
||||
char msg[8192];
|
||||
};
|
||||
|
||||
|
||||
#endif /* Cgen_includeD */
|
||||
|
222
libcevap/cgen.txt
Normal file
222
libcevap/cgen.txt
Normal file
@ -0,0 +1,222 @@
|
||||
|
||||
|
||||
Description of the helper program stic*/bin/cgen
|
||||
|
||||
cgen is copyright 2001 to 2007, Thomas Schmitt <stic-source@gmx.net>
|
||||
and provided under BSD license.
|
||||
|
||||
Compilation:
|
||||
cc -g -o cgen cgen.c ctyp.c smem.c
|
||||
|
||||
|
||||
cgen produces a class stub in C programming language. The data structure of
|
||||
the class is described by some lines which get read from stdin. The stub will
|
||||
consist of four files which emerge in the current working directory:
|
||||
<classname>.h public header file of the class
|
||||
<classname>.c automatically generated C code of the class
|
||||
plus a copy of <classname>.c.methods
|
||||
<classname>_private.h private header file of the class
|
||||
<classname>.c.methods safe storage for manually created functions.
|
||||
From here they get copied into the generated stub.
|
||||
If such a file is missing, a dummy gets created.
|
||||
It will define a struct <ClassnamE> for representing the class data aspects,
|
||||
construtor <Classname>_new(), destructor <Classname>_destroy(),
|
||||
getter <Classname>_<element>_get() for each structure element.
|
||||
Some more functions get added for particular class and element roles.
|
||||
|
||||
cgen normally refuses to overwrite existing files because it supposes that
|
||||
those contain code added by the human programmer.
|
||||
Human programmer enhancements may be explanatory comments, class specific
|
||||
methods, initial element values and other special precautions within the
|
||||
generated functions.
|
||||
As long as the modelling phase is going on, one may store such human code
|
||||
in <classname>.c.methods and may use command line option -overwrite for
|
||||
modelling development cycles.
|
||||
|
||||
At some point of model matureness one may decide to give up cgen and the
|
||||
.c.method files and to go on only with _private.h , .h and .c files.
|
||||
|
||||
|
||||
Command line options
|
||||
|
||||
-no_stic prevents usage of stic_dir/s_tools/*.[ch]
|
||||
|
||||
-ansi generates ANSI C function heads and makes file <classname>.h hold
|
||||
only public definitions: an opaque declaration of the class struct
|
||||
and a list of function prototypes. The definiton of the class
|
||||
struct is then in <classname>_private.h .
|
||||
-global_include filename
|
||||
sets the name of a file which will contain globally necessary
|
||||
declarations. Currently it lists the existence of all class
|
||||
structs.
|
||||
-lowercase generate struct <classname> rather than struct <ClassnamE> and
|
||||
function names <classname>_func() rather than <Classname>_func() .
|
||||
-overwrite allows to overwrite files <classname>_private.h, <classname>.h
|
||||
and <classname>.c, but not <classname>.c.methods.
|
||||
|
||||
|
||||
Input line format:
|
||||
|
||||
There are two states of input: class level and element level.
|
||||
Exampes are shown below with class roles and element roles.
|
||||
|
||||
Input starts at class level. A class level line may be one of
|
||||
|
||||
- Comment. A line which begins with '#' is ignored on class level.
|
||||
|
||||
- Empty. A line with no characters is a comment with empty text (i.e. ignored).
|
||||
|
||||
- Class. Options which begin with '-' and finally a word in lowercase letters
|
||||
which defines the <classname>. The classname leads to a struct ClassnamE
|
||||
and some class methods implemented as C functions <Classnname>_<func>().
|
||||
|
||||
- End of input. Line "@@@" or EOF at stdin end the program run.
|
||||
|
||||
After a class line, input switches to element level where a line may be:
|
||||
|
||||
- Comment. A line which after some white space begins with '#' is considered
|
||||
a comment. The preceeding white space is ignored and the text after '#' is
|
||||
eventuellay trimmed by a single blank at both ends. This text will be part
|
||||
of the class struct definition within file <classname_private>.h as a single
|
||||
C comment line /* ... */. The sequence of elements and comments is preserved.
|
||||
An empty comment text leads to an empty line in <classname_private>.h.
|
||||
|
||||
- Empty. A line with no characters is a comment with empty text.
|
||||
|
||||
- Element. Options which begin with '-', eventual C keywords "unsigned" or
|
||||
"volatile", type or "struct <NamE>", element name. This leads to a struct
|
||||
element which is taken into respect in some class methods. Depending on the
|
||||
options in this line, some element methods <Classnname>_<func>_<element>()
|
||||
may get generated.
|
||||
|
||||
- End of class. A single '@' marks the end of the element list and brings
|
||||
input back to class level. I.e. next is expected another class name or
|
||||
"@@@" or EOF at stdin.
|
||||
|
||||
Input semantics:
|
||||
|
||||
A class can have one of two roles:
|
||||
|
||||
- Standalone class.
|
||||
Input example:
|
||||
my_class
|
||||
|
||||
- Listable class, which has pointers to peer instances: .prev and .next
|
||||
Such classes get a list destructor <Classname>_destroy_all() which destroys
|
||||
all members of a list (which is given by any of the list members).
|
||||
Such a class should have a pointer *boss as first element in which case
|
||||
the constructor will look like
|
||||
<Classname>_new(struct <ClassnamE> **o,struct <Some_clasS> *boss,int flag);
|
||||
There is a function <Classname>_link() which inserts an instance into a list
|
||||
and a function <Classname>_count() which tells the number of list members.
|
||||
For pseudo random access there is function <Classname>_by_idx().
|
||||
Input example:
|
||||
-l my_class
|
||||
|
||||
|
||||
A modifier is defined for classes:
|
||||
|
||||
- Bossless. Disables a special boss-subordinate relationship which is created
|
||||
if the first element of a class is a struct pointer with the name "boss".
|
||||
Like
|
||||
-l <classname>
|
||||
-v struct Some_clasS *boss
|
||||
Normally such a parameter *boss becomes part of the constructor method
|
||||
<Classname>_new(struct <ClassnamE> **o, struct Some_clasS *boss, int flag);
|
||||
This relationship is typical for a listable class and a single class which
|
||||
is designed to host instances of that listable class. Therefore one gets a
|
||||
warning if a listable class does not begin with a struct pointer *boss.
|
||||
But if -b is given, then CgeN ill not include a parameter *boss into the
|
||||
constructor. It will rather look normal:
|
||||
<Classname>_new(struct <ClassnamE> **o, int flag);
|
||||
It will not warn if the first element of a listable class is not struct
|
||||
pointer *boss.
|
||||
|
||||
|
||||
Elements have one of the following roles:
|
||||
|
||||
- Value. It provides only storage for a C data type (which may be a C pointer
|
||||
despite the role name "value"), a getter method <Classname>_<element>_get(),
|
||||
and a setter method <Classname>_<element>_set().
|
||||
Input examples:
|
||||
-v int i
|
||||
-v int a[100]
|
||||
-v char *cpt
|
||||
-v struct xyz x
|
||||
-v struct xyz *xpt
|
||||
|
||||
- Managed. This has to be a pointer to a struct <XyZ> or to char. It will not
|
||||
get attached to an object by the stub's code but its destructor
|
||||
<Xyz>_destroy() will be called by <Classname>_destruct(). In case of (char *)
|
||||
it is supposed that a non-NULL value has been allocated by malloc().
|
||||
Managed (char *) types get a setter function <Classname>_<element>_set()
|
||||
which allocates memory and copies the textstring from its parameter.
|
||||
Input examples:
|
||||
-m struct XyZ *xyzpt
|
||||
-m char *textstring
|
||||
|
||||
- Chainlink. A pair of prev-next-style pointers to the own class struct.
|
||||
Function <Classname>_destruct() will unlink the affected instance and
|
||||
put together its link partners.
|
||||
Input example (there must always be two consequtive -c lines):
|
||||
-c struct My_clasS *up
|
||||
-c struct My_clasS *down
|
||||
|
||||
- List. A pair of pointers to the struct <XyZ> of a listable class. The first
|
||||
one <ls> holds the start of the list, the second one <eol> holds the end.
|
||||
The getter function has an additional argument idx:
|
||||
<Classname>_get_<ls>(struct <ClassnamE> *o, int idx, struct <XyZ> **pt,
|
||||
int flag)
|
||||
idx == 0 is the start of the list, idx=1 the next element, ...
|
||||
idx == -1 retrieves the last element of the list.
|
||||
For insertion of list items there is provided method <Classname>_new_<ls>().
|
||||
The inserted item is reachable via the getter function with idx == -1
|
||||
<Classname>_destroy() instance calls <Xyz>_destroy_all(). Note that the end
|
||||
pointer is always generated as private element (-p).
|
||||
Input example (there must always be a -l and a -v line):
|
||||
-l struct XyZ *list_start
|
||||
-v struct XyZ *list_end
|
||||
|
||||
The availability of getter method <Classname>_get_<element>(), and setter
|
||||
method <Classname>_set_<element>_set() can be controled by two modifiers:
|
||||
|
||||
- Readonly. Only a getter method.
|
||||
Input example
|
||||
-r -v int broadcasted_status
|
||||
|
||||
- Private. Neither getter nor setter method.
|
||||
Input example
|
||||
-p -v int private_value
|
||||
|
||||
- Bossless listable. This marks elements which are listable objects but do not
|
||||
expect a boss pointer in their constructor. See above: Listable class and
|
||||
the bossless modifier for classes.
|
||||
Input example
|
||||
-b -l struct XyZ *list
|
||||
-v struct XyZ *last_in_list
|
||||
|
||||
- Initialization free. The class constructor will not initialize this element.
|
||||
This modifier has to be used if neither NULL nor 0 are suitable
|
||||
initialization values.
|
||||
|
||||
Example run:
|
||||
|
||||
rm class_x.c class_x.h class_y.c class_y.h
|
||||
bin/cgen <<+
|
||||
-l class_x
|
||||
-r -v struct Boss_clasS *boss
|
||||
-v int x
|
||||
-r -v struct stat stbuf
|
||||
-m struct Class_Y *y
|
||||
-m char *text
|
||||
-c struct Class_X *master
|
||||
-c struct Class_X *slave
|
||||
-b -l struct Class_X *provider
|
||||
-p -v struct Class_X *last_provider
|
||||
@
|
||||
-b -l class_y
|
||||
-r -v char providername[80]
|
||||
@
|
||||
+
|
||||
|
||||
|
364
libcevap/ctyp.c
Normal file
364
libcevap/ctyp.c
Normal file
@ -0,0 +1,364 @@
|
||||
|
||||
/*
|
||||
cc -g -o ctyp.c
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "smem.h"
|
||||
extern char *Sfile_fgets();
|
||||
extern int Sregex_string();
|
||||
extern int Sregex_trimline();
|
||||
|
||||
#include "ctyp.h"
|
||||
|
||||
|
||||
/* -------------------------- CtyP ----------------------- */
|
||||
|
||||
|
||||
int Ctyp_new(objpt,link,flag)
|
||||
struct CtyP **objpt;
|
||||
struct CtyP *link;
|
||||
int flag;
|
||||
{
|
||||
struct CtyP *o;
|
||||
int ret;
|
||||
|
||||
*objpt= o= TSOB_FELD(struct CtyP,1);
|
||||
if(o==NULL)
|
||||
return(-1);
|
||||
|
||||
o->is_comment= 0;
|
||||
o->is_pointer= 0;
|
||||
o->is_struct= 0;
|
||||
o->is_unsigned= 0;
|
||||
o->is_volatile= 0;
|
||||
o->array_size= 0;
|
||||
o->management= 0;
|
||||
o->with_getter= 1;
|
||||
o->with_setter= 1;
|
||||
o->bossless_list= 0;
|
||||
o->no_initializer= 0;
|
||||
o->dtype= NULL;
|
||||
o->name= NULL;
|
||||
o->prev= NULL;
|
||||
o->next= NULL;
|
||||
|
||||
if(link!=NULL)
|
||||
link->next= o;
|
||||
o->prev= link;
|
||||
|
||||
return(1);
|
||||
failed:;
|
||||
Ctyp_destroy(objpt,0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_destroy(objpt,flag)
|
||||
struct CtyP **objpt;
|
||||
int flag;
|
||||
{
|
||||
struct CtyP *o;
|
||||
|
||||
o= *objpt;
|
||||
if(o==NULL)
|
||||
return(0);
|
||||
|
||||
if(o->prev!=NULL)
|
||||
o->prev->next= o->next;
|
||||
if(o->next!=NULL)
|
||||
o->next->prev= o->prev;
|
||||
Sregex_string(&(o->dtype),NULL,0);
|
||||
Sregex_string(&(o->name),NULL,0);
|
||||
|
||||
free((char *) o);
|
||||
*objpt= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_get_pointer_level(ct,flag)
|
||||
struct CtyP *ct;
|
||||
int flag;
|
||||
{
|
||||
return(ct->is_pointer);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_is_struct(ct,flag)
|
||||
struct CtyP *ct;
|
||||
int flag;
|
||||
{
|
||||
return(ct->is_struct);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_get_array_size(ct,flag)
|
||||
struct CtyP *ct;
|
||||
int flag;
|
||||
{
|
||||
return(ct->array_size);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_get_management(ct,flag)
|
||||
struct CtyP *ct;
|
||||
int flag;
|
||||
{
|
||||
return(ct->management);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_get_with_getter(ct,flag)
|
||||
struct CtyP *ct;
|
||||
int flag;
|
||||
{
|
||||
return(ct->with_getter);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_get_with_setter(ct,flag)
|
||||
struct CtyP *ct;
|
||||
int flag;
|
||||
{
|
||||
return(ct->with_setter);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_get_dtype(ct,text,flag)
|
||||
struct CtyP *ct;
|
||||
char **text; /* must point to NULL of freeable memory */
|
||||
int flag;
|
||||
/*
|
||||
bit0=eventually prepend "struct "
|
||||
*/
|
||||
{
|
||||
if((flag&1) && ct->is_struct) {
|
||||
if(Sregex_string(text,"struct ",0)<=0)
|
||||
return(-1);
|
||||
} else {
|
||||
if(Sregex_string(text,"",0)<=0)
|
||||
return(-1);
|
||||
}
|
||||
if(Sregex_string(text,ct->dtype,1)<=0)
|
||||
return(-1);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_get_name(ct,text,flag)
|
||||
struct CtyP *ct;
|
||||
char **text; /* must point to NULL of freeable memory */
|
||||
int flag;
|
||||
{
|
||||
if(Sregex_string(text,ct->name,0)<=0)
|
||||
return(-1);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_get_type_mod(ct,is_spointer,is_struct,array_size,flag)
|
||||
struct CtyP *ct;
|
||||
int *is_spointer,*is_struct,*array_size;
|
||||
int flag;
|
||||
{
|
||||
*is_spointer= ct->is_pointer;
|
||||
*is_struct= ct->is_struct;
|
||||
*array_size= ct->array_size;
|
||||
}
|
||||
|
||||
int Ctyp_new_from_line(ct,link,line,msg,flag)
|
||||
struct CtyP **ct;
|
||||
struct CtyP *link;
|
||||
char *line;
|
||||
char *msg;
|
||||
int flag;
|
||||
/*
|
||||
bit0= make struct ClassnamE to struct classname
|
||||
*/
|
||||
{
|
||||
struct CtyP *o;
|
||||
char *cpt,*bpt;
|
||||
int ret,l;
|
||||
char orig_line[4096];
|
||||
|
||||
ret= Ctyp_new(ct,*ct,0);
|
||||
if(ret<=0) {
|
||||
sprintf(msg,"Failed to create CtyP object (due to lack of memory ?)");
|
||||
goto ex;
|
||||
}
|
||||
o= *ct;
|
||||
|
||||
strcpy(orig_line,line);
|
||||
cpt= line;
|
||||
while(*cpt!=0 && isspace(*cpt)) cpt++;
|
||||
if(cpt[0]=='#') {
|
||||
cpt++;
|
||||
if(cpt[1]==' ')
|
||||
cpt++;
|
||||
l= strlen(cpt);
|
||||
if(cpt[0]==' ')
|
||||
cpt++;
|
||||
if(l>1)
|
||||
if(cpt[l-1]==' ')
|
||||
cpt[l-1]= 0;
|
||||
if(Sregex_string(&(o->name),cpt,0)<=0)
|
||||
{ret= -1; goto ex;}
|
||||
o->is_comment= 1;
|
||||
{ret= 1; goto ex;}
|
||||
} else if(cpt[0]==0) {
|
||||
if(Sregex_string(&(o->name),cpt,0)<=0)
|
||||
{ret= -1; goto ex;}
|
||||
o->is_comment= 1;
|
||||
{ret= 1; goto ex;}
|
||||
} else if(cpt[0]=='/' && cpt[1]=='*') {
|
||||
sprintf(msg,
|
||||
"C-style multi line comments (/* ... */) not supported yet. Use #.");
|
||||
goto ex;
|
||||
|
||||
/* >>> */
|
||||
|
||||
}
|
||||
cpt= line;
|
||||
while(cpt[0]=='-') {
|
||||
/* look for management specifiers:
|
||||
-v* just a value
|
||||
-m* allocated memory which needs to be freed
|
||||
-c* mutual link (like prev+next)
|
||||
-l* list of -m chained by mutual links prev and next
|
||||
|
||||
-r* read-only : no setter function
|
||||
-p* private : neither setter nor getter function
|
||||
-b* bossless_list : Class_new(o,flag), not Class_new(o,boss,flag)
|
||||
-i* no_initializer : do not initialize element in <Class>_new()
|
||||
#... line is a comment
|
||||
*/
|
||||
if(cpt[1]=='v' || cpt[1]=='V') {
|
||||
o->management= 0;
|
||||
} else if(cpt[1]=='m' || cpt[1]=='M') {
|
||||
o->management= 1;
|
||||
} else if(cpt[1]=='c' || cpt[1]=='C') {
|
||||
o->management= 2;
|
||||
if(o->prev!=NULL)
|
||||
if(o->prev->management==2)
|
||||
o->management= 3;
|
||||
} else if(cpt[1]=='l' || cpt[1]=='L') {
|
||||
o->management= 4;
|
||||
} else if(cpt[1]=='r' || cpt[1]=='R') {
|
||||
o->with_setter= 0;
|
||||
} else if(cpt[1]=='p' || cpt[1]=='P') {
|
||||
o->with_setter= 0;
|
||||
o->with_getter= 0;
|
||||
} else if(cpt[1]=='b' || cpt[1]=='B') {
|
||||
o->bossless_list= 1;
|
||||
} else if(cpt[1]=='i' || cpt[1]=='I') {
|
||||
o->no_initializer= 1;
|
||||
}
|
||||
while(*cpt!=0 && !isspace(*cpt)) cpt++;
|
||||
while(*cpt!=0 && isspace(*cpt)) cpt++;
|
||||
if(*cpt==0)
|
||||
goto no_name;
|
||||
}
|
||||
|
||||
if(strncmp(cpt,"struct ",7)==0) {
|
||||
o->is_struct= 1;
|
||||
cpt+= 7;
|
||||
} else if(strncmp(cpt,"unsigned ",9)==0) {
|
||||
o->is_unsigned= 1;
|
||||
cpt+= 9;
|
||||
} else if(strncmp(cpt,"volatile ",9)==0) {
|
||||
o->is_volatile= 1;
|
||||
cpt+= 9;
|
||||
if(strncmp(cpt,"unsigned ",9)==0) {
|
||||
o->is_unsigned= 1;
|
||||
cpt+= 9;
|
||||
}
|
||||
}
|
||||
if(*cpt==0)
|
||||
goto no_name;
|
||||
while(*cpt!=0 && isspace(*cpt)) cpt++;
|
||||
bpt= cpt;
|
||||
while(*bpt!=0 && !isspace(*bpt)) bpt++;
|
||||
if(*bpt==0)
|
||||
goto no_name;
|
||||
if(*bpt==0) {
|
||||
no_name:;
|
||||
sprintf(msg,"No name found after type description : %s",orig_line);
|
||||
ret= 0; goto ex;
|
||||
}
|
||||
*bpt= 0;
|
||||
if(Sregex_string(&(o->dtype),cpt,0)<=0)
|
||||
{ret= -1; goto ex;}
|
||||
if((flag&1) && o->is_struct && strlen(o->dtype)>=3)
|
||||
if(isupper(o->dtype[0]) && islower(o->dtype[1]) &&
|
||||
isupper(o->dtype[strlen(o->dtype)-1])) {
|
||||
o->dtype[0]= tolower(o->dtype[0]);
|
||||
o->dtype[strlen(o->dtype)-1]= tolower(o->dtype[strlen(o->dtype)-1]);
|
||||
}
|
||||
cpt= bpt+1;
|
||||
while(*cpt!=0 && isspace(*cpt)) cpt++;
|
||||
if(*cpt==0)
|
||||
goto no_name;
|
||||
for(;*cpt=='*';cpt++)
|
||||
o->is_pointer++;
|
||||
if(*cpt==0)
|
||||
goto no_name;
|
||||
bpt= strchr(cpt,'[');
|
||||
if(bpt!=NULL) {
|
||||
if(strchr(bpt,']')!=NULL)
|
||||
*strchr(bpt,']')= 0;
|
||||
sscanf(bpt+1,"%lu",&(o->array_size));
|
||||
*bpt= 0;
|
||||
}
|
||||
if(Sregex_string(&(o->name),cpt,0)<=0)
|
||||
{ret= -1; goto ex;}
|
||||
if(o->management==1) {
|
||||
if((!(o->is_pointer>=1 && o->is_pointer<=2)) ||
|
||||
((!o->is_struct) && strcmp(o->dtype,"char")!=0 &&
|
||||
(strcmp(o->dtype,"unsigned char")!=0))) {
|
||||
sprintf(msg,"-m can only be applied to pointers of struct or char : %s",
|
||||
orig_line);
|
||||
ret= 0; goto ex;
|
||||
}
|
||||
}
|
||||
ret= 1;
|
||||
ex:;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
int Ctyp_read_fp(ct,fp,msg,flag)
|
||||
struct CtyP **ct;
|
||||
FILE *fp;
|
||||
char msg[]; /* at least [4096+256] */
|
||||
int flag;
|
||||
/*
|
||||
bit0= make struct ClassnamE to struct classname
|
||||
*/
|
||||
{
|
||||
int ret;
|
||||
char line[4096];
|
||||
struct CtyP *o;
|
||||
|
||||
line[0]= 0;
|
||||
printf(
|
||||
"[-value|-managed|-chain|-list] class element ? (e.g.: -l struct XyZ)\n");
|
||||
if(Sfile_fgets(line,sizeof(line)-1,fp)==NULL)
|
||||
{ret= 2; goto ex;}
|
||||
printf("%s\n",line);
|
||||
Sregex_trimline(line,0);
|
||||
if(strcmp(line,"@")==0)
|
||||
{ret= 2; goto ex;}
|
||||
ret= Ctyp_new_from_line(ct,*ct,line,msg,flag&1);
|
||||
if(ret<=0)
|
||||
goto ex;
|
||||
ret= 1;
|
||||
ex:;
|
||||
return(ret);
|
||||
}
|
||||
|
41
libcevap/ctyp.h
Normal file
41
libcevap/ctyp.h
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
#ifndef Ctyp_includeD
|
||||
#define Ctyp_includeD
|
||||
|
||||
|
||||
|
||||
struct CtyP {
|
||||
|
||||
/* if 1 : .name contains comment text, all other elements are invalid */
|
||||
int is_comment;
|
||||
|
||||
int is_pointer; /* number of asterisks */
|
||||
int is_struct;
|
||||
int is_unsigned;
|
||||
int is_volatile;
|
||||
unsigned long array_size;
|
||||
|
||||
int management; /*
|
||||
-v 0= just a value
|
||||
-m 1= allocated memory which needs to be freed
|
||||
-c 2= mutual link with the next element
|
||||
-c 3= mutual link with the prev element
|
||||
-l 4= list of -m , chained by -c pair named 'prev','next'
|
||||
supposed to be followed by a -v of the same type
|
||||
which will mark the end of the list
|
||||
*/
|
||||
int with_getter;
|
||||
int with_setter;
|
||||
int bossless_list;
|
||||
int no_initializer;
|
||||
|
||||
char *dtype;
|
||||
char *name;
|
||||
|
||||
struct CtyP *prev;
|
||||
struct CtyP *next;
|
||||
};
|
||||
|
||||
|
||||
#endif /* Ctyp_includeD */
|
||||
|
30
libcevap/extract_cgen_input.sh
Executable file
30
libcevap/extract_cgen_input.sh
Executable file
@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
|
||||
copy_mode=0
|
||||
|
||||
while true
|
||||
do
|
||||
read line
|
||||
if test "$copy_mode" = "0"
|
||||
then
|
||||
if echo " $line" | grep '^ Cgen=' >/dev/null 2>&1
|
||||
then
|
||||
copy_mode=1
|
||||
if echo " $line" | grep '^ Cgen=..' >/dev/null 2>&1
|
||||
then
|
||||
echo " $line" | sed -e 's/^ Cgen=//'
|
||||
fi
|
||||
elif echo " $line" | grep '^ =end Model=' >/dev/null 2>&1
|
||||
then
|
||||
break
|
||||
fi
|
||||
else
|
||||
if test " $line" = " @"
|
||||
then
|
||||
copy_mode=0
|
||||
echo "@"
|
||||
else
|
||||
echo " $line" | sed -e 's/^ //'
|
||||
fi
|
||||
fi
|
||||
done
|
16
libcevap/libcevap_gen.sh
Executable file
16
libcevap/libcevap_gen.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_dir=.
|
||||
model_file=./libdax_model.txt
|
||||
xtr_dir=.
|
||||
cgen_dir=.
|
||||
# cgen_dir=~/projekte/cdrskin_dir/libburn-develop/libcevap
|
||||
|
||||
cd "$test_dir" || exit 1
|
||||
test -e smem.h || exit 1
|
||||
|
||||
cat "$model_file" | \
|
||||
"$xtr_dir"/extract_cgen_input.sh | \
|
||||
"$cgen_dir"/cgen -smem_local -ansi -global_include cevap_global.h \
|
||||
-overwrite "$@"
|
||||
|
BIN
libcevap/libdax_equip.gif
Normal file
BIN
libcevap/libdax_equip.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
libcevap/libdax_job.gif
Normal file
BIN
libcevap/libdax_job.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
944
libcevap/libdax_model.txt
Normal file
944
libcevap/libdax_model.txt
Normal file
@ -0,0 +1,944 @@
|
||||
|
||||
#
|
||||
# libdax is the early working name for the successor software of libburn,
|
||||
# a library for writing information onto optical media, i.e. CD and DVD.
|
||||
# The current working name is libcevap, refering to various kinds of roasts in
|
||||
# Europe and Asia which share the property to be structured in smaller pieces.
|
||||
#
|
||||
# The reason for the replacement is the unclear copyright situation as well
|
||||
# as libburn's sketchy original state and the subsequential evolutionary
|
||||
# damages done by us in libburn code.
|
||||
# This does not mean libburn is shaky. Its current state just reflects the
|
||||
# virtual conflict of at least two programmer personalities and their goals.
|
||||
#
|
||||
|
||||
#
|
||||
# Please: Nobody shall take the development of libcevap as a reason for not
|
||||
# programming an application which uses libburn.
|
||||
# libburn works now. libcevap is planned to work in future.
|
||||
#
|
||||
# libcevap will replace libburn in a controlled, application friendly way.
|
||||
# The first application of libcevap will be a libburn API wrapper which will
|
||||
# allow to perform all API calls of libburn which are proveable to work in
|
||||
# the current implementation. (Some CD stuff is not understood by us yet.
|
||||
# We will have to learn.)
|
||||
#
|
||||
# The libburn API will be frozen when libcevap has closed up to its current
|
||||
# capabilities. Nevertheless it may take profit from some of the future
|
||||
# progress in libcevap (e.g. new media types).
|
||||
# We hope that finally libcevap will have capabilities superior to libburn.
|
||||
# This will then be a reason to port applications to the libcevap API.
|
||||
#
|
||||
# Application programmers are advised to encapsulate their libburn API calls
|
||||
# in an own abstraction layer. The semantic concepts of burning will be
|
||||
# compatible between libburn and libcevap. I.e you will have a library object
|
||||
# to be started up, drives to be found and grabbed, media and their states
|
||||
# to be identified, sessions, tracks, burn options to be set, blanking,
|
||||
# formatting, and so on.
|
||||
# Data types, function calls, and quirks will be incompatible between both
|
||||
# APIs, though.
|
||||
#
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# Originally this was a backup of text input clicketitoggled into ArgoUML
|
||||
# Meanwhile it becomes an intermediate storage for attributes and
|
||||
# class interconnections in the notation of my C stub generator CgeN
|
||||
# (see also end of this text)
|
||||
|
||||
# next : work on completeness : cevapformat
|
||||
|
||||
# Open questions:
|
||||
# - how to connect to GESTURES ? Globally ?
|
||||
|
||||
|
||||
Model=libdax
|
||||
|
||||
ClassDiagram=Overview
|
||||
|
||||
Class=API
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
The API is the only layer visible to the applications. It exposes MMC concepts
|
||||
which it reflects and augments by its own architectural concepts.
|
||||
Subordinates=EQUIP,JOB,AUX
|
||||
Cgen=\
|
||||
cevapi
|
||||
-r -m struct CevapequiP *equip
|
||||
-r -m struct CevapjoB *job
|
||||
-r -m struct CevapauX *aux
|
||||
-r -m struct CevapgestureS *gestures
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=EQUIP
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
EQUIP represents the physical and logical equipment in reach of libdax.
|
||||
This includes the system, drives, media, and their current states.
|
||||
PeerToPeer=GESTURES
|
||||
Boss=API
|
||||
Cgen=\
|
||||
cevapequip
|
||||
-r -v struct CevapI *boss
|
||||
-r -m struct CevapsysteM *sys
|
||||
-v struct CevapgestureS *gestures
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=JOB
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
JOB models the tasks to be performed via libdax.
|
||||
This includes disc, session, track, source, fifo, dewav, burn options.
|
||||
PeerToPeer=GESTURES
|
||||
Boss=API
|
||||
Cgen=\
|
||||
cevapjob
|
||||
-r -v struct CevapI *boss
|
||||
-r -m struct CevaptodO *todo
|
||||
-v struct CevapgestureS *gestures
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=AUX
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
AUX bundles any models which are neither EQUIP nor JOB.
|
||||
This includes abort handler and message system.
|
||||
PeerToPeer=GESTURES
|
||||
Boss=API
|
||||
Cgen=\
|
||||
cevapaux
|
||||
-r -v struct CevapI *boss
|
||||
-v struct CevapgestureS *gestures
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=GESTURES
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
GESTURES ist the procedural repertoire which interconnects EQUIP, JOB, and AUX
|
||||
and also provides to them the services from the SCSI oriented layers.
|
||||
PeerToPeer=EQUIP,JOB,AUX
|
||||
Subordinates=SCSI_CMD
|
||||
Cgen=\
|
||||
cevapgestures
|
||||
-r -v struct CevapI *boss
|
||||
-v struct CevapequiP *equip
|
||||
-v struct CevapjoB *job
|
||||
-v struct CevapauX *aux
|
||||
-r -m struct CevapscmD *scsi_cmd
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=SCSI_CMD
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
SCSI_CMD represents the semantic part of SCSI (i.e. mainly MMC) specs.
|
||||
This layer models each SCSI command that is used by libdax. It knows about
|
||||
its parameters and constraints with particular equipment and jobs.
|
||||
Boss=GESTURES
|
||||
Subordinates=Classes with SCSI_EXEC Interface
|
||||
Cgen=\
|
||||
cevapscmd
|
||||
-r -v struct CevapgestureS *boss
|
||||
-r -m struct CevapsexeC *scsi_exec
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Interface=SCSI_EXEC
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=16.03.2007
|
||||
Documentation=\
|
||||
SCSI_EXEC hides the difference between the implementation principle of
|
||||
SCSI format+transport and the principle of SCSI service.
|
||||
Boss=SCSI_CMD
|
||||
Implementations=SCSI_FORMAT,SCSI_SERVICE
|
||||
Cgen=\
|
||||
cevapsexec
|
||||
-r -v struct CevapscmD *boss
|
||||
-p -v struct CevapsforM *scsi_format
|
||||
-p -v struct CevapsservicE *scsi_service
|
||||
-v int silent_on_scsi_error
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Interface
|
||||
|
||||
|
||||
Class=OSDriveAspect
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=18.08.2007
|
||||
Documentation=\
|
||||
OSDriveAspect encapsulates operating system specific properties of an
|
||||
individual drive. It shall be handed out by SCSI_EXEC via the GESTURES layer
|
||||
to EquipDrive where it forms the link between cevap drive model and operating
|
||||
system driver.
|
||||
This class description models the implementation specific to Linux.
|
||||
Cgen=\
|
||||
cevaposdrv
|
||||
-r -v int fd
|
||||
|
||||
# >>> ??? implement the sibling stuff which never worked properly ?
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
|
||||
Class=SCSI_FORMAT
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
SCSI_FORMAT translates parameters of SCSI commands into CDBs, takes care for
|
||||
transport and decodes the reply into parameters.
|
||||
Boss=SCSI_CMD via SCSI_EXEC
|
||||
Subordinates=SCSI_TRANSPORT
|
||||
Cgen=\
|
||||
cevapsform
|
||||
-r -v struct CevapsexeC *boss
|
||||
-p -v struct CevapstransP *scsi_transport
|
||||
|
||||
# former struct command
|
||||
-v unsigned char opcode[16]
|
||||
-v int oplen
|
||||
-v int dir
|
||||
-v int dxfer_len
|
||||
-v unsigned char sense[128]
|
||||
-v int error
|
||||
-v int retry
|
||||
-v struct CevapbuffeR *page
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=SCSI_TRANSPORT
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
SCSI_TRANSPORT takes a formatted CDB from SCSI_FORMAT and makes the operating
|
||||
system perform a SCSI transaction. It then returns the reply data in raw form.
|
||||
Boss=SCSI_FORMAT
|
||||
Os_specific=yes
|
||||
Cgen=\
|
||||
cevapstransp
|
||||
-r -v struct CevapsforM *boss
|
||||
|
||||
# >>>
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=SCSI_SERVICE
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=11.03.2007
|
||||
Documentation=\
|
||||
SCSI_SERVICE provides the combined services of SCSI_FORMAT and SCSI_TRANSPORT
|
||||
via a set of parametrized functions which abstract SCSI command transactions.
|
||||
Boss=SCSI_CMD via SCSI_EXEC
|
||||
Os_specific=yes
|
||||
Cgen=\
|
||||
cevapsservice
|
||||
-r -v struct CevapsexeC *boss
|
||||
|
||||
# >>>
|
||||
@
|
||||
=end Class
|
||||
|
||||
=end ClassDiagram=Overview
|
||||
|
||||
|
||||
|
||||
ClassDiagram=Equip_overview
|
||||
|
||||
Class=EquipSystem
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=16.03.2007
|
||||
Documentation=\
|
||||
EquipSystem is the inner root class of EQUIP. It describes the system on
|
||||
which libdax is working. This includes the operating system, the system
|
||||
adapter classes, the drives.
|
||||
Boss=EQUIP
|
||||
Subordinates=EquipDrive*N
|
||||
Cgen=\
|
||||
cevapsystem
|
||||
-r -v struct CevapequiP *boss
|
||||
-r -m char *infotext
|
||||
-r -l struct CevapdrivE *drive
|
||||
-p -v struct CevapdrivE *eol_drive
|
||||
|
||||
# >>> be boss of SCSI_CMD ? (Rather than GESTURES)
|
||||
|
||||
# >>>
|
||||
@
|
||||
=end Class
|
||||
|
||||
|
||||
Class=EquipDrive
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=16.03.2007
|
||||
Documentation=\
|
||||
EquipDrive represents a drive, including its capabilities, its processing
|
||||
status, the media loaded.
|
||||
Subordinates=EquipMedia
|
||||
Boss=EquipSystem
|
||||
Cgen=\
|
||||
-l cevapdrive
|
||||
-r -v struct CevapsysteM *boss
|
||||
|
||||
# Drive number
|
||||
-r -v int global_index
|
||||
|
||||
# Persistent system drive address
|
||||
-r -m char *devname
|
||||
|
||||
# Traditional SCSI address parameters (-1 if not applicable)
|
||||
-r -v int bus_no
|
||||
-r -v int host
|
||||
-r -v int id
|
||||
-r -v int channel
|
||||
-r -v int lun
|
||||
|
||||
# (former struct burn_scsi_inquiry_data idata)
|
||||
# From 12h INQUIRY , spc3r23.pdf , 6.4.2 , Table 81
|
||||
-r -v char vendor[9]
|
||||
-r -v char product[17]
|
||||
-r -v char revision[5]
|
||||
# 1= above elements contain valid information
|
||||
-r -v int idata_valid
|
||||
|
||||
# mc5r03c.pdf 5.3.2 Physical Interface Standard
|
||||
# 1=SCSI, 2=ATAPI, 3,4,6=FireWire, 7=SATA, 8=USB
|
||||
-r -v int phys_if_std
|
||||
# MMC-5 5.3.2 table 91 , e.g. "SCSI Family"
|
||||
-r -m char *phys_if_name
|
||||
|
||||
# System despendent aspect of the drive (e.g. int fd;)
|
||||
-r -v struct CevaposdrV *system_dep_drive_info
|
||||
|
||||
# Result of the CD write mode x block type tests:
|
||||
# Index is for write mode : 0=packet , 1=TAO , 2=SAO , 3=raw
|
||||
# Bits are for block type
|
||||
# Numbering as in mc5r03c.pdf 7.5.4.13 Data Block Type, Table 668 :
|
||||
# 0=RAW0 (2352, Raw data)
|
||||
# 1=RAW16 (2368, Raw data with P and Q Sub-channel
|
||||
# 2=RAW96P (2448, Raw data with P-W Sub-channel appended)
|
||||
# 3=RAW96R (2448, Raw data with raw P-W Sub-channel appended)
|
||||
# 8=MODE1 (2048, ISO/IEC 10149)
|
||||
# 9=MODE2R (2336, Mode 2 formless)
|
||||
# 10=MODE2F1 (2048, CD-ROM XA, form 1)
|
||||
# 11=MODE2F1X (2056, CD-ROM XA, form 1 plus 8 byte subheader)
|
||||
# 12=MODE2F2 (2324, CD-ROM XA, form 2)
|
||||
# 13=MODE2MIX (2332, CD-ROM XA, form 1, form 2, or mixed form)
|
||||
-r -v int block_types[4]
|
||||
|
||||
# (former struct scsi_mode_data)
|
||||
# Information about the drive's capabilities, obtained via 5Ah MODE SENSE
|
||||
# from mode page 2Ah , mmc3r10g.pdf , 6.3.11 , Table 361
|
||||
# (which is deprecated in MMC-5 E.11)
|
||||
-p -v int mdata_buffer_size
|
||||
-p -v int mdata_dvdram_read
|
||||
-p -v int mdata_dvdram_write
|
||||
-p -v int mdata_dvdr_read
|
||||
-p -v int mdata_dvdr_write
|
||||
-p -v int mdata_dvdrom_read
|
||||
-p -v int mdata_cdrw_read
|
||||
-p -v int mdata_cdrw_write
|
||||
-p -v int mdata_cdr_read
|
||||
-p -v int mdata_cdr_write
|
||||
-p -v int mdata_max_read_speed
|
||||
-p -v int mdata_max_write_speed
|
||||
-p -v int madata_min_write_speed
|
||||
-p -v int mdata_cur_read_speed
|
||||
-p -v int mdata_cur_write_speed
|
||||
-p -v int mdata_simulate
|
||||
-p -v int mdata_c2_pointers
|
||||
-r -v int mdata_underrun_proof
|
||||
|
||||
# Results from ACh GET PERFORMANCE, Type 03h
|
||||
# (Speed values go into *_*_speed)
|
||||
# (speed_descriptors became cevapperf which is under cevapmedia)
|
||||
-p -v int min_end_lba
|
||||
-p -v int max_end_lba
|
||||
|
||||
# from mode page 01h , mmc5r03c.pdf , 7.3.2.1 , Table 657
|
||||
-p -v int mdata_retry_page_length
|
||||
-p -v int mdata_retry_page_valid
|
||||
|
||||
# from mode page 05h , mmc5r03c.pdf , 7.5.4.1 , Table 664
|
||||
-p -v int mdata_write_page_length
|
||||
-p -v int mdata_write_page_valid
|
||||
|
||||
# 1= above elements contain valid information
|
||||
-p -v int mdata_valid
|
||||
|
||||
# The mutex shall be used to coordinate access to the drive in situations
|
||||
# where multi-threaded race conditions could disturb operations.
|
||||
# E.g. lock, read busy state, interpret, set busy state, unlock
|
||||
# A mere reader of the busy state does not have to lock because
|
||||
# reading of the state itself is atomar.
|
||||
-i -v pthread_mutex_t access_lock
|
||||
|
||||
# Flags from feature 002Fh feature descriptor mmc5r03c.pdf 5.3.25 :
|
||||
# bit1= DVD-RW supported
|
||||
# bit2= Test Write available
|
||||
# bit3= DVD-R DL supported
|
||||
# bit6= Buffer Under-run Free recording available (page 05h BUFE)
|
||||
# Value -1 indicates that no 002Fh was current in the features list.
|
||||
-r -v int current_feat2fh_byte4
|
||||
|
||||
# 0= drive is grabbed, 1= drive is not grabbed
|
||||
-v volatile int released
|
||||
|
||||
# File descriptor of an eventual emulated drive
|
||||
-v int stdio_fd
|
||||
|
||||
# >>> ???
|
||||
# (do we need a drive owned buffer to carry data from call to call or what ?)
|
||||
-v struct CevapbuffeR *buffer
|
||||
|
||||
# List of profiles as reported by the drive
|
||||
-r -l struct CevapprofilE *profile
|
||||
-p -v struct CevapprofilE *eol_profile
|
||||
|
||||
# Media currently loaded in the drive
|
||||
-r -m struct CevapmediA *media
|
||||
|
||||
|
||||
# >>> transport.h : toc_temp (what is this ? It belongs to BURN_WRITE_RAW)
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
|
||||
Class=EquipMedia
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=16.03.2007
|
||||
Documentation=\
|
||||
EquipMedia represents an optical disc, including its type, its writeability,
|
||||
its formatting, its available formats and performances.
|
||||
Subordinates=\
|
||||
EquipProfile*N,EquipFormat*N,EquipPerformance*N,EquipStatus,EquipMulticaps
|
||||
Boss=EquipDrive
|
||||
Cgen=\
|
||||
cevapmedia
|
||||
-r -v struct CevapdrivE *boss
|
||||
|
||||
# Volatile and/or public properties of the media
|
||||
-r -m struct CevapstatuS *status
|
||||
|
||||
# MMC-to-MMC feature info from 46h for DVD-RW.
|
||||
# Quite internal. Regard as opaque :)
|
||||
# 1 = incremental recording available, 0 = not available
|
||||
-r -v int current_has_feat21h
|
||||
|
||||
# Link Size item number 0 from feature 0021h descriptor
|
||||
-r -v int current_feat21h_link_size
|
||||
|
||||
# Wether a DVD-RW media holds an incomplete session
|
||||
# (which could need closing after write)
|
||||
-v int needs_close_session
|
||||
|
||||
# From 51h READ DISC INFORMATION
|
||||
# 0=needs format start, 1=needs format restart
|
||||
-r -v int bg_format_status
|
||||
|
||||
# From 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24
|
||||
# 1=unformatted, 2=formatted, 3=unclear
|
||||
-r -v int format_descr_type
|
||||
# meaning depends on format_descr_type
|
||||
-r -v off_t format_curr_max_size
|
||||
# dito
|
||||
-r -v unsigned int format_curr_blsas
|
||||
-r -v int best_format_type
|
||||
-r -v off_t best_format_size
|
||||
-r -l struct CevapformaT *format_descriptor
|
||||
-p -v struct CevapformaT *eol_format_descriptor
|
||||
|
||||
# The specific capabilities and restrictions of the media
|
||||
-r -m struct CevapmcapS *multicaps
|
||||
|
||||
# Results from ACh GET PERFORMANCE, Type 03h
|
||||
# (Speed values go into drive.mdata_*_*_speed)
|
||||
-r -l struct CevapperF *speed_descriptor
|
||||
-p -v struct CevapperF *eol_speed_descriptor
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
|
||||
Class=EquipProfile
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=16.03.2007
|
||||
Documentation=\
|
||||
EquipProfile maps a MMC profile into libdax (See mmc5r03c.pdf chapter 5).
|
||||
A profile describes a set of features and may be either current, possible,
|
||||
disabled, or unavailable.
|
||||
Subordinates=EquipFeature*N
|
||||
Boss=EquipMedia
|
||||
Cgen=\
|
||||
-l cevapprofile
|
||||
-r -v struct CevapdrivE *boss
|
||||
-r -v int is_current
|
||||
-r -v int profile_code
|
||||
-r -v char *profile_text
|
||||
-r -v int is_cd_profile
|
||||
-r -v int is_supported_profile
|
||||
-r -l struct CevapfeaturE *feature
|
||||
-p -v struct CevapfeaturE *eol_feature
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=EquipFeature
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=16.03.2007
|
||||
Documentation=\
|
||||
EquipFeature maps a MMC feature into libdax (See mmc5r03c.pdf chapter 5).
|
||||
A feature describes a set of SCSI commands and (implicitely) of use cases.
|
||||
Boss=EquipProfile
|
||||
Cgen=\
|
||||
-l cevapfeature
|
||||
-r -v struct CevapprofilE *boss
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=EquipFormat
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=
|
||||
Documentation=\
|
||||
EquipFormat represents a single Formattable Capacity Descriptor
|
||||
as of mmc5r03c.pdf 6.24.3.3 .
|
||||
Boss=EquipMedia
|
||||
Cgen=\
|
||||
-l cevapformat
|
||||
-r -v struct CevapmediA *boss
|
||||
|
||||
# format type: e.g 0x00 is "Full", 0x15 is "Quick"
|
||||
-r -v int type
|
||||
|
||||
# the size in bytes derived from Number of Blocks
|
||||
-r -v off_t size
|
||||
|
||||
# the Type Dependent Parameter (usually the write alignment size)
|
||||
-r -v unsigned int tdp
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=EquipPerformance
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=
|
||||
Documentation=\
|
||||
>>> EquipPerformance
|
||||
Boss=EquipMedia
|
||||
Cgen=\
|
||||
-l cevapperf
|
||||
-r -v struct CevapmediA *boss
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=EquipStatus
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=17.3.2007
|
||||
Documentation=\
|
||||
EquipStatus represents the status of media and drive. This includes
|
||||
blank/appendable/closed, progress indicator.
|
||||
Boss=EquipMedia
|
||||
Cgen=\
|
||||
cevapstatus
|
||||
-r -v struct CevapmediA *boss
|
||||
-v int status
|
||||
-m char *status_text
|
||||
-v volatile int busy
|
||||
|
||||
# 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.
|
||||
-v off_t media_capacity_remaining
|
||||
|
||||
# Current write address during write jobs. (Next address to be written)
|
||||
# <<< does this belong to JOB ?
|
||||
-r -v int nwa
|
||||
|
||||
# if > 0 : first lba on media that is too high for write
|
||||
-v int media_lba_limit
|
||||
|
||||
-v struct CevapprogresS *progress
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=EquipMulticaps
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=14.8.2007
|
||||
Documentation=\
|
||||
EquipMulticaps represents media dependent properties and media states which
|
||||
are either volatile or especially interesting to several other modules. This
|
||||
includes eventually existing sessions, closure status, profile dependent
|
||||
capabilities.
|
||||
Boss=EquipMedia
|
||||
Cgen=\
|
||||
cevapmcaps
|
||||
|
||||
# The current profile out of the drive profile list
|
||||
-v struct CevapprofilE *current_profile
|
||||
|
||||
# Wether the media is erasable (or overwriteable)
|
||||
-v int erasable
|
||||
|
||||
# A description of the existing media content structure
|
||||
-r -m struct CevapdisC *disc
|
||||
|
||||
# Start and end addresses out of ATIP.
|
||||
# From 43h READ TOC/PMA/ATIP , mmc5r03c.pdf , 6.26
|
||||
-r -v int start_lba
|
||||
-r -v int end_lba
|
||||
|
||||
# From 51h READ DISC INFORMATION Number of Sessions (-1)
|
||||
-v int complete_sessions
|
||||
|
||||
# From 51h READ DISC INFORMATION Last Track Number in Last Session
|
||||
-v int last_track_no
|
||||
|
||||
# >>> libburn.h:struct burn_multi_caps
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=EquipTocItem
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=14.8.2007
|
||||
Boss=
|
||||
Cgen=\
|
||||
-l cevaptocitem
|
||||
-r -v struct CevapdisC *boss
|
||||
-v int session
|
||||
-v int valid
|
||||
-v int control
|
||||
|
||||
# obscure info from CD TOC : possibly length of track
|
||||
-v unsigned char point
|
||||
-v unsigned char min
|
||||
-v unsigned char sec
|
||||
-v unsigned char frame
|
||||
|
||||
-v int pmin
|
||||
-v int psec
|
||||
-v int pframe
|
||||
|
||||
-v int start_lba
|
||||
-v int track_blocks
|
||||
@
|
||||
=end Class
|
||||
|
||||
|
||||
|
||||
=end ClassDiagram=Equip_overview
|
||||
|
||||
|
||||
ClassDiagram=Job_overview
|
||||
|
||||
Class=JobTodo
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=18.3.2007
|
||||
Documentation=\
|
||||
JobTodo records what is to be done during a job. This includes peripheral
|
||||
actions like tray load/eject and central actions like blank, format, burn.
|
||||
Subordinates=JobDisc,JobOptions
|
||||
Cgen=\
|
||||
cevaptodo
|
||||
-v volatile int cancel
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=JobDisc
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=18.3.2007
|
||||
Documentation=\
|
||||
JobDisc models a disc structure. Either one which already exists or
|
||||
one which is to be created in a job run.
|
||||
Subordinates=JobSession*N
|
||||
Boss=JobTodo
|
||||
Cgen=\
|
||||
cevapdisc
|
||||
-l struct CevapsessioN *session
|
||||
-p -v struct CevapsessioN *eol_session
|
||||
-l struct CevaptociteM *toc_entry
|
||||
-p -v struct CevaptociteM *eol_toc_entry
|
||||
|
||||
# >>> take over services of struct burn_disc
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=JobSession
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=18.3.2007
|
||||
Documentation=\
|
||||
JobSession represents a recording session. A session usually bundles
|
||||
several tracks. Traditionally the last session of a disc is recognized
|
||||
by operating systems as the thing to be mounted.
|
||||
Subordinates=JobTrack*N,JobFifo
|
||||
Boss=JobDisc
|
||||
Cgen=\
|
||||
-l cevapsession
|
||||
-r -v struct CevapdisC *boss
|
||||
|
||||
# >>>
|
||||
|
||||
-l struct CevaptracK *track
|
||||
-p -v struct CevaptracK *eol_track
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=JobTrack
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=18.3.2007
|
||||
Documentation=\
|
||||
JobTrack represents a track to be recorded. A track mainly is associated with
|
||||
a data source but in many cases it also becomes a recognizable entity on the
|
||||
target media.
|
||||
Subordinates=JobBlock*N,JobTrackFilter,JobSource
|
||||
Boss=JobSession
|
||||
Cgen=\
|
||||
-l cevaptrack
|
||||
-r -v struct CevapsessioN *boss
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=JobBlock
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=18.3.2007
|
||||
Documentation=\
|
||||
JobBlock represents a single output data transaction unit. On CD this is
|
||||
the same as an addressable media block resp. sector. On DVD this might be
|
||||
an addressable block od 2k or a packet of e.g. 32k.
|
||||
Boss=JobTrack
|
||||
Cgen=\
|
||||
cevapblock
|
||||
-v int alba
|
||||
-v int rlba
|
||||
|
||||
# >>>
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=JobSource
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=8.4.2007
|
||||
Documentation=\
|
||||
JobSource represents a data source for a track. Typically this is a disk
|
||||
file or a stream file descriptor like stdin.
|
||||
Subordinates=JobSourceBlock*N
|
||||
Boss=JobTrack
|
||||
=end Class
|
||||
|
||||
Class=JobSourceBlock
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=8.4.2007
|
||||
Documentation=\
|
||||
JobSourceBlock represents a single input data transaction unit.
|
||||
Boss=JobSource
|
||||
=end Class
|
||||
|
||||
Class=JobFifo
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=8.4.2007
|
||||
Documentation=\
|
||||
JobFifo reads data via JobTrackFilter and buffers them until JobBlock can
|
||||
accept them.
|
||||
Boss=JobSession
|
||||
=end Class
|
||||
|
||||
Class=JobTrackFilter
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=8.4.2007
|
||||
Documentation=\
|
||||
JobTrackFilter reads data from JobSourceBlock, processes them and presents
|
||||
them to JobFifo or JobBlock. This includes stripping of .wav headers.
|
||||
Boss=JobTrack
|
||||
=end Class
|
||||
|
||||
Class=JobOptions
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=18.3.2007
|
||||
Documentation=\
|
||||
JobOptions bundles the adjustable parameters of a job. This includes dummy
|
||||
mode, speed, appendability, blank mode, format selection, write mode,
|
||||
underrun protection, random access addressing.
|
||||
Boss=JobTodo
|
||||
Cgen=\
|
||||
cevapjobopts
|
||||
|
||||
# >>>
|
||||
|
||||
# Keeping an eye on the drive buffer
|
||||
-v int wait_for_buffer_free
|
||||
-v unsigned int wfb_min_usec
|
||||
-v unsigned int wfb_max_usec
|
||||
-v unsigned int wfb_timeout_sec
|
||||
-v unsigned int wfb_min_percent
|
||||
-v unsigned int wfb_max_percent
|
||||
|
||||
# >>> -m struct params params (used by disabled read cd funtionality)
|
||||
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=JobBuffer
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=13.8.2007
|
||||
Documentation=\
|
||||
JobBuffer is an intermediate storage for the content of several JobBlock
|
||||
or JobSourceBlock.
|
||||
Cgen=\
|
||||
cevapbuffer
|
||||
-r -m unsigned char *data
|
||||
-v int sectors
|
||||
-v int bytes
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=JobProgress
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=13.8.2007
|
||||
Documentation=\
|
||||
JobProgress reflects the state and parts of the history of a job
|
||||
Cgen=\
|
||||
cevapprogress
|
||||
|
||||
# Keeping an eye on the drive buffer
|
||||
-v int nominal_write_speed
|
||||
-v off_t pessimistic_buffer_free
|
||||
-v int pbf_altered
|
||||
-v unsigned int pessimistic_writes
|
||||
-v unsigned int waited_writes
|
||||
-v unsigned int waited_tries
|
||||
-v unsigned int waited_usec
|
||||
|
||||
# >>> the info provided by struct burn_progress
|
||||
|
||||
# >>>
|
||||
@
|
||||
=end Class
|
||||
|
||||
Class=
|
||||
Author=Thomas Schmitt <scdbackup@gmx.net>
|
||||
Version=1.0
|
||||
Since=
|
||||
Documentation=\
|
||||
=end Class
|
||||
|
||||
=end ClassDiagram=Equip_overview
|
||||
|
||||
|
||||
ClassDiagram=Gestures_overview
|
||||
|
||||
# >>>
|
||||
|
||||
=end ClassDiagram=Gestures_overview
|
||||
|
||||
|
||||
|
||||
=end Model=libdax
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Notes:
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Compile cgen:
|
||||
( cd libcevap && cc -g -o cgen cgen.c ctyp.c smem.c )
|
||||
|
||||
Generate C stubs:
|
||||
( cd libcevap && ./libcevap_gen.sh )
|
||||
Option -lowercase would generate all lowercase struct and function names
|
||||
|
||||
Compile test:
|
||||
( cd libcevap && ( rm a.out ; cc -g main.c cevap*.c smem.c ) )
|
||||
Option -DCevap_lowercasE would tell main.c that -lowercase was used above.
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
For a description of CgeN see libcevap/cgen.txt
|
||||
|
||||
The generated code uses smem.[ch] out of one of my BSD licensed projects.
|
||||
For a description see end of libcevap/smem.h .
|
||||
|
||||
------------------------------------------------------------------------
|
BIN
libcevap/libdax_overview.gif
Normal file
BIN
libcevap/libdax_overview.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
39
libcevap/main.c
Normal file
39
libcevap/main.c
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
/*
|
||||
cc -g -DCevap_lowercasE -c main.c
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cevapi.h"
|
||||
|
||||
#include "smem.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#ifdef Cevap_lowercasE
|
||||
struct cevapi *cevap= NULL;
|
||||
#else
|
||||
struct CevapI *cevap= NULL;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
/* full memory supervision */
|
||||
Smem_set_record_items(1);
|
||||
|
||||
/* one short trip for testing */
|
||||
#ifdef Cevap_lowercasE
|
||||
ret= cevapi_new(&cevap,0);
|
||||
if(ret>0)
|
||||
cevapi_destroy(&cevap,0);
|
||||
#else /* Cevap_lowercasE */
|
||||
ret= Cevapi_new(&cevap,0);
|
||||
if(ret>0)
|
||||
Cevapi_destroy(&cevap,0);
|
||||
#endif /* ! Cevap_lowercasE */
|
||||
|
||||
/* report any leaked memory */
|
||||
Smem_stderr(1|2);
|
||||
|
||||
exit(ret<=0);
|
||||
}
|
445
libcevap/smem.c
Normal file
445
libcevap/smem.c
Normal file
@ -0,0 +1,445 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define Smem_included_by_smem_C
|
||||
#include "smem.h"
|
||||
|
||||
|
||||
|
||||
/* ------------------------------ SmemiteM ----------------------------- */
|
||||
|
||||
|
||||
int Smemitem_new(item,data,size,next,hash_start,flag)
|
||||
struct SmemiteM **item;
|
||||
char *data;
|
||||
size_t size;
|
||||
struct SmemiteM *next;
|
||||
struct SmemiteM **hash_start;
|
||||
int flag;
|
||||
{
|
||||
struct SmemiteM *t;
|
||||
|
||||
*item= t= (struct SmemiteM *) malloc(sizeof(struct SmemiteM));
|
||||
if(t==NULL)
|
||||
return(-1);
|
||||
t->data= data;
|
||||
t->size= size;
|
||||
t->prev= NULL;
|
||||
t->next= next;
|
||||
|
||||
#ifdef Smem_with_hasH
|
||||
t->hash_next= NULL;
|
||||
t->hash_prev= NULL;
|
||||
#endif /* Smem_with_hasH */
|
||||
|
||||
if(next!=NULL) {
|
||||
if(next->prev!=NULL) {
|
||||
t->prev= next->prev;
|
||||
next->prev->next= t;
|
||||
}
|
||||
next->prev= t;
|
||||
}
|
||||
|
||||
#ifdef Smem_with_hasH
|
||||
if(hash_start!=NULL) {
|
||||
t->hash_next= *hash_start;
|
||||
if(t->hash_next!=NULL) {
|
||||
t->hash_next->hash_prev= t;
|
||||
}
|
||||
*hash_start= t;
|
||||
}
|
||||
#endif /* Smem_with_hasH */
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Smemitem_destroy(in_item,hash_start,flag)
|
||||
struct SmemiteM **in_item;
|
||||
struct SmemiteM **hash_start;
|
||||
int flag;
|
||||
{
|
||||
struct SmemiteM *item;
|
||||
|
||||
item= *in_item;
|
||||
if(item==NULL)
|
||||
return(0);
|
||||
if(item==Smem_start_iteM)
|
||||
Smem_start_iteM= item->next;
|
||||
if(item->prev!=NULL)
|
||||
item->prev->next= item->next;
|
||||
if(item->next!=NULL)
|
||||
item->next->prev= item->prev;
|
||||
|
||||
#ifdef Smem_with_hasH
|
||||
if(hash_start!=NULL) {
|
||||
if(item==*hash_start)
|
||||
*hash_start= item->hash_next;
|
||||
if(item->hash_prev!=NULL)
|
||||
item->hash_prev->hash_next= item->hash_next;
|
||||
if(item->hash_next!=NULL)
|
||||
item->hash_next->hash_prev= item->hash_prev;
|
||||
}
|
||||
#endif /* Smem_with_hasH */
|
||||
|
||||
free((char *) item);
|
||||
*in_item= NULL;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Smemitem_report(item,line,flag)
|
||||
struct SmemiteM *item;
|
||||
char line[1024];
|
||||
int flag;
|
||||
{
|
||||
char *cpt;
|
||||
int i,upto;
|
||||
|
||||
sprintf(line,"%4lu bytes at %8.8lx ",(unsigned long) item->size,
|
||||
(unsigned long) item->data);
|
||||
cpt= line+strlen(line);
|
||||
if(item->size<=256)
|
||||
upto= item->size;
|
||||
else
|
||||
upto= 256;
|
||||
if(item->data!=NULL) {
|
||||
strcpy(cpt,"= \"");
|
||||
cpt+= 3;
|
||||
for(i=0;i<upto;i++){
|
||||
if(item->data[i]<32 || item->data[i]>=127 || item->data[i]=='\\') {
|
||||
sprintf(cpt,"\\%2.2X",(unsigned char) item->data[i]);
|
||||
cpt+= 3;
|
||||
} else {
|
||||
*(cpt++)= item->data[i];
|
||||
}
|
||||
}
|
||||
if(i<item->size) {
|
||||
sprintf(cpt,"\" [truncated]");
|
||||
} else {
|
||||
*(cpt++)= '"';
|
||||
*cpt= 0;
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Smemitem_stderr(item,flag)
|
||||
struct SmemiteM *item;
|
||||
int flag;
|
||||
{
|
||||
char line[1024];
|
||||
Smemitem_report(item,line,0);
|
||||
fprintf(stderr,"%s\n",line);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------- Smem ------------------------------ */
|
||||
|
||||
|
||||
int Smem_protest(line,flag)
|
||||
char *line;
|
||||
int flag;
|
||||
{
|
||||
fprintf(stderr,"%s\n",line);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Smem_hashindex(ptr,flag)
|
||||
char *ptr;
|
||||
int flag;
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
idx= (unsigned long) ptr;
|
||||
return((idx>>Smem_hashshifT)%(Smem_hashsizE));
|
||||
}
|
||||
|
||||
|
||||
/* find a certain memory item */
|
||||
struct SmemiteM *Smem_find_item(ptr,flag)
|
||||
char *ptr;
|
||||
int flag;
|
||||
{
|
||||
int misscount= 0,idx;
|
||||
struct SmemiteM *current;
|
||||
|
||||
#ifdef Smem_with_hasH
|
||||
|
||||
idx= Smem_hashindex(ptr,0);
|
||||
for(current= Smem_hasH[idx];current!=NULL;current= current->hash_next) {
|
||||
if(current->data==ptr)
|
||||
return(current);
|
||||
misscount++;
|
||||
}
|
||||
|
||||
#else /* Smem_with_hasH */
|
||||
|
||||
for(current= Smem_start_iteM;current!=NULL;current= current->next) {
|
||||
if(current->data==ptr)
|
||||
return(current);
|
||||
misscount++;
|
||||
}
|
||||
|
||||
#endif /* ! Smem_with_hasH */
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
int Smem_search_and_delete(ptr,flag)
|
||||
char *ptr;
|
||||
int flag;
|
||||
/*
|
||||
bit0= revoke registration : decrement counters
|
||||
*/
|
||||
{
|
||||
int idx;
|
||||
struct SmemiteM *current;
|
||||
|
||||
current= Smem_find_item(ptr,0);
|
||||
if(current==NULL)
|
||||
return(0);
|
||||
Smem_record_counT--;
|
||||
Smem_record_byteS-= current->size;
|
||||
idx= Smem_hashindex(ptr,0);
|
||||
Smemitem_destroy(¤t,&(Smem_hasH[idx]),0);
|
||||
Smem_hash_counteR[idx]-= 1.0;
|
||||
if(flag&1) {
|
||||
Smem_malloc_counT--;
|
||||
Smem_pending_counT--;
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
char *Smem_malloc(size)
|
||||
size_t size;
|
||||
{
|
||||
int idx;
|
||||
char *cpt;
|
||||
|
||||
if(size==0) {
|
||||
Smem_protest("########### smem.c : malloc(0) caught",0);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* if(size==1032)
|
||||
cpt= NULL; / * set breakpoint here to find requests of certain size */
|
||||
|
||||
cpt= (char *) malloc(size);
|
||||
if(cpt==NULL) {
|
||||
char text[161];
|
||||
sprintf(text,"########### smem.c : malloc( %lu ) returned NULL",
|
||||
(unsigned long) size);
|
||||
Smem_protest(text,0);
|
||||
return(NULL);
|
||||
}
|
||||
/* if(cpt==0x080a1e20)
|
||||
cpt= NULL; / * set breakpoint here to find origin of certain address */
|
||||
|
||||
Smem_malloc_counT++;
|
||||
Smem_pending_counT++;
|
||||
if(Smem_record_itemS) {
|
||||
idx= Smem_hashindex(cpt,0);
|
||||
Smem_hash_counteR[idx]+= 1.0;
|
||||
if(Smemitem_new(&Smem_start_iteM,cpt,size,Smem_start_iteM,
|
||||
&(Smem_hasH[idx]),0)<=0) {
|
||||
Smem_protest(
|
||||
"########### smem.c : malloc( sizeof(SmemiteM) ) returned NULL",0);
|
||||
return(NULL);
|
||||
}
|
||||
Smem_record_counT++;
|
||||
Smem_record_byteS+= size;
|
||||
}
|
||||
return(cpt);
|
||||
}
|
||||
|
||||
|
||||
int Smem_free(ptr)
|
||||
char *ptr;
|
||||
{
|
||||
if(ptr==NULL) {
|
||||
Smem_protest("########### smem.c : free() of NULL pointer caught",0);
|
||||
return(0);
|
||||
}
|
||||
if(Smem_record_itemS) {
|
||||
if(Smem_search_and_delete(ptr,0)<=0) {
|
||||
Smem_protest("########### smem.c : free() of unrecorded pointer caught",0);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
Smem_free_counT++;
|
||||
Smem_pending_counT--;
|
||||
free(ptr);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Smem_report(line,flag)
|
||||
char line[1024];
|
||||
int flag;
|
||||
{
|
||||
sprintf(line,"malloc= %.f , free= %.f , pending= %.f",
|
||||
Smem_malloc_counT,Smem_free_counT,Smem_pending_counT);
|
||||
if(Smem_record_itemS) {
|
||||
sprintf(line+strlen(line)," , bytes=%.f , records= %.f",
|
||||
Smem_record_byteS,Smem_record_counT);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Smem_stderr(flag)
|
||||
int flag;
|
||||
/*
|
||||
bit0= report 50 youngest pending items too
|
||||
bit1= do not report if nothing is pending
|
||||
*/
|
||||
{
|
||||
struct SmemiteM *current;
|
||||
char line[1024];
|
||||
int i= 0;
|
||||
|
||||
if(flag&2)
|
||||
if(Smem_pending_counT==0.0
|
||||
&& Smem_record_counT==0.0
|
||||
&& Smem_record_byteS==0.0)
|
||||
return(2);
|
||||
Smem_report(line,0);
|
||||
fprintf(stderr,"%s\n",line);
|
||||
if(flag&1) {
|
||||
for(current= Smem_start_iteM;current!=NULL;current= current->next) {
|
||||
Smemitem_stderr(current,0);
|
||||
if(++i>=50)
|
||||
break;
|
||||
}
|
||||
if(current!=NULL)
|
||||
if(current->next!=NULL)
|
||||
fprintf(stderr,"[list truncated]\n");
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Smem_set_record_items(value)
|
||||
int value;
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!Smem_hash_initializeD) {
|
||||
for(i=0;i<Smem_hashsizE;i++) {
|
||||
Smem_hasH[i]= NULL;
|
||||
Smem_hash_counteR[i]= 0.0;
|
||||
}
|
||||
Smem_hash_initializeD= 1;
|
||||
}
|
||||
Smem_record_itemS= value;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
int Smem_is_recorded(ptr,flag)
|
||||
char *ptr;
|
||||
int flag;
|
||||
/*
|
||||
bit0= complain if return(0)
|
||||
*/
|
||||
{
|
||||
if(Smem_record_itemS==0)
|
||||
return(2);
|
||||
if(Smem_find_item(ptr,0)!=NULL)
|
||||
return(1);
|
||||
if(flag&1)
|
||||
Smem_protest("########### smem.c : free() of unrecorded pointer caught",0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* A simple C string cloner */
|
||||
int Smem_clone_string(ptr,text)
|
||||
char **ptr;
|
||||
char *text;
|
||||
{
|
||||
*ptr= Smem_malloC(strlen(text)+1);
|
||||
if(*ptr==NULL)
|
||||
return(-1);
|
||||
strcpy(*ptr,text);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* ----------------- for usage via debugger commands --------------------- */
|
||||
|
||||
|
||||
/* find a certain memory item */
|
||||
struct SmemiteM *Smem_find_data(ptr)
|
||||
char *ptr;
|
||||
{
|
||||
return(Smem_find_item(ptr,0));
|
||||
}
|
||||
|
||||
|
||||
/* browsing the list */
|
||||
struct SmemiteM *Smem_fetch_item(step,flag)
|
||||
int step;
|
||||
int flag;
|
||||
/*
|
||||
bit0= reset cursor (and therefore address absolutely)
|
||||
*/
|
||||
{
|
||||
static struct SmemiteM *current= NULL;
|
||||
|
||||
if((flag&1)||current==NULL)
|
||||
current= Smem_start_iteM;
|
||||
if(step>0) {
|
||||
for(;current!=NULL;current= current->next) {
|
||||
if(step==0)
|
||||
return(current);
|
||||
step--;
|
||||
}
|
||||
} else if(step<0) {
|
||||
for(;current!=NULL;current= current->prev) {
|
||||
if(step==0)
|
||||
return(current);
|
||||
step++;
|
||||
}
|
||||
} else {
|
||||
return(current);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
int Smem_print_hash_counter() {
|
||||
int i;
|
||||
|
||||
for(i=0;i<Smem_hashsizE;i++)
|
||||
printf("%4d : %10.f\n",i,Smem_hash_counteR[i]);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* delete all recorded memory items */
|
||||
int Smem_delete_all_items()
|
||||
{
|
||||
int ret;
|
||||
|
||||
while(Smem_start_iteM!=NULL) {
|
||||
ret= Smem_free(Smem_start_iteM->data);
|
||||
if(ret<=0)
|
||||
return(0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
165
libcevap/smem.h
Normal file
165
libcevap/smem.h
Normal file
@ -0,0 +1,165 @@
|
||||
|
||||
#ifndef Smem_includeD
|
||||
#define Smem_includeD
|
||||
|
||||
|
||||
/* compile time adjustable parameters : */
|
||||
|
||||
/* if not defined, flat malloc() and free() is used */
|
||||
#define Smem_own_functionS
|
||||
#ifdef Smem_no_own_functionS
|
||||
#undef Smem_own_functionS
|
||||
#endif /* Smem_no_own_functionS */
|
||||
|
||||
/* if not defined, the record items will be smaller by 8 byte
|
||||
but deletion of items may be much slower */
|
||||
#define Smem_with_hasH
|
||||
|
||||
|
||||
|
||||
struct SmemiteM {
|
||||
|
||||
char *data;
|
||||
size_t size;
|
||||
|
||||
struct SmemiteM *prev,*next;
|
||||
|
||||
struct SmemiteM *hash_prev,*hash_next;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef Smem_own_functionS
|
||||
|
||||
char *Smem_malloc();
|
||||
int Smem_free();
|
||||
|
||||
#define TSOB_FELD(typ,anz) (typ *) Smem_malloc((anz)*sizeof(typ));
|
||||
#define Smem_malloC Smem_malloc
|
||||
#define Smem_freE Smem_free
|
||||
|
||||
#else /* Smem_own_functionS */
|
||||
|
||||
#define TSOB_FELD(typ,anz) (typ *) malloc((anz)*sizeof(typ));
|
||||
#define Smem_malloC malloc
|
||||
#define Smem_freE free
|
||||
|
||||
#endif /* ! Smem_own_functionS */
|
||||
|
||||
int Smem_set_record_items();
|
||||
int Smem_stderr();
|
||||
int Smem_clone_string();
|
||||
|
||||
|
||||
#define Smem_hashsizE 251
|
||||
#define Smem_hashshifT 8
|
||||
|
||||
#ifdef Smem_included_by_smem_C
|
||||
|
||||
double Smem_malloc_counT= 0.0;
|
||||
double Smem_free_counT= 0.0;
|
||||
double Smem_pending_counT= 0.0;
|
||||
struct SmemiteM *Smem_start_iteM= NULL;
|
||||
struct SmemiteM *Smem_hasH[Smem_hashsizE];
|
||||
double Smem_hash_counteR[Smem_hashsizE];
|
||||
|
||||
/* these both init values are essential, since setting Smem_record_itemS=1
|
||||
by use of Smem_set_record_items() initializes the hash array
|
||||
(i do not really trust the compiler producers to have read K&R) */
|
||||
int Smem_hash_initializeD= 0;
|
||||
int Smem_record_itemS= 0;
|
||||
|
||||
double Smem_record_counT= 0.0;
|
||||
double Smem_record_byteS= 0.0;
|
||||
|
||||
#else /* Smem_included_by_smem_C */
|
||||
|
||||
extern double Smem_malloc_counT;
|
||||
extern double Smem_free_counT;
|
||||
extern double Smem_pending_counT;
|
||||
extern struct SmemiteM *Smem_start_iteM;
|
||||
extern struct SmemiteM *Smem_hasH[Smem_hashsizE];
|
||||
extern double Smem_hash_counteR[Smem_hashsizE];
|
||||
extern int Smem_hash_initializeD;
|
||||
extern int Smem_record_itemS;
|
||||
extern double Smem_record_counT;
|
||||
extern double Smem_record_byteS;
|
||||
|
||||
#endif /* ! Smem_included_by_smem_C */
|
||||
|
||||
|
||||
|
||||
#endif /* ! Smem_includeD */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
smem
|
||||
|
||||
Functions to replace malloc() and free() in order to get more control
|
||||
over memory leaks or spurious errors caused by faulty usage of malloc()
|
||||
and free().
|
||||
|
||||
|
||||
Sourcecode provisions:
|
||||
|
||||
Use only the following macros for memory management:
|
||||
TSOB_FELD(type,count) creates an array of items of given type
|
||||
Smem_malloC() analogue of malloc()
|
||||
Smem_freE() analogue of free()
|
||||
One may #define malloc Smem_malloC resp. #define free Smem_freE
|
||||
but better would be to review (and often to streamline) the sourcecode
|
||||
in respect to those two functions.
|
||||
|
||||
|
||||
Speed versus control:
|
||||
|
||||
In production versions, where maximum speed is required, one may undefine
|
||||
the macro Smem_own_functionS in smem.h .
|
||||
This causes the above macros to directly invoke malloc() and free() without
|
||||
any speed reduction (and without any additional use).
|
||||
Undefinitio can be done globaly by modifying smem.h or locally by defining
|
||||
Smem_no_own_functionS before including smem.h .
|
||||
|
||||
If Smem_own_functionS remains defined, then the functions
|
||||
Smem_malloc()
|
||||
Smem_free()
|
||||
are used rather than malloc() and free().
|
||||
They count the number of calls to maintain a rough overview of memory usage.
|
||||
Smem_malloc() additionally checks for 0 size and Smem_free() checks for
|
||||
NULL pointers, which they both report to stderr. Eventually one should set
|
||||
a breakpoint in function Smem_protest() to learn about the origin of such
|
||||
messages.
|
||||
A status line may be obtained by Smem_report() or printed by Smem_stderr().
|
||||
|
||||
As long as the variable Smem_record_itemS is set to 0, there is not very much
|
||||
overhead compared with malloc() and free().
|
||||
If the variable is set to 1 by Smem_set_record_items() then all malloc()
|
||||
results are kept in a list where they will be deleted by their corresponding
|
||||
Smem_free() calls. If a pointer is to be freed, which is not recorded in the
|
||||
list then an error message will be printed to stderr. The memory will not
|
||||
be freed !
|
||||
This mode not only may be very slow, it also consumes at least 16 byte per
|
||||
piece of data which was obtained by malloc as long as it has not been freed.
|
||||
Due to the current nature of the list, large numbers of memory items are freed
|
||||
much faster in the reverse order of their creation. If there is a list of
|
||||
100000 strings to delete, it is very rewarding to free the youngest ones first.
|
||||
A shortcut via hashing is available but consumes 24 bytes rather than 16.
|
||||
(see above Smem_with_hasH )
|
||||
|
||||
The function Smem_is_recorded() can be used to check wether a pointer is
|
||||
valid according to the list. It returns :
|
||||
0 = is not in list , 1 = is in list , 2 = recording is off
|
||||
|
||||
If one decides to start recording malloc() results in the midst of a program
|
||||
run, one has to be aware of false protests of Smem_free() if a memory piece
|
||||
has been allocated before recording started. This will also cause those pieces
|
||||
to be memory leaks because Smem_free() refuses to delete them. (Freeing memory
|
||||
that was not obtained by malloc or was already freed previously can result in
|
||||
deferred SIGSEGV or similar trouble, depending on OS and library.)
|
||||
Also in that case one should stop recording before ending the program, to
|
||||
avoid a lot of false complaints about longliving memory objects.
|
||||
|
||||
*/
|
@ -1,15 +1,15 @@
|
||||
|
||||
/* test/libburner.c , API illustration of burning data or audio tracks to CD */
|
||||
/* Copyright (C) 2005 - 2006 Thomas Schmitt <scdbackup@gmx.net> */
|
||||
/* Provided under GPL, see also "License and copyright aspects" at file end */
|
||||
/* Copyright (C) 2005 - 2007 Thomas Schmitt <scdbackup@gmx.net> */
|
||||
/* Provided under GPLv2,see also "License and copyright aspects" at file end */
|
||||
|
||||
|
||||
/** Overview
|
||||
|
||||
libburner is a minimal demo application for the library libburn as provided
|
||||
on http://libburnia.pykix.org . It can list the available devices, can
|
||||
on http://libburnia-project.org . It can list the available devices, can
|
||||
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.
|
||||
DVD+R, DVD+R/DL, DVD+RW, DVD-RAM or DVD-RW. Not supported yet: DVD-R/DL, BD.
|
||||
|
||||
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
|
||||
@ -29,7 +29,7 @@
|
||||
libburner_blank_disc()
|
||||
or you can format a DVD-RW to profile "Restricted Overwrite" (needed once)
|
||||
libburner_format_row()
|
||||
With the aquired drive you can burn to CD-R, CD-RW, DVD+RW, DVD-RAM, DVD-RW
|
||||
With the aquired drive you can burn to CD or DVD
|
||||
libburner_payload()
|
||||
When everything is done, main() releases the drive and shuts down libburn:
|
||||
burn_drive_release();
|
||||
@ -123,21 +123,28 @@ int libburner_aquire_by_adr(char *drive_adr)
|
||||
int ret;
|
||||
char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
|
||||
|
||||
/* Some not-so-harmless drive addresses get blocked in this demo */
|
||||
if (strncmp(drive_adr, "stdio:/dev/fd/", 14) == 0 ||
|
||||
strcmp(drive_adr, "stdio:-") == 0) {
|
||||
fprintf(stderr, "Will not work with pseudo-drive '%s'\n",
|
||||
drive_adr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This tries to resolve links or alternative device files */
|
||||
ret = burn_drive_convert_fs_adr(drive_adr, libburn_drive_adr);
|
||||
if (ret<=0) {
|
||||
fprintf(stderr,"Address does not lead to a CD burner: '%s'\n",
|
||||
fprintf(stderr, "Address does not lead to a CD burner: '%s'\n",
|
||||
drive_adr);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Aquiring drive '%s' ...\n",libburn_drive_adr);
|
||||
ret = burn_drive_scan_and_grab(&drive_list,libburn_drive_adr,1);
|
||||
fprintf(stderr,"Aquiring drive '%s' ...\n", libburn_drive_adr);
|
||||
ret = burn_drive_scan_and_grab(&drive_list, libburn_drive_adr, 1);
|
||||
if (ret <= 0) {
|
||||
fprintf(stderr,"FAILURE with persistent drive address '%s'\n",
|
||||
libburn_drive_adr);
|
||||
} else {
|
||||
printf("Done\n");
|
||||
fprintf(stderr,"Done\n");
|
||||
drive_is_grabbed = 1;
|
||||
}
|
||||
return ret;
|
||||
@ -163,7 +170,7 @@ int libburner_aquire_by_driveno(int *driveno)
|
||||
|
||||
printf("Beginning to scan for devices ...\n");
|
||||
while (!burn_drive_scan(&drive_list, &drive_count))
|
||||
usleep(1002);
|
||||
usleep(100002);
|
||||
if (drive_count <= 0 && *driveno >= 0) {
|
||||
printf("FAILED (no drives found)\n");
|
||||
return 0;
|
||||
@ -352,6 +359,10 @@ int libburner_format_row(struct burn_drive *drive)
|
||||
To make sure a data image is fully readable on any Linux machine, this
|
||||
function adds 300 kiB of padding to the (usualy single) track.
|
||||
Audio tracks get padded to complete their last sector.
|
||||
A fifo of 4 MB is installed between each track and its data source.
|
||||
Each of the 4 MB buffers gets allocated automatically as soon as a track
|
||||
begins to be processed and it gets freed as soon as the track is done.
|
||||
The fifos do not wait for buffer fill but writing starts immediately.
|
||||
|
||||
In case of external signals expect abort handling of an ongoing burn to
|
||||
last up to a minute. Wait the normal burning timespan before any kill -9.
|
||||
@ -363,7 +374,7 @@ int libburner_payload(struct burn_drive *drive,
|
||||
char source_adr[][4096], int source_adr_count,
|
||||
int multi, int simulate_burn, int all_tracks_type)
|
||||
{
|
||||
struct burn_source *data_src;
|
||||
struct burn_source *data_src, *fifo_src[99];
|
||||
struct burn_disc *target_disc;
|
||||
struct burn_session *session;
|
||||
struct burn_write_opts *burn_options;
|
||||
@ -372,6 +383,7 @@ int libburner_payload(struct burn_drive *drive,
|
||||
struct burn_progress progress;
|
||||
time_t start_time;
|
||||
int last_sector = 0, padding = 0, trackno, unpredicted_size = 0, fd;
|
||||
int fifo_chunksize = 2352, fifo_chunks = 1783; /* ~ 4 MB fifo */
|
||||
off_t fixed_size;
|
||||
char *adr, reasons[BURN_REASONS_LEN];
|
||||
struct stat stbuf;
|
||||
@ -380,6 +392,8 @@ int libburner_payload(struct burn_drive *drive,
|
||||
all_tracks_type = BURN_MODE1;
|
||||
/* a padding of 300 kiB helps to avoid the read-ahead bug */
|
||||
padding = 300*1024;
|
||||
fifo_chunksize = 2048;
|
||||
fifo_chunks = 2048; /* 4 MB fifo */
|
||||
}
|
||||
|
||||
target_disc = burn_disc_create();
|
||||
@ -390,6 +404,7 @@ int libburner_payload(struct burn_drive *drive,
|
||||
tracklist[trackno] = track = burn_track_create();
|
||||
burn_track_define_data(track, 0, padding, 1, all_tracks_type);
|
||||
|
||||
/* Open file descriptor to source of track data */
|
||||
adr = source_adr[trackno];
|
||||
fixed_size = 0;
|
||||
if (adr[0] == '-' && adr[1] == 0) {
|
||||
@ -403,6 +418,8 @@ int libburner_payload(struct burn_drive *drive,
|
||||
}
|
||||
if (fixed_size==0)
|
||||
unpredicted_size = 1;
|
||||
|
||||
/* Convert this filedescriptor into a burn_source object */
|
||||
data_src = NULL;
|
||||
if (fd>=0)
|
||||
data_src = burn_fd_source_new(fd, -1, fixed_size);
|
||||
@ -414,14 +431,29 @@ int libburner_payload(struct burn_drive *drive,
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (burn_track_set_source(track, data_src) != BURN_SOURCE_OK) {
|
||||
printf("FATAL: Cannot attach source object to track object\n");
|
||||
/* Install a fifo object on top of that data source object */
|
||||
fifo_src[trackno] = burn_fifo_source_new(data_src,
|
||||
fifo_chunksize, fifo_chunks, 0);
|
||||
if (fifo_src[trackno] == NULL) {
|
||||
fprintf(stderr,
|
||||
"FATAL: Could not create fifo object of 4 MB\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use the fifo object as data source for the track */
|
||||
if (burn_track_set_source(track, fifo_src[trackno])
|
||||
!= BURN_SOURCE_OK) {
|
||||
fprintf(stderr,
|
||||
"FATAL: Cannot attach source object to track object\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
burn_session_add_track(session, track, BURN_POS_END);
|
||||
printf("Track %d : source is '%s'\n", trackno+1, adr);
|
||||
|
||||
/* Give up local reference to the data burn_source object */
|
||||
burn_source_free(data_src);
|
||||
|
||||
} /* trackno loop end */
|
||||
|
||||
/* Evaluate drive and media */
|
||||
@ -461,25 +493,44 @@ int libburner_payload(struct burn_drive *drive,
|
||||
|
||||
burn_write_opts_free(burn_options);
|
||||
while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
|
||||
usleep(1002);
|
||||
usleep(100002);
|
||||
while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
|
||||
if( progress.sectors <= 0 || progress.sector == last_sector)
|
||||
if (progress.sectors <= 0 ||
|
||||
(progress.sector >= progress.sectors - 1 &&
|
||||
!unpredicted_size) ||
|
||||
(unpredicted_size && progress.sector == last_sector))
|
||||
printf(
|
||||
"Thank you for being patient since %d seconds.\n",
|
||||
"Thank you for being patient since %d seconds.",
|
||||
(int) (time(0) - start_time));
|
||||
else if(unpredicted_size)
|
||||
printf("Track %d : sector %d\n", progress.track+1,
|
||||
printf("Track %d : sector %d", progress.track+1,
|
||||
progress.sector);
|
||||
else
|
||||
printf("Track %d : sector %d of %d\n",progress.track+1,
|
||||
printf("Track %d : sector %d of %d",progress.track+1,
|
||||
progress.sector, progress.sectors);
|
||||
last_sector = progress.sector;
|
||||
if (progress.track >= 0 && progress.track < source_adr_count) {
|
||||
int size, free_bytes, ret;
|
||||
char *status_text;
|
||||
|
||||
ret = burn_fifo_inquire_status(
|
||||
fifo_src[progress.track], &size, &free_bytes,
|
||||
&status_text);
|
||||
if (ret >= 0 )
|
||||
printf(" [fifo %s, %2d%% fill]", status_text,
|
||||
(int) (100.0 - 100.0 *
|
||||
((double) free_bytes) /
|
||||
(double) size));
|
||||
}
|
||||
printf("\n");
|
||||
sleep(1);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (trackno = 0 ; trackno < source_adr_count; trackno++)
|
||||
for (trackno = 0 ; trackno < source_adr_count; trackno++) {
|
||||
burn_source_free(fifo_src[trackno]);
|
||||
burn_track_free(tracklist[trackno]);
|
||||
}
|
||||
burn_session_free(session);
|
||||
burn_disc_free(target_disc);
|
||||
if (multi && current_profile != 0x1a && current_profile != 0x13 &&
|
||||
@ -620,7 +671,7 @@ int main(int argc, char **argv)
|
||||
if (ret)
|
||||
exit(ret);
|
||||
|
||||
printf("Initializing libburnia.pykix.org ...\n");
|
||||
printf("Initializing libburnia-project.org ...\n");
|
||||
if (burn_initialize())
|
||||
printf("Done\n");
|
||||
else {
|
||||
|
221
test/telltoc.c
221
test/telltoc.c
@ -1,11 +1,12 @@
|
||||
|
||||
/* test/telltoc.c , API illustration of obtaining media status info */
|
||||
/* Copyright (C) 2006 Thomas Schmitt <scdbackup@gmx.net> Provided under GPL */
|
||||
/* Copyright (C) 2006 - 2007 Thomas Schmitt <scdbackup@gmx.net>
|
||||
Provided under GPL version 2 */
|
||||
|
||||
/** Overview
|
||||
|
||||
telltoc is a minimal demo application for the library libburn as provided
|
||||
on http://libburnia.pykix.org . It can list the available devices, can
|
||||
on http://libburnia-project.org . It can list the available devices, can
|
||||
display some drive properties, the type of media, eventual table of content
|
||||
and multisession info for mkisofs option -C .
|
||||
It's main purpose, nevertheless, is to show you how to use libburn and also
|
||||
@ -24,6 +25,8 @@
|
||||
telltoc_media() prints some information about the media in a drive
|
||||
telltoc_toc() prints a table of content (if there is content)
|
||||
telltoc_msinfo() prints parameters for mkisofs option -C
|
||||
telltoc_read_and_print() reads from data CD or from DVD and prints 7-bit
|
||||
to stdout (encodings 0,2) or 8-bit to file (encoding 1)
|
||||
When everything is done, main() releases the drive and shuts down libburn:
|
||||
burn_drive_release();
|
||||
burn_finish()
|
||||
@ -72,6 +75,11 @@ int telltoc_aquire_by_adr(char *drive_adr);
|
||||
int telltoc_aquire_by_driveno(int *drive_no, int silent);
|
||||
|
||||
|
||||
/* A message from --toc to --read_and_print (CD tracksize is a bit tricky) */
|
||||
static int last_track_start = 0, last_track_size = -1;
|
||||
static int media_is_cd_profile = 0;
|
||||
|
||||
|
||||
/* ------------------------------- API gestures ---------------------------- */
|
||||
|
||||
/** You need to aquire a drive before burning. The API offers this as one
|
||||
@ -100,22 +108,33 @@ int telltoc_aquire_drive(char *drive_adr, int *driveno, int silent_drive)
|
||||
/** If the persistent drive address is known, then this approach is much
|
||||
more un-obtrusive to the systemwide livestock of drives. Only the
|
||||
given drive device will be opened during this procedure.
|
||||
Special drive addresses stdio:<path> direct output to a hard disk file
|
||||
which will behave much like a DVD-RAM.
|
||||
*/
|
||||
int telltoc_aquire_by_adr(char *drive_adr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
|
||||
|
||||
/* <<< ts A70907 FOR TESTING ONLY !
|
||||
struct burn_drive_info *test_drive_list;
|
||||
*/
|
||||
|
||||
/* This tries to resolve links or alternative device files */
|
||||
ret = burn_drive_convert_fs_adr(drive_adr, libburn_drive_adr);
|
||||
if (ret<=0) {
|
||||
fprintf(stderr,"Address does not lead to a CD burner: '%s'\n",
|
||||
fprintf(stderr, "Address does not lead to a CD burner: '%s'\n",
|
||||
drive_adr);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr,"Aquiring drive '%s' ...\n",libburn_drive_adr);
|
||||
ret = burn_drive_scan_and_grab(&drive_list,libburn_drive_adr,1);
|
||||
|
||||
/* <<< ts A70907 FOR TESTING ONLY !
|
||||
ret = burn_drive_scan_and_grab(&test_drive_list, "/dev/sg2", 1);
|
||||
*/
|
||||
|
||||
fprintf(stderr,"Aquiring drive '%s' ...\n", libburn_drive_adr);
|
||||
ret = burn_drive_scan_and_grab(&drive_list, libburn_drive_adr, 1);
|
||||
|
||||
if (ret <= 0) {
|
||||
fprintf(stderr,"FAILURE with persistent drive address '%s'\n",
|
||||
libburn_drive_adr);
|
||||
@ -123,6 +142,11 @@ int telltoc_aquire_by_adr(char *drive_adr)
|
||||
fprintf(stderr,"Done\n");
|
||||
drive_is_grabbed = 1;
|
||||
}
|
||||
|
||||
/* <<< ts A70907 FOR TESTING ONLY !
|
||||
burn_drive_info_free(test_drive_list);
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -147,7 +171,7 @@ int telltoc_aquire_by_driveno(int *driveno, int silent_drive)
|
||||
|
||||
fprintf(stderr, "Beginning to scan for devices ...\n");
|
||||
while (!burn_drive_scan(&drive_list, &drive_count))
|
||||
usleep(1002);
|
||||
usleep(100002);
|
||||
if (drive_count <= 0 && *driveno >= 0) {
|
||||
fprintf(stderr, "FAILED (no drives found)\n");
|
||||
return 0;
|
||||
@ -234,7 +258,7 @@ int telltoc_media(struct burn_drive *drive)
|
||||
|
||||
printf("Media current: ");
|
||||
ret = burn_disc_get_profile(drive, &profile_no, profile_name);
|
||||
if (profile_no > 0 && ret >0) {
|
||||
if (profile_no > 0 && ret > 0) {
|
||||
if (profile_name[0])
|
||||
printf("%s\n", profile_name);
|
||||
else
|
||||
@ -443,8 +467,9 @@ int telltoc_formatlist(struct burn_drive *drive)
|
||||
int telltoc_toc(struct burn_drive *drive)
|
||||
{
|
||||
int num_sessions = 0 , num_tracks = 0 , lba = 0, pmin, psec, pframe;
|
||||
int track_count = 0;
|
||||
int track_count = 0, pno;
|
||||
int session_no, track_no;
|
||||
char profile_name[80];
|
||||
struct burn_disc *disc= NULL;
|
||||
struct burn_session **sessions;
|
||||
struct burn_track **tracks;
|
||||
@ -479,6 +504,7 @@ int telltoc_toc(struct burn_drive *drive)
|
||||
track_count,
|
||||
((toc_entry.control&7)<4?"audio":"data "),
|
||||
lba, pmin, psec, pframe);
|
||||
last_track_start = lba;
|
||||
}
|
||||
burn_session_get_leadout_entry(sessions[session_no],
|
||||
&toc_entry);
|
||||
@ -494,6 +520,11 @@ int telltoc_toc(struct burn_drive *drive)
|
||||
printf("Media content: session %2d ", session_no+1);
|
||||
printf("leadout lba: %9d %4.2d:%2.2d:%2.2d\n",
|
||||
lba, pmin, psec, pframe);
|
||||
last_track_size = lba - last_track_start;
|
||||
if (burn_disc_get_profile(drive, &pno, profile_name) > 0)
|
||||
if (pno == 0x09 || pno == 0x0a)
|
||||
media_is_cd_profile = 1;
|
||||
|
||||
}
|
||||
if (disc!=NULL)
|
||||
burn_disc_free(disc);
|
||||
@ -558,6 +589,125 @@ ex:;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@param encoding determins how to format output on stdout:
|
||||
0 = default , 1 = raw 8 bit (dangerous for tty) , 2 = hex
|
||||
*/
|
||||
int telltoc_read_and_print(struct burn_drive *drive,
|
||||
int start_sector, int sector_count, char *raw_file, int encoding)
|
||||
{
|
||||
int j, i, request = 16, done, lbas = 0, final_cd_try = -1, todo;
|
||||
int ret = 0;
|
||||
char buf[16 * 2048], line[81];
|
||||
off_t data_count, total_count= 0, last_reported_count= 0;
|
||||
struct stat stbuf;
|
||||
FILE *raw_fp = NULL;
|
||||
|
||||
if (start_sector == -1)
|
||||
start_sector = last_track_start;
|
||||
if (sector_count == -1) {
|
||||
sector_count = last_track_start + last_track_size
|
||||
- start_sector;
|
||||
if (media_is_cd_profile) /* In case it is a TAO track */
|
||||
final_cd_try = 0; /* allow it (-1 is denial) */
|
||||
}
|
||||
if (start_sector < 0)
|
||||
start_sector = 0;
|
||||
if (sector_count <= 0)
|
||||
sector_count = 2147483632;
|
||||
|
||||
if (sector_count <= 0)
|
||||
return -1;
|
||||
if (encoding == 1) {
|
||||
if (stat(raw_file,&stbuf) != -1) {
|
||||
if (!(S_ISCHR(stbuf.st_mode) || S_ISFIFO(stbuf.st_mode)
|
||||
|| (stbuf.st_mode & S_IFMT) == S_IFSOCK )) {
|
||||
fprintf(stderr,
|
||||
"SORRY: target file '%s' already existing\n",
|
||||
raw_file);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
raw_fp = fopen(raw_file,"w");
|
||||
if (raw_fp == NULL) {
|
||||
fprintf(stderr,"SORRY: cannot open target file '%s' (%s)\n", raw_file, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
printf(
|
||||
"Data : start=%ds , count=%ds , read=0s , encoding=%d:'%s'\n",
|
||||
start_sector, sector_count, encoding, raw_file);
|
||||
} else
|
||||
printf(
|
||||
"Data : start=%ds , count=%ds , read=0 , encoding=%d\n",
|
||||
start_sector, sector_count, encoding);
|
||||
todo = sector_count - 2*(final_cd_try > -1);
|
||||
for (done = 0; done < todo && final_cd_try != 1; done += request) {
|
||||
if (todo - done > 16)
|
||||
request = 16;
|
||||
else
|
||||
request = todo - done;
|
||||
ret = burn_read_data(drive,
|
||||
((off_t) start_sector + done) * (off_t) 2048,
|
||||
buf, (off_t) (request * 2048), &data_count, 1);
|
||||
|
||||
print_result:;
|
||||
total_count += data_count;
|
||||
if (encoding == 1) {
|
||||
if (data_count > 0)
|
||||
fwrite(buf, data_count, 1, raw_fp);
|
||||
} else for (i = 0; i < data_count; i += 16) {
|
||||
if (encoding == 0) {
|
||||
sprintf(line, "%8ds + %4d : ",
|
||||
start_sector + done + i / 2048,
|
||||
i % 2048);
|
||||
lbas = strlen(line);
|
||||
}
|
||||
for (j = 0; j < 16 && i + j < data_count; j++) {
|
||||
if (buf[i + j] >= ' ' && buf[i + j] <= 126 &&
|
||||
encoding != 2)
|
||||
sprintf(line + lbas + 3 * j, " %c ",
|
||||
(int) buf[i + j]);
|
||||
else
|
||||
sprintf(line + lbas + 3 * j, "%2.2X ",
|
||||
(unsigned char) buf[i + j]);
|
||||
}
|
||||
line[lbas + 3 * (j - 1) + 2] = 0;
|
||||
printf("%s\n",line);
|
||||
}
|
||||
if (encoding == 1 &&
|
||||
total_count - last_reported_count >= 1000 * 2048) {
|
||||
fprintf(stderr,
|
||||
"\rReading data : start=%ds , count=%ds , read=%ds ",
|
||||
start_sector, sector_count,
|
||||
(int) (total_count / (off_t) 2048));
|
||||
last_reported_count = total_count;
|
||||
}
|
||||
if (ret <= 0) {
|
||||
fprintf(stderr, "SORRY : Reading failed.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret > 0 && media_is_cd_profile && final_cd_try == 0) {
|
||||
/* In a SAO track the last 2 frames should be data too */
|
||||
final_cd_try = 1;
|
||||
burn_read_data(drive,
|
||||
((off_t) start_sector + todo) * (off_t) 2048,
|
||||
buf, (off_t) (2 * 2048), &data_count, 2);
|
||||
if (data_count < 2 * 2048)
|
||||
fprintf(stderr, "\rNOTE : Last two frames of CD track unreadable. This is normal if TAO track.\n");
|
||||
if (data_count > 0)
|
||||
goto print_result;
|
||||
}
|
||||
if (last_reported_count > 0)
|
||||
fprintf(stderr,
|
||||
"\r \r");
|
||||
printf("End Of Data : start=%ds , count=%ds , read=%ds\n",
|
||||
start_sector, sector_count,(int) (total_count / (off_t) 2048));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/** The setup parameters of telltoc */
|
||||
static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
|
||||
static int driveno = 0;
|
||||
@ -566,6 +716,8 @@ static int do_toc = 0;
|
||||
static int do_msinfo = 0;
|
||||
static int print_help = 0;
|
||||
static int do_capacities = 0;
|
||||
static int read_start = -2, read_count = -2, print_encoding = 0;
|
||||
static char print_raw_file[4096] = {""};
|
||||
|
||||
|
||||
/** Converts command line arguments into above setup parameters.
|
||||
@ -608,6 +760,26 @@ int telltoc_setup(int argc, char **argv)
|
||||
} else if (!strcmp(argv[i], "--toc")) {
|
||||
do_toc = 1;
|
||||
|
||||
} else if (!strcmp(argv[i], "--read_and_print")) {
|
||||
i+= 3;
|
||||
if (i >= argc) {
|
||||
fprintf(stderr,"--read_and_print requires three arguments: start count encoding(try 0, not 1)\n");
|
||||
return 1;
|
||||
}
|
||||
sscanf(argv[i-2], "%d", &read_start);
|
||||
sscanf(argv[i-1], "%d", &read_count);
|
||||
print_encoding = 0;
|
||||
if(strncmp(argv[i], "raw:", 4) == 0 || strcmp(argv[i],"1:") == 0) {
|
||||
print_encoding = 1;
|
||||
strcpy(print_raw_file, strchr(argv[i], ':') + 1);
|
||||
if (strcmp(print_raw_file, "-") == 0) {
|
||||
fprintf(stderr,
|
||||
"--read_and_print does not write to \"-\" as stdout.\n");
|
||||
return 1;
|
||||
}
|
||||
} else if(strcmp(argv[i], "hex") == 0 || strcmp(argv[i], "2") == 0)
|
||||
print_encoding = 2;
|
||||
|
||||
} else if (!strcmp(argv[i], "--help")) {
|
||||
print_help = 1;
|
||||
|
||||
@ -622,6 +794,7 @@ int telltoc_setup(int argc, char **argv)
|
||||
printf("Usage: %s\n", argv[0]);
|
||||
printf(" [--drive <address>|<driveno>|\"-\"]\n");
|
||||
printf(" [--media] [--capacities] [--toc] [--msinfo]\n");
|
||||
printf(" [--read_and_print <start> <count> \"0\"|\"hex\"|\"raw\":<path>]\n");
|
||||
printf("Examples\n");
|
||||
printf("A bus scan (needs rw-permissions to see a drive):\n");
|
||||
printf(" %s --drive -\n",argv[0]);
|
||||
@ -635,6 +808,12 @@ int telltoc_setup(int argc, char **argv)
|
||||
printf(" mkisofs ... -C \"$msinfo\" ...\n");
|
||||
printf("Obtain what is available about drive 0 and its media\n");
|
||||
printf(" %s --drive 0\n",argv[0]);
|
||||
printf("View blocks 16 to 19 of data CD or DVD in human readable form\n");
|
||||
printf(" %s --drive /dev/sr1 --read_and_print 16 4 0 | less\n",
|
||||
argv[0]);
|
||||
printf("Copy last data track from CD to file /tmp/data\n");
|
||||
printf(" %s --drive /dev/sr1 --toc --read_and_print -1 -1 raw:/tmp/data\n",
|
||||
argv[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -656,14 +835,14 @@ int main(int argc, char **argv)
|
||||
msinfo_alone = 1;
|
||||
}
|
||||
/* Default option is to do everything if possible */
|
||||
if (do_media==0 && do_msinfo==0 && do_capacities==0 && do_toc==0
|
||||
&& driveno!=-1) {
|
||||
if (do_media==0 && do_msinfo==0 && do_capacities==0 && do_toc==0 &&
|
||||
(read_start < 0 || read_count <= 0) && driveno!=-1) {
|
||||
if(print_help)
|
||||
exit(0);
|
||||
full_default = do_media = do_msinfo = do_capacities= do_toc = 1;
|
||||
full_default = do_media = do_msinfo = do_capacities= do_toc= 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Initializing libburnia.pykix.org ...\n");
|
||||
fprintf(stderr, "Initializing libburnia-project.org ...\n");
|
||||
if (burn_initialize())
|
||||
fprintf(stderr, "Done\n");
|
||||
else {
|
||||
@ -671,8 +850,11 @@ int main(int argc, char **argv)
|
||||
exit(33);
|
||||
}
|
||||
|
||||
/* Print messages of severity SORRY or more directly to stderr */
|
||||
burn_msgs_set_severities("NEVER", "SORRY", "telltoc : ");
|
||||
/* Print messages of severity WARNING or more directly to stderr */
|
||||
burn_msgs_set_severities("NEVER", "WARNING", "telltoc : ");
|
||||
|
||||
/* Activate the default signal handler */
|
||||
burn_set_signal_handling("telltoc : ", NULL, 0);
|
||||
|
||||
/** Note: driveno might change its value in this call */
|
||||
ret = telltoc_aquire_drive(drive_adr, &driveno, !full_default);
|
||||
@ -709,6 +891,13 @@ int main(int argc, char **argv)
|
||||
if (ret<=0)
|
||||
{ret = 38; goto release_drive; }
|
||||
}
|
||||
if (read_start >= -1 && (read_count > 0 || read_count == -1)) {
|
||||
ret = telltoc_read_and_print(drive_list[driveno].drive,
|
||||
read_start, read_count, print_raw_file,
|
||||
print_encoding);
|
||||
if (ret<=0)
|
||||
{ret = 40; goto release_drive; }
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (toc_failed)
|
||||
|
Reference in New Issue
Block a user