Compare commits
404 Commits
ZeroThreeF
...
ZeroFiveTw
Author | SHA1 | Date | |
---|---|---|---|
b3bd643d7b | |||
30721ca007 | |||
e98cd4704b | |||
3b5ad306c1 | |||
f64ed23a98 | |||
730c1555ab | |||
acd7dbc5c6 | |||
6dc9ecbcad | |||
5a99f9c4d8 | |||
ea17318e18 | |||
98d742a4ef | |||
332a92ac78 | |||
6c50416d3c | |||
91d678a503 | |||
76e85e600c | |||
9d48bb6892 | |||
38f0399fff | |||
39198ff8cb | |||
67ca4a251a | |||
b1c6953b61 | |||
eb95d89272 | |||
548051e53f | |||
a72b38c116 | |||
a67aa2ccee | |||
2fb5ea8def | |||
55061cb7cf | |||
4b3ec06cc4 | |||
ad6bd91b21 | |||
0e2aaa2d59 | |||
4244a3c141 | |||
e4d30e4762 | |||
2856e9c984 | |||
6660ef7ece | |||
37092086d9 | |||
35d1394262 | |||
4dec38984d | |||
be0626ae9e | |||
a54113267e | |||
2d9d250471 | |||
ff7520f2f5 | |||
d0d90fc902 | |||
1d41767348 | |||
12b0fbf17c | |||
44368aef6c | |||
43b6ad6008 | |||
f006ee5436 | |||
5e4da147a5 | |||
103b301b09 | |||
0386feabfe | |||
4e949d79fe | |||
422a97a2f2 | |||
a52ea438a5 | |||
62f41452bb | |||
015bc00a91 | |||
d6fde26824 | |||
1cfb29f032 | |||
65cf751a30 | |||
4683386de1 | |||
5d51869c3b | |||
fe8a6c6224 | |||
db5568c03b | |||
a07631c57b | |||
e522db6220 | |||
51ac900de6 | |||
cdea153443 | |||
0ce3f7c224 | |||
8de0a3dc6c | |||
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 | |||
7d23984220 | |||
aba535d700 | |||
203f158f5b | |||
e274c90f9d | |||
bf25c6edc8 | |||
2c467c8378 | |||
bdadae6ba5 | |||
1087d402f2 | |||
dc97c0d0df | |||
8b8afdd59b | |||
4dd8f098ac | |||
16b6e1905a | |||
22d1d56ebd | |||
0217702b8c | |||
81d68aeb83 | |||
0e23721f2d | |||
3a771b3da2 | |||
bacb815ecc | |||
f34d9efdb2 | |||
8efb863d5d | |||
d7ca1dd333 | |||
ddc2745495 | |||
12c4c73535 | |||
3326fcdb2d | |||
fba8eaef80 | |||
15a70555b2 | |||
83e196d69f | |||
c86f5d7cde | |||
8d7d177ce3 | |||
cd7b4e6de4 | |||
79adcb520b | |||
41f2a40a58 | |||
9b663f15d9 | |||
ed9d3e2545 | |||
ba7cd6d66e | |||
660bf40a3c | |||
25ba84a7e2 | |||
6566771834 | |||
2d2a2f8c1b | |||
329f266cea | |||
dce1ba57f3 | |||
d3f08d4f96 | |||
ddb63509af | |||
96098b3f2d | |||
256139c9d6 | |||
fd5b681bc6 | |||
2a38890c5f | |||
2ec2a34f51 | |||
10e320911a | |||
9699880581 | |||
13b9f910e1 | |||
acaba76cda | |||
927a820aec | |||
3b9f66a765 | |||
5d2ad006a4 | |||
aa03717f24 | |||
ab5f39b8bb | |||
e1b8edb437 | |||
a78e6f9b29 | |||
047f9c75f5 | |||
159715ebaa | |||
f617567e03 | |||
10a7a9d5e8 | |||
76ed9570c9 | |||
4bc8e4caea | |||
1a054b54c9 | |||
76a9fa4fa2 | |||
4c85686aad | |||
a686340407 | |||
16c7cf1889 | |||
15b33422d0 | |||
649f67697a | |||
125e28160d | |||
eb860ee4b7 | |||
a8c69206fe | |||
26745b4064 | |||
962f68b1d6 | |||
cc5560fc86 | |||
5d65697697 | |||
749d12591e | |||
98f0dab87e | |||
17c87b78a6 | |||
ecbe1c0f39 | |||
9507587652 | |||
dba40c756b | |||
fd9e5dc935 | |||
2816d8b569 | |||
64233b0ccc | |||
9e1b3719d6 | |||
6086b59301 | |||
c345426299 | |||
05216162ef | |||
13e2b23ace | |||
820f0924f9 |
@ -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
@ -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 - A70210
|
||||
## cdrskin construction site - ts A60816 - A80820
|
||||
cdrskin_cdrskin_CPPFLAGS = -Ilibburn
|
||||
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_3_3
|
||||
cdrskin_cdrskin_LDADD = $(libburn_libburn_la_OBJECTS) $(THREAD_LIBS)
|
||||
cdrskin_cdrskin_CFLAGS = -DCdrskin_libburn_0_5_2
|
||||
|
||||
# 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"
|
||||
|
184
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,43 @@ 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
|
||||
To make libburn accessible for running resp. application development,
|
||||
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.
|
||||
Above procedure installs cdrskin depending on libburn.so.4 .
|
||||
For a standalone cdrskin binary, see cdrskin/README.
|
||||
|
||||
|
||||
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 +77,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 +117,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).
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
@ -127,13 +167,13 @@ Project history as far as known to me:
|
||||
It has meanwhile moved to use vanilla libburn.pykix.org , though.
|
||||
Version 0.1.4 constitutes the first release of this kind.
|
||||
|
||||
- In Juli 2006 our team mate Mario Danic announced a revival of libburn
|
||||
- In July 2006 our team mate Mario Danic announced a revival of libburn
|
||||
which by about nearly everybody else was perceived as unfriendly fork.
|
||||
Derek Foreman four days later posted a message which expressed his
|
||||
discontent.
|
||||
The situation first caused me to publically regret it and then - after i
|
||||
got the opportunity to move in with cdrskin - gave me true reason to
|
||||
personally apologize to Derek Foreman, Ben Jansens and the contibutors at
|
||||
personally apologize to Derek Foreman, Ben Jansens and the contributors at
|
||||
icculus.org/burn. Posted to both projects:
|
||||
http://lists.freedesktop.org/archives/libburn/2006-August/000446.html
|
||||
http://mailman-mail1.webfaction.com/pipermail/libburn-hackers/2006-August/000024.html
|
||||
@ -192,15 +232,87 @@ Project history as far as known to me:
|
||||
|
||||
- 11th February 2007 version 0.3.2 covers sequential DVD-RW and DVD-R with
|
||||
multi-session and with DAO.
|
||||
This means all single layer DVD media except DVD+R are supported now.
|
||||
|
||||
- 12th March 2007 version 0.3.4 supports DVD+R and thus covers all single layer
|
||||
DVD media. Code for double layer DVD+/-R is implemented but awaits a tester
|
||||
yet.
|
||||
|
||||
- 23th April 2007 version 0.3.6 follows the unanimous opinion of Linux kernel
|
||||
people that one should not use /dev/sg on kernel 2.6.
|
||||
|
||||
- 31st July 2007 version 0.3.8 marks the first anniversary of libburn revival.
|
||||
We look back on improved stability, a substantially extended list of media
|
||||
and write modes, and better protection against typical user mishaps.
|
||||
|
||||
- 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.
|
||||
|
||||
- 27th Apr 2008 libisofs-0.6.4 can now read data file content from images
|
||||
and can map pieces of disk files onto image files. Image directory iteration
|
||||
has been enhanced. Input data streams and extended information have been
|
||||
exposed in the API to allow future development.
|
||||
|
||||
- 29th Apr 2008 libisoburn-0.1.4 was made more efficient with reading of
|
||||
image tree nodes. It now depends on libisofs-0.6.4 and libburn-0.4.4.
|
||||
xorriso makes use of new libisofs features by performing incremental
|
||||
updates of directory trees and by cutting oversized data files into
|
||||
pieces. A primitive single session emulation of cdrcord and mkisofs is
|
||||
provided.
|
||||
|
||||
- 10th May 2008 libburn-0.4.6 supports formatting and writing of BD-RE,
|
||||
full nominal speed for DVD-RAM and BD-RE. cdrskin has a unified blank
|
||||
type with automatic media state recognition.
|
||||
|
||||
- 17th May 2008 an old bug with DVD-RAM and now with BD-RE is fixed by
|
||||
libburn-0.4.8 to allow libisoburn emulation of multisession on those media.
|
||||
|
||||
- 19th May 2008 libisoburn-0.1.6 brings better table-of-content emulation
|
||||
on overwriteble media and disk files.
|
||||
|
||||
- 1st Jun 2008 libisofs-0.6.6 fixes some problems around device files.
|
||||
|
||||
- 3rd Jun 2008 libisoburn-0.1.8 fixes a bug with overwriteable media.
|
||||
|
||||
- 23rd Jun 2008 libisoburn-0.2.0 introduces extraction of files from
|
||||
ISO images.
|
||||
|
||||
- 16th Jul 2008 libburn-0.5.0 handles systems with no /dev/sr* but only
|
||||
/dev/scd*.
|
||||
|
||||
- 19th Jul 2008 libisoburn/xorriso-0.2.2 can do multi-session in mkisofs
|
||||
and cdrecord style. xorriso now can serve underneath growisofs.
|
||||
|
||||
- 20th Aug 2008 libburn-0.5.2 revokes the necessity that a drive must be
|
||||
enumerable in order to be adressable. Enumeration is enhanced by examining
|
||||
/proc/sys/dev/cdrom/info.
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
the Free Software Foundation. To be exact: version 2 of that License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
376
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.3.tar.gz
|
||||
Copyright (C) 2006-2007 Thomas Schmitt
|
||||
|
||||
http://scdbackup.sourceforge.net/cdrskin-0.5.2.pl00.tar.gz
|
||||
Copyright (C) 2006-2008 Thomas Schmitt, provided under GPL version 2.
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
On top of libburn there is implemented cdrskin 0.3.3, 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.3.tar.gz, take it to a directory of your choice and do:
|
||||
Obtain cdrskin-0.5.2.pl00.tar.gz, take it to a directory of your choice and do:
|
||||
|
||||
tar xzf cdrskin-0.3.3.tar.gz
|
||||
cd cdrskin-0.3.3
|
||||
tar xzf cdrskin-0.5.2.pl00.tar.gz
|
||||
cd cdrskin-0.5.2
|
||||
|
||||
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.3 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:
|
||||
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.
|
||||
|
||||
With that static binary 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
|
||||
|
||||
@ -126,20 +92,32 @@ The superuser should be able to see any usable drive and then set the
|
||||
permissions as needed. If this hangs then there is a drive with
|
||||
unexpected problems (locked, busy, broken, whatever). You might have to
|
||||
guess the address of your (non-broken) burner by other means, then.
|
||||
On Linux 2.4 this would be some /dev/sgN and on 2.6. some /dev/hdX.
|
||||
On Linux 2.4 this would be some /dev/sgN and on 2.6. some /dev/srM or /dev/hdX.
|
||||
|
||||
The output of cdrskin --devices might look like
|
||||
|
||||
0 dev='/dev/sg0' rwrwr- : '_NEC' 'DVD_RW ND-4570A'
|
||||
1 dev='/dev/sg1' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
|
||||
0 dev='/dev/sr0' rwrwr- : '_NEC' 'DVD_RW ND-4570A'
|
||||
1 dev='/dev/sr1' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
|
||||
|
||||
So full and insecure enabling of both for everybody would look like
|
||||
|
||||
chmod a+rw /dev/sg0 /dev/sg1
|
||||
chmod a+rw /dev/sr0 /dev/sr1
|
||||
|
||||
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
|
||||
|
||||
@ -152,7 +130,7 @@ Get an overview of cdrecord style addresses of available devices
|
||||
cdrskin --devices
|
||||
|
||||
Adresses reported with dev=ATA need prefix "ATA:". Address examples:
|
||||
dev=0,1,0 dev=ATA:1,0,0 dev=/dev/sg1 dev=/dev/hdc
|
||||
dev=0,1,0 dev=ATA:1,0,0 dev=/dev/sg1 dev=/dev/hdc dev=/dev/sr0
|
||||
See also "Drive Addressing" below.
|
||||
|
||||
Obtain some info about the drive
|
||||
@ -161,8 +139,8 @@ Obtain some info about the drive
|
||||
Obtain some info about the drive and the inserted media
|
||||
cdrskin dev=0,1,0 -atip -v
|
||||
|
||||
Make used CD-RW or used unformatted DVD-RW writeable again
|
||||
cdrskin -v dev=0,1,0 blank=fast -eject
|
||||
Prepare CD-RW or DVD-RW for re-use, DVD-RAM or BD-RE for first use
|
||||
cdrskin -v dev=/dev/sg1 blank=as_needed -eject
|
||||
|
||||
Format DVD-RW to avoid need for blanking before re-use
|
||||
cdrskin -v dev=0,1,0 blank=format_overwrite
|
||||
@ -174,18 +152,18 @@ 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
|
||||
cdrskin dev=/dev/hdc padsize=300k -tao 4.iso
|
||||
cdrskin dev=/dev/hdc padsize=300k -multi 2.iso
|
||||
cdrskin dev=/dev/hdc padsize=300k -multi 3.iso
|
||||
cdrskin dev=/dev/hdc padsize=300k 4.iso
|
||||
|
||||
Get multi-session info for option -C of program mkisofs:
|
||||
c_values=$(cdrskin dev=/dev/hdc -msinfo 2>/dev/null)
|
||||
mkisofs ... -C "$c_values" ...
|
||||
|
||||
Burn a compressed afio archive to media on-the-fly
|
||||
find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 -tao \
|
||||
find . | afio -oZ - | cdrskin -v dev=0,1,0 fs=32m speed=8 \
|
||||
driveropts=burnfree padsize=300k -
|
||||
|
||||
Burn 6 audio tracks from files with different formats to CD (not to any DVD).
|
||||
@ -201,44 +179,30 @@ 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/sg1"
|
||||
|
||||
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.)
|
||||
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 +213,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 /dev/sgN with is looked up with matching
|
||||
scsibus,target,lun as given by the operating system.
|
||||
With dev=ATA: or dev=ATAPI: the translation to /dev/hdX is purely literal
|
||||
but matches the cdrecord addresses on all systems tested so far:
|
||||
X = 'a' + 2 * scsibus + target
|
||||
where target only may have the values 0 or 1.
|
||||
|
||||
In this mode, option -scanbus will list only SCSI devices unless option
|
||||
dev=ATA or dev=ATAPI are given, which will suppress SCSI devices and only
|
||||
show IDE drives (i.e. /dev/hdX without ide-scsi emulation).
|
||||
|
||||
|
||||
In mode --old_pseudo_scsi_adr there is a scsibus,target,lun representation
|
||||
which has nothing to do with SCSI and thus is not compatible to cdrecord.
|
||||
Each number triple corresponds either to a device file address or to a
|
||||
libburn drive number.
|
||||
Component "scsibus" indicates the translation method. Defined busses are:
|
||||
0 target is the libburn drivenumber as listed with --devices
|
||||
1 associated to device file /dev/sgN , target chooses N
|
||||
2 associated to device file /dev/hdX , target 0='a', 1='b' ..., 25='z'
|
||||
|
||||
So "1,1,0" is /dev/sg1, "2,3,0" is /dev/hdd, "0,2,0" is libburn drive #2 at
|
||||
some unspecified device file.
|
||||
This scheme shall help to keep cdrecord-style addresses stable and exchangeable
|
||||
between users without excluding drives with unexpected device addresses.
|
||||
The numbering on bus 0 is prone to arbitrary changes caused by changes in
|
||||
drive accessability.
|
||||
Further busses may emerge as libburn evolves. "prefix" and "lun" may get
|
||||
a meaning. To stay upward compatible, use addresses as printed by -scanbus.
|
||||
|
||||
User Defined Device Address Translation
|
||||
|
||||
Some programs or users have their own ideas about the address of their burner.
|
||||
K3b 0.10 for example derives cdrecord addresses by own examination of the
|
||||
devices and not by calling cdrecord -scanbus.
|
||||
Standard mode will hopefully be fully compatible with their ideas.
|
||||
|
||||
Old frontends which do not know dev=ATA or dev=ATAPI and which do ask their
|
||||
"cdrecord" via -scanbus may be well served with option --old_pseudo_scsi_adr .
|
||||
|
||||
To direct any remaining stubborn callers to the appropriate drives, cdrskin
|
||||
allows to define device address aliases. Like
|
||||
cdrskin dev_translation=+1,0,0+/dev/sg1 \
|
||||
dev_translation=+ATA:1,0,0+/dev/sg1 \
|
||||
dev_translation=-"cd+dvd"-0,1,0 \
|
||||
...
|
||||
Any of the addresses dev=1,0,0, dev=ATA:1,0,0, dev=cd+dvd will be mapped to
|
||||
/dev/sg1 resp. to 0,1,0.
|
||||
The first character after "dev_translation=" defines the character which
|
||||
separates the two parts of the translation pair. (Above: "+" and "-".)
|
||||
|
||||
In K3b 0.10 it is possible to employ alternative writer programs by setting
|
||||
their full path (e.g. /usr/bin/cdrskin) in menu
|
||||
Settings:Configure K3b...:Programs:Search Path
|
||||
and to make them default in menu
|
||||
Settings:Configure K3b...:Programs:Programs:
|
||||
A suitable setting for "cdrecord" in menu
|
||||
Settings:Configure K3b...:Programs:User Parameters
|
||||
would then probably be
|
||||
-v dev_translation=+1,0,0+/dev/sg1
|
||||
You will learn from button "Show Debugging Output" after a failed burn run
|
||||
what cdrecord command was used with what address "dev=...". This address "..."
|
||||
will be the right one to replace "1,0,0" in above example.
|
||||
|
||||
|
||||
Startup Files
|
||||
|
||||
If not --no_rc is the first argument then cdrskin attempts on startup to read
|
||||
@ -352,8 +228,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
|
||||
@ -386,33 +260,38 @@ I myself am not into audio. So libburn-hackers@pykix.org might be the
|
||||
best address for suggestions, requests and bug reports.
|
||||
|
||||
|
||||
DVD+RW and DVD-RAM
|
||||
DVD+RW , DVD-RAM , BD-RE
|
||||
|
||||
DVD+RW and DVD-RAM media get treated as blank media regardless wether they
|
||||
These random access media get treated as blank media regardless wether they
|
||||
hold data or not. Options -audio and -multi are not allowed. Only one track
|
||||
is allowed. -toc does not return information about the media content.
|
||||
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.
|
||||
Speed is counted in DVD units (i.e. 1x = 1,385,000 bytes/second) or BD units
|
||||
(1x = 4,495,625 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 MB).
|
||||
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 ...
|
||||
BD-RE media need formatting before first use. cdrskin option "blank=as_needed"
|
||||
recognizes unformatted BD-RE and applies a lengthy formatting run.
|
||||
|
||||
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.
|
||||
During write operations DVD-RAM and BD-RE automatically apply defect
|
||||
management. This usually slows them down to half nominal speed. If drive
|
||||
and media produce flawless results anyway, then one can try to reach full
|
||||
nominal speed by option "stream_recording=on".
|
||||
In this case bad blocks are not detected during write and not even previously
|
||||
known bad blocks are avoided. So you have to make your own readability tests
|
||||
and go back to half speed as soon as the first read errors show up.
|
||||
|
||||
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 +307,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 +316,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
|
||||
@ -447,7 +326,7 @@ too on blanking by cdrecord, dvd+rw-format or cdrskin. Perils of DVD-RW.
|
||||
There are three DVD-RW formatting variants with cdrskin currently:
|
||||
|
||||
blank=format_overwrite uses "DVD-RW Quick" formatting (MMC-type 15h)
|
||||
and writes a first session of 128 MB. This leads to media which are expandable
|
||||
and writes a first session of 128 MiB. This leads to media which are expandable
|
||||
and random addressable by cdrskin.
|
||||
|
||||
blank=format_overwrite_quickest uses "DVD-RW Quick" formatting (type 15h) too,
|
||||
@ -470,10 +349,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 a 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 +391,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 imposed the need to reboot the
|
||||
system because of drives gnawing endlessly on ill media. Permanent hardware
|
||||
damage did not occur in 2.5 years of development. But one never knows ...
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
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 +431,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,8 +38,8 @@ original="./libburn_svn_release.tgz"
|
||||
# My changes are in $changes , mainly in $changes/cdrskin
|
||||
changes="./libburn-release"
|
||||
|
||||
skin_release="0.3.2"
|
||||
patch_level=".pl01"
|
||||
skin_release="0.5.2"
|
||||
patch_level=".pl00"
|
||||
skin_rev="$skin_release""$patch_level"
|
||||
|
||||
# The result directory and the name of the result tarballs
|
||||
@ -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"
|
||||
@ -103,9 +104,9 @@ cdrskin_target="$target"/cdrskin
|
||||
libburn_target="$target"/libburn
|
||||
|
||||
# Create version timestamp
|
||||
timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
|
||||
echo "$timestamp"
|
||||
echo '#define Cdrskin_timestamP "'"$timestamp"'"' >"$cdrskin_dir"/cdrskin_timestamp.h
|
||||
# timestamp="$(date -u '+%Y.%m.%d.%H%M%S')"
|
||||
# echo "$timestamp"
|
||||
# echo '#define Cdrskin_timestamP "'"$timestamp"'"' >"$cdrskin_dir"/cdrskin_timestamp.h
|
||||
|
||||
# Add the cdrskin files
|
||||
if test -e "$cdrskin_target"
|
||||
@ -114,7 +115,8 @@ then
|
||||
fi
|
||||
cp -a "$cdrskin_dir" "$cdrskin_target"
|
||||
|
||||
# Remove copied binaries
|
||||
# Remove copied vim.swp and binaries
|
||||
rm "$cdrskin_target"/.*.swp
|
||||
rm "$cdrskin_target"/*.o
|
||||
rm "$cdrskin_target"/cdrfifo
|
||||
rm "$cdrskin_target"/cdrskin
|
||||
@ -137,7 +139,7 @@ do
|
||||
done
|
||||
|
||||
# Remove GIFs of cdrskin_eng.html
|
||||
rm "$cdrskin_target"/doener_*.gif
|
||||
rm "$cdrskin_target"/doener_*.gif "$cdrskin_target"/doener_*.png
|
||||
|
||||
# Remove automatically generated HTML man page
|
||||
rm "$cdrskin_target"/man_1_cdrskin.html
|
||||
@ -153,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
|
||||
@ -192,6 +198,18 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
# Repair non-portable shell code output of ./bootstrap
|
||||
(
|
||||
cd "$compile_dir" || exit 1
|
||||
sed -e 's/^for ac_header in$/test -z 1 \&\& for ac_header in dummy/' \
|
||||
< ./configure > ./configure-repaired
|
||||
if test "$?" = 0
|
||||
then
|
||||
echo "$0: Empty 'for ac_header in' found in configure." >&2
|
||||
fi
|
||||
mv ./configure-repaired ./configure
|
||||
chmod a+rx,go-w,u+w ./configure
|
||||
)
|
||||
|
||||
# Pack it up to the new libburn+cdrskin-tarball
|
||||
tar czf "$cdrskin_tarball" "$target"
|
@ -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.3"
|
||||
skin_release="0.5.3"
|
||||
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"
|
||||
@ -114,7 +114,8 @@ then
|
||||
fi
|
||||
cp -a "$cdrskin_dir" "$cdrskin_target"
|
||||
|
||||
# Remove copied binaries
|
||||
# Remove copied vim.swp and binaries
|
||||
rm "$cdrskin_target"/.*.swp
|
||||
rm "$cdrskin_target"/*.o
|
||||
rm "$cdrskin_target"/cdrfifo
|
||||
rm "$cdrskin_target"/cdrskin
|
||||
@ -137,11 +138,14 @@ do
|
||||
done
|
||||
|
||||
# Remove GIFs of cdrskin_eng.html
|
||||
rm "$cdrskin_target"/doener_*.gif
|
||||
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
|
||||
@ -192,6 +196,19 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
# Repair non-portable shell code output of ./bootstrap
|
||||
(
|
||||
cd "$compile_dir" || exit 1
|
||||
sed -e 's/^for ac_header in$/test -z 1 \&\& for ac_header in dummy/' \
|
||||
< ./configure > ./configure-repaired
|
||||
if test "$?" = 0
|
||||
then
|
||||
echo "$0: Empty 'for ac_header in' found in configure." >&2
|
||||
fi
|
||||
mv ./configure-repaired ./configure
|
||||
chmod a+rx,go-w,u+w ./configure
|
||||
)
|
||||
|
||||
|
||||
# Pack it up to the new libburn+cdrskin-tarball
|
||||
tar czf "$cdrskin_tarball" "$target"
|
||||
@ -201,13 +218,15 @@ tar czf "$cdrskin_tarball" "$target"
|
||||
cd "$compile_dir" || exit 1
|
||||
./configure
|
||||
make
|
||||
"$compile_cmd" -O2 -do_strip
|
||||
"$compile_cmd" -libburn_svn -O2 -do_strip
|
||||
cp "$compile_result" "../$bintarget_dynamic"
|
||||
if test -n "$compile_static_opts"
|
||||
then
|
||||
"$compile_cmd" $compile_static_opts -O2 -do_strip
|
||||
"$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" ..
|
||||
)
|
@ -77,6 +77,9 @@ struct CdrfifO {
|
||||
double empty_counter;
|
||||
double full_counter;
|
||||
|
||||
/* 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 */
|
||||
@ -159,6 +162,8 @@ int Cdrfifo_new(struct CdrfifO **ff, int source_fd, int dest_fd,
|
||||
o->get_counter= 0.0;
|
||||
o->empty_counter= 0.0;
|
||||
o->full_counter= 0.0;
|
||||
o->iso_fs_size= -1.0;
|
||||
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;
|
||||
@ -219,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);
|
||||
@ -390,6 +397,21 @@ int Cdrfifo_get_min_fill(struct CdrfifO *o, int *total_min_fill,
|
||||
}
|
||||
|
||||
|
||||
int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes, int flag)
|
||||
{
|
||||
*size_in_bytes= o->iso_fs_size;
|
||||
return(o->iso_fs_size>=2048);
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
@ -398,7 +420,7 @@ int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
|
||||
double *empty_counter, double *full_counter,
|
||||
int flag)
|
||||
{
|
||||
*put_counter= o->put_counter;;
|
||||
*put_counter= o->put_counter;
|
||||
*get_counter= o->get_counter;
|
||||
*empty_counter= o->empty_counter;
|
||||
*full_counter= o->full_counter;
|
||||
@ -870,6 +892,29 @@ int Cdrfifo_fill(struct CdrfifO *o, int size, int flag)
|
||||
if(ret==2)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef Cdrfifo_standalonE
|
||||
if(fill>=32*2048) {
|
||||
int Scan_for_iso_size(unsigned char data[2048], double *size_in_bytes,
|
||||
int flag);
|
||||
int bs= 16*2048;
|
||||
double size;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
#endif
|
||||
|
||||
o->total_min_fill= fill;
|
||||
o->interval_min_fill= fill;
|
||||
return(1);
|
||||
|
@ -117,6 +117,21 @@ int Cdrfifo_get_cdr_counters(struct CdrfifO *o,
|
||||
double *empty_counter, double *full_counter,
|
||||
int flag);
|
||||
|
||||
/** Inquire the eventually detected size of an eventual ISO-9660 file system
|
||||
@return 0=no ISO resp. size detected, 1=size_in_bytes is valid
|
||||
*/
|
||||
int Cdrfifo_get_iso_fs_size(struct CdrfifO *o, double *size_in_bytes,int flag);
|
||||
|
||||
|
||||
/** 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
|
||||
|
2770
cdrskin/cdrskin.c
@ -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, 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, BD-RE, cdrecord, compatible, scdbackup">
|
||||
<META NAME="robots" CONTENT="follow">
|
||||
<TITLE>cdrskin homepage english</TITLE>
|
||||
</HEAD>
|
||||
@ -12,39 +12,40 @@
|
||||
|
||||
<CENTER>
|
||||
<A HREF="http://en.wikipedia.org/wiki/D%C3%B6ner_kebab">
|
||||
<IMG SRC="doener_150x200_tr_octx.gif" BORDER=0
|
||||
<IMG SRC="doener_150x200_tr_octx.png" BORDER=0
|
||||
ALT="cdrskin logo: Doener mit Scharf">
|
||||
</A>
|
||||
<P><H2> Homepage of </H2>
|
||||
<H1> cdrskin </H1>
|
||||
<!-- <FONT SIZE=+0><A HREF="cdrskin_ger.html">deutsch (german)</A></FONT> -->
|
||||
|
||||
<H2>Limited cdrecord compatibility wrapper for libburn</H2>
|
||||
</CENTER>
|
||||
|
||||
<P>
|
||||
<H2>Purpose:</H2>
|
||||
<UL>
|
||||
<LI>Burns preformatted data to CD-R, CD-RW, DVD-R, DVD-RW, DVD-RAM, DVD+RW</LI>
|
||||
</UL>
|
||||
Burns preformatted data to CD, DVD, and BD media:<BR>
|
||||
CD-R, DVD-R, DVD+R, DVD+R/DL, CD-RW, DVD-RW, DVD-RAM, DVD+RW, BD-RE
|
||||
</P>
|
||||
<P>
|
||||
|
||||
<HR>
|
||||
|
||||
<A HREF="#download">Direct hop to download links -></A>
|
||||
|
||||
<P>
|
||||
<H2>Hardware requirements:</H2>
|
||||
A CD/DVD recorder suitable for
|
||||
<A HREF="http://libburnia.pykix.org">libburnia.pykix.org</A>
|
||||
(SCSI or IDE/ATAPI writers compliant to standard MMC-3 or higher).
|
||||
A CD/DVD/BD recorder suitable for
|
||||
<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 or BD).
|
||||
<BR>
|
||||
</P>
|
||||
|
||||
<P>
|
||||
<H2>Software requirements :</H2>
|
||||
<DL>
|
||||
<DT>Linux kernel 2.4 or higher</DT>
|
||||
<DD>With kernel 2.4 the drive has to be under ide-scsi emulation.</DD>
|
||||
<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>
|
||||
<DD>is supposed to be a standard system component.</DD>
|
||||
@ -56,9 +57,10 @@ A CD/DVD recorder suitable for
|
||||
GPL software included:<BR>
|
||||
</H2>
|
||||
<DL>
|
||||
<DT>libburn-0.3.2</DT>
|
||||
<DD>(by Derek Foreman, Ben Jansens, and team of libburnia.pykix.org)</DD>
|
||||
<DD>transfers data to CD</DD>
|
||||
<DT>libburn-0.5.2</DT>
|
||||
<DD>(founded by Derek Foreman and Ben Jansens,
|
||||
furthered since August 2006 by Thomas Schmitt from team of libburnia-project.org)</DD>
|
||||
<DD>transfers data to CD, DVD, BD-RE</DD>
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
@ -81,32 +83,31 @@ Ports to other usable systems are appreciated. Reports are welcome.
|
||||
<P>
|
||||
<H2>Commands:</H2>
|
||||
<DL>
|
||||
<DT>The goal is to provide some of cdrecord's options in a compatible way.
|
||||
This has been achieved quite sufficiently for the needs of backup tool
|
||||
<A HREF="http://scdbackup.sourceforge.net/main_eng.html">scdbackup</A>
|
||||
and for data CD projects of <A HREF="http://www.k3b.org">K3b</A>
|
||||
(see <A HREF="#examples">examples</A>).
|
||||
Suitability for audio CD frontends has been improved much and is now being
|
||||
evaluated.<BR>
|
||||
Most DVD types are written in pseudo -tao modes which are very different
|
||||
from the write mode DAO used by cdrecord(-ProDVD). With DVD-R[W] cdrskin
|
||||
can use this write mode, too.<BR>
|
||||
Further enhancements depend on people who can describe and discuss their
|
||||
wishes as well as on the development of libburn.</DT>
|
||||
<DT>The most common options of cdrecord for data and audio on CD media
|
||||
are provided in a compatible way.<BR>
|
||||
On all DVD media except DVD-R DL, cdrskin is able to perform any recording job
|
||||
which is possible with cdrecord.
|
||||
Other than with cdrecord, option -multi is supported with many DVD types and
|
||||
write mode -tao works with anything but quickly blanked DVD-RW.
|
||||
</DT>
|
||||
<BR><BR>
|
||||
<DT>Get an overview of drives and their addresses:</DT>
|
||||
<DD>$<KBD> cdrskin -scanbus</KBD></DD>
|
||||
<DD>$<KBD> cdrskin dev=ATA -scanbus</KBD></DD>
|
||||
<DD>$<KBD> cdrskin --devices</KBD></DD>
|
||||
<DT>Get an overview of drives and their addresses</DT>
|
||||
<DD>#<KBD> cdrskin -scanbus</KBD></DD>
|
||||
<DD>#<KBD> cdrskin dev=ATA -scanbus</KBD></DD>
|
||||
<DD>#<KBD> cdrskin --devices</KBD></DD>
|
||||
<DT>Being superuser avoids permission problems with /dev/srN resp. /dev/hdX .
|
||||
</DT>
|
||||
<DT>Ordinary users should then get granted rw access to the /dev files
|
||||
as listed by option --devices.</DT>
|
||||
<DT> </DT>
|
||||
|
||||
<DT>Get info about a particular drive or loaded media:</DT>
|
||||
<DD>$<KBD> cdrskin dev=0,1,0 -checkdrive</KBD></DD>
|
||||
<DD>$<KBD> cdrskin dev=ATA:1,0,0 -v -atip</KBD></DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -toc</KBD></DD>
|
||||
|
||||
<DT>Make used CD-RW or used unformatted DVD-RW writable again:</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/sg1 blank=fast -eject</KBD></DD>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/dvd blank=all -eject</KBD></DD>
|
||||
<DT>Prepare CD-RW or DVD-RW for re-use, DVD-RAM or BD-RE for first use:</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/sg1 blank=as_needed -eject</KBD></DD>
|
||||
|
||||
<DT>Format DVD-RW to avoid need for blanking before re-use:</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/sr0 blank=format_overwrite</KBD></DD>
|
||||
@ -117,26 +118,31 @@ wishes as well as on the development of libburn.</DT>
|
||||
<DT>Write ISO-9660 filesystem image as only one to blank or formatted media:
|
||||
</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=/dev/hdc speed=12 fs=8m \</KBD></DD>
|
||||
<DD><KBD> -sao -eject padsize=300k my_image.iso</KBD></DD>
|
||||
<DD><KBD> blank=as_needed -eject padsize=300k my_image.iso</KBD></DD>
|
||||
|
||||
<DT>Write compressed afio archive on-the-fly:</DT>
|
||||
<DD>$<KBD> find . | afio -oZ - | \</KBD></DD>
|
||||
<DD><KBD> cdrskin -v dev=0,1,0 fs=32m speed=8 \</KBD></DD>
|
||||
<DD><KBD> -tao padsize=300k -</KBD></DD>
|
||||
<DD><KBD> blank=as_needed padsize=300k -</KBD></DD>
|
||||
|
||||
<DT>Write several sessions to the same CD or DVD-R[W]:</DT>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 1.iso</KBD>
|
||||
<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 1.iso</KBD>
|
||||
</DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 2.iso</KBD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi 2.iso</KBD>
|
||||
</DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi -tao 3.iso</KBD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -multi 3.iso</KBD>
|
||||
</DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k -tao 4.iso</KBD></DD>
|
||||
<DD>$<KBD> cdrskin dev=/dev/hdc -v padsize=300k 4.iso</KBD></DD>
|
||||
|
||||
<DT>Get CD or DVD-R[W] multi-session info for option -C of program mkisofs:</DT>
|
||||
<DT>Get multi-session info for option -C of program mkisofs:</DT>
|
||||
<DD>$<KBD> c_values=$(cdrskin dev=/dev/sr0 -msinfo 2>/dev/null)</KBD></DD>
|
||||
<DD>$<KBD> mkisofs ... -C "$c_values" ...</KBD></DD>
|
||||
|
||||
<DT>Inquire free space on media for a -multi run:</DT>
|
||||
<DD>$<KBD> x=$(cdrskin dev=/dev/sr0 -multi \</KBD></DD>
|
||||
<DD><KBD> --tell_media_space 2>/dev/null)</KBD></DD>
|
||||
<DD>$<KBD> echo "Available: $x blocks of 2048 data bytes"</KBD></DD>
|
||||
|
||||
<DT>Write audio tracks to CD:</DT>
|
||||
<DD>$<KBD> cdrskin -v dev=ATA:1,0,0 speed=48 -sao \</KBD></DD>
|
||||
<DD><KBD> track1.wav track2.au -audio -swab track3.raw</KBD></DD>
|
||||
@ -150,7 +156,6 @@ wishes as well as on the development of libburn.</DT>
|
||||
<DT>Read the detailed manual page:</DT>
|
||||
<DD>$<KBD> <A HREF="man_1_cdrskin.html">man cdrskin</A></KBD></DD>
|
||||
</DL>
|
||||
|
||||
<DL>
|
||||
<DT>Read about the standard for which cdrskin is striving:</DT>
|
||||
<DD>$<KBD>
|
||||
@ -161,58 +166,54 @@ man cdrecord</A></KBD></DD>
|
||||
this "don't bother Joerg" demand.)
|
||||
</DD>
|
||||
</DL>
|
||||
</P>
|
||||
<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 DVD-R DL media
|
||||
or to do experiments on BD-R media.
|
||||
|
||||
<P>
|
||||
<H2>Known deficiencies:</H2>
|
||||
<UL>
|
||||
<DT></DT>
|
||||
<LI>
|
||||
Appending sessions to unclosed media is restricted to write mode TAO.
|
||||
</LI>
|
||||
<LI>
|
||||
cdrskin -scanbus or --devices hangs for quite a while if there is
|
||||
a CD drive which does not work properly (e.g. because it has individual
|
||||
problems with DMA).
|
||||
So if the superuser gets no result with cdrskin --devices then one should
|
||||
disable DMA with the problematic CD drives
|
||||
(like: <KBD>hdparm -d0 /dev/hdd</KBD> )
|
||||
and try again.<BR>
|
||||
In severe cases it might be necessary to guess the device name /dev/sgN resp.
|
||||
/dev/hdX of the non-ill burner if it cannot be found otherwise among its
|
||||
ill peers. Alternatively one can guess the address of the ill device, remove
|
||||
rw-permissions and retry the bus scan as non-superuser.
|
||||
</UL>
|
||||
</P>
|
||||
|
||||
<HR>
|
||||
|
||||
<A NAME="download"></A>
|
||||
|
||||
<P>
|
||||
<DL>
|
||||
<DT>Download as source code (see README):</DT>
|
||||
<DD><A HREF="cdrskin-0.3.2.pl01.tar.gz">cdrskin-0.3.2.pl01.tar.gz</A>
|
||||
(570 KB).
|
||||
<DD><A HREF="cdrskin-0.5.2.pl00.tar.gz">cdrskin-0.5.2.pl00.tar.gz</A>
|
||||
(735 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 since spring 2008
|
||||
<DD> </DD>
|
||||
<DT>Download as single x86 binaries (untar and move to /usr/bin/cdrskin):</DT>
|
||||
<DD><A HREF="cdrskin_0.3.2.pl01-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.3.2.pl01-x86-suse9_0.tar.gz</A>, (80 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.2.pl01-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.3.2.pl01-x86-suse9_0-static.tar.gz</A>, (285 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>
|
||||
@ -235,42 +236,47 @@ cdrskin_0.3.2.pl01-x86-suse9_0-static.tar.gz</A>, (285 KB), -static compiled,
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
Enhancements towards previous stable version cdrskin-0.3.0:
|
||||
Enhancements towards previous stable version cdrskin-0.5.0.pl00:
|
||||
<UL>
|
||||
<LI>Burnfree enabled by default</LI>
|
||||
<LI>Multi-session burning to DVD-R
|
||||
and sequential (i.e. unformatted) DVD-RW</LI>
|
||||
<LI>Option -toc with sequential DVD-R[W]</LI>
|
||||
<LI>Options -msinfo and msifile= with appendable DVD-R[W]</LI>
|
||||
<LI>Single session DAO write mode with DVD-R[W]</LI>
|
||||
<LI>It is now possible to use drives which are not found by --devices</LI>
|
||||
<!--
|
||||
<LI>none</LI>
|
||||
-->
|
||||
</UL>
|
||||
Bug fixes towards cdrskin-0.3.2.pl00:
|
||||
|
||||
Bug fixes towards cdrskin-0.5.0.pl00:
|
||||
<UL>
|
||||
<LI>Multi-track runs with fifo could stall in rare cases</LI>
|
||||
<LI>none</LI>
|
||||
<!--
|
||||
-->
|
||||
</UL>
|
||||
|
||||
</P>
|
||||
|
||||
<HR>
|
||||
|
||||
<P>
|
||||
<DL>
|
||||
<DT><H3>Development snapshot, version 0.3.3 :</H3></DT>
|
||||
<DD>Enhancements towards stable version 0.3.2:
|
||||
<DT><H3>Development snapshot, version 0.5.3 :</H3></DT>
|
||||
<DD>Enhancements towards current stable version 0.5.2.pl00:
|
||||
<UL>
|
||||
<LI>New option --tell_media_space tells the maximum size for the next burn</LI>
|
||||
<!--
|
||||
-->
|
||||
<LI>none yet</LI>
|
||||
|
||||
</UL>
|
||||
</DD>
|
||||
<DD> </DD>
|
||||
<DD><A HREF="README_cdrskin_devel">README 0.3.3</A>
|
||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.3.3 --help</A></DD>
|
||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.3.3 -help</A></DD>
|
||||
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.3.3)</A></DD>
|
||||
<DD><A HREF="README_cdrskin_devel">README 0.5.3</A>
|
||||
<DD><A HREF="cdrskin__help_devel">cdrskin_0.5.3 --help</A></DD>
|
||||
<DD><A HREF="cdrskin_help_devel">cdrskin_0.5.3 -help</A></DD>
|
||||
<DD><A HREF="man_1_cdrskin_devel.html">man cdrskin (as of 0.5.3)</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.
|
||||
@ -278,22 +284,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.3.tar.gz">cdrskin-0.3.3.tar.gz</A>
|
||||
(570 KB).
|
||||
<A HREF="cdrskin-0.5.3.tar.gz">cdrskin-0.5.3.tar.gz</A>
|
||||
(735 KB).
|
||||
</DD>
|
||||
|
||||
<!-- This is not offered any more since spring 2008
|
||||
|
||||
<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.3-x86-suse9_0.tar.gz">
|
||||
cdrskin_0.3.3-x86-suse9_0.tar.gz</A>, (80 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.3-x86-suse9_0-static.tar.gz">
|
||||
cdrskin_0.3.3-x86-suse9_0-static.tar.gz</A>, (280 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>
|
||||
|
||||
@ -319,14 +332,33 @@ provide libburn with invaluable examples on how to deal with DVD media.
|
||||
<A NAME="examples">
|
||||
<P>
|
||||
<DL>
|
||||
<DT>Example for a setup of device permissions. To be done by the superuser:</DT>
|
||||
<DT>(CD devices which offer no r-permission are invisible to normal users.)</DT>
|
||||
<DT>(CD devices which offer no w-permission are not useable.)</DT>
|
||||
<DT>Example for a setup of device permissions.</DT>
|
||||
<DT>
|
||||
Newer Linux distros enable rw-access for the desktop user automatically.
|
||||
So try as normal user whether all your drives are found.
|
||||
CD devices which offer no rw-permission will stay invisible.
|
||||
</DT>
|
||||
<DD>$ <KBD><B>cdrskin --devices</B></KBD></DD>
|
||||
<DT>If not all desired drives show up, become superuser and do again:</DT>
|
||||
</DT>
|
||||
<DD># <KBD><B>cdrskin --devices</B></KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD>0 dev='/dev/sg0' rwrwr- : 'TEAC' 'CD-ROM CD-532S'</KBD></DD>
|
||||
<DD><KBD>0 dev='/dev/sr0' rwr-r- : 'TEAC' 'CD-ROM CD-532S'</KBD></DD>
|
||||
<DD><KBD>1 dev='/dev/hdc' rwrw-- : 'LITE-ON' 'LTR-48125S'</KBD></DD>
|
||||
<DD># <KBD><B>chmod a+rw /dev/sg0 /dev/hdc</B></KBD></DD>
|
||||
<DT>Most simple and most insecure is this equivalent
|
||||
of the usual cdrecord permissions u+s,a+x:</DT>
|
||||
<DD># <KBD><B>chmod a+rw /dev/sr0 /dev/hdc</B></KBD></DD>
|
||||
<DT>
|
||||
More secure is to put the permitted users into a group like
|
||||
"floppy", to assign /dev/sr0 /dev/hdc to this group,
|
||||
and to allow rw-access only to group members.
|
||||
</DT>
|
||||
<DD># <KBD><B>vi /etc/group</B></KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD>floppy:x:19:thomas,scdbackup</KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD># <KBD><B>chgrp floppy /dev/sr0 /dev/hdc</B></KBD></DD>
|
||||
<DD># <KBD><B>chmod g+rw /dev/sr0 /dev/hdc</B></KBD></DD>
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
@ -341,6 +373,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">
|
||||
@ -363,7 +397,7 @@ is a GUI frontend which uses cdrecord for CD burning.)
|
||||
<DD>$ <KBD><B>export SCDBACKUP_USE_CDRSKIN=1</B></KBD></DD>
|
||||
<DD>$ <KBD><B>./CONFIGURE_CD</B></KBD></DD>
|
||||
<DD><KBD>...</KBD></DD>
|
||||
<DD><KBD>cdrskin 0.3.2 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
|
||||
<DD><KBD>cdrskin 0.3.8 : limited cdrecord compatibility wrapper for libburn</KBD></DD>
|
||||
</DL>
|
||||
If your system is stricken with some ill CD device then this can stall
|
||||
and you will have to press <KBD>Ctrl+C</KBD> to abort.
|
||||
@ -395,6 +429,8 @@ and try again.
|
||||
</DL>
|
||||
</P>
|
||||
|
||||
-->
|
||||
|
||||
<HR>
|
||||
|
||||
<A NAME="cdrecord">
|
||||
@ -407,7 +443,7 @@ cdrecord but not vice versa.
|
||||
I am a long time user of cdrecord and it works fine for me.
|
||||
Especially i do appreciate its write mode -tao which allows to pipe arbitrary
|
||||
data on CD and CD-RW via stdin. cdrecord is reliable, versatile and well
|
||||
maintained. So for me - there would be not problem with it.
|
||||
maintained. So for me - there would be no problem with it.
|
||||
<BR>
|
||||
But the author of cdrecord and the Linux kernel people foster a very hostile
|
||||
relationship. Ok, that's their business, not mine (or ours if you are with me).
|
||||
@ -422,8 +458,8 @@ Contact me. Let's see what we can achieve.
|
||||
<BR>
|
||||
<BR>
|
||||
libburn and cdrskin are now mature enough to substitute cdrecord in its
|
||||
major use cases of CD burning. It is possible to foist cdrskin on various
|
||||
software packages if it gets falsely named "cdrecord".
|
||||
major use cases of CD and DVD burning. It is possible to foist cdrskin on
|
||||
various software packages if it gets falsely named "cdrecord".
|
||||
I do not encourage this approach, but of course such a replacement
|
||||
opportunity is the goal of a cdrecord compatibility wrapper.
|
||||
<BR>
|
||||
@ -440,7 +476,7 @@ I owe him much. For cdrecord, for mkisofs, for star. Chapeau.
|
||||
<BR><BR>
|
||||
-->
|
||||
<A HREF="http://en.wikipedia.org/wiki/D%C3%B6ner_kebab">
|
||||
<IMG SRC="doener_150x200_tr.gif" BORDER=0
|
||||
<IMG SRC="doener_150x200_tr.png" BORDER=0
|
||||
ALT="cdrskin logo: Doener mit Scharf"></A>
|
||||
<BR><BR>
|
||||
<FONT SIZE=+0>Enjoying free Open Source hosting by <A HREF="http://www.webframe.org">www.webframe.org</A><BR>
|
||||
@ -454,14 +490,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.03.09.134622"
|
||||
#define Cdrskin_timestamP "2008.08.20.080001"
|
||||
|
@ -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_3"
|
||||
libvers="-DCdrskin_libburn_0_5_2"
|
||||
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_2"
|
||||
elif test "$i" = "-libburn_0_5_2"
|
||||
then
|
||||
libvers="-DCdrskin_libburn_0_3_2"
|
||||
libvers="-DCdrskin_libburn_0_5_2"
|
||||
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_3"
|
||||
libvers="-DCdrskin_libburn_0_5_3"
|
||||
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_2 set macro to match libburn-0.3.2."
|
||||
echo " -libburn_0_5_2 set macro to match libburn-0.5.2"
|
||||
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"
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB |
BIN
cdrskin/doener_150x200_tr.png
Normal file
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 29 KiB |
BIN
cdrskin/doener_150x200_tr_octx.png
Normal file
After Width: | Height: | Size: 9.2 KiB |
@ -1,30 +1,29 @@
|
||||
--------------------------------------------------------------------------
|
||||
cdrskin Wiki - plain text copy
|
||||
--------------------------------------------------------------------------
|
||||
[[Image(source:/libburn/trunk/cdrskin/doener_150x200_tr.gif)]] [http://en.wikipedia.org/wiki/D%C3%B6ner_kebab Doener]
|
||||
[[Image(source:/libburn/trunk/cdrskin/doener_150x200_tr.png)]] [http://en.wikipedia.org/wiki/D%C3%B6ner_kebab Doener]
|
||||
|
||||
'''cdrskin is the cdrecord compatibility middleware of libburn.'''
|
||||
|
||||
Its paragon, cdrecord, is a powerful GPL'ed burn program included in Joerg
|
||||
Schilling's cdrtools. cdrskin strives to be a second source for the services
|
||||
traditionally provided by cdrecord. Currently it does CD-R and CD-RW 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
|
||||
Overwriteable media DVD-RAM, DVD+RW, DVD-RW, and BD-RE are handled differently
|
||||
than with cdrecord-ProDVD in order to offer TAO-like single track recording.
|
||||
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.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
@ -67,7 +66,7 @@ and displays their detected properties.
|
||||
The drives are listed one per line, with fields:
|
||||
libburn-drive-number, sysadmin-device-file, permissions, vendor, type
|
||||
{{{
|
||||
0 dev='/dev/sg0' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
|
||||
0 dev='/dev/sr0' rwrw-- : 'HL-DT-ST' 'DVDRAM GSA-4082B'
|
||||
}}}
|
||||
This feature is valuable since cdrskin -scanbus will not give you
|
||||
the device file name and its current permissions.
|
||||
@ -80,12 +79,58 @@ 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.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
blank=as_needed applies the suitable blanking or formatting to make
|
||||
any supported type of media ready for writing from scratch.
|
||||
If this is not possible, e.g. because the media is written and not
|
||||
re-usable, then the program run fails.
|
||||
|
||||
Option blank= offers several specialized blanking and formatting types,
|
||||
which one may use for particular purposes on DVD-RW, DVD-RAM and BD-RE.
|
||||
(See also below: blank=format_overwrite)
|
||||
The drive offers a list of possible formats by cdrskin option --list_formats.
|
||||
One should aquire MMC background information before making use of them.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
@ -94,9 +139,9 @@ disc from its initial profile "Sequential Recording" into profile state
|
||||
cdrskin dev=/dev/sr0 -v blank=format_overwrite
|
||||
}}}
|
||||
|
||||
DVD-RAM, DVD+RW and overwriteable DVD-RW appear to cdrskin as blank media
|
||||
which are capable of taking only a single track. This track may be positioned
|
||||
on a 32KiB aligned address, though.
|
||||
DVD-RAM, DVD+RW, BD-RE and overwriteable DVD-RW appear to cdrskin as blank
|
||||
media which are capable of taking only a single track. This track may be
|
||||
positioned on a 32KiB aligned address, though.
|
||||
{{{
|
||||
cdrskin ... write_start_address=2412m ...
|
||||
}}}
|
||||
@ -107,8 +152,9 @@ 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 +163,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, DVD+RW, BD-RE 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
|
||||
@ -127,7 +180,7 @@ E.g. cdrskin aborts with an error message if
|
||||
{{{
|
||||
assert_write_lba=0
|
||||
}}}
|
||||
is given but an appendable media is to be burned which would start ati
|
||||
is given but an appendable media is to be burned which would start at
|
||||
block 68432.
|
||||
|
||||
|
||||
@ -228,10 +281,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/BD media other than DVD-RAM, DVD+RW, DVD+R, DVD+R DL,
|
||||
DVD-RW, DVD-R, BD-RE, 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 +292,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, BD-RE
|
||||
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].
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
|
117
configure.ac
@ -1,4 +1,4 @@
|
||||
AC_INIT([libburn], [0.3.3], [http://libburnia.pykix.org])
|
||||
AC_INIT([libburn], [0.5.2], [http://libburnia-project.org])
|
||||
AC_PREREQ([2.50])
|
||||
dnl AC_CONFIG_HEADER([config.h])
|
||||
|
||||
@ -7,35 +7,108 @@ 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 0.4.6 = libburn.so.4.11.0
|
||||
dnl 0.4.8 = libburn.so.4.13.0
|
||||
dnl 0.5.0 = libburn.so.4.15.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=3
|
||||
BURN_INTERFACE_AGE=0
|
||||
BURN_BINARY_AGE=0
|
||||
BURN_MINOR_VERSION=5
|
||||
BURN_MICRO_VERSION=2
|
||||
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=`expr $BURN_MICRO_VERSION - $BURN_INTERFACE_AGE`
|
||||
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 A80820
|
||||
dnl This is the release version libburn-0.5.2 = libburn.so.4.17.0
|
||||
dnl ### This is the development version after above release version
|
||||
dnl ### LT_CURRENT++, LT_AGE++ has not yet happened.
|
||||
dnl ### LT_CURRENT++, LT_AGE++ has happened meanwhile.
|
||||
dnl
|
||||
dnl SONAME = 21 - 17 = 4 . Library name = libburn.so.4.17.0
|
||||
LT_CURRENT=21
|
||||
LT_AGE=17
|
||||
LT_REVISION=0
|
||||
LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
|
||||
|
||||
AC_SUBST(LT_RELEASE)
|
||||
@ -44,6 +117,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
|
||||
|
||||
|
53
doc/comments
@ -7,10 +7,12 @@
|
||||
|
||||
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, BD-RE.
|
||||
|
||||
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-R (blue ray). Testers for
|
||||
DVD-R/DL are wanted, though. BD-R programming efforts would be made
|
||||
if an interested tester contacts us.
|
||||
|
||||
The project comprises of several more or less interdependent parts which
|
||||
together strive to be a usable foundation for application development.
|
||||
@ -22,18 +24,23 @@ 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.
|
||||
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
|
||||
@ -43,24 +50,48 @@ 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
|
||||
the services traditionally provided by cdrecord. Additionally it
|
||||
provides libburn's DVD capabilities, where only -sao is compatible
|
||||
with cdrecord.
|
||||
provides libburn's DVD/BD capabilities, where only -sao is
|
||||
compatible with cdrecord.
|
||||
cdrskin does not contain any bytes copied from cdrecord's sources.
|
||||
Many bytes have been copied from the message output of cdrecord
|
||||
runs, though.
|
||||
See cdrskin/README for more.
|
||||
|
||||
- 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. An incremental backup feature is provided.
|
||||
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 +120,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.
|
||||
|
||||
|
164
doc/cookbook.txt
@ -1,11 +1,11 @@
|
||||
libburnia.pykix.org Optical Media Rotisserie Recipes as of February 2007
|
||||
libburnia-project.org Optical Media Rotisserie Recipes as of April 2008
|
||||
|
||||
Content:
|
||||
- TAO Multi-Session CD Cookbook (CD-R, CD-RW)
|
||||
- SAO CD Cookbook (CD-R, CD-RW, pure audio or pure data only)
|
||||
- Overwriteable DVD Cookbook (DVD-RAM, DVD+RW, DVD-RW)
|
||||
- Overwriteable DVD Cookbook (DVD-RAM, DVD+RW, DVD-RW, BD-RE)
|
||||
- Sequential DVD-R[W] Cookbook
|
||||
- DVD+R Cookbook (still emerging)
|
||||
- DVD+R[/DL] Cookbook
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
TAO Multi-Session CD Cookbook
|
||||
@ -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>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -403,9 +403,10 @@ correctness of Pre-gap and Post-gap would become evident.
|
||||
-------------------------------------------------------------------------------
|
||||
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.
|
||||
by own experiments with drives NEC ND-4570A, LG GSA-4082B, PHILIPS SPD3300L,
|
||||
and by BD-RE experiments done by Giulio Orsero on LG BE06LU10.
|
||||
|
||||
For libburnia.pykix.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -416,18 +417,20 @@ DVD-RAM 0012h
|
||||
DVD-RW Restricted Overwrite 0013h
|
||||
DVD-RW Sequential Recording 0014h (i.e. unformatted)
|
||||
DVD+RW 001Ah
|
||||
BD-RE 0043h
|
||||
|
||||
A short compilation of the write model:
|
||||
- Overwriting in general
|
||||
|
||||
The recipes described here are depending on formatting state:
|
||||
- DVD-RAM, fully formatted DVD+RW or DVD-RW
|
||||
- DVD-RAM, fully formatted DVD+RW, DVD-RW, BD-RE
|
||||
- Unformatted DVD+RW
|
||||
- Partly formatted DVD+RW
|
||||
- Unformatted DVD-RW
|
||||
- Partly formatted DVD-RW
|
||||
- Intermediate state DVD-RW
|
||||
|
||||
- DVD-RAM and BD-RE formatting
|
||||
- DVD-RAM and BD-RE speed tuning
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Overwriting in general :
|
||||
@ -444,7 +447,7 @@ Optimal performance is promised without any speed setting. But my experiments
|
||||
showed that SET STREAMING values persist after media change.
|
||||
|
||||
In the formatted area of the media, coarse random access is possible.
|
||||
For DVD-RAM and DVD+RW write addresses and data size need to be aligned
|
||||
For DVD-RAM, DVD+RW, BD-RE write addresses and data size need to be aligned
|
||||
to 2 KiB. For DVD-RW alignment has to be 32 KiB. Within these limitations
|
||||
the write address is at the discretion of the sending program.
|
||||
Just use 2Ah WRITE to send data.
|
||||
@ -483,9 +486,12 @@ software did anything wrong.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
DVD-RAM, fully formatted DVD+RW or DVD-RW :
|
||||
DVD-RAM, fully formatted DVD+RW, DVD-RW, BD-RE :
|
||||
|
||||
Full format is the natural state of DVD-RAM.
|
||||
Full format is the natural state of DVD-RAM.
|
||||
|
||||
BD-RE are sold unformatted and need to be fully formatted first.
|
||||
See paragraph about DVD-RAM and BD-RE formatting below.
|
||||
|
||||
DVD+RW reaches this state if Background Formatting is allowed to finish without
|
||||
being stopped by 5Bh CLOSE TRACK SESSION.
|
||||
@ -671,6 +677,91 @@ of Intermediate state by 5Bh CLOSE TRACK SESSION with Close Function 010b.
|
||||
(mmc5r03c.pdf 6.3.3.2.3)
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
DVD-RAM and BD-RE formatting :
|
||||
|
||||
Although DVD-RAM usually are sold formatted, there may still arise the wish
|
||||
to adjust formatting.
|
||||
BD-RE are sold unformatted and need to be formatted prior to usage.
|
||||
|
||||
Two format types are relevant for DVD-RAM : 00h and 01h.
|
||||
00h offers the default size format and usually a maximum payload size format.
|
||||
Even with that maximum size payload there is hardware defect management.
|
||||
(mmc5r03c.pdf 6.5.4.2.1.2)
|
||||
01h allows to convert payload capacity into spare blocks for defect
|
||||
managment. There is no way to increase payload capacity by format 01h.
|
||||
(mmc5r03c.pdf 6.5.4.2.2.1)
|
||||
|
||||
With BD-RE there are three format types : 00h, 30h and 31h.
|
||||
00h offers the default size format.
|
||||
30h offers several sizes with defect management. Usually there are three
|
||||
size to choose: #1: default size, #2: maximum spare area, #3: minimal spare.
|
||||
31h offers a single size and disables defect management. This has the side
|
||||
effect to speed up writing to nominal speed.
|
||||
(mmc5r03c.pdf 6.5.4.2.15, 6.24.3.3, Table 472)
|
||||
|
||||
Only format sizes from the list of format descriptors are permissible
|
||||
for DVD-RAM. The format list can be obtained by 23h READ FORMAT CAPACITIES.
|
||||
It also includes a description of the current formatting state.
|
||||
(mmc5r03c.pdf 6.24, 6.24.3.2, 6.24.3.3)
|
||||
|
||||
Formatting is done by command 04h FORMAT UNIT. Its data payload consists
|
||||
of a Format List Header and a Format Descriptor. It is advisable to set
|
||||
the Immed bit and the FOV bit in header byte number 1. The descriptor should
|
||||
be a copy of a descriptor from 23h READ FORMAT CAPACITIES.
|
||||
(mmc5r03c.pdf 6.5, 6.5.3.2, 6.5.3.3)
|
||||
With nearly all formats Sub-type should be set to 0. But with BD-RE formats
|
||||
30h and 31h the Sub-type selects the certification mode.
|
||||
Usable with 30h seem 10b Full Certification and 11b Quick Certification.
|
||||
Usable with 31h seem also 00b Quick Reformat and 01b No Certification.
|
||||
(mmc5r03c.pdf 6.5.4.2.15.1)
|
||||
|
||||
Other format types have their certification intensity controlled by
|
||||
a pair of bits: CmpList and DCRT.
|
||||
CmpList resides in CDB byte 1 as bit 3. DCRT resides in the payload byte 1
|
||||
as bit 5. Both together should request a quick size change without lengthy
|
||||
certification but maintaining the list of known defects.
|
||||
(mmc5r03c.pdf 6.5, table 249, 6.5.3.2)
|
||||
With DVD-RAM on my PHILIPS SPD3300L drive they prevent any format size
|
||||
change though. The TSSTcorp SH-S203B works properly.
|
||||
With BD-RE format 00h, the default is specified to be Quick Reformat,
|
||||
and with 00h in general certification can only be disabled not enabled.
|
||||
(mmc5r03c.pdf 6.5.4.2.1.7)
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
DVD-RAM and BD-RE tuning :
|
||||
|
||||
A special aspect of DVD-RAM and BD-RE is their low speed with write operations,
|
||||
which usually is only half than the nominal speed of media and drive.
|
||||
This is blamed to the automatic checkreading which happens ifor managing
|
||||
eventual defects.
|
||||
|
||||
Defect management of BD-RE can be disabled by format type 31h. See above.
|
||||
There is no drive known yet which would apply command 2Ah WRITE10 to DVD-RAM
|
||||
with full speed.
|
||||
|
||||
The only known way to get full speed from DVD-RAM or BD-RE with enabled defect
|
||||
management is the use of AAh WRITE12 with Streaming Bit set to 1.
|
||||
(mmc5r03c.pdf 6.45)
|
||||
With some DVD-RAM drives this fails if a write buffer is not full 32 kB.
|
||||
With the tested BD-RE ione has to write write full 64 kB buffers.
|
||||
|
||||
Although it seems not optimal, this is specified not only to disable the
|
||||
cumbersome checkread but also to ignore known defects and to write data
|
||||
to these defective addresses.
|
||||
(mmc5r03c.pdf 4.8.5)
|
||||
So the speed-up is only advisable as long as the media are free of
|
||||
incorrectable errors.
|
||||
|
||||
Caveat:
|
||||
MMC-5 does not guarantee AAh WRITE12 to work on DVD-RAM or BD-RE at all.
|
||||
None of the features of profiles 0012h and 0043 promises the existence of
|
||||
AAh WRITE12.
|
||||
Nevertheless it worked on all tested drives is proper alignment was observed.
|
||||
(mmc5r03c.pdf 5.4.13, 6.45)
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
@ -680,7 +771,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>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -788,12 +879,12 @@ growisofs (transport.hxx) sets Link Size to 16 for profiles 0011h and 0014h.
|
||||
libburn now records the first link size from feature 0021h in its burn_drive
|
||||
structure. If another link size item is 16, then 16 is used.
|
||||
[*4:]
|
||||
growisofs takes Packet Size from 52h. Specs predict it will be 16 (= 32 kB).
|
||||
growisofs takes Packet Size from 52h. Specs predict it will be 16 (= 32 kiB).
|
||||
(mmc5r03.pdf 7.5.4.16)
|
||||
|
||||
The writing process is much like in "Writing a session to CD in TAO mode" :
|
||||
Next Writeable Address is fetched from the reply of 52h READ TRACK INFORMATION.
|
||||
libburn writes full 32 kB buffers via 2Ah WRITE.
|
||||
libburn writes full 32 kiB buffers via 2Ah WRITE.
|
||||
(mmc5r03c.pdf, 6.27 READ TRACK INFORMATION, 6.44 WRITE)
|
||||
When writing is done, it is mandatory to force the drive's buffer to media by
|
||||
35h SYNCHRONIZE CACHE.
|
||||
@ -860,7 +951,8 @@ tested yet, what happens if not enough data get written.
|
||||
(mmc5r03c.pdf 6.31)
|
||||
|
||||
Next Writeable Address is fetched from the reply of 52h READ TRACK INFORMATION.
|
||||
The reply is supposed to be 0. libburn writes full 32 kB buffers via 2Ah WRITE.
|
||||
The reply is supposed to be 0. libburn writes full 32 kiB buffers via
|
||||
2Ah WRITE.
|
||||
(mmc5r03c.pdf, 6.27 READ TRACK INFORMATION, 6.44 WRITE)
|
||||
If the track source delivers less than the announced size then libburn pads up
|
||||
by zeros.
|
||||
@ -989,15 +1081,12 @@ close session if multi-session is demanded.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
INCOMPLETE YET
|
||||
|
||||
DVD+R Cookbook
|
||||
DVD+R[/DL] 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>
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -1008,7 +1097,7 @@ DVD+R/DL 002bh
|
||||
|
||||
- About empty, appendable and finalized DVD+R
|
||||
- Writing a Pseudo Session to DVD+R
|
||||
- >>> Hearsay about DVD+R/DL (Dual Layer) :
|
||||
- DVD+R/DL (Dual Layer
|
||||
|
||||
The following two chapters of the Sequential DVD-R[W] Cookbook are valid for
|
||||
DVD+R media too:
|
||||
@ -1063,7 +1152,7 @@ The specs promise to pad up the track if not enough data get written.
|
||||
Next Writeable Address is fetched from the reply of 52h READ TRACK INFORMATION
|
||||
with track number FFh.
|
||||
(mmc5r03c.pdf 6.27)
|
||||
Since the fixely set write type is 16-block packet, full 32 kB buffers have
|
||||
Since the fixely set write type is 16-block packet, full 32 kiB buffers have
|
||||
to be transmitted via 2Ah WRITE.
|
||||
(mmc5r03c.pdf 4.3.6.2.2)
|
||||
|
||||
@ -1078,22 +1167,35 @@ libburn obtains the necessary logical track number from Last Track Number in
|
||||
Last Session from the reply of 51h READ DISC INFORMATION requesting
|
||||
Data Type 000b.
|
||||
(mmc5r03c.pdf 6.22)
|
||||
|
||||
After each track 5Bh CLOSE TRACK SESSION Close Function 010b with Logical Track
|
||||
Number 0 closes the DVD+R session but keeps the media appendable.
|
||||
(mmc5r03c.pdf 6.3.3.4.3)
|
||||
|
||||
|
||||
>>> This is not tested yet. growisofs has code for that gesture but explicitly
|
||||
avoids to use it. Instead it recommends to fill up the media with zeros.
|
||||
Eventually 5Bh CLOSE TRACK SESSION Close Function 101b is used to finalize
|
||||
the media with minimal radius. After that the disc is not appendable any more !
|
||||
If the media shall not stay appendable then the last DVD+R session is to be
|
||||
closed by Close Function 101b rather than 010b. This finalizes the media
|
||||
"with minimal radius".
|
||||
(mmc5r03c.pdf 6.3.3.4.4)
|
||||
|
||||
Note: growisofs has code for that gesture but explicitly avoids to use it, 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) :
|
||||
DVD+R/DL (Dual Layer) :
|
||||
|
||||
>>>
|
||||
libburn treats DL media just like their single layer equivalents.
|
||||
This seems to work fine for DVD+R/DL, according to a report by nightmorph
|
||||
in http://libburnia-project.org/ticket/13 .
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
388
doc/ddlp.txt
Normal file
@ -0,0 +1,388 @@
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Users of modern desktop Linux installations report misburns with CD/DVD
|
||||
recording due to concurrency problems.
|
||||
|
||||
This text describes two locking protocols which have been developed by our
|
||||
best possible effort. But finally they rather serve as repelling example of
|
||||
what would be needed in user space to achieve an insufficient partial solution.
|
||||
|
||||
Ted Ts'o was so friendly to help as critic with his own use cases. It turned
|
||||
out that we cannot imagine a way in user space how to cover reliably the needs
|
||||
of callers of libblkid and the needs of our burn programs.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Content:
|
||||
|
||||
The "Delicate Device Locking Protocol" shall demonstrate our sincere
|
||||
consideration of the problem.
|
||||
|
||||
"What are the Stumble Stones ?" lists reasons why the effort finally failed.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
Delicate Device Locking Protocol
|
||||
(a joint sub project of cdrkit and libburnia)
|
||||
(contact: scdbackup@gmx.net )
|
||||
|
||||
Our projects provide programs which allow recording of data on CD or DVD.
|
||||
We encounter an increasing number of bug reports about spoiled burn runs and
|
||||
wasted media which obviously have one common cause: interference by other
|
||||
programs which access the drive's device files.
|
||||
There is some riddling about which gestures exactly are dangerous for
|
||||
ongoing recordings or can cause weirdly misformatted drive replies to MMC
|
||||
commands.
|
||||
We do know, nevertheless, that these effects do not occur if no other program
|
||||
accesses a device file of the drive while our programs use it.
|
||||
|
||||
DDLP shall help to avoid collisions between programs in the process of
|
||||
recording to a CD or DVD drive and other programs which access that drive.
|
||||
The protocol intends to provide advisory locking. So any good-willing program
|
||||
has to take some extra precautions to participate.
|
||||
|
||||
If a program does not feel vulnerable to disturbance, then the precautions
|
||||
impose much less effort than if the program feels the need for protection.
|
||||
|
||||
Two locking strategies are specified:
|
||||
DDLP-A operates on device files only. It is very Linux specific.
|
||||
DDLP-B adds proxy lock files, inspired by FHS /var/lock standard.
|
||||
|
||||
|
||||
DDLP-A
|
||||
|
||||
This protocol relies on the hardly documented feature open(O_EXCL | O_RDWR)
|
||||
with Linux device files and on POSIX compliant fcntl(F_SETLK).
|
||||
|
||||
Other than the original meaning of O_EXCL with creating regular files, the
|
||||
effect on device files is mutual exclusion of access. I.e. if one
|
||||
filedescriptor is open on that combination of major-minor device number, then
|
||||
no other open(O_EXCL) will succeed. But open() without O_EXCL would succeed.
|
||||
So this is advisory and exclusive locking.
|
||||
With kernel 2.6 it seems to work on all device drivers which might get used
|
||||
to access a CD/DVD drive.
|
||||
|
||||
The vulnerable programs shall not start their operation before they occupied a
|
||||
wide collection of drive representations.
|
||||
Non-vulnerable programs shall take care to detect the occupation of _one_ such
|
||||
representation.
|
||||
|
||||
So for Friendly Programs
|
||||
|
||||
A program which does not feel vulnerable to disturbance is urged to access
|
||||
CD/DVD drives by opening a file descriptor which will uphold the lock
|
||||
as long as it does not get closed. There are two alternative ways to achieve
|
||||
this.
|
||||
Very reliable is
|
||||
|
||||
open( some_path , O_EXCL | ...)
|
||||
|
||||
But O_EXCL imposes restrictions and interferences:
|
||||
- O_EXCL | O_RDONLY does not succeed with /dev/sg* !
|
||||
- O_EXCL cannot provide shared locks for programs which only want to lock
|
||||
against burn programs but not against their own peers.
|
||||
- O_EXCL keeps from obtaining information by harmless activities.
|
||||
- O_EXCL already has a meaning with devices which are mounted as filesystems.
|
||||
This priority meaning is more liberal than the one needed for CD/DV recording
|
||||
protection.
|
||||
|
||||
So it may be necessary to use a cautious open() without O_EXCL and to aquire
|
||||
a POSIX lock via fcntl(). "Cautious" means to add O_NDELAY to the flags of
|
||||
open(), because this is declared to avoid side effects within open().
|
||||
|
||||
With this gesture it is important to use the paths expected by our burn
|
||||
programs: /dev/sr[0..255] /dev/scd[0..255] /dev/sg[0..255] /dev/hd[a..z]
|
||||
because fcntl(F_SETLK) does not lock the device but only a device-inode.
|
||||
|
||||
std_path = one of the standard device files:
|
||||
/dev/sr[0..255] /dev/scd[0..255] /dev/sg[0..255] /dev/hd[a..z]
|
||||
or a symbolic link pointing to one of them.
|
||||
open( std_path , ... | O_NDELAY)
|
||||
fcntl(F_SETLK) and close() on failure
|
||||
... eventually disable O_NDELAY by fcntl(F_SETFL) ...
|
||||
|
||||
There is a pitfall mentioned in man 2 fcntl :
|
||||
"locks are automatically released [...] if it closes any file descriptor
|
||||
referring to a file on which locks are held. This is bad [...]"
|
||||
So you may have to re-lock after some temporary fd got closed.
|
||||
|
||||
|
||||
Vulnerable Programs
|
||||
|
||||
For programs which do feel vulnerable, O_EXCL would suffice for the /dev/hd*
|
||||
device file family and their driver. But USB and SATA recorders appear with
|
||||
at least two different major-minor combinations simultaneously.
|
||||
One as /dev/sr* alias /dev/scd*, the other as /dev/sg*.
|
||||
The same is true for ide-scsi or recorders attached to SCSI controllers.
|
||||
|
||||
So, in order to lock any access to the recorder, one has to open(O_EXCL)
|
||||
not only the device file that is intended for accessing the recorder but also
|
||||
a device file of any other major-minor representation of the recorder.
|
||||
This is done via the SCSI address parameter vector (Host,Channel,Id,Lun)
|
||||
and a search on standard device file paths /dev/sr* /dev/scd* /dev/sg*.
|
||||
In this text the alternative device representations are called "siblings".
|
||||
|
||||
For finding them, it is necessary to apply open() to many device files which
|
||||
might be occupied by delicate operations. On the other hand it is very
|
||||
important to occupy all reasonable representations of the drive.
|
||||
So the reading of the (Host,Channel,Id,Lun) parameters demands an
|
||||
open(O_RDONLY | O_NDELAY) _without_ fcntl() in order to find the outmost
|
||||
number of representations among the standard device files. Only ioctls
|
||||
SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER are applied.
|
||||
Hopefully this gesture is unable to cause harmful side effects on kernel 2.6.
|
||||
|
||||
At least one file of each class sr, scd and sg should be found to regard
|
||||
the occupation as satisfying. Thus corresponding sr-scd-sg triplets should have
|
||||
matching ownerships and access permissions.
|
||||
One will have to help the sysadmins to find those triplets.
|
||||
|
||||
A spicy detail is that sr and scd may be distinct device files for the same
|
||||
major-minor combination. In this case fcntl() locks on both are needed
|
||||
but O_EXCL can only be applied to one of them.
|
||||
|
||||
|
||||
An open and free implementation ddlpa.[ch] is provided as
|
||||
http://libburnia.pykix.org/browser/libburn/trunk/libburn/ddlpa.h?format=txt
|
||||
http://libburnia.pykix.org/browser/libburn/trunk/libburn/ddlpa.c?format=txt
|
||||
The current version of this text is
|
||||
http://libburnia.pykix.org/browser/libburn/trunk/doc/ddlp.txt?format=txt
|
||||
|
||||
Put ddlpa.h and ddlpa.c into the same directory and compile as test program by
|
||||
cc -g -Wall -DDDLPA_C_STANDALONE -o ddlpa ddlpa.c
|
||||
|
||||
Use it to occupy a drive's representations for a given number of seconds
|
||||
./ddlpa /dev/sr0 300
|
||||
|
||||
It should do no harm to any of your running activities.
|
||||
If it does: Please, please alert us.
|
||||
|
||||
Your own programs should not be able to circumvent the occupation if they
|
||||
obey above rules for Friendly Programs.
|
||||
Of course ./ddlpa should be unable to circumvent itself.
|
||||
|
||||
A successfull occupation looks like
|
||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/scd0") = "/dev/sr0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sr0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/scd0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sg0"
|
||||
DDLPA_DEBUG: ddlpa_occupy() : '/dev/scd0'
|
||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/sg0'
|
||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/sr0'
|
||||
---------------------------------------------- Lock gained
|
||||
ddlpa: opened /dev/sr0
|
||||
ddlpa: opened siblings: /dev/scd0 /dev/sg0
|
||||
slept 1 seconds of 300
|
||||
|
||||
Now an attempt via device file alias /dev/NEC must fail:
|
||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/NEC") = "/dev/sg0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sr0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/scd0"
|
||||
DDLPA_DEBUG: ddlpa_collect_siblings() found "/dev/sg0"
|
||||
Cannot exclusively open '/dev/sg0'
|
||||
Reason given : Failed to open O_RDWR | O_NDELAY | O_EXCL : '/dev/sr0'
|
||||
Error condition : 16 'Device or resource busy'
|
||||
|
||||
With hdc, of course, things are trivial
|
||||
DDLPA_DEBUG: ddlpa_std_by_rdev("/dev/hdc") = "/dev/hdc"
|
||||
DDLPA_DEBUG: ddlpa_occupy() O_EXCL : '/dev/hdc'
|
||||
---------------------------------------------- Lock gained
|
||||
ddlpa: opened /dev/hdc
|
||||
slept 1 seconds of 1
|
||||
|
||||
|
||||
Ted Ts'o provided program open-cd-excl which allows to explore open(2) on
|
||||
device files with combinations of read-write, O_EXCL, and fcntl().
|
||||
(This does not mean that Ted endorsed our project yet. He helps exploring.)
|
||||
|
||||
Friendly in the sense of DDLP-A would be any run which uses at least one of
|
||||
the options -e (i.e. O_EXCL) or -f (i.e. F_SETLK, applied to a file
|
||||
descriptor which was obtained from a standard device file path).
|
||||
The code is available under GPL at
|
||||
http://libburnia.pykix.org/browser/libburn/trunk/test/open-cd-excl.c?format=txt
|
||||
To be compiled by
|
||||
cc -g -Wall -o open-cd-excl open-cd-excl.c
|
||||
|
||||
Options:
|
||||
-e : open O_EXCL
|
||||
-f : aquire lock by fcntl(F_SETLK) after sucessful open
|
||||
-i : do not wait in case of success but exit 0 immediately
|
||||
-r : open O_RDONLY , with -f use F_RDLCK
|
||||
-w : open O_RDWR , with -f use F_WRLCK
|
||||
plus the path of the devce file to open.
|
||||
|
||||
Friendly Programs would use gestures like:
|
||||
./open-cd-excl -e -r /dev/sr0
|
||||
./open-cd-excl -e -w /dev/sg1
|
||||
./open-cd-excl -e -w /dev/black-drive
|
||||
./open-cd-excl -f -r /dev/sg1
|
||||
./open-cd-excl -e -f -w /dev/sr0
|
||||
|
||||
Ignorant programs would use and cause potential trouble by:
|
||||
./open-cd-excl -r /dev/sr0
|
||||
./open-cd-excl -w /dev/sg1
|
||||
./open-cd-excl -f -w /dev/black-drive
|
||||
where "/dev/black-drive" is _not_ a symbolic link to
|
||||
any of /dev/sr* /dev/scd* /dev/sg* /dev/hd*, but has an own inode.
|
||||
|
||||
Prone to failure without further reason is:
|
||||
./open-cd-excl -e -r /dev/sg1
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
DDLP-B
|
||||
|
||||
This protocol relies on proxy lock files in some filesystem directory. It can
|
||||
be embedded into DDLP-A or it can be used be used standalone, outside DDLP-A.
|
||||
|
||||
DDLP-A shall be kept by DDLP-B from trying to access any device file which
|
||||
might already be in use. There is a problematic gesture in DDLP-A when SCSI
|
||||
address parameters are to be retrieved. For now this gesture seems to be
|
||||
harmless. But one never knows.
|
||||
Vice versa DDLP-B may get from DDLP-A the service to search for SCSI device
|
||||
file siblings. So they are best as a couple.
|
||||
|
||||
But they are not perfect. Not even as couple. fcntl() locking is flawed.
|
||||
|
||||
|
||||
There is a proxy file locking protocol described in FHS:
|
||||
http://www.pathname.com/fhs/pub/fhs-2.3.html#VARLOCKLOCKFILES
|
||||
|
||||
But it has shortcommings (see below). Decisive obstacle for its usage are the
|
||||
possibility for stale locks and the lack of shared locks.
|
||||
|
||||
DDLP-B rather defines a "path prefix" which is advised to be
|
||||
/tmp/ddlpb-lock-
|
||||
This prefix will get appended "device specific suffixes" and then form the path
|
||||
of a "lockfile".
|
||||
Not the existence of a lockfile but its occupation by an fcntl(F_SETLK) will
|
||||
constitute a lock. Lockfiles may get prepared by the sysadmin in directories
|
||||
where normal users are not allowed to create new files. Their rw-permissions
|
||||
then act as additional access restriction to the device files.
|
||||
The use of fcntl(F_SETLK) will prevent any stale locks after the process ended.
|
||||
It will also allow to obtain shared locks as well as exclusive locks.
|
||||
|
||||
There are two classes of device specific suffixes:
|
||||
|
||||
- Device file path suffix. Absolute paths only. "/" gets replaced by "_-".
|
||||
Eventual "_-" in path gets replaced by "_-_-". The leading group of "_-"
|
||||
is always interpreted as a group of "/", though. E.g.:
|
||||
/dev/sr0 <-> "_-dev_-sr0"
|
||||
/mydevs/burner/nec <-> "_-mydevs_-burners_-nec"
|
||||
/dev/rare_-name <-> "_-dev_-rare_-_-name"
|
||||
///strange/dev/x <-> "_-_-_-strange_-dev_-x"
|
||||
|
||||
- st_rdev suffix. A hex representation of struct stat.st_rdev. Capital letters.
|
||||
The number of characters is pare with at most one leading 0. I.e. bytewise
|
||||
printf("%2.2X") beginning with the highest order byte that is not zero.
|
||||
E.g. : "0B01", "2200", "01000000000004001"
|
||||
|
||||
If a lockfile does not exist and cannot be created then this shall not keep
|
||||
a program from working on a device. But if a lockfile exists and if permissions
|
||||
or locking state do not allow to obtain a lock of the appropirate type, then
|
||||
this shall prevent any opening of device file in question resp. shall cause
|
||||
immediate close(2) of an already opened device file.
|
||||
|
||||
The vulnerable programs shall not start their operation before they locked a
|
||||
wide collection of drive representations.
|
||||
|
||||
Non-vulnerable programs shall take care to lock the suffix resulting from the
|
||||
path they will be using and the suffix from the st_rdev from that path.
|
||||
The latter is to be obtained by call stat(2).
|
||||
|
||||
Locks get upheld as long as their file descriptor is not closed or no other
|
||||
incident as described in man 2 fcntl releases the lock.
|
||||
|
||||
So with shared locks there are no imandatory further activities after they
|
||||
have been obtained.
|
||||
|
||||
In case of exclusive locks, the file has to have been opened for writing and
|
||||
must be truncated to 0 bytes length immediately after obtaining the lock.
|
||||
When releasing an exclusive lock it is a nice gesture to
|
||||
already do this truncation.
|
||||
Then a /var/lock/ compatible first line has to be written.
|
||||
E.g. by: printf("%10u\n",(unsigned) getpid()) yielding " 1230\n".
|
||||
|
||||
Any further lines are optional. They shall have the form Name=Value and must
|
||||
be printable cleartext. If such further lines exist, then the last one must
|
||||
have the name "endmark".
|
||||
Defined Names are:
|
||||
hostid =hostname of the machine where the process number of line 1 is valid
|
||||
start =start time of lock in seconds since 1970. E.g: 1177147634.592410
|
||||
program =self chosen name of the program which obtained the lock
|
||||
argv0 =argv[0] of that program
|
||||
mainpath =device file path which will be used for operations by that program
|
||||
path =device file path which lead to the lock
|
||||
st_rdev =st_rdev suffix which is associated with path
|
||||
scsi_hcil=eventual SCSI parameters Host,Channel,Id,Lun
|
||||
scsi_bus =eventual SCSI parameter Bus
|
||||
endmark =declares the info as complete.
|
||||
Any undefined name or a line without "=" shall be handled as comment.
|
||||
"=" in the value is allowed. Any line beginning with an "=" character is an
|
||||
extension of the previous value.
|
||||
|
||||
If programs encounter an exclusive lock, they are invited to read the content
|
||||
of the lockfile anyway. But they should be aware that the info might be in the
|
||||
progress of emerging. There is a race condition possible in the short time
|
||||
between obtaining the exclusive lock and erasing the file content.
|
||||
If it is not crucial to obtain most accurate info then one may take the newline
|
||||
of the first line as indicator of a valid process number and the "endmark"
|
||||
name as indicator that the preceding lines are valid.
|
||||
Very cautious readers should obtain the info twice with a decent waiting period
|
||||
inbetween. Only if both results are identical they should be considered valid.
|
||||
|
||||
|
||||
There is no implementation of DDLP-B yet.
|
||||
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
What are the Stumble Stones ?
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Any of the considered locking mechanisms has decisive shortcommings
|
||||
which keeps it from being the solution to all known legitimate use cases.
|
||||
|
||||
The attempt has failed to compose a waterproof locking mechanism from means of
|
||||
POSIX, FHS and from hardly documented Linux open(O_EXCL) on device files.
|
||||
The resulting mechanisms would need about 1000 lines of code and still do
|
||||
not close all gaps resp. cover the well motivated use cases.
|
||||
This attempt you see above: DDLP-A and DDLP-B.
|
||||
|
||||
|
||||
Summary of the reasons why the established locking mechanisms do not suffice:
|
||||
|
||||
None of the mechanisms can take care of the double device driver identity
|
||||
sr versus sg. To deduce the one device file from the other involves the need
|
||||
to open many other (possibly unrelated) device files with the risk to disturb
|
||||
them.
|
||||
This hard to solve problem is aggravated by the following facts.
|
||||
|
||||
Shortcommings of Linux specific open(O_EXCL) :
|
||||
|
||||
- O_EXCL | O_RDONLY does not succeed with /dev/sg*
|
||||
- O_EXCL cannot provide shared locks for programs which only want to lock
|
||||
against burn programs but not against their own peers.
|
||||
- O_EXCL keeps from obtaining information by harmless activities.
|
||||
- O_EXCL already has a meaning with devices which are mounted as filesystems.
|
||||
This priority meaning is more liberal than the one needed for CD/DV recording
|
||||
protection.
|
||||
|
||||
Shortcommings of POSIX fcntl(F_SETLK) :
|
||||
|
||||
- fcntl() demands an open file descriptor. open(2) might have side effects.
|
||||
- fcntl() locks can be released inadvertedly by submodules which just open and
|
||||
close the same file (inode ?) without refering to fcntl locks in any way.
|
||||
See man 2 fcntl "This is bad:".
|
||||
Stacking of software modules is a widely used design pattern. But fcntl()
|
||||
cannot cope with that.
|
||||
|
||||
Shortcommings of FHS /var/lock/ :
|
||||
|
||||
- Stale locks are possible.
|
||||
- It is necessary to create a file (using the _old_ meaning of O_EXCL flag ?)
|
||||
but /var/lock/ might not be available early during system start and it often
|
||||
has restrictive permission settings.
|
||||
- There is no way to indicate a difference between exclusive and shared locks.
|
||||
- The FHS prescription relies entirely on the basename of the device file path.
|
||||
|
1178
doc/doxygen.conf.in
@ -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
|
||||
|
261
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>
|
||||
@ -20,7 +43,15 @@
|
||||
#include "libdax_msgs.h"
|
||||
extern struct libdax_msgs *libdax_messenger;
|
||||
|
||||
#define SCAN_GOING() (workers && !workers->drive)
|
||||
/* ts A80714 : introduced type codes for the worker list */
|
||||
#define Burnworker_type_scaN 0
|
||||
#define Burnworker_type_erasE 1
|
||||
#define Burnworker_type_formaT 2
|
||||
#define Burnworker_type_writE 3
|
||||
#define Burnworker_type_fifO 4
|
||||
|
||||
#define SCAN_GOING() (workers != NULL && \
|
||||
workers->w_type == Burnworker_type_scaN)
|
||||
|
||||
typedef void *(*WorkerFunc) (void *);
|
||||
|
||||
@ -53,9 +84,18 @@ struct write_opts
|
||||
struct burn_disc *disc;
|
||||
};
|
||||
|
||||
struct fifo_opts
|
||||
{
|
||||
struct burn_source *source;
|
||||
int flag;
|
||||
};
|
||||
|
||||
|
||||
struct w_list
|
||||
{
|
||||
/* ts A80714 */
|
||||
int w_type; /* see above define Burnworker_type_* */
|
||||
|
||||
struct burn_drive *drive;
|
||||
pthread_t thread;
|
||||
|
||||
@ -67,10 +107,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)
|
||||
{
|
||||
@ -82,12 +124,19 @@ static struct w_list *find_worker(struct burn_drive *d)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void add_worker(struct burn_drive *d, WorkerFunc f, void *data)
|
||||
static void add_worker(int w_type, 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->w_type = w_type;
|
||||
a->drive = d;
|
||||
a->u = *(union w_list_data *)data;
|
||||
|
||||
@ -96,26 +145,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,8 +218,13 @@ 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);
|
||||
w->u.scan.done = 1;
|
||||
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 +258,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;
|
||||
@ -178,7 +272,8 @@ drive_is_active:;
|
||||
o.drives = drives;
|
||||
o.n_drives = n_drives;
|
||||
o.done = 0;
|
||||
add_worker(NULL, (WorkerFunc) scan_worker_func, &o);
|
||||
add_worker(Burnworker_type_scaN, NULL,
|
||||
(WorkerFunc) scan_worker_func, &o);
|
||||
} else if (workers->u.scan.done) {
|
||||
/* its done */
|
||||
ret = workers->u.scan.done;
|
||||
@ -189,7 +284,7 @@ drive_is_active:;
|
||||
if (workers != NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x00020101,
|
||||
LIBDAX_MSGS_SEV_WARNING, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"After scan a drive operation is still going on",
|
||||
"After scan a drive operation is still going on",
|
||||
0, 0);
|
||||
return -1;
|
||||
}
|
||||
@ -211,9 +306,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()); */
|
||||
@ -225,7 +317,7 @@ void burn_disc_erase(struct burn_drive *drive, int fast)
|
||||
"NULL pointer caught in burn_disc_erase", 0, 0);
|
||||
return;
|
||||
}
|
||||
if ((SCAN_GOING()) || find_worker(drive)) {
|
||||
if ((SCAN_GOING()) || find_worker(drive) != NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
||||
0x00020102,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
@ -233,12 +325,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 +344,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,
|
||||
@ -258,7 +357,8 @@ void burn_disc_erase(struct burn_drive *drive, int fast)
|
||||
|
||||
o.drive = drive;
|
||||
o.fast = fast;
|
||||
add_worker(drive, (WorkerFunc) erase_worker_func, &o);
|
||||
add_worker(Burnworker_type_erasE, drive,
|
||||
(WorkerFunc) erase_worker_func, &o);
|
||||
}
|
||||
|
||||
|
||||
@ -279,7 +379,7 @@ void burn_disc_format(struct burn_drive *drive, off_t size, int flag)
|
||||
int ok = 0;
|
||||
char msg[160];
|
||||
|
||||
if ((SCAN_GOING()) || find_worker(drive)) {
|
||||
if ((SCAN_GOING()) || find_worker(drive) != NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, drive->global_index,
|
||||
0x00020102,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
@ -287,6 +387,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 */
|
||||
|
||||
@ -299,6 +407,10 @@ void burn_disc_format(struct burn_drive *drive, off_t size, int flag)
|
||||
size = 0;
|
||||
flag &= ~(2|8); /* no insisting in size 0, no expansion */
|
||||
flag |= 4; /* format up to maximum size */
|
||||
} else if (drive->current_profile == 0x12) {
|
||||
ok = 1; /* DVD-RAM */
|
||||
} else if (drive->current_profile == 0x43) {
|
||||
ok = 1; /* BD-RE */
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
@ -314,13 +426,20 @@ void burn_disc_format(struct burn_drive *drive, off_t size, int flag)
|
||||
o.drive = drive;
|
||||
o.size = size;
|
||||
o.flag = flag;
|
||||
add_worker(drive, (WorkerFunc) format_worker_func, &o);
|
||||
add_worker(Burnworker_type_formaT, drive,
|
||||
(WorkerFunc) format_worker_func, &o);
|
||||
}
|
||||
|
||||
|
||||
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,10 +453,18 @@ 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
|
||||
|
||||
/* ts A61006 */
|
||||
/* a ssert(!SCAN_GOING()); */
|
||||
/* a ssert(!find_worker(opts->drive)); */
|
||||
if ((SCAN_GOING()) || find_worker(opts->drive) != NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, opts->drive->global_index,
|
||||
0x00020102,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"A drive operation is still going on (want to write)",
|
||||
0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* For the next lines any return indicates failure */
|
||||
opts->drive->cancel = 1;
|
||||
@ -346,19 +473,16 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
if (opts->write_type == BURN_WRITE_NONE)
|
||||
return;
|
||||
|
||||
/* ts A61006 */
|
||||
/* a ssert(!SCAN_GOING()); */
|
||||
/* a ssert(!find_worker(opts->drive)); */
|
||||
if ((SCAN_GOING()) || find_worker(opts->drive)) {
|
||||
if (opts->drive->drive_role == 0) {
|
||||
libdax_msgs_submit(libdax_messenger, opts->drive->global_index,
|
||||
0x00020102,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"A drive operation is still going on (want to write)",
|
||||
0, 0);
|
||||
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 +496,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;
|
||||
@ -422,9 +511,45 @@ void burn_disc_write(struct burn_write_opts *opts, struct burn_disc *disc)
|
||||
|
||||
opts->refcount++;
|
||||
|
||||
add_worker(opts->drive, (WorkerFunc) write_disc_worker_func, &o);
|
||||
add_worker(Burnworker_type_writE, 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(Burnworker_type_fifO, 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 +557,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 */
|
||||
|
614
libburn/ddlpa.c
Normal file
@ -0,0 +1,614 @@
|
||||
|
||||
/* ddlpa
|
||||
Implementation of Delicate Device Locking Protocol level A.
|
||||
Copyright (C) 2007 Thomas Schmitt <scdbackup@gmx.net>
|
||||
Provided under any of the following licenses: GPL, LGPL, BSD. Choose one.
|
||||
|
||||
|
||||
Compile as test program:
|
||||
|
||||
cc -g -Wall \
|
||||
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE \
|
||||
-DDDLPA_C_STANDALONE -o ddlpa ddlpa.c
|
||||
|
||||
The system macros enable 64-bit off_t and open(2) flag O_LARGEFILE, which
|
||||
are not absolutely necessary but explicitely take into respect that
|
||||
our devices can offer more than 2 GB of addressable data.
|
||||
|
||||
Run test program:
|
||||
|
||||
./ddlpa /dev/sr0 15
|
||||
./ddlpa 0,0,0 15
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
||||
|
||||
/* All callers of ddlpa must do this */
|
||||
#include "ddlpa.h"
|
||||
|
||||
|
||||
/* 1 = Enable progress message on stderr, 0 = normal silent operation */
|
||||
static int ddlpa_debug_mode = 1;
|
||||
|
||||
|
||||
/* #define _GNU_SOURCE or _LARGEFILE64_SOURCE to get real O_LARGEFILE */
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
|
||||
/* ----------------------- private -------------------- */
|
||||
|
||||
|
||||
static int ddlpa_new(struct ddlpa_lock **lck, int o_flags, int ddlpa_flags)
|
||||
{
|
||||
int i;
|
||||
struct ddlpa_lock *o;
|
||||
|
||||
o = *lck = (struct ddlpa_lock *) malloc(sizeof(struct ddlpa_lock));
|
||||
if (o == NULL)
|
||||
return ENOMEM;
|
||||
for (i = 0; i < sizeof(struct ddlpa_lock); i++)
|
||||
((char *) o)[i] = 0;
|
||||
o->path = NULL;
|
||||
o->fd = -1;
|
||||
for (i = 0; i < DDLPA_MAX_SIBLINGS; i++)
|
||||
o->sibling_fds[i] = -1;
|
||||
o->errmsg = NULL;
|
||||
|
||||
o->o_flags = o_flags;
|
||||
o->ddlpa_flags = ddlpa_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_enumerate(struct ddlpa_lock *o, int *idx,
|
||||
char path[DDLPA_MAX_STD_LEN + 1])
|
||||
{
|
||||
if (*idx < 0)
|
||||
*idx = 0;
|
||||
|
||||
if (*idx < 26)
|
||||
sprintf(path, "/dev/hd%c", 'a' + *idx);
|
||||
else if (*idx < 256 + 26)
|
||||
sprintf(path, "/dev/sr%d", *idx - 26);
|
||||
else if (*idx < 2 * 256 + 26)
|
||||
sprintf(path, "/dev/scd%d", *idx - 256 - 26);
|
||||
else if (*idx < 3 * 256 + 26)
|
||||
sprintf(path, "/dev/sg%d", *idx - 2 * 256 - 26);
|
||||
else
|
||||
return 1;
|
||||
(*idx)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_std_by_rdev(struct ddlpa_lock *o)
|
||||
{
|
||||
int idx = 0;
|
||||
char try_path[DDLPA_MAX_STD_LEN+1];
|
||||
struct stat path_stbuf, try_stbuf;
|
||||
|
||||
if (!o->path_is_valid)
|
||||
return EFAULT;
|
||||
if (stat(o->path, &path_stbuf) == -1)
|
||||
return errno;
|
||||
|
||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
||||
if (stat(try_path, &try_stbuf) == -1)
|
||||
continue;
|
||||
if (path_stbuf.st_rdev != try_stbuf.st_rdev)
|
||||
continue;
|
||||
strcpy(o->std_path, try_path);
|
||||
|
||||
if (ddlpa_debug_mode)
|
||||
fprintf(stderr,
|
||||
"DDLPA_DEBUG: ddlpa_std_by_rdev(\"%s\") = \"%s\"\n",
|
||||
o->path, o->std_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
|
||||
/* Caution : these tests are valid only with standard paths */
|
||||
|
||||
static int ddlpa_is_scsi(struct ddlpa_lock *o, char *path)
|
||||
{
|
||||
return (strncmp(path, "/dev/s", 6) == 0);
|
||||
}
|
||||
|
||||
static int ddlpa_is_sg(struct ddlpa_lock *o, char *path)
|
||||
{
|
||||
return (strncmp(path, "/dev/sg", 7) == 0);
|
||||
}
|
||||
|
||||
static int ddlpa_is_sr(struct ddlpa_lock *o, char *path)
|
||||
{
|
||||
return (strncmp(path, "/dev/sr", 7) == 0);
|
||||
}
|
||||
|
||||
static int ddlpa_is_scd(struct ddlpa_lock *o, char *path)
|
||||
{
|
||||
return (strncmp(path, "/dev/scd", 8) == 0);
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_fcntl_lock(struct ddlpa_lock *o, int fd, int l_type)
|
||||
{
|
||||
struct flock lockthing;
|
||||
int ret;
|
||||
|
||||
memset(&lockthing, 0, sizeof(lockthing));
|
||||
lockthing.l_type = l_type;
|
||||
lockthing.l_whence = SEEK_SET;
|
||||
lockthing.l_start = 0;
|
||||
lockthing.l_len = 0;
|
||||
ret = fcntl(fd, F_SETLK, &lockthing);
|
||||
if (ret == -1)
|
||||
return EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_occupy(struct ddlpa_lock *o, char *path, int *fd,
|
||||
int no_o_excl)
|
||||
{
|
||||
int ret, o_flags, o_rw, l_type;
|
||||
char *o_rwtext;
|
||||
|
||||
o_flags = o->o_flags | O_NDELAY;
|
||||
if(!no_o_excl)
|
||||
o_flags |= O_EXCL;
|
||||
o_rw = (o_flags) & (O_RDONLY | O_WRONLY | O_RDWR);
|
||||
o_rwtext = (o_rw == O_RDONLY ? "O_RDONLY" :
|
||||
(o_rw == O_WRONLY ? "O_WRONLY" :
|
||||
(o_rw == O_RDWR ? "O_RDWR " : "O_?rw-mode?")));
|
||||
|
||||
*fd = open(path, o_flags);
|
||||
if (*fd == -1) {
|
||||
o->errmsg = malloc(strlen(path)+160);
|
||||
if (o->errmsg)
|
||||
sprintf(o->errmsg,
|
||||
"Failed to open %s | O_NDELAY %s: '%s'",
|
||||
o_rwtext,
|
||||
(o_flags & O_EXCL ? "| O_EXCL " : ""), path);
|
||||
return (errno ? errno : EBUSY);
|
||||
}
|
||||
if (o_rw == O_RDWR || o_rw == O_WRONLY)
|
||||
l_type = F_WRLCK;
|
||||
else
|
||||
l_type = F_RDLCK;
|
||||
ret = ddlpa_fcntl_lock(o, *fd, l_type);
|
||||
if (ret) {
|
||||
o->errmsg = malloc(strlen(path)+160);
|
||||
if (o->errmsg)
|
||||
sprintf(o->errmsg,
|
||||
"Failed to lock fcntl(F_WRLCK) : '%s'",path);
|
||||
close(*fd);
|
||||
*fd = -1;
|
||||
return ret;
|
||||
}
|
||||
if (ddlpa_debug_mode)
|
||||
fprintf(stderr, "DDLPA_DEBUG: ddlpa_occupy() %s %s: '%s'\n",
|
||||
o_rwtext,
|
||||
(no_o_excl ? " " : "O_EXCL "), path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_obtain_scsi_adr(struct ddlpa_lock *o, char *path,
|
||||
int *bus, int *host, int *channel, int *id, int *lun)
|
||||
{
|
||||
int fd, ret, open_mode = O_RDONLY | O_NDELAY;
|
||||
struct my_scsi_idlun {
|
||||
int x;
|
||||
int host_unique_id;
|
||||
};
|
||||
struct my_scsi_idlun idlun;
|
||||
|
||||
fd = open(path, open_mode);
|
||||
if (fd == -1)
|
||||
return (errno ? errno : EBUSY);
|
||||
if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, bus) == -1)
|
||||
*bus = -1;
|
||||
ret = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &idlun);
|
||||
close(fd);
|
||||
if (ret == -1)
|
||||
return (errno ? errno : EIO);
|
||||
*host = (idlun.x >> 24) & 255;
|
||||
*channel = (idlun.x >> 16) & 255;
|
||||
*id = (idlun.x) & 255;
|
||||
*lun = (idlun.x >> 8 ) & 255;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_collect_siblings(struct ddlpa_lock *o)
|
||||
{
|
||||
int idx = 0, ret, have_sg = 0, have_sr = 0, have_scd = 0;
|
||||
dev_t path_dev;
|
||||
ino_t path_inode;
|
||||
struct stat stbuf;
|
||||
char *path, try_path[DDLPA_MAX_STD_LEN+1];
|
||||
int t_bus, t_host, t_channel, t_id, t_lun;
|
||||
|
||||
if (o->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
||||
path = o->path;
|
||||
else
|
||||
path = o->std_path;
|
||||
if (path[0] == 0 || o->num_siblings != 0)
|
||||
return EFAULT;
|
||||
if (!ddlpa_is_scsi(o, o->std_path))
|
||||
return EFAULT;
|
||||
|
||||
if (stat(path, &stbuf) == -1)
|
||||
return errno;
|
||||
path_inode = stbuf.st_ino;
|
||||
path_dev = stbuf.st_dev;
|
||||
o->rdev = stbuf.st_rdev;
|
||||
o->dev = stbuf.st_dev;
|
||||
o->ino = stbuf.st_ino;
|
||||
ret = ddlpa_obtain_scsi_adr(o, path,
|
||||
&(o->bus), &(o->host), &(o->channel),
|
||||
&(o->id), &(o->lun));
|
||||
if (ret) {
|
||||
o->errmsg = strdup(
|
||||
"Cannot obtain SCSI parameters host,channel,id,lun");
|
||||
return ret;
|
||||
}
|
||||
o->hcilb_is_valid = 1;
|
||||
|
||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
||||
if (!ddlpa_is_scsi(o, try_path))
|
||||
continue;
|
||||
if (stat(try_path, &stbuf) == -1)
|
||||
continue;
|
||||
ret = ddlpa_obtain_scsi_adr(o, try_path,
|
||||
&t_bus, &t_host, &t_channel, &t_id, &t_lun);
|
||||
if (ret) {
|
||||
|
||||
/* >>> interpret error, memorize busy, no permission */
|
||||
|
||||
continue;
|
||||
}
|
||||
if (t_host != o->host || t_channel != o->channel ||
|
||||
t_id != o->id || t_lun != o->lun)
|
||||
continue;
|
||||
|
||||
if (o->num_siblings >= DDLPA_MAX_SIBLINGS) {
|
||||
o->errmsg =
|
||||
strdup("Too many matching device files found");
|
||||
return ERANGE;
|
||||
}
|
||||
if (ddlpa_is_sg(o, try_path))
|
||||
have_sg = 1;
|
||||
else if (ddlpa_is_sr(o, try_path))
|
||||
have_sr = 1;
|
||||
else if (ddlpa_is_scd(o, try_path))
|
||||
have_scd = 1;
|
||||
strcpy(o->sibling_paths[o->num_siblings], try_path);
|
||||
o->sibling_rdevs[o->num_siblings] = stbuf.st_rdev;
|
||||
o->sibling_devs[o->num_siblings] = stbuf.st_dev;
|
||||
o->sibling_inodes[o->num_siblings] = stbuf.st_ino;
|
||||
|
||||
if (ddlpa_debug_mode)
|
||||
fprintf(stderr,
|
||||
"DDLPA_DEBUG: ddlpa_collect_siblings() found \"%s\"\n",
|
||||
try_path);
|
||||
|
||||
(o->num_siblings)++;
|
||||
}
|
||||
if (have_sg && have_sr && have_scd)
|
||||
return 0;
|
||||
if (o->ddlpa_flags & DDLPA_ALLOW_MISSING_SGRCD)
|
||||
return 0;
|
||||
|
||||
o->errmsg = strdup("Did not find enough siblings");
|
||||
|
||||
/* >>> add more info about busy and forbidden paths */
|
||||
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_std_by_btl(struct ddlpa_lock *o)
|
||||
{
|
||||
int idx = 0, ret;
|
||||
char try_path[DDLPA_MAX_STD_LEN+1];
|
||||
int t_bus, t_host, t_channel, t_id, t_lun;
|
||||
|
||||
if (!o->inbtl_is_valid)
|
||||
return EFAULT;
|
||||
|
||||
while (ddlpa_enumerate(o, &idx, try_path) == 0) {
|
||||
if (!ddlpa_is_sr(o, try_path))
|
||||
continue;
|
||||
ret = ddlpa_obtain_scsi_adr(o, try_path,
|
||||
&t_bus, &t_host, &t_channel, &t_id, &t_lun);
|
||||
if (ret) {
|
||||
|
||||
/* >>> interpret error, memorize busy, no permission */
|
||||
|
||||
continue;
|
||||
}
|
||||
if (t_bus != o->in_bus || t_id != o->in_target ||
|
||||
t_lun != o->in_lun)
|
||||
continue;
|
||||
strcpy(o->std_path, try_path);
|
||||
|
||||
if (ddlpa_debug_mode)
|
||||
fprintf(stderr,
|
||||
"DDLPA_DEBUG: ddlpa_std_by_btl(%d,%d,%d) = \"%s\"\n",
|
||||
t_bus, t_id, t_lun, o->std_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* >>> add more info about busy and forbidden paths */
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
|
||||
static int ddlpa_open_all(struct ddlpa_lock *o)
|
||||
{
|
||||
int i, j, ret, no_o_excl;
|
||||
|
||||
if (ddlpa_is_scsi(o, o->std_path)) {
|
||||
ret = ddlpa_collect_siblings(o);
|
||||
if (ret)
|
||||
return ret;
|
||||
for (i = 0; i < o->num_siblings; i++) {
|
||||
|
||||
/* Watch out for the main personality of the drive. */
|
||||
/* No need to occupy identical path or softlink path */
|
||||
if (o->sibling_devs[i] == o->dev &&
|
||||
o->sibling_inodes[i] == o->ino)
|
||||
continue;
|
||||
/* There may be the same rdev but different inode. */
|
||||
no_o_excl = (o->sibling_rdevs[i] == o->rdev);
|
||||
|
||||
/* Look for multiply registered device drivers with
|
||||
distinct inodes. */
|
||||
for (j = 0; j < i; j++) {
|
||||
if (o->sibling_devs[j] == o->sibling_devs[i] &&
|
||||
o->sibling_inodes[j] == o->sibling_inodes[i])
|
||||
break;
|
||||
if (o->sibling_rdevs[j] == o->sibling_rdevs[i])
|
||||
no_o_excl = 1;
|
||||
}
|
||||
if (j < i)
|
||||
continue; /* inode is already occupied */
|
||||
|
||||
ret = ddlpa_occupy(o, o->sibling_paths[i],
|
||||
&(o->sibling_fds[i]), no_o_excl);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (o->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
||||
ret = ddlpa_occupy(o, o->path, &(o->fd), 0);
|
||||
else
|
||||
ret = ddlpa_occupy(o, o->std_path, &(o->fd), 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* >>> use fcntl() to adjust O_NONBLOCK */;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------- public -------------------- */
|
||||
|
||||
|
||||
int ddlpa_destroy(struct ddlpa_lock **lockbundle)
|
||||
{
|
||||
struct ddlpa_lock *o;
|
||||
int i;
|
||||
|
||||
o= *lockbundle;
|
||||
if (o == NULL)
|
||||
return 0;
|
||||
for (i = 0; i < o->num_siblings; i++)
|
||||
if (o->sibling_fds[i] != -1)
|
||||
close(o->sibling_fds[i]);
|
||||
if(o->fd != -1)
|
||||
close(o->fd);
|
||||
if (o->path != NULL)
|
||||
free(o->path);
|
||||
if (o->errmsg != NULL)
|
||||
free(o->errmsg);
|
||||
free((char *) o);
|
||||
*lockbundle = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ddlpa_lock_path(char *path, int o_flags, int ddlpa_flags,
|
||||
struct ddlpa_lock **lockbundle, char **errmsg)
|
||||
{
|
||||
struct ddlpa_lock *o;
|
||||
int ret;
|
||||
|
||||
*errmsg = NULL;
|
||||
if (ddlpa_new(&o, o_flags, ddlpa_flags))
|
||||
return ENOMEM;
|
||||
*lockbundle = o;
|
||||
|
||||
o->path = strdup(path);
|
||||
if (o->path == NULL)
|
||||
return ENOMEM;
|
||||
o->path_is_valid = 1;
|
||||
|
||||
ret = ddlpa_std_by_rdev(o);
|
||||
if (ret) {
|
||||
*errmsg = strdup(
|
||||
"Cannot find equivalent of given path among standard paths");
|
||||
return ret;
|
||||
}
|
||||
ret = ddlpa_open_all(o);
|
||||
if (ret) {
|
||||
*errmsg = o->errmsg;
|
||||
o->errmsg = NULL;
|
||||
ddlpa_destroy(&o);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int ddlpa_lock_btl(int bus, int target, int lun,
|
||||
int o_flags, int ddlpa_flags,
|
||||
struct ddlpa_lock **lockbundle, char **errmsg)
|
||||
{
|
||||
struct ddlpa_lock *o;
|
||||
int ret;
|
||||
|
||||
*errmsg = NULL;
|
||||
ddlpa_flags &= ~DDLPA_OPEN_GIVEN_PATH;
|
||||
if (ddlpa_new(&o, o_flags, ddlpa_flags))
|
||||
return ENOMEM;
|
||||
*lockbundle = o;
|
||||
|
||||
o->in_bus = bus;
|
||||
o->in_target = target;
|
||||
o->in_lun = lun;
|
||||
o->inbtl_is_valid = 1;
|
||||
ret = ddlpa_std_by_btl(o);
|
||||
if (ret) {
|
||||
*errmsg = strdup(
|
||||
"Cannot find /dev/sr* with given Bus,Target,Lun");
|
||||
return ret;
|
||||
}
|
||||
ret = ddlpa_open_all(o);
|
||||
if (ret) {
|
||||
*errmsg = o->errmsg;
|
||||
o->errmsg = NULL;
|
||||
ddlpa_destroy(&o);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DDLPA_C_STANDALONE
|
||||
|
||||
/* ----------------------------- Test / Demo -------------------------- */
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ddlpa_lock *lck = NULL;
|
||||
char *errmsg = NULL, *opened_path = NULL, *my_path = NULL;
|
||||
int i, ret, fd = -1, duration = -1, bus = -1, target = -1, lun = -1;
|
||||
|
||||
if (argc < 3) {
|
||||
usage:;
|
||||
fprintf(stderr, "usage: %s device_path duration\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
my_path = argv[1];
|
||||
sscanf(argv[2], "%d", &duration);
|
||||
if (duration < 0)
|
||||
goto usage;
|
||||
|
||||
|
||||
/* For our purpose, only O_RDWR is a suitable access mode.
|
||||
But in order to allow experiments, o_flags are freely adjustable.
|
||||
|
||||
Warning: Do _not_ set an own O_EXCL flag with the following calls !
|
||||
|
||||
(This freedom to fail may get removed in a final version.)
|
||||
*/
|
||||
if (my_path[0] != '/' && my_path[0] != '.' &&
|
||||
strchr(my_path, ',') != NULL) {
|
||||
/*
|
||||
cdrecord style dev=Bus,Target,Lun
|
||||
*/
|
||||
|
||||
sscanf(my_path, "%d,%d,%d", &bus, &target, &lun);
|
||||
ret = ddlpa_lock_btl(bus, target, lun, O_RDWR | O_LARGEFILE,
|
||||
0, &lck, &errmsg);
|
||||
} else {
|
||||
/*
|
||||
This substitutes for:
|
||||
fd = open(my_path, O_RDWR | O_EXCL | O_LARGEFILE);
|
||||
|
||||
*/
|
||||
|
||||
ret = ddlpa_lock_path(my_path, O_RDWR | O_LARGEFILE,
|
||||
0, &lck, &errmsg);
|
||||
}
|
||||
if (ret) {
|
||||
fprintf(stderr, "Cannot exclusively open '%s'\n", my_path);
|
||||
if (errmsg != NULL)
|
||||
fprintf(stderr, "Reason given : %s\n",
|
||||
errmsg);
|
||||
free(errmsg);
|
||||
fprintf(stderr, "Error condition : %d '%s'\n",
|
||||
ret, strerror(ret));
|
||||
exit(2);
|
||||
}
|
||||
fd = lck->fd;
|
||||
|
||||
printf("---------------------------------------------- Lock gained\n");
|
||||
|
||||
|
||||
/* Use fd for the usual operations on the device depicted by my_path.
|
||||
*/
|
||||
|
||||
|
||||
/* This prints an overview of the impact of the lock */
|
||||
if (lck->ddlpa_flags & DDLPA_OPEN_GIVEN_PATH)
|
||||
opened_path = lck->path;
|
||||
else
|
||||
opened_path = lck->std_path;
|
||||
printf("ddlpa: opened %s", opened_path);
|
||||
|
||||
if (strcmp(opened_path, lck->std_path) != 0)
|
||||
printf(" (an alias of '%s')", lck->std_path);
|
||||
printf("\n");
|
||||
if (lck->num_siblings > 0) {
|
||||
printf("ddlpa: opened siblings:");
|
||||
for (i = 0; i < lck->num_siblings; i++)
|
||||
if (lck->sibling_fds[i] != -1)
|
||||
printf(" %s", lck->sibling_paths[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
/* This example waits a while. So other lock candidates can collide. */
|
||||
for (i = 0; i < duration; i++) {
|
||||
sleep(1);
|
||||
fprintf(stderr, "\rslept %d seconds of %d", i + 1, duration);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
|
||||
/* When finally done with the drive, this substitutes for:
|
||||
close(fd);
|
||||
*/
|
||||
if (ddlpa_destroy(&lck)) {
|
||||
/* Well, man 2 close says it can fail. */
|
||||
exit(3);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
#endif /* DDLPA_C_STANDALONE */
|
||||
|
107
libburn/ddlpa.h
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
/* ddlpa
|
||||
Implementation of Delicate Device Locking Protocol level A.
|
||||
Copyright (C) 2007 Thomas Schmitt <scdbackup@gmx.net>
|
||||
Provided under any of the following licenses: GPL, LGPL, BSD. Choose one.
|
||||
|
||||
See ../doc/ddlp.txt for a description of the protocol.
|
||||
*/
|
||||
|
||||
#ifndef DDLPA_H_INCLUDED
|
||||
#define DDLPA_H_INCLUDED 1
|
||||
|
||||
|
||||
/* An upper limit for the length of standard paths and sibling paths */
|
||||
#define DDLPA_MAX_STD_LEN 15
|
||||
|
||||
/* An upper limit for the number of siblings */
|
||||
#define DDLPA_MAX_SIBLINGS 5
|
||||
|
||||
struct ddlpa_lock {
|
||||
|
||||
/* Recorded input parameters of locking call */
|
||||
char *path;
|
||||
int path_is_valid;
|
||||
int in_bus, in_target, in_lun;
|
||||
int inbtl_is_valid;
|
||||
int ddlpa_flags;
|
||||
int o_flags;
|
||||
|
||||
/* Result of locking call */
|
||||
char std_path[DDLPA_MAX_STD_LEN + 1];
|
||||
int fd;
|
||||
dev_t rdev;
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
int host, channel, id, lun, bus;
|
||||
int hcilb_is_valid;
|
||||
int num_siblings;
|
||||
char sibling_paths[DDLPA_MAX_SIBLINGS][DDLPA_MAX_STD_LEN + 1];
|
||||
int sibling_fds[DDLPA_MAX_SIBLINGS];
|
||||
dev_t sibling_rdevs[DDLPA_MAX_SIBLINGS];
|
||||
dev_t sibling_devs[DDLPA_MAX_SIBLINGS];
|
||||
ino_t sibling_inodes[DDLPA_MAX_SIBLINGS];
|
||||
|
||||
/* Is NULL if all goes well. Else it may contain a text message. */
|
||||
char *errmsg;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Lock a recorder by naming a device file path. Allocate a new container.
|
||||
@param path Gives the file system path of the recorder
|
||||
as known to the calling program.
|
||||
@param o_flags flags for open(2). Do not use O_EXCL here because this
|
||||
is done automatically whenever appropriate.
|
||||
Advised is O_RDWR | O_LARGEFILE, eventually | O_NDELAY.
|
||||
@param ddlpa_flags 0 = default behavior: the standard path will be opened
|
||||
and treated by fcntl(F_SETLK)
|
||||
DDLPA_OPEN_GIVEN_PATH causes the input parameter "path"
|
||||
to be used with open(2) and fcntl(2).
|
||||
DDLPA_ALLOW_MISSING_SGRCD allows to grant a lock
|
||||
although not all three, a sg, a sr and a scd device
|
||||
file have been found during sibling search. Normally
|
||||
this is counted as failure due to EBUSY.
|
||||
@param lockbundle gets allocated and then represents the locking state
|
||||
@param errmsg if *errmsg is not NULL after the call, it contains an
|
||||
error message. Then to be released by free(3).
|
||||
It is NULL in case of success or lack of memory.
|
||||
@return 0=success , else an errno compatible error number
|
||||
*/
|
||||
int ddlpa_lock_path(char *path, int o_flags, int ddlpa_flags,
|
||||
struct ddlpa_lock **lockbundle, char **errmsg);
|
||||
|
||||
|
||||
/** Lock a recorder by naming a Bus,Target,Lun number triple.
|
||||
Allocate a new container.
|
||||
@param bus parameter to match ioctl(SCSI_IOCTL_GET_BUS_NUMBER)
|
||||
@param target parameter to match ioctl(SCSI_IOCTL_GET_IDLUN) &0xff
|
||||
@param lun parameter to match ioctl(SCSI_IOCTL_GET_IDLUN) &0xff00
|
||||
@param o_flags see ddlpa_lock_path().
|
||||
@param ddlpa_flags see ddlpa_lock_path(). Flag DDLPA_OPEN_GIVEN_PATH
|
||||
will be ignored.
|
||||
@param lockbundle see ddlpa_lock_path().
|
||||
@param errmsg see ddlpa_lock_path().
|
||||
@return 0=success , else an errno compatible error number
|
||||
*/
|
||||
int ddlpa_lock_btl(int bus, int target, int lun,
|
||||
int o_flags, int ddlpa_flags,
|
||||
struct ddlpa_lock **lockbundle, char **errmsg);
|
||||
|
||||
|
||||
/** Release the lock by closing all filedescriptors and freeing memory.
|
||||
@param lockbundle the lock which is to be released.
|
||||
*lockbundle will be set to NULL by this call.
|
||||
@return 0=success , 1=failure
|
||||
*/
|
||||
int ddlpa_destroy(struct ddlpa_lock **lockbundle);
|
||||
|
||||
|
||||
|
||||
/** Definitions of macros used in above functions */
|
||||
|
||||
#define DDLPA_OPEN_GIVEN_PATH 1
|
||||
#define DDLPA_ALLOW_MISSING_SGRCD 2
|
||||
|
||||
|
||||
#endif /* DDLPA_H_INCLUDED */
|
941
libburn/drive.c
@ -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,25 @@ 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);
|
||||
|
||||
|
||||
/* ts A51221 - A80731 : Whitelist inquiry functions */
|
||||
int burn_drive_is_banned(char *device_address);
|
||||
int burn_drive_whitelist_count(void);
|
||||
char *burn_drive_whitelist_item(int idx, int flag);
|
||||
|
||||
|
||||
/* ts A80801 */
|
||||
int burn_drive_is_listed(char *path, struct burn_drive **found, int flag);
|
||||
|
||||
|
||||
#endif /* __DRIVE */
|
||||
|
459
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)
|
||||
fs->subfd = fd2;
|
||||
/* 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,417 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
int burn_fifo_peek_data(struct burn_source *source, char *buf, int bufsize,
|
||||
int flag)
|
||||
{
|
||||
int size, free_bytes, ret, wait_count= 0;
|
||||
char *status_text;
|
||||
struct burn_source_fifo *fs = source->data;
|
||||
|
||||
/* Eventually start fifo thread by reading 0 bytes */
|
||||
ret = fifo_read(source, (unsigned char *) NULL, 0);
|
||||
if (ret<0)
|
||||
return 0;
|
||||
|
||||
/* wait for at least bufsize bytes being ready */
|
||||
while (1) {
|
||||
ret= burn_fifo_inquire_status(source,
|
||||
&size, &free_bytes, &status_text);
|
||||
if (size < bufsize) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x0002015c,
|
||||
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Fifo size is smaller than desired peek buffer", 0, 0);
|
||||
return -1;
|
||||
}
|
||||
if (fs->out_counter > 0 || (ret & 4) || fs->buf == NULL) {
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x0002015e,
|
||||
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Fifo is already under consumption when peeking is desired",
|
||||
0, 0);
|
||||
return -1;
|
||||
}
|
||||
if(size - free_bytes >= bufsize) {
|
||||
|
||||
/* <<<
|
||||
fprintf(stderr,
|
||||
"libburn_DEBUG: after waiting cycle %d : fifo %s , %d bytes\n",
|
||||
wait_count, status_text, size - free_bytes);
|
||||
*/
|
||||
|
||||
memcpy(buf, fs->buf, bufsize);
|
||||
return 1;
|
||||
}
|
||||
if (ret&2) { /* input has ended, not enough data arrived */
|
||||
libdax_msgs_submit(libdax_messenger, -1, 0x0002015d,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
"Fifo input ended short of desired peek buffer size",
|
||||
0, 0);
|
||||
return 0;
|
||||
}
|
||||
usleep(100000);
|
||||
wait_count++;
|
||||
|
||||
/* <<<
|
||||
if(wait_count%10==0)
|
||||
fprintf(stderr,
|
||||
"libburn_DEBUG: waiting cycle %d : fifo %s , %d bytes\n",
|
||||
wait_count, status_text, size - free_bytes);
|
||||
*/
|
||||
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
186
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
|
||||
@ -26,9 +32,22 @@ struct libdax_msgs *libdax_messenger= NULL;
|
||||
|
||||
int burn_running = 0;
|
||||
|
||||
/* ts A60813 : wether to use O_EXCL and/or O_NONBLOCK in libburn/sg.c */
|
||||
/* ts A60813 : Linux: wether to use O_EXCL on open() of device files */
|
||||
int burn_sg_open_o_excl = 1;
|
||||
|
||||
/* ts A70403 : Linux: wether to use fcntl(,F_SETLK,)
|
||||
after open() of device files */
|
||||
int burn_sg_fcntl_f_setlk = 1;
|
||||
|
||||
/* ts A70314 : Linux: what device family to use :
|
||||
0= default family
|
||||
1= sr
|
||||
2= scd
|
||||
(3= st)
|
||||
4= sg
|
||||
*/
|
||||
int burn_sg_use_family = 0;
|
||||
|
||||
/* O_NONBLOCK was hardcoded in enumerate_ata() which i hardly use.
|
||||
For enumerate_sg() it seems ok.
|
||||
So it should stay default mode until enumerate_ata() without O_NONBLOCK
|
||||
@ -40,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"
|
||||
@ -48,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 */
|
||||
@ -94,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" */
|
||||
@ -119,10 +142,11 @@ void burn_preset_device_open(int exclusive, int blocking, int abort_on_busy)
|
||||
/* a ssert(burn_running); */
|
||||
if (!burn_running)
|
||||
return;
|
||||
|
||||
burn_sg_open_o_excl= exclusive;
|
||||
burn_sg_open_o_nonblock= !blocking;
|
||||
burn_sg_open_abort_busy= !!abort_on_busy;
|
||||
burn_sg_open_o_excl = exclusive & 3;
|
||||
burn_sg_fcntl_f_setlk = !!(exclusive & 32);
|
||||
burn_sg_use_family = (exclusive >> 2) & 7;
|
||||
burn_sg_open_o_nonblock = !blocking;
|
||||
burn_sg_open_abort_busy = !!abort_on_busy;
|
||||
}
|
||||
|
||||
|
||||
@ -186,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)
|
||||
@ -212,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)
|
||||
kill(abort_control_pid, signum);
|
||||
d->busy = BURN_DRIVE_IDLE;
|
||||
|
||||
/* >>> ??? end thread */;
|
||||
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);
|
||||
}
|
||||
|
||||
#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);
|
||||
@ -253,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);
|
||||
}
|
||||
|
||||
@ -275,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;
|
||||
}
|
||||
|
||||
|
||||
@ -286,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 */
|
||||
|
@ -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
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
@ -300,9 +427,13 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
0x00020002 (SORRY,HIGH) = Encountered error when closing drive
|
||||
0x00020003 (SORRY,HIGH) = Could not grab drive
|
||||
0x00020004 (NOTE,HIGH) = Opened O_EXCL scsi sibling
|
||||
0x00020005 (FATAL,HIGH) = Failed to open device
|
||||
0x00020005 (SORRY,HIGH) = Failed to open device
|
||||
0x00020006 (FATAL,HIGH) = Too many scsi siblings
|
||||
0x00020007 (NOTE,HIGH) = Closed O_EXCL scsi siblings
|
||||
0x00020008 (SORRY,HIGH) = Device busy. Failed to fcntl-lock
|
||||
0x00020009 (SORRY,HIGH) = Neither stdio-path nor its directory exist
|
||||
0x0002000a (FAILURE,HIGH) = Cannot accept '...' as SG_IO CDROM drive
|
||||
0x0002000b (FAILURE,HIGH) = File object '...' not found
|
||||
|
||||
General library operations:
|
||||
|
||||
@ -312,7 +443,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
|
||||
@ -365,12 +496,158 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
|
||||
0x00020138 (FATAL,HIGH) = Cannot reserve track
|
||||
0x00020139 (SORRY,HIGH) = Write job parameters are unsuitable
|
||||
0x0002013a (FATAL,HIGH) = No suitable media detected
|
||||
0x0002013b (DEBUG,HIGH) = SCSI command indicates host or driver error
|
||||
0x0002013c (SORRY,HIGH) = Malformed capabilities page 2Ah received
|
||||
0x0002013d (DEBUG,LOW) = Waiting for free buffer space takes long time
|
||||
0x0002013e (SORRY,HIGH) = Timeout with waiting for free buffer. Now disabled
|
||||
0x0002013f (DEBUG,LOW) = Reporting total time spent with waiting for buffer
|
||||
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
|
||||
0x0002015a (NOTE,HIGH) = Could not examine busy device
|
||||
0x0002015b (HINT,HIGH) = Busy '...' seems to be a hard disk, as '...1' exists
|
||||
0x0002015c (FAILURE,HIGH) = Fifo size is smaller than desired peek buffer
|
||||
0x0002015d (FAILURE,HIGH) = Fifo input ended short of desired peek buffer size
|
||||
0x0002015e (FATAL,HIGH) = Fifo is already under consumption when peeking
|
||||
|
||||
libdax_audioxtr:
|
||||
0x00020200 (SORRY,HIGH) = Cannot open audio source file
|
||||
0x00020201 (SORRY,HIGH) = Audio source file has unsuitable format
|
||||
0x00020202 (SORRY,HIGH) = Failed to prepare reading of audio data
|
||||
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
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
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
|
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
|
||||
|
1573
libburn/mmc.c
@ -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
|
||||
|
@ -38,6 +38,7 @@ struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive)
|
||||
opts->start_byte = -1;
|
||||
opts->fill_up_media = 0;
|
||||
opts->force_is_set = 0;
|
||||
opts->do_stream_recording = 0;
|
||||
opts->has_mediacatalog = 0;
|
||||
opts->format = BURN_CDROM;
|
||||
opts->multi = 0;
|
||||
@ -124,16 +125,26 @@ void burn_write_opts_set_format(struct burn_write_opts *opts, int format)
|
||||
|
||||
int burn_write_opts_set_simulate(struct burn_write_opts *opts, int sim)
|
||||
{
|
||||
/* <<< ts A70529 :
|
||||
One cannot predict the ability to simulate from page 05h
|
||||
information alone. This check is now done later in
|
||||
function burn_write_opts_auto_write_type().
|
||||
|
||||
if (opts->drive->mdata->simulate) {
|
||||
opts->simulate = sim;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
*/
|
||||
opts->simulate = !!sim;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
@ -265,6 +276,8 @@ no_caps:;
|
||||
} else if (caps->might_do_sao >= 3 && !(flag & 1))
|
||||
goto try_tao;
|
||||
do_sao:;
|
||||
if (caps->might_simulate == 0 && opts->simulate && !opts->force_is_set)
|
||||
goto no_simulate;
|
||||
if (!(flag & 1))
|
||||
burn_write_opts_set_write_type(
|
||||
opts, BURN_WRITE_SAO, BURN_BLOCK_SAO);
|
||||
@ -296,6 +309,8 @@ try_tao:;
|
||||
if (strcmp(reason_pt, "TAO: ") != 0)
|
||||
goto no_tao;
|
||||
/* ( TAO data/audio block size will be handled automatically ) */
|
||||
if (caps->might_simulate == 0 && opts->simulate && !opts->force_is_set)
|
||||
goto no_simulate;
|
||||
if (!(flag & 1))
|
||||
burn_write_opts_set_write_type(
|
||||
opts, BURN_WRITE_TAO, BURN_BLOCK_MODE1);
|
||||
@ -323,13 +338,21 @@ try_raw:;
|
||||
strcat(reasons, "drive dislikes block type, ");
|
||||
if (strcmp(reason_pt, "RAW: ") != 0)
|
||||
goto no_write_mode;
|
||||
if (!opts->force_is_set)
|
||||
goto no_simulate;
|
||||
|
||||
/* For now: no setting of raw write modes */
|
||||
|
||||
{wt = BURN_WRITE_RAW; goto ex;}
|
||||
|
||||
no_write_mode:;
|
||||
wt = BURN_WRITE_NONE;
|
||||
{wt = BURN_WRITE_NONE; goto ex;}
|
||||
|
||||
no_simulate:;
|
||||
strcat(reasons,
|
||||
"simulation of write job not supported by drive and media, ");
|
||||
{wt = BURN_WRITE_NONE; goto ex;}
|
||||
|
||||
ex:;
|
||||
burn_disc_free_multi_caps(&caps);
|
||||
if (wt == BURN_WRITE_NONE && !(flag & 3)) {
|
||||
@ -358,6 +381,23 @@ void burn_write_opts_set_force(struct burn_write_opts *opts, int use_force)
|
||||
}
|
||||
|
||||
|
||||
/* ts A80412: API */
|
||||
void burn_write_opts_set_stream_recording(struct burn_write_opts *opts,
|
||||
int value)
|
||||
{
|
||||
opts->do_stream_recording = !!value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 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;
|
||||
|
@ -49,6 +49,11 @@ struct burn_write_opts
|
||||
*/
|
||||
int force_is_set;
|
||||
|
||||
/* ts A80412 : whether to use WRITE12 with Streaming bit set
|
||||
rather than WRITE10. Speeds up DVD-RAM. Might help with BD-RE.
|
||||
This gets transferred to burn_drive.do_stream_recording */
|
||||
int do_stream_recording;
|
||||
|
||||
/** A disc can have a media catalog number */
|
||||
int has_mediacatalog;
|
||||
unsigned char mediacatalog[13];
|
||||
|
@ -42,15 +42,31 @@ SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH
|
||||
|
||||
/* The maximum size for a (SCSI) i/o transaction */
|
||||
/* Important : MUST be at least 32768 ! */
|
||||
/* ts A70523 : >32k seems not good with kernel 2.4 USB drivers and audio
|
||||
#define BURN_OS_TRANSPORT_BUFFER_SIZE 32768
|
||||
*/
|
||||
/* ts A80414 : curbed in write.c CD media to Libburn_cd_obS = 32 kiB
|
||||
re-enlarged transport to 64 kiB for BD-RE experiments
|
||||
*/
|
||||
#define BURN_OS_TRANSPORT_BUFFER_SIZE 65536
|
||||
|
||||
|
||||
/* To hold the index number of the most recently delivered address from
|
||||
/* To hold the position of the most recently delivered address from
|
||||
device enumeration.
|
||||
*/
|
||||
#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
|
||||
typedef int burn_drive_enumerator_t;
|
||||
struct burn_drive_enumerator_struct {
|
||||
int pos;
|
||||
int info_count;
|
||||
char **info_list;
|
||||
};
|
||||
|
||||
#define BURN_OS_DEFINE_DRIVE_ENUMERATOR_T \
|
||||
typedef struct burn_drive_enumerator_struct burn_drive_enumerator_t;
|
||||
|
||||
|
||||
/* Parameters for sibling list. See sibling_fds, sibling_fnames */
|
||||
#define BURN_OS_SG_MAX_SIBLINGS 5
|
||||
#define BURN_OS_SG_MAX_NAMELEN 16
|
||||
|
||||
/* The list of operating system dependent elements in struct burn_drive.
|
||||
Usually they are initialized in sg-*.c:enumerate_common().
|
||||
@ -60,5 +76,7 @@ int fd; \
|
||||
\
|
||||
/* ts A60926 : trying to lock against growisofs /dev/srN, /dev/scdN */ \
|
||||
int sibling_count; \
|
||||
int sibling_fds[LIBBURN_SG_MAX_SIBLINGS];
|
||||
int sibling_fds[BURN_OS_SG_MAX_SIBLINGS]; \
|
||||
/* ts A70409 : DDLP */ \
|
||||
char sibling_fnames[BURN_OS_SG_MAX_SIBLINGS][BURN_OS_SG_MAX_NAMELEN];
|
||||
|
||||
|
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 */
|
||||
if(!(flag & 4))
|
||||
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;
|
||||
}
|
||||
if (!(flag & 2))
|
||||
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;
|
||||
}
|
||||
|
@ -3,39 +3,76 @@
|
||||
/* scsi block commands */
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "transport.h"
|
||||
#include "sbc.h"
|
||||
#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 char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
|
||||
static char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
|
||||
static char SBC_START_UNIT[] = { 0x1b, 0, 0, 0, 1, 0 };
|
||||
static unsigned char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
|
||||
static unsigned char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
|
||||
static unsigned char SBC_START_UNIT[] = { 0x1b, 0, 0, 0, 1, 0 };
|
||||
|
||||
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));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SBC_LOAD);
|
||||
c.dir = NO_TRANSFER;
|
||||
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);
|
||||
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;
|
||||
|
||||
c.page = NULL;
|
||||
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 = 1;
|
||||
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 ? */
|
||||
@ -43,13 +80,25 @@ 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));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SBC_START_UNIT);
|
||||
c.dir = NO_TRANSFER;
|
||||
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) */
|
||||
@ -218,7 +223,8 @@ static unsigned char *get_sector(struct burn_write_opts *opts,
|
||||
seclen += burn_subcode_length(outmode);
|
||||
|
||||
/* ts A61219 : opts->obs is eventually a 32k trigger for DVD */
|
||||
if (out->bytes + (seclen) > BUFFER_SIZE || out->bytes == opts->obs) {
|
||||
if (out->bytes + seclen > BUFFER_SIZE ||
|
||||
(opts->obs > 0 && out->bytes + seclen > opts->obs)) {
|
||||
int err;
|
||||
err = d->write(d, d->nwa, out);
|
||||
if (err == BE_CANCELLED)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
1125
libburn/sg-linux.c
@ -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*/
|
||||
|
315
libburn/spc.c
@ -27,9 +27,15 @@
|
||||
#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 */
|
||||
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 255, 0 };
|
||||
/* ts A70519 : allocation length byte 3+4 was 0,255 */
|
||||
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 36, 0 };
|
||||
|
||||
/*static char SPC_TEST[]={0,0,0,0,0,0};*/
|
||||
static unsigned char SPC_PREVENT[] = { 0x1e, 0, 0, 0, 1, 0 };
|
||||
@ -40,28 +46,144 @@ static unsigned char SPC_MODE_SELECT[] =
|
||||
static unsigned char SPC_REQUEST_SENSE[] = { 0x03, 0, 0, 0, 18, 0 };
|
||||
static unsigned char SPC_TEST_UNIT_READY[] = { 0x00, 0, 0, 0, 0, 0 };
|
||||
|
||||
int spc_test_unit_ready(struct burn_drive *d)
|
||||
|
||||
/* ts A70519 : An initializer for the abstract SCSI command structure */
|
||||
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen)
|
||||
{
|
||||
if (oplen > 16)
|
||||
return 0;
|
||||
memcpy(c->opcode, opcode, oplen);
|
||||
c->oplen = oplen;
|
||||
c->dir = NO_TRANSFER;
|
||||
c->dxfer_len = -1;
|
||||
memset(c->sense, 0, sizeof(c->sense));
|
||||
c->error = 0;
|
||||
c->retry = 0;
|
||||
c->page = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq)
|
||||
{
|
||||
struct command c;
|
||||
|
||||
c.retry = 0;
|
||||
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);
|
||||
memcpy(c.opcode, SPC_TEST_UNIT_READY, sizeof(SPC_TEST_UNIT_READY));
|
||||
c.page = NULL;
|
||||
*/
|
||||
c.retry = 0;
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
if (c.error)
|
||||
if (c.error) {
|
||||
*key= c.sense[2];
|
||||
*asc= c.sense[12];
|
||||
*ascq= c.sense[13];
|
||||
return (c.sense[2] & 0xF) == 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int spc_test_unit_ready(struct burn_drive *d)
|
||||
{
|
||||
int key,asc,ascq;
|
||||
|
||||
return spc_test_unit_ready_r(d, &key, &asc, &ascq);
|
||||
}
|
||||
|
||||
|
||||
/* ts A70315 */
|
||||
/** @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, char *cmd_text,
|
||||
int flag)
|
||||
{
|
||||
int i, ret = 1, key = 0, asc = 0, ascq = 0;
|
||||
char msg[160];
|
||||
|
||||
if (!(flag & 1))
|
||||
usleep(100000);
|
||||
for(i = !(flag & 1); i < max_sec * 10; i++) {
|
||||
ret = spc_test_unit_ready_r(d, &key, &asc, &ascq);
|
||||
|
||||
/* <<<
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
/*
|
||||
c.oplen = sizeof(SPC_REQUEST_SENSE);
|
||||
memcpy(c.opcode, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
|
||||
*/
|
||||
c.dxfer_len= c.opcode[4];
|
||||
c.retry = 0;
|
||||
c.page = buf;
|
||||
c.page->sectors = 0;
|
||||
c.page->bytes = 0;
|
||||
@ -73,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];
|
||||
}
|
||||
@ -83,24 +208,32 @@ 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));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_INQUIRY);
|
||||
*/
|
||||
c.dxfer_len= (c.opcode[3] << 8) | c.opcode[4];
|
||||
c.retry = 1;
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
c.page->sectors = 0;
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
|
||||
id = (struct burn_scsi_inquiry_data *)d->idata;
|
||||
id->vendor[8] = 0;
|
||||
id->product[16] = 0;
|
||||
id->revision[4] = 0;
|
||||
|
||||
memset(id->vendor, 0, 9);
|
||||
memset(id->product, 0, 17);
|
||||
memset(id->revision, 0, 5);
|
||||
if (c.error) {
|
||||
id->valid = -1;
|
||||
return;
|
||||
}
|
||||
memcpy(id->vendor, c.page->data + 8, 8);
|
||||
memcpy(id->product, c.page->data + 16, 16);
|
||||
memcpy(id->revision, c.page->data + 32, 4);
|
||||
|
||||
id->valid = 1;
|
||||
return;
|
||||
}
|
||||
@ -109,10 +242,16 @@ 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));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_PREVENT);
|
||||
c.page = NULL;
|
||||
*/
|
||||
c.retry = 1;
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
}
|
||||
@ -121,19 +260,30 @@ 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));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_ALLOW);
|
||||
c.page = NULL;
|
||||
*/
|
||||
c.retry = 1;
|
||||
c.dir = NO_TRANSFER;
|
||||
d->issue_command(d, &c);
|
||||
}
|
||||
|
||||
void spc_sense_caps(struct burn_drive *d)
|
||||
/*
|
||||
ts A70518 : Do not call with *alloc_len < 8
|
||||
*/
|
||||
/** flag&1= do only inquire alloc_len */
|
||||
static int spc_sense_caps_al(struct burn_drive *d, int *alloc_len, int flag)
|
||||
{
|
||||
struct buffer buf;
|
||||
struct scsi_mode_data *m;
|
||||
int size, page_length, num_write_speeds = 0, i, speed, ret;
|
||||
int old_alloc_len, was_error = 0;
|
||||
unsigned char *page;
|
||||
struct command c;
|
||||
struct burn_speed_descriptor *sd;
|
||||
@ -141,15 +291,30 @@ void spc_sense_caps(struct burn_drive *d)
|
||||
/* ts A61225 : 1 = report about post-MMC-1 speed descriptors */
|
||||
static int speed_debug = 0;
|
||||
|
||||
if (*alloc_len < 8)
|
||||
return 0;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SENSE);
|
||||
*/
|
||||
c.dxfer_len = *alloc_len;
|
||||
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
|
||||
c.opcode[8] = c.dxfer_len & 0xff;
|
||||
c.retry = 1;
|
||||
c.opcode[2] = 0x2A;
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
c.page->sectors = 0;
|
||||
c.dir = FROM_DRIVE;
|
||||
d->issue_command(d, &c);
|
||||
if (c.error) {
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
d->mdata->valid = -1;
|
||||
was_error = 1;
|
||||
}
|
||||
|
||||
size = c.page->data[0] * 256 + c.page->data[1];
|
||||
m = d->mdata;
|
||||
@ -162,6 +327,14 @@ void spc_sense_caps(struct burn_drive *d)
|
||||
set of speed descriptors. In MMC-5 E.11 it is declared "legacy".
|
||||
*/
|
||||
page_length = page[1];
|
||||
old_alloc_len = *alloc_len;
|
||||
*alloc_len = page_length + 8;
|
||||
if (flag & 1)
|
||||
return !was_error;
|
||||
if (page_length + 8 > old_alloc_len)
|
||||
page_length = old_alloc_len - 8;
|
||||
if (page_length < 22)
|
||||
return 0;
|
||||
|
||||
m->valid = 0;
|
||||
burn_mdata_free_subs(m);
|
||||
@ -211,6 +384,18 @@ void spc_sense_caps(struct burn_drive *d)
|
||||
|
||||
num_write_speeds = page[30] * 256 + page[31];
|
||||
m->max_write_speed = m->min_write_speed = m->cur_write_speed;
|
||||
|
||||
if (32 + 4 * num_write_speeds > page_length + 2) {
|
||||
char msg[161];
|
||||
|
||||
sprintf(msg, "Malformed capabilities page 2Ah received (len=%d, #speeds=%d)", page_length, num_write_speeds);
|
||||
libdax_msgs_submit(libdax_messenger, d->global_index,
|
||||
0x0002013c,
|
||||
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
||||
msg, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_write_speeds; i++) {
|
||||
speed = page[32 + 4*i + 2] * 256 + page[32 + 4*i + 3];
|
||||
|
||||
@ -252,6 +437,27 @@ try_mmc_get_performance:;
|
||||
fprintf(stderr,
|
||||
"LIBBURN_DEBUG: ACh min_write_speed = %d , max_write_speed = %d\n",
|
||||
m->min_write_speed, m->max_write_speed);
|
||||
return !was_error;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
/*
|
||||
fprintf(stderr,"LIBBURN_DEBUG: 5Ah alloc_len = %d , ret = %d\n",
|
||||
alloc_len, ret);
|
||||
*/
|
||||
if (alloc_len >= start_len && ret > 0)
|
||||
/* second execution with announced length */
|
||||
spc_sense_caps_al(d, &alloc_len, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -259,13 +465,22 @@ void spc_sense_error_params(struct burn_drive *d)
|
||||
{
|
||||
struct buffer buf;
|
||||
struct scsi_mode_data *m;
|
||||
int size;
|
||||
int size, alloc_len = 12 ;
|
||||
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));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SENSE);
|
||||
*/
|
||||
c.dxfer_len = alloc_len;
|
||||
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
|
||||
c.opcode[8] = c.dxfer_len & 0xff;
|
||||
c.retry = 1;
|
||||
c.opcode[2] = 0x01;
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
@ -287,9 +502,15 @@ 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));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SELECT);
|
||||
*/
|
||||
c.retry = 1;
|
||||
c.opcode[8] = 8 + 2 + d->mdata->retry_page_length;
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
@ -318,17 +539,26 @@ void spc_sense_write_params(struct burn_drive *d)
|
||||
{
|
||||
struct buffer buf;
|
||||
struct scsi_mode_data *m;
|
||||
int size, dummy;
|
||||
int size, dummy, alloc_len = 10;
|
||||
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); */
|
||||
|
||||
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SENSE);
|
||||
*/
|
||||
c.dxfer_len = alloc_len;
|
||||
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
|
||||
c.opcode[8] = c.dxfer_len & 0xff;
|
||||
c.retry = 1;
|
||||
c.opcode[2] = 0x05;
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
@ -336,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;
|
||||
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;
|
||||
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)) {
|
||||
@ -373,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); */
|
||||
|
||||
@ -383,9 +620,12 @@ void spc_select_write_params(struct burn_drive *d,
|
||||
o->block_type,spc_block_type(o->block_type));
|
||||
*/
|
||||
|
||||
scsi_init_command(&c, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SELECT);
|
||||
*/
|
||||
c.retry = 1;
|
||||
c.opcode[8] = 8 + 2 + d->mdata->write_page_length;
|
||||
c.page = &buf;
|
||||
c.page->bytes = 0;
|
||||
@ -410,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);
|
||||
@ -429,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,
|
||||
@ -443,9 +689,12 @@ void spc_probe_write_modes(struct burn_drive *d)
|
||||
try_block_type = useable_block_type;
|
||||
last_try= 1;
|
||||
}
|
||||
scsi_init_command(&c, SPC_MODE_SELECT,sizeof(SPC_MODE_SELECT));
|
||||
/*
|
||||
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
|
||||
c.retry = 1;
|
||||
c.oplen = sizeof(SPC_MODE_SELECT);
|
||||
*/
|
||||
c.retry = 1;
|
||||
c.opcode[8] = 8 + 2 + 0x32;
|
||||
c.page = &buf;
|
||||
|
||||
@ -592,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) {
|
||||
@ -605,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)
|
||||
|
@ -20,8 +20,17 @@ void spc_probe_write_modes(struct burn_drive *);
|
||||
void spc_request_sense(struct burn_drive *d, struct buffer *buf);
|
||||
int spc_block_type(enum burn_block_types b);
|
||||
int spc_get_erase_progress(struct burn_drive *d);
|
||||
|
||||
/* ts A70315 : test_unit_ready with result parameters */
|
||||
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq);
|
||||
|
||||
int spc_test_unit_ready(struct burn_drive *d);
|
||||
|
||||
/* ts A70315 */
|
||||
/** Wait until the drive state becomes clear in or until max_sec elapsed */
|
||||
int spc_wait_unit_attention(struct burn_drive *d, int max_sec, char *cmd_text,
|
||||
int flag);
|
||||
|
||||
/* ts A61021 : the spc specific part of sg.c:enumerate_common()
|
||||
*/
|
||||
int spc_setup_drive(struct burn_drive *d);
|
||||
@ -47,4 +56,7 @@ enum response scsi_error_msg(struct burn_drive *d, unsigned char *sense,
|
||||
int scsi_notify_error(struct burn_drive *, struct command *c,
|
||||
unsigned char *sense, int senselen, int flag);
|
||||
|
||||
/* ts A70519 */
|
||||
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen);
|
||||
|
||||
#endif /*__SPC*/
|
||||
|
@ -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;
|
||||
@ -324,11 +330,19 @@ void burn_track_clear_isrc(struct burn_track *t)
|
||||
int burn_track_get_sectors(struct burn_track *t)
|
||||
{
|
||||
/* ts A70125 : was int */
|
||||
off_t size;
|
||||
off_t size = 0;
|
||||
int sectors, seclen;
|
||||
|
||||
seclen = burn_sector_length(t->mode);
|
||||
size = t->offset + t->source->get_size(t->source) + t->tail;
|
||||
if (t->source != NULL) /* ts A80808 : mending sigsegv */
|
||||
size = t->offset + t->source->get_size(t->source) + t->tail;
|
||||
else if(t->entry != NULL) {
|
||||
/* ts A80808 : all burn_toc_entry of track starts should now
|
||||
have (extensions_valid & 1), even those from CD.
|
||||
*/
|
||||
if (t->entry->extensions_valid & 1)
|
||||
size = ((off_t) t->entry->track_blocks) * (off_t) 2048;
|
||||
}
|
||||
sectors = size / seclen;
|
||||
if (size % seclen)
|
||||
sectors++;
|
||||
@ -353,9 +367,13 @@ int burn_track_set_sectors(struct burn_track *t, int sectors)
|
||||
}
|
||||
|
||||
|
||||
/* ts A70218 */
|
||||
/* ts A70218 , API since A70328 */
|
||||
int burn_track_set_size(struct burn_track *t, off_t size)
|
||||
{
|
||||
if (t->source == NULL)
|
||||
return 0;
|
||||
if (t->source->set_size == NULL)
|
||||
return 0;
|
||||
t->open_ended = (size <= 0);
|
||||
return t->source->set_size(t->source, size);
|
||||
}
|
||||
@ -458,6 +476,7 @@ int burn_session_get_sectors(struct burn_session *s)
|
||||
return sectors;
|
||||
}
|
||||
|
||||
|
||||
int burn_disc_get_sectors(struct burn_disc *d)
|
||||
{
|
||||
int sectors = 0, i;
|
||||
@ -505,3 +524,40 @@ int burn_session_get_hidefirst(struct burn_session *session)
|
||||
{
|
||||
return session->hidefirst;
|
||||
}
|
||||
|
||||
|
||||
/* ts A80808 : Enhance CD toc to DVD toc */
|
||||
int burn_disc_cd_toc_extensions(struct burn_disc *d, int flag)
|
||||
{
|
||||
int sidx, tidx;
|
||||
struct burn_toc_entry *entry, *prev_entry= NULL;
|
||||
|
||||
for (sidx = 0; sidx < d->sessions; sidx++) {
|
||||
for (tidx = 0; tidx < d->session[sidx]->tracks + 1; tidx++) {
|
||||
if (tidx < d->session[sidx]->tracks)
|
||||
entry = d->session[sidx]->track[tidx]->entry;
|
||||
else
|
||||
entry = d->session[sidx]->leadout_entry;
|
||||
entry->session_msb = 0;
|
||||
entry->point_msb = 0;
|
||||
entry->start_lba = burn_msf_to_lba(entry->pmin,
|
||||
entry->psec, entry->pframe);
|
||||
if (tidx > 0) {
|
||||
prev_entry->track_blocks =
|
||||
entry->start_lba
|
||||
- prev_entry->start_lba;
|
||||
prev_entry->extensions_valid |= 1;
|
||||
}
|
||||
if (tidx == d->session[sidx]->tracks) {
|
||||
entry->session_msb = 0;
|
||||
entry->point_msb = 0;
|
||||
entry->track_blocks = 0;
|
||||
entry->extensions_valid |= 1;
|
||||
}
|
||||
prev_entry = entry;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -109,4 +109,8 @@ int burn_track_apply_fillup(struct burn_track *t, off_t max_size, int flag);
|
||||
off_t burn_track_get_default_size(struct burn_track *t);
|
||||
|
||||
|
||||
/* ts A80808 : Enhance CD toc to DVD toc */
|
||||
int burn_disc_cd_toc_extensions(struct burn_disc *d, int flag);
|
||||
|
||||
|
||||
#endif /* BURN__STRUCTURE_H */
|
||||
|
@ -128,9 +128,14 @@ void toc_find_modes(struct burn_drive *d)
|
||||
if (e && !(e->control & 4)) {
|
||||
t->mode = BURN_AUDIO;
|
||||
} else {
|
||||
|
||||
t->mode = BURN_MODE1;
|
||||
/* ts A70519 : this does not work with Linux 2.4 USB because one cannot
|
||||
predict the exact dxfer_size without knowing the sector type.
|
||||
mem.sectors = 1;
|
||||
d->read_sectors(d, lba, mem.sectors, &o, &mem);
|
||||
t->mode = sector_identify(mem.data);
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ struct command
|
||||
unsigned char opcode[16];
|
||||
int oplen;
|
||||
int dir;
|
||||
int dxfer_len;
|
||||
unsigned char sense[128];
|
||||
int error;
|
||||
int retry;
|
||||
@ -113,15 +114,21 @@ struct burn_format_descr {
|
||||
off_t size;
|
||||
|
||||
/* the Type Dependent Parameter (usually the write alignment size) */
|
||||
unsigned tdp;
|
||||
unsigned int tdp;
|
||||
};
|
||||
|
||||
|
||||
#define LIBBURN_SG_MAX_SIBLINGS 16
|
||||
|
||||
/** 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;
|
||||
@ -173,9 +180,17 @@ 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 A80412 : whether to use WRITE12 with Streaming bit set
|
||||
rather than WRITE10. Speeds up DVD-RAM. Might help
|
||||
with BD-RE */
|
||||
int do_stream_recording;
|
||||
|
||||
/* ts A61218 from 51h READ DISC INFORMATION */
|
||||
int bg_format_status; /* 0=needs format start, 1=needs format restart*/
|
||||
@ -183,7 +198,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;
|
||||
|
||||
@ -197,6 +212,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 */
|
||||
@ -225,8 +242,29 @@ struct burn_drive
|
||||
struct buffer *buffer;
|
||||
struct burn_progress progress;
|
||||
|
||||
/* ts A70711 : keeping an eye on the drive buffer */
|
||||
off_t pessimistic_buffer_free;
|
||||
int pbf_altered;
|
||||
int wait_for_buffer_free;
|
||||
int nominal_write_speed;
|
||||
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 *);
|
||||
@ -306,8 +344,18 @@ 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 */
|
||||
|
||||
/* ts A80422 : centralizing this setting for debugging purposes
|
||||
*/
|
||||
int burn_drive_set_media_capacity_remaining(struct burn_drive *d, off_t value);
|
||||
|
||||
|
||||
#endif /* __TRANSPORT */
|
||||
|
@ -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
|
||||
}
|
||||
|
886
libburn/write.c
1503
libcevap/cgen.c
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
@ -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
@ -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
@ -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
@ -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
@ -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
After Width: | Height: | Size: 10 KiB |
BIN
libcevap/libdax_job.gif
Normal file
After Width: | Height: | Size: 10 KiB |
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
After Width: | Height: | Size: 12 KiB |
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
@ -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
@ -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.
|
||||
|
||||
*/
|
154
test/libburner.c
@ -1,15 +1,16 @@
|
||||
|
||||
/* 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
|
||||
blank a CD-RW or DVD-RW, can format a DVD-RW, and can burn to CD-R, CD-RW,
|
||||
DVD+RW, DVD-RAM or DVD-RW. Not supported yet: DVD+R [DL].
|
||||
on http://libburnia-project.org . It can list the available devices, can
|
||||
blank a CD-RW or DVD-RW, can format DVD-RW and BD-RE, can burn to CD-R,
|
||||
CD-RW, DVD-R, DVD+R, DVD+R/DL, DVD+RW, DVD-RW, DVD-RAM, BD-RE.
|
||||
Not supported yet: DVD-R/DL, BD-R.
|
||||
|
||||
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
|
||||
@ -28,8 +29,9 @@
|
||||
With that aquired drive you can blank a CD-RW
|
||||
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
|
||||
or an unused BD-RE to default size
|
||||
libburner_format_owrt()
|
||||
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 +125,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",
|
||||
drive_adr);
|
||||
return ret;
|
||||
fprintf(stderr, "Address does not lead to a CD burner: '%s'\n",
|
||||
drive_adr);
|
||||
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 +172,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;
|
||||
@ -306,26 +315,45 @@ int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
|
||||
}
|
||||
|
||||
|
||||
/** Persistently changes DVD-RW profile 0014h "Sequential Recording" to
|
||||
profile 0013h "Restricted Overwrite" which needs no blanking for re-use
|
||||
but is not capable of multi-session.
|
||||
|
||||
/** Formats unformatted DVD-RW to profile 0013h "Restricted Overwrite"
|
||||
which needs no blanking for re-use but is not capable of multi-session.
|
||||
Expect a behavior similar to blanking with unusual noises from the drive.
|
||||
|
||||
Formats unformatted BD-RE to default size. This will allocate some
|
||||
reserve space, test for bad blocks and make the media ready for writing.
|
||||
Expect a very long run time.
|
||||
*/
|
||||
int libburner_format_row(struct burn_drive *drive)
|
||||
int libburner_format_owrt(struct burn_drive *drive)
|
||||
{
|
||||
struct burn_progress p;
|
||||
double percent = 1.0;
|
||||
int ret, status, num_formats, format_flag= 0;
|
||||
off_t size = 0;
|
||||
unsigned dummy;
|
||||
|
||||
if (current_profile == 0x13) {
|
||||
fprintf(stderr, "IDLE: DVD-RW media is already formatted\n");
|
||||
return 2;
|
||||
} else if (current_profile != 0x14) {
|
||||
fprintf(stderr, "FATAL: Can only format DVD-RW\n");
|
||||
} else if (current_profile == 0x43) {
|
||||
ret = burn_disc_get_formats(drive, &status, &size, &dummy,
|
||||
&num_formats);
|
||||
if (ret > 0 && status == BURN_FORMAT_IS_FORMATTED) {
|
||||
fprintf(stderr,
|
||||
"IDLE: BD-RE media is already formatted\n");
|
||||
return 2;
|
||||
}
|
||||
size = 0; /* does not really matter */
|
||||
format_flag = 3<<1; /* format to default size, no quick */
|
||||
} else if (current_profile == 0x14) { /* sequential DVD-RW */
|
||||
size = 128 * 1024 * 1024;
|
||||
format_flag = 1; /* write initial 128 MiB */
|
||||
} else {
|
||||
fprintf(stderr, "FATAL: Can only format DVD-RW or BD-RE\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("Beginning to format media.\n");
|
||||
burn_disc_format(drive, (off_t) 0, 0);
|
||||
burn_disc_format(drive, size, format_flag);
|
||||
|
||||
sleep(1);
|
||||
while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
|
||||
@ -337,9 +365,10 @@ int libburner_format_row(struct burn_drive *drive)
|
||||
}
|
||||
burn_disc_get_profile(drive_list[0].drive, ¤t_profile,
|
||||
current_profile_name);
|
||||
printf("Media type now: %4.4xh \"%s\"\n",
|
||||
current_profile, current_profile_name);
|
||||
if (current_profile != 0x13) {
|
||||
if (current_profile == 0x14 || current_profile == 0x13)
|
||||
printf("Media type now: %4.4xh \"%s\"\n",
|
||||
current_profile, current_profile_name);
|
||||
if (current_profile == 0x14) {
|
||||
fprintf(stderr,
|
||||
"FATAL: Failed to change media profile to desired value\n");
|
||||
return 0;
|
||||
@ -350,8 +379,12 @@ int libburner_format_row(struct burn_drive *drive)
|
||||
|
||||
/** Brings preformatted track images (ISO 9660, audio, ...) onto media.
|
||||
To make sure a data image is fully readable on any Linux machine, this
|
||||
function adds 300 kB of padding to the (usualy single) track.
|
||||
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 +396,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,14 +405,17 @@ 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;
|
||||
|
||||
if (all_tracks_type != BURN_AUDIO) {
|
||||
all_tracks_type = BURN_MODE1;
|
||||
/* a padding of 300 kB helps to avoid the read-ahead bug */
|
||||
/* 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 +426,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 +440,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 +453,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,29 +515,49 @@ 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 &&
|
||||
current_profile != 0x12) /* not with DVD+RW, DVD-RW, DVD-RAM */
|
||||
current_profile != 0x12 && current_profile != 0x43)
|
||||
/* not with DVD+RW, formatted DVD-RW, DVD-RAM, BD-RE */
|
||||
printf("NOTE: Media left appendable.\n");
|
||||
if (simulate_burn)
|
||||
printf("\n*** Did TRY to SIMULATE burning ***\n\n");
|
||||
@ -620,7 +694,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 {
|
||||
@ -646,7 +720,7 @@ int main(int argc, char **argv)
|
||||
{ ret = 0; goto release_drive; }
|
||||
if (do_blank) {
|
||||
if (do_blank > 100)
|
||||
ret = libburner_format_row(drive_list[driveno].drive);
|
||||
ret = libburner_format_owrt(drive_list[driveno].drive);
|
||||
else
|
||||
ret = libburner_blank_disc(drive_list[driveno].drive,
|
||||
do_blank == 1);
|
||||
|
133
test/open-cd-excl.c
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* open-cd-excl.c --- This program tries to open a block device
|
||||
* by various exclusive and non-exclusive gestures in order to explore
|
||||
* their impact on running CD/DVD recordings.
|
||||
*
|
||||
* Copyright 2007, by Theodore Ts'o.
|
||||
*
|
||||
* Detail modifications 2007, by Thomas Schmitt.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* for O_LARGEFILE *//*ts A70417: or _LARGEFILE64_SOURCE */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
|
||||
const char *progname;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-feirw] device\n", progname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* ts A70417: added parameter do_rdwr */
|
||||
static void init_flock(struct flock *fl, int do_rdwr)
|
||||
{
|
||||
memset(fl, 0, sizeof(struct flock));
|
||||
if (do_rdwr)
|
||||
fl->l_type = F_WRLCK;
|
||||
else
|
||||
fl->l_type = F_RDLCK;
|
||||
fl->l_whence = SEEK_SET;
|
||||
fl->l_start = 0;
|
||||
fl->l_len = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct flock fl;
|
||||
char *device_name;
|
||||
int fd, c, f_opt = 0, do_rdwr = 0, end_immediately = 0;
|
||||
int flags = O_NONBLOCK|O_LARGEFILE;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
/* ts A70417: added -w , -r , -i */
|
||||
while ((c = getopt (argc, argv, "feirw")) != EOF) {
|
||||
switch (c) {
|
||||
case 'e':
|
||||
flags |= O_EXCL;
|
||||
break;
|
||||
case 'f':
|
||||
f_opt++;
|
||||
break;
|
||||
case 'i':
|
||||
end_immediately = 1;
|
||||
break;
|
||||
case 'r':
|
||||
do_rdwr = 0;
|
||||
break;
|
||||
case 'w':
|
||||
do_rdwr = 1;
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc)
|
||||
usage();
|
||||
device_name = argv[optind++];
|
||||
|
||||
/* ts A70417 : made read-write adjustable independently of f_opt */
|
||||
if (do_rdwr) {
|
||||
flags |= O_RDWR;
|
||||
printf("Using O_RDWR\n");
|
||||
} else {
|
||||
flags |= O_RDONLY;
|
||||
printf("Using O_RDONLY\n");
|
||||
}
|
||||
|
||||
if (flags & O_EXCL)
|
||||
printf("Trying to open %s with O_EXCL ...\n", device_name);
|
||||
fd = open(device_name, flags, 0);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
printf("failed\n");
|
||||
exit(1);
|
||||
}
|
||||
if (flags & O_EXCL)
|
||||
printf("succeeded\n");
|
||||
|
||||
if (f_opt) {
|
||||
init_flock(&fl, do_rdwr);
|
||||
if (fcntl(fd, F_GETLK, &fl) < 0) {
|
||||
perror("fcntl: F_GETLK: ");
|
||||
exit(1);
|
||||
}
|
||||
printf("fcntl lock apparently %sLOCKED\n",
|
||||
(fl.l_type == F_UNLCK) ? "NOT " : "");
|
||||
|
||||
init_flock(&fl, do_rdwr);
|
||||
printf("Trying to grab fcntl lock...\n");
|
||||
if (fcntl(fd, F_SETLK, &fl) < 0) {
|
||||
perror("fcntl: F_SETLK: ");
|
||||
printf("failed\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("succeeded\n");
|
||||
}
|
||||
|
||||
/* ts A70417: added end_immediately */
|
||||
printf("Holding %s open.\n", device_name);
|
||||
usleep(100000);
|
||||
if (end_immediately)
|
||||
exit(0);
|
||||
printf("Press ^C to exit.\n");
|
||||
while (1) {
|
||||
sleep(300);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
return 0;
|
||||
}
|
226
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
|
||||
@ -312,6 +336,11 @@ int telltoc_media(struct burn_drive *drive)
|
||||
caps->advised_write_mode == BURN_WRITE_RAW ?
|
||||
" (advised)" : "");
|
||||
printf("\n");
|
||||
printf("Write dummy : ");
|
||||
if (caps->might_simulate)
|
||||
printf("supposed to work with non-RAW modes\n");
|
||||
else
|
||||
printf("will not work\n");
|
||||
o= burn_write_opts_new(drive);
|
||||
if (o != NULL) {
|
||||
burn_write_opts_set_perform_opc(o, 0);
|
||||
@ -438,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;
|
||||
@ -474,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);
|
||||
@ -489,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);
|
||||
@ -553,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;
|
||||
@ -561,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.
|
||||
@ -603,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;
|
||||
|
||||
@ -617,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]);
|
||||
@ -630,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;
|
||||
}
|
||||
@ -651,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 {
|
||||
@ -666,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);
|
||||
@ -704,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)
|
||||
|